built-migration-worker.e2e.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import { existsSync } from 'node:fs'
  2. import { join } from 'node:path'
  3. import { fileURLToPath } from 'node:url'
  4. import { execa } from 'execa'
  5. import { describe, expect, it } from 'vitest'
  6. const packageRoot = fileURLToPath(new URL('..', import.meta.url))
  7. const built = ['lib/index.js', 'lib/worker.cjs']
  8. .every(path => existsSync(join(packageRoot, path)))
  9. describe.skipIf(!built)('built migration verifier (plain node)', () => {
  10. it('publishes history and verifies it without runtime workspace imports', async () => {
  11. const script = `
  12. import { copyFile, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
  13. import { tmpdir } from 'node:os'
  14. import { join } from 'node:path'
  15. import { Worker } from 'node:worker_threads'
  16. import { Context } from '@deepseek-ai/cordis'
  17. import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl'
  18. const root = await mkdtemp(join(tmpdir(), 'dsh-built-migration-'))
  19. const id = 'built-migration-worker'
  20. const directory = join(root, '_no-cwd', id)
  21. const ctx = new Context()
  22. try {
  23. await mkdir(directory, { recursive: true })
  24. await writeFile(join(directory, 'session.jsonl'), JSON.stringify({
  25. type: 'session', version: 0, id, createdAt: 1, delegationDepth: 0,
  26. }) + '\\n')
  27. await ctx.plugin(JsonlSessionPersistence, { root, compression: 'none' })
  28. const handle = await ctx.sessionPersistence.open(id, 'write')
  29. await handle.close()
  30. await ctx.sessionPersistence.flush()
  31. const currentPath = join(directory, 'session.v3.jsonl')
  32. const header = JSON.parse((await readFile(currentPath, 'utf8')).trim())
  33. await mkdir(join(root, 'lib'))
  34. await copyFile('package.json', join(root, 'package.json'))
  35. const workerPath = join(root, 'lib', 'worker.cjs')
  36. await copyFile('lib/worker.cjs', workerPath)
  37. async function verify(expectedEventCount) {
  38. const worker = new Worker(workerPath, { workerData: {
  39. path: currentPath, compression: 'none', expectedId: id, expectedEventCount,
  40. } })
  41. try {
  42. return await new Promise((resolve, reject) => {
  43. worker.once('message', resolve)
  44. worker.once('error', reject)
  45. worker.once('exit', code => reject(new Error('verifier exited before a result: ' + code)))
  46. })
  47. } finally {
  48. await worker.terminate()
  49. }
  50. }
  51. const verified = await verify(0)
  52. const refused = await verify(1)
  53. console.log(JSON.stringify({ id: header.id, version: header.version,
  54. verified: verified.ok, refused: refused.ok, refusal: refused.message }))
  55. } finally {
  56. await ctx.fiber.dispose()
  57. await rm(root, { recursive: true, force: true })
  58. }
  59. `
  60. const { exitCode, stdout, stderr } = await execa(
  61. process.execPath,
  62. ['--input-type=module', '-e', script],
  63. {
  64. cwd: packageRoot, env: { NODE_PATH: undefined, NODE_OPTIONS: undefined },
  65. stdin: 'ignore', timeout: 30_000, killSignal: 'SIGKILL', reject: false,
  66. },
  67. )
  68. expect(exitCode, `stderr:\n${stderr}`).toBe(0)
  69. expect(JSON.parse(stdout.trim())).toEqual({
  70. id: 'built-migration-worker', version: 3, verified: true, refused: false,
  71. refusal: 'current session generation contains 0 events, expected 1',
  72. })
  73. })
  74. })