consortium
Version:
Remote control and session sharing CLI for AI coding agents
228 lines (209 loc) • 6.06 kB
JavaScript
/**
* Standalone test for verify-platform.cjs.
*
* Runs the script in a child process with a temp CONSORTIUM_HOME_DIR and
* asserts the sentinel file is created, exits 0, and contains a schema
* that matches what Phase 2 will consume.
*
* Not a vitest test on purpose — the postinstall script must be runnable
* before devDependencies (including vitest) have been installed, so the
* sanity check must be runnable with plain `node`.
*
* Usage: node scripts/verify-platform.test.cjs
*/
;
const fs = require('fs');
const os = require('os');
const path = require('path');
const { spawnSync } = require('child_process');
const assert = require('assert');
const SCRIPT = path.resolve(__dirname, 'verify-platform.cjs');
function makeTmpDir() {
return fs.mkdtempSync(path.join(os.tmpdir(), 'csm-preflight-test-'));
}
function rmrf(dir) {
try {
fs.rmSync(dir, { recursive: true, force: true });
} catch (_e) {
/* ignore */
}
}
function runScript(env) {
return spawnSync(process.execPath, [SCRIPT], {
env: { ...process.env, ...env },
encoding: 'utf8',
});
}
function assertSentinelSchema(sentinel) {
const requiredKeys = [
'schemaVersion',
'platform',
'supported',
'musl',
'glibcVersion',
'binaryGlibcRequired',
'platformPackageName',
'platformPackageVersion',
'platformPackagePresent',
'warnings',
'errors',
'cliVersion',
'cliPackageName',
'generatedAt',
];
for (const k of requiredKeys) {
assert.ok(
Object.prototype.hasOwnProperty.call(sentinel, k),
`sentinel missing key: ${k}`
);
}
assert.strictEqual(sentinel.schemaVersion, 1, 'schemaVersion must be 1');
assert.strictEqual(
typeof sentinel.platform,
'string',
'platform must be a string'
);
assert.match(
sentinel.platform,
/^[a-z0-9]+-[a-z0-9]+$/,
`platform must be <os>-<arch>, got ${sentinel.platform}`
);
assert.strictEqual(
typeof sentinel.supported,
'boolean',
'supported must be bool'
);
assert.strictEqual(typeof sentinel.musl, 'boolean', 'musl must be bool');
assert.ok(Array.isArray(sentinel.warnings), 'warnings must be an array');
assert.ok(Array.isArray(sentinel.errors), 'errors must be an array');
for (const arr of [sentinel.warnings, sentinel.errors]) {
for (const item of arr) {
assert.strictEqual(
typeof item.code,
'string',
'entry.code must be a string'
);
assert.strictEqual(
typeof item.message,
'string',
'entry.message must be a string'
);
if (item.remediation !== undefined) {
assert.strictEqual(
typeof item.remediation,
'string',
'entry.remediation must be a string'
);
}
}
}
assert.ok(
typeof sentinel.generatedAt === 'string' &&
!Number.isNaN(Date.parse(sentinel.generatedAt)),
'generatedAt must be an ISO timestamp'
);
assert.strictEqual(
typeof sentinel.cliPackageName,
'string',
'cliPackageName must be a string'
);
assert.strictEqual(
typeof sentinel.cliVersion,
'string',
'cliVersion must be a string'
);
}
const tests = [];
let passed = 0;
let failed = 0;
function test(name, fn) {
tests.push({ name, fn });
}
function run() {
for (const { name, fn } of tests) {
try {
fn();
console.log(` ok - ${name}`);
passed++;
} catch (e) {
console.log(` FAIL - ${name}`);
console.log(` ${e.stack || e.message}`);
failed++;
}
}
console.log(`\n${passed} passed, ${failed} failed`);
process.exit(failed === 0 ? 0 : 1);
}
// --- test cases -------------------------------------------------------
test('writes preflight.json to CONSORTIUM_HOME_DIR and exits 0', () => {
const tmp = makeTmpDir();
try {
const res = runScript({ CONSORTIUM_HOME_DIR: tmp });
assert.strictEqual(
res.status,
0,
`expected exit 0, got ${res.status}. stderr:\n${res.stderr}`
);
const sentinelPath = path.join(tmp, 'preflight.json');
assert.ok(
fs.existsSync(sentinelPath),
`sentinel not found at ${sentinelPath}`
);
const body = fs.readFileSync(sentinelPath, 'utf8');
const parsed = JSON.parse(body);
assertSentinelSchema(parsed);
} finally {
rmrf(tmp);
}
});
test('creates CONSORTIUM_HOME_DIR recursively if missing', () => {
const parent = makeTmpDir();
const target = path.join(parent, 'deep', 'nested', 'dir');
try {
assert.ok(!fs.existsSync(target), 'precondition: target must not exist');
const res = runScript({ CONSORTIUM_HOME_DIR: target });
assert.strictEqual(
res.status,
0,
`expected exit 0, got ${res.status}. stderr:\n${res.stderr}`
);
assert.ok(fs.existsSync(path.join(target, 'preflight.json')));
} finally {
rmrf(parent);
}
});
test('writes stdout summary with "Run `consortium doctor` for details"', () => {
const tmp = makeTmpDir();
try {
const res = runScript({ CONSORTIUM_HOME_DIR: tmp });
assert.ok(
/consortium doctor/.test(res.stdout),
`expected doctor hint in stdout, got:\n${res.stdout}`
);
} finally {
rmrf(tmp);
}
});
test('exported parseGlibc / compareGlibc work', () => {
const mod = require(SCRIPT);
assert.deepStrictEqual(mod.parseGlibc('2.31'), [2, 31, 0]);
assert.deepStrictEqual(mod.parseGlibc('2.34.1'), [2, 34, 1]);
assert.strictEqual(mod.parseGlibc('garbage'), null);
assert.ok(mod.compareGlibc('2.31', '2.34') < 0);
assert.ok(mod.compareGlibc('2.34', '2.31') > 0);
assert.strictEqual(mod.compareGlibc('2.34', '2.34'), 0);
});
test('platform field uses <process.platform>-<process.arch> format', () => {
const tmp = makeTmpDir();
try {
runScript({ CONSORTIUM_HOME_DIR: tmp });
const parsed = JSON.parse(
fs.readFileSync(path.join(tmp, 'preflight.json'), 'utf8')
);
assert.strictEqual(parsed.platform, `${process.platform}-${process.arch}`);
} finally {
rmrf(tmp);
}
});
run();