59 lines
3.7 KiB
JavaScript
59 lines
3.7 KiB
JavaScript
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs/promises')
|
|
const path = require('node:path')
|
|
const os = require('node:os')
|
|
const { build } = require('esbuild')
|
|
|
|
async function main() {
|
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'ycode-projects-'))
|
|
try {
|
|
const bundle = path.join(root, 'projects.cjs')
|
|
await build({ entryPoints: [path.resolve('src/main/projects.ts')], bundle: true, platform: 'node', format: 'cjs', outfile: bundle, logLevel: 'silent' })
|
|
const { ProjectRepository, buildProjectPrompt } = require(bundle)
|
|
const filename = path.join(root, 'data', 'projects.json')
|
|
const repository = new ProjectRepository(filename)
|
|
const input = { name: ' 项目测试 ', instructions: ' 项目约束 ', experts: [{ id: 'expert', source: 'local' }], skills: [{ id: 'skill', source: 'market', provider: 'skillhub' }], connectors: ['mcp', 'mcp'], templateId: 'custom' }
|
|
assert.deepEqual(await repository.list(), [])
|
|
const created = await Promise.all(Array.from({ length: 12 }, (_, i) => repository.create({ ...input, name: `项目${i}` })))
|
|
assert.equal(new Set(created.map(item => item.projectId)).size, 12)
|
|
const reloaded = await new ProjectRepository(filename).list()
|
|
assert.equal(reloaded.length, 12)
|
|
assert.deepEqual(new Set(reloaded.map(item => item.projectId)), new Set(created.map(item => item.projectId)))
|
|
assert.equal(reloaded[0].instructions, '项目约束')
|
|
assert.deepEqual(reloaded[0].connectors, ['mcp'])
|
|
assert.deepEqual(reloaded[0].experts, input.experts)
|
|
assert.deepEqual(reloaded[0].skills, input.skills)
|
|
assert.equal((await repository.get(created[0].projectId)).projectId, created[0].projectId)
|
|
await assert.rejects(repository.get('missing-project'))
|
|
assert.equal(buildProjectPrompt(undefined), '')
|
|
assert.equal(buildProjectPrompt({ ...created[0], instructions: ' ' }), '')
|
|
assert.equal(buildProjectPrompt(created[0]), '项目:项目0\n项目指令:\n项目约束')
|
|
assert.ok(!buildProjectPrompt(created[0]).includes('skillhub'))
|
|
await Promise.all([
|
|
repository.update(created[0].projectId, { name: '改名项目' }),
|
|
repository.update(created[0].projectId, { instructions: '更新后的项目指令' })
|
|
])
|
|
const edited = await new ProjectRepository(filename).get(created[0].projectId)
|
|
assert.equal(edited.name, '改名项目')
|
|
assert.equal(edited.instructions, '更新后的项目指令')
|
|
assert.equal(edited.createdAt, created[0].createdAt)
|
|
assert.deepEqual(edited.skills, input.skills)
|
|
await assert.rejects(repository.update(created[0].projectId, { projectId: 'forged' }))
|
|
await assert.rejects(repository.update('missing-project', { name: '不存在' }))
|
|
await assert.rejects(repository.update(created[0].projectId, { name: '' }))
|
|
assert.deepEqual(await repository.get(created[0].projectId), edited)
|
|
await assert.rejects(repository.create({ ...input, name: ' ' }))
|
|
await assert.rejects(repository.create({ ...input, name: '1234567890123456' }))
|
|
await assert.rejects(repository.create({ ...input, experts: [{ id: '../x', source: 'invalid' }] }))
|
|
assert.equal((await repository.list()).length, 12)
|
|
await repository.create({ ...input, name: '恢复写入' })
|
|
assert.equal((await repository.list()).length, 13)
|
|
await fs.writeFile(filename, '{broken')
|
|
await assert.rejects(repository.list())
|
|
await assert.rejects(repository.create(input))
|
|
assert.equal(await fs.readFile(filename, 'utf8'), '{broken')
|
|
console.log('PASS project persistence: concurrent creates, reload, references, validation, queue recovery, corruption preservation')
|
|
} finally { await fs.rm(root, { recursive: true, force: true }) }
|
|
}
|
|
main().catch(error => { console.error(error); process.exitCode = 1 })
|