import assert from 'node:assert/strict' import { lstat, mkdir, mkdtemp, readFile, readlink, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import test from 'node:test' import { PlatformPaths, preparePersistentLayout, rejectLegacyLayout, resetRuntimeLayout, trustStateRootForAuthority, } from '../lib/paths.mjs' test('creates state, store, cache, and logs without persistent runtime views', async () => { const root = await mkdtemp(join(tmpdir(), 'dsh-layout-')) const paths = new PlatformPaths(join(root, 'platform'), join(root, 'run')) await preparePersistentLayout(paths) assert.equal(paths.developmentTrustStateRoot, join(paths.trustStateRoot, 'development')) assert.equal(paths.proxyStateRoot, join(paths.stateRoot, 'proxy')) assert.equal(paths.proxyTestStatePath, join(paths.proxyStateRoot, 'test-tasks.json')) assert.equal(paths.accessStateRoot, join(paths.stateRoot, 'access')) assert.equal(paths.accessSocket, join(paths.runRoot, 'access', 'access.sock')) assert.equal(paths.accessRecoverySocket, join(paths.runRoot, 'access', 'recovery.sock')) assert.equal(paths.accessLaunchSocket, join(paths.runRoot, 'access-launch.sock')) assert.equal(paths.proxyProviderInventoryPath, join(paths.managementStateRoot, 'proxy-provider-inventory.json')) for (const path of [ paths.trustStateRoot, paths.bootstrapStateRoot, paths.deploymentStateRoot, paths.updaterStateRoot, paths.managementStateRoot, paths.objectsRoot, paths.bootstrapStoreRoot, paths.environmentsRoot, paths.pristineRoot, paths.runtimesRoot, paths.systemPluginsRoot, paths.snapshotsRoot, paths.userPluginSnapshotsRoot, paths.downloadsRoot, paths.npmCacheRoot, paths.logsRoot, ]) assert.equal((await lstat(path)).isDirectory(), true) assert.equal(paths.systemSkillCatalogsRoot, join(paths.environmentsRoot, 'versions', '.system-skill-catalogs')) await assert.rejects(lstat(paths.systemSkillCatalogsRoot), { code: 'ENOENT' }) await assert.rejects(lstat(paths.runRoot), { code: 'ENOENT' }) }) test('isolates development trust without changing the formal trust ledger', () => { const paths = new PlatformPaths('/data/platform', '/run/dsh-platform') assert.equal(trustStateRootForAuthority(paths, 'development'), paths.developmentTrustStateRoot) assert.equal(trustStateRootForAuthority(paths, 'stable'), paths.trustStateRoot) }) test('rejects legacy platform volumes without changing DSH user data', async () => { const root = await mkdtemp(join(tmpdir(), 'dsh-legacy-layout-')) const dataRoot = join(root, 'platform') const dshRoot = join(root, 'dsh') const paths = new PlatformPaths(dataRoot, join(root, 'run')) await mkdir(join(dataRoot, 'runtime'), { recursive: true }) await mkdir(dshRoot) await writeFile(join(dshRoot, 'sentinel'), 'user-data') await assert.rejects(rejectLegacyLayout(paths), error => ( /clear only .*platform/.test(error.message) && /Do not delete \/data\/dsh/.test(error.message) )) assert.equal(await readFile(join(dshRoot, 'sentinel'), 'utf8'), 'user-data') }) test('rebuilds only the ephemeral run directory', async () => { const root = await mkdtemp(join(tmpdir(), 'dsh-run-layout-')) const paths = new PlatformPaths(join(root, 'platform'), join(root, 'run')) await preparePersistentLayout(paths) await mkdir(paths.runRoot) await writeFile(join(paths.runRoot, 'stale.sock'), 'stale') await writeFile(join(paths.updaterStateRoot, 'sentinel'), 'persistent') await resetRuntimeLayout(paths) await assert.rejects(lstat(join(paths.runRoot, 'stale.sock')), { code: 'ENOENT' }) assert.equal((await lstat(paths.viewsRoot)).isDirectory(), true) assert.equal((await lstat(paths.deploymentViewsRoot)).isDirectory(), true) assert.equal(await readlink(join(paths.viewsRoot, 'runtime')), join('..', 'deployment', 'runtime')) assert.equal(await readlink(join(paths.viewsRoot, 'environment')), join('..', 'deployment', 'environment')) assert.equal(await readlink(join(paths.viewsRoot, 'system-plugins')), join('..', 'system-plugin-views', 'current')) assert.equal((await lstat(paths.systemPluginViewsRoot)).isDirectory(), true) assert.equal(paths.dshLifecycleSocket, join(paths.runRoot, 'dsh-lifecycle.sock')) assert.equal(paths.proxyControlSocket, join(paths.runRoot, 'outbound-proxy.sock')) assert.equal(paths.proxyRoutingStatePath, join(paths.runRoot, 'outbound-proxy-routing.json')) assert.equal(paths.proxyLaunchSocket, join(paths.runRoot, 'proxy-launch.sock')) assert.equal( await readlink(join(paths.systemPluginViewsRoot, 'current')), join('..', 'deployment', 'system-plugins'), ) assert.equal(await readFile(join(paths.updaterStateRoot, 'sentinel'), 'utf8'), 'persistent') })