BMAD-METHOD/_bmad/scripts/memtrace/memtrace-restart.test.mjs

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');
});
});