Files
ECC/tests/lib/opencode-script-boundary.test.js
T

151 lines
7.3 KiB
JavaScript

'use strict';
const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { spawnSync } = require('child_process');
const { createManifestInstallPlan, applyInstallPlan } = require('../../scripts/lib/install-executor');
const { withHookConsent } = require('../../scripts/lib/install/hook-consent');
const { repairInstalledStates, uninstallInstalledStates } = require('../../scripts/lib/install-lifecycle');
const { readInstallState } = require('../../scripts/lib/install-state');
const repo = path.resolve(__dirname, '../..');
const build = spawnSync(process.execPath, [path.join(repo, 'scripts/build-opencode.js')], { encoding: 'utf8' });
assert.strictEqual(build.status, 0, build.stderr || build.stdout);
let passed = 0;
let failed = 0;
function test(name, fn) {
const dir = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-opencode-boundary-')));
const home = path.join(dir, 'home');
const project = path.join(dir, 'project');
fs.mkdirSync(home);
fs.mkdirSync(project);
const root = path.join(home, '.config/opencode');
const scripts = path.join(root, 'scripts');
const marker = path.join(scripts, 'package.json');
const options = { repoRoot: repo, homeDir: home, projectRoot: project, env: {}, targets: ['opencode'] };
const plan = () => withHookConsent(createManifestInstallPlan({
sourceRoot: repo, homeDir: home, projectRoot: project, env: {}, target: 'opencode',
moduleIds: ['platform-configs', 'hooks-runtime'],
}), 'enabled');
const write = (file, bytes) => { fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, bytes); };
const probe = file => {
const result = spawnSync(process.execPath, ['--input-type=module', '-e',
'const m=await import(requirePath); console.log(m.default ?? m.value);'.replace('requirePath', JSON.stringify(require('url').pathToFileURL(file).href))],
{ encoding: 'utf8', cwd: project });
assert.strictEqual(result.status, 0, result.stderr);
return result.stdout.trim();
};
try { fn({ home, project, root, scripts, marker, options, plan, write, probe }); passed++; console.log(`PASS ${name}`); }
catch (error) { failed++; console.error(`FAIL ${name}: ${error.stack}`); }
finally { fs.rmSync(dir, { recursive: true, force: true }); }
}
test('refuses unowned ESM scripts before copies or install-state writes', f => {
f.write(path.join(f.root, 'package.json'), '{"type":"module"}\n');
const sentinel = path.join(f.scripts, 'user.js');
f.write(sentinel, 'export const value = 42;\n');
assert.strictEqual(f.probe(sentinel), '42');
const plan = f.plan();
assert.throws(() => applyInstallPlan(plan), /unowned or edited JavaScript/);
assert.ok(!fs.existsSync(f.marker));
assert.ok(!fs.existsSync(plan.installStatePath));
assert.ok(!fs.existsSync(path.join(f.root, 'plugins')));
assert.strictEqual(f.probe(sentinel), '42');
});
test('preserves an unowned CommonJS boundary without repair or uninstall adoption', f => {
const bytes = '{"type":"commonjs","user":"keep"}\n';
f.write(f.marker, bytes);
const sentinel = path.join(f.scripts, 'user.js');
f.write(sentinel, 'module.exports = 43;\n');
const plan = f.plan();
applyInstallPlan(plan);
const owned = () => readInstallState(plan.installStatePath).operations.some(operation => operation.destinationPath === f.marker);
assert.strictEqual(owned(), false);
assert.strictEqual(repairInstalledStates(f.options).summary.errorCount, 0);
assert.strictEqual(owned(), false);
assert.strictEqual(fs.readFileSync(f.marker, 'utf8'), bytes);
assert.strictEqual(f.probe(sentinel), '43');
assert.strictEqual(uninstallInstalledStates(f.options).summary.errorCount, 0);
assert.strictEqual(fs.readFileSync(f.marker, 'utf8'), bytes);
assert.strictEqual(f.probe(sentinel), '43');
});
test('refuses an existing user ESM package boundary without changing it', f => {
const bytes = '{"type":"module","user":"keep"}\n';
f.write(f.marker, bytes);
const sentinel = path.join(f.scripts, 'user.js');
f.write(sentinel, 'export const value = 44;\n');
const plan = f.plan();
assert.throws(() => applyInstallPlan(plan), /existing user module boundary/);
assert.strictEqual(fs.readFileSync(f.marker, 'utf8'), bytes);
assert.ok(!fs.existsSync(plan.installStatePath));
assert.strictEqual(f.probe(sentinel), '44');
});
test('a nested user ESM scope remains unchanged across install and uninstall', f => {
f.write(path.join(f.scripts, 'user/package.json'), '{"type":"module"}\n');
const sentinel = path.join(f.scripts, 'user/index.js');
f.write(sentinel, 'export const value = 45;\n');
const explicitModule = path.join(f.scripts, 'user-module.mjs');
f.write(explicitModule, 'export const value = 48;\n');
applyInstallPlan(f.plan());
assert.strictEqual(f.probe(sentinel), '45');
assert.strictEqual(f.probe(explicitModule), '48');
assert.strictEqual(uninstallInstalledStates(f.options).summary.errorCount, 0);
assert.ok(!fs.existsSync(f.marker));
assert.strictEqual(f.probe(sentinel), '45');
assert.strictEqual(f.probe(explicitModule), '48');
});
test('partial uninstall retains an owned boundary while user JavaScript relies on it', f => {
const plan = f.plan();
applyInstallPlan(plan);
const sentinel = path.join(f.scripts, 'user.js');
f.write(sentinel, 'module.exports = 46;\n');
const result = uninstallInstalledStates(f.options);
assert.strictEqual(result.results[0].status, 'partial');
assert.ok(result.results[0].retainedPaths.includes(f.marker));
assert.strictEqual(f.probe(sentinel), '46');
assert.ok(readInstallState(plan.installStatePath).operations.some(operation => operation.destinationPath === f.marker));
fs.unlinkSync(sentinel);
assert.strictEqual(uninstallInstalledStates(f.options).summary.errorCount, 0);
assert.ok(!fs.existsSync(f.marker));
assert.ok(!fs.existsSync(plan.installStatePath));
});
test('rechecks newly introduced user JavaScript before boundary publication', f => {
const sentinel = path.join(f.scripts, 'user.js');
const plan = f.plan();
assert.throws(() => applyInstallPlan(plan, { beforeOperationWrite({ operation }) {
if (operation.destinationPath === f.marker) f.write(sentinel, 'export const value = 47;\n');
} }), /unowned or edited JavaScript/);
assert.ok(!fs.existsSync(f.marker));
assert.strictEqual(f.probe(sentinel), '47');
});
test('refuses a concurrent edit to a just-installed script before boundary publication', f => {
const plan = f.plan();
const sentinel = path.join(f.scripts, 'hooks/skill-run-tracker.js');
assert.throws(() => applyInstallPlan(plan, { beforeOperationWrite({ operation }) {
if (operation.destinationPath === f.marker) f.write(sentinel, 'export const value = 49;\n');
} }), /unowned or edited JavaScript/);
assert.ok(!fs.existsSync(f.marker));
assert.strictEqual(f.probe(sentinel), '49');
});
test('repair restores a missing owned boundary and preserves runtime script ownership', f => {
const plan = f.plan();
applyInstallPlan(plan);
fs.unlinkSync(f.marker);
assert.strictEqual(repairInstalledStates(f.options).summary.errorCount, 0);
assert.strictEqual(JSON.parse(fs.readFileSync(f.marker, 'utf8')).type, 'commonjs');
assert.ok(readInstallState(plan.installStatePath).operations.some(operation => operation.destinationPath === f.marker));
});
console.log(`Passed: ${passed}`);
console.log(`Failed: ${failed}`);
process.exitCode = failed ? 1 : 0;