mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 01:32:44 +08:00
116 lines
3.8 KiB
JavaScript
116 lines
3.8 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { test } = require('node:test');
|
|
|
|
const {
|
|
LocalApplicationStartupReceiptError,
|
|
buildLocalApplicationStartupReceipt,
|
|
localApplicationStartupReceiptPath,
|
|
observeLocalApplicationStartup,
|
|
parseLinuxProcessStartTicks,
|
|
parseLocalApplicationStartupReceipt,
|
|
publishLocalApplicationStartupReceipt,
|
|
} = require('../dist/production-process/startupReceipt.js');
|
|
|
|
function directory(t) {
|
|
const value = fs.mkdtempSync(path.join(os.tmpdir(), 'ql3-startup-receipt-'));
|
|
t.after(() => fs.rmSync(value, { recursive: true, force: true }));
|
|
return value;
|
|
}
|
|
|
|
function receipt(activeBootAgeMs = 1_250, processId = 41) {
|
|
return buildLocalApplicationStartupReceipt({
|
|
instanceId: 'edge-router-1',
|
|
profile: 'edge',
|
|
aiStatus: 'deployment_excluded',
|
|
observation: {
|
|
bootId: '12345678-1234-4abc-8def-123456789abc',
|
|
activeBootAgeMs,
|
|
processId,
|
|
processStartTicks: String(100 + processId),
|
|
nodeExecutable: '/usr/bin/node',
|
|
nodeVersion: 'v24.18.0',
|
|
},
|
|
});
|
|
}
|
|
|
|
test('parses Linux stat after the final command delimiter', () => {
|
|
const fields = [
|
|
'S',
|
|
...Array.from({ length: 18 }, (_, index) => String(index + 1)),
|
|
'987654',
|
|
'21',
|
|
];
|
|
assert.equal(
|
|
parseLinuxProcessStartTicks(`41 (node worker) name) ${fields.join(' ')}`),
|
|
'987654',
|
|
);
|
|
assert.throws(
|
|
() => parseLinuxProcessStartTicks('41 invalid'),
|
|
LocalApplicationStartupReceiptError,
|
|
);
|
|
});
|
|
|
|
test('publishes one bounded current receipt with atomic replacement', (t) => {
|
|
const root = directory(t);
|
|
const configFilePath = path.join(root, 'local-application.json');
|
|
const first = receipt();
|
|
const target = publishLocalApplicationStartupReceipt(configFilePath, first);
|
|
assert.equal(target, localApplicationStartupReceiptPath(configFilePath));
|
|
assert.equal(fs.statSync(target).mode & 0o777, 0o600);
|
|
assert.equal(fs.existsSync(`${target}.stage`), false);
|
|
assert.deepEqual(
|
|
parseLocalApplicationStartupReceipt(fs.readFileSync(target, 'utf8')),
|
|
first,
|
|
);
|
|
|
|
const second = receipt(1_500, 42);
|
|
assert.equal(
|
|
publishLocalApplicationStartupReceipt(configFilePath, second),
|
|
target,
|
|
);
|
|
assert.equal(fs.statSync(target).mode & 0o777, 0o600);
|
|
assert.equal(fs.statSync(target).nlink, 1);
|
|
assert.deepEqual(
|
|
parseLocalApplicationStartupReceipt(fs.readFileSync(target, 'utf8')),
|
|
second,
|
|
);
|
|
});
|
|
|
|
test('rejects a forged digest and an unsafe deterministic stage', (t) => {
|
|
const root = directory(t);
|
|
const configFilePath = path.join(root, 'local-application.json');
|
|
const target = localApplicationStartupReceiptPath(configFilePath);
|
|
const valid = receipt();
|
|
const forged = { ...valid, activeBootAgeMs: valid.activeBootAgeMs + 1 };
|
|
assert.throws(
|
|
() => parseLocalApplicationStartupReceipt(JSON.stringify(forged)),
|
|
/digest is invalid/,
|
|
);
|
|
|
|
const outside = path.join(root, 'outside');
|
|
fs.writeFileSync(outside, 'do-not-replace', { mode: 0o600 });
|
|
fs.symlinkSync(outside, `${target}.stage`);
|
|
assert.throws(
|
|
() => publishLocalApplicationStartupReceipt(configFilePath, valid),
|
|
/existing receipt stage is not a private regular file/,
|
|
);
|
|
assert.equal(fs.readFileSync(outside, 'utf8'), 'do-not-replace');
|
|
assert.equal(fs.existsSync(target), false);
|
|
});
|
|
|
|
test(
|
|
'observes the live Linux boot and direct Node process when available',
|
|
{ skip: process.platform !== 'linux' },
|
|
() => {
|
|
const observed = observeLocalApplicationStartup();
|
|
assert.equal(observed.processId, process.pid);
|
|
assert.match(observed.bootId, /^[0-9a-f-]{36}$/);
|
|
assert.match(observed.processStartTicks, /^[1-9][0-9]+$/);
|
|
assert.equal(path.isAbsolute(observed.nodeExecutable), true);
|
|
assert.equal(observed.nodeVersion, process.version);
|
|
},
|
|
);
|