built-lib.e2e.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /** Installed packer/runtime interoperability without either package's source tree. */
  2. import { existsSync } from 'node:fs'
  3. import { mkdir, mkdtemp, readFile, readdir, realpath, rm, symlink, unlink, writeFile } from 'node:fs/promises'
  4. import { tmpdir } from 'node:os'
  5. import { dirname, join } from 'node:path'
  6. import { fileURLToPath } from 'node:url'
  7. import { execa } from 'execa'
  8. import { expect, it } from 'vitest'
  9. import { pnpmInvocation } from '../../../../scripts/pnpm-invocation.ts'
  10. const experimentalDirectory = fileURLToPath(new URL('../..', import.meta.url))
  11. const packages = ['webworker-runtime', 'webworker-packer']
  12. const packageNames = new Set(packages.map(name => `@deepseek-ai/dsh-experimental-${name}`))
  13. it('loads both tarballs through plain Node and mounts their base image and overlay', { retry: 0 }, async (test) => {
  14. const root = await mkdtemp(join(tmpdir(), 'dsh-webworker-packed-'))
  15. const links: string[] = []
  16. let pending: Promise<string> = Promise.resolve('')
  17. test.onTestFinished(async () => {
  18. try {
  19. await pending
  20. } finally {
  21. for (const path of links.reverse()) await unlink(path)
  22. await rm(root, { recursive: true, force: true })
  23. }
  24. })
  25. const run = (command: string, args: string[], cwd: string): Promise<string> => {
  26. pending = execa(command, args, {
  27. cwd,
  28. env: { NODE_OPTIONS: undefined, NODE_PATH: undefined, TSX_TSCONFIG_PATH: undefined },
  29. stdin: 'ignore',
  30. timeout: test.task.timeout,
  31. cancelSignal: test.signal,
  32. killSignal: 'SIGKILL',
  33. reject: false,
  34. }).then((result) => {
  35. expect(result.timedOut, `stderr:\n${result.stderr}`).toBe(false)
  36. expect(result.isCanceled, `stderr:\n${result.stderr}`).toBe(false)
  37. expect(result.signal, `stderr:\n${result.stderr}`).toBeUndefined()
  38. expect(result.exitCode, `stderr:\n${result.stderr}`).toBe(0)
  39. return result.stdout
  40. })
  41. return pending
  42. }
  43. await writeFile(join(root, 'package.json'), JSON.stringify({ private: true, type: 'module' }))
  44. for (const name of packages) {
  45. const source = join(experimentalDirectory, name)
  46. const directory = join(root, 'node_modules/@deepseek-ai', `dsh-experimental-${name}`)
  47. const packRoot = join(root, name)
  48. await mkdir(packRoot, { recursive: true })
  49. await mkdir(directory, { recursive: true })
  50. const invocation = pnpmInvocation(['pack', '--pack-destination', packRoot])
  51. await run(invocation.command, invocation.args, source)
  52. const archives = (await readdir(packRoot)).filter(file => file.endsWith('.tgz'))
  53. expect(archives).toHaveLength(1)
  54. await run('tar', ['-xzf', join(packRoot, archives[0]!), '-C', directory, '--strip-components=1'], root)
  55. expect(existsSync(join(directory, 'src'))).toBe(false)
  56. const manifest = JSON.parse(await readFile(join(directory, 'package.json'), 'utf8')) as {
  57. dependencies?: Record<string, string>
  58. peerDependencies?: Record<string, string>
  59. }
  60. // Only the two subjects resolve from tarballs; their declared external dependencies use the built checkout.
  61. for (const dependency of Object.keys({ ...manifest.dependencies, ...manifest.peerDependencies })) {
  62. if (packageNames.has(dependency)) continue
  63. const target = join(root, 'node_modules', dependency)
  64. if (existsSync(target)) continue
  65. await mkdir(dirname(target), { recursive: true })
  66. await symlink(await realpath(join(source, 'node_modules', dependency)), target, process.platform === 'win32' ? 'junction' : 'dir')
  67. links.push(target)
  68. }
  69. }
  70. const script = `
  71. import assert from 'node:assert/strict'
  72. import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
  73. import { fileURLToPath } from 'node:url'
  74. import * as packer from '@deepseek-ai/dsh-experimental-webworker-packer'
  75. import * as runtime from '@deepseek-ai/dsh-experimental-webworker-runtime'
  76. import * as client from '@deepseek-ai/dsh-experimental-webworker-runtime/client'
  77. for (const name of ['webworker-packer', 'webworker-runtime']) {
  78. assert.equal(import.meta.resolve('@deepseek-ai/dsh-experimental-' + name),
  79. new URL('./node_modules/@deepseek-ai/dsh-experimental-' + name + '/lib/index.js', import.meta.url).href)
  80. }
  81. assert.equal(typeof client.connectWorkerHost, 'function')
  82. const worker = fileURLToPath(import.meta.resolve('@deepseek-ai/dsh-experimental-webworker-runtime/worker'))
  83. assert.ok(existsSync(worker))
  84. assert.equal(readFileSync(worker, 'utf8').match(/^import[ \\t]/m), null)
  85. const base = packer.packVfsImage({ config: '[]\\n', profile: 'packed-consumer', workspaces: new Map(), resolveFrom: process.cwd(), entries: [] })
  86. assert.deepEqual(base.missing, [])
  87. const vfs = runtime.loadVfsImage(await runtime.inflateImage(base.image, 'packed base'))
  88. assert.ok(vfs.existsSync('/dsh/' + packer.MANIFEST_PATH))
  89. mkdirSync('overlay')
  90. writeFileSync('overlay/hello.txt', 'packed worker pair\\n')
  91. const overlay = packer.packVfsOverlay([{ mount: 'workspace', directory: fileURLToPath(new URL('./overlay', import.meta.url)) }])
  92. runtime.loadVfsOverlay(await runtime.inflateImage(overlay.image, 'packed overlay'), '/dsh', vfs)
  93. assert.equal(vfs.readFileSync('/dsh/workspace/hello.txt', 'utf8'), 'packed worker pair\\n')
  94. console.log('packed image and overlay mounted')
  95. `
  96. await writeFile(join(root, 'consumer.mjs'), script)
  97. expect((await run(process.execPath, ['consumer.mjs'], root)).trim()).toBe('packed image and overlay mounted')
  98. })