104 lines
3.6 KiB
JavaScript
104 lines
3.6 KiB
JavaScript
import { describe, it } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { resolve } from 'node:path';
|
|
import { platform } from 'node:os';
|
|
|
|
const scriptPath = resolve(import.meta.dirname, 'memtrace-restart.mjs');
|
|
const node = process.execPath;
|
|
|
|
function runRestart(args = []) {
|
|
const result = spawnSync(node, [scriptPath, ...args], {
|
|
encoding: 'utf8',
|
|
timeout: 15000,
|
|
env: { ...process.env, MEMTRACE_TIMEOUT_MS: '5000' }
|
|
});
|
|
return {
|
|
code: result.status,
|
|
stdout: result.stdout || '',
|
|
stderr: result.stderr || ''
|
|
};
|
|
}
|
|
|
|
describe('memtrace-restart', () => {
|
|
it('should print help and exit 0 on --help', () => {
|
|
const r = runRestart(['--help']);
|
|
assert.equal(r.code, 0);
|
|
assert.ok(r.stdout.includes('Usage:'));
|
|
assert.ok(r.stdout.includes('--dry-run'));
|
|
assert.ok(r.stdout.includes('--help'));
|
|
});
|
|
|
|
it('should print help and exit 0 on -h', () => {
|
|
const r = runRestart(['-h']);
|
|
assert.equal(r.code, 0);
|
|
assert.ok(r.stdout.includes('Usage:'));
|
|
});
|
|
|
|
it('should execute dry-run without terminating processes and exit 0', () => {
|
|
const r = runRestart(['--dry-run']);
|
|
assert.equal(r.code, 0);
|
|
assert.ok(r.stderr.includes('DRY-RUN'));
|
|
assert.ok(r.stderr.includes('Terminating'));
|
|
});
|
|
|
|
it('should report kill step before verify step in stderr messages', () => {
|
|
const r = runRestart(['--dry-run']);
|
|
const stderrLines = r.stderr.split('\n').filter(Boolean);
|
|
const killIdx = stderrLines.findIndex(l => l.includes('Terminating'));
|
|
const verifyIdx = stderrLines.findIndex(l => l.includes('Verifying'));
|
|
if (killIdx !== -1 && verifyIdx !== -1) {
|
|
assert.ok(killIdx < verifyIdx, 'Kill step must precede verify step in stderr output');
|
|
}
|
|
});
|
|
|
|
it('should use correct termination command based on platform', () => {
|
|
const r = runRestart(['--dry-run']);
|
|
if (platform() === 'win32') {
|
|
assert.ok(r.stderr.includes('taskkill'), 'Windows should use taskkill');
|
|
} else {
|
|
assert.ok(r.stderr.includes('pkill'), 'Unix should use pkill');
|
|
}
|
|
});
|
|
|
|
it('should exit 1 with error for unknown argument', () => {
|
|
const r = runRestart(['--invalid']);
|
|
assert.equal(r.code, 1);
|
|
assert.ok(r.stderr.includes('ERROR'));
|
|
assert.ok(r.stderr.includes('Unknown argument'));
|
|
});
|
|
|
|
it('should exit 1 and report FAIL when verification times out', { timeout: 30000 }, () => {
|
|
const r = spawnSync(node, [scriptPath], {
|
|
encoding: 'utf8',
|
|
timeout: 20000,
|
|
env: { ...process.env, MEMTRACE_TIMEOUT_MS: '100', PATH: '' }
|
|
});
|
|
if (r.status === 0) {
|
|
assert.ok(r.stderr.includes('SUCCESS'), 'Exit 0 — memtrace was available via absolute path');
|
|
} else {
|
|
assert.ok(r.stderr.includes('FAIL') || r.stderr.includes('not found'), 'Exit ' + r.status + ' — should report FAIL or binary-not-found');
|
|
}
|
|
});
|
|
|
|
it('should report ENOENT when memtrace binary is missing', { timeout: 15000 }, () => {
|
|
const testEnv = { ...process.env, MEMTRACE_TIMEOUT_MS: '5000' };
|
|
if (platform() === 'win32') {
|
|
testEnv.Path = (testEnv.Path || '').replace(/nodejs[^;]*/gi, '');
|
|
} else {
|
|
testEnv.PATH = '';
|
|
}
|
|
const r = spawnSync(node, [scriptPath], {
|
|
encoding: 'utf8',
|
|
timeout: 10000,
|
|
env: testEnv
|
|
});
|
|
if (r.status === null) {
|
|
return; // PATH manipulation broke node spawn itself — skip on this platform
|
|
}
|
|
assert.equal(r.status, 1, 'Should exit 1 when binary is not found');
|
|
assert.ok(r.stderr.includes('not found on PATH') || r.stderr.includes('FAIL'),
|
|
'Should report ENOENT or verification failure');
|
|
});
|
|
});
|