* test(#3314): backfill deterministic clock-seam coverage (failing-first) Replaces loose regex/range assertions with exact-value and boundary tests for the CLI-subprocess and in-process clock-touching call sites identified by H2's audit (epic #3053): cmdCurrentTimestamp, _wsParseRetryAfter (commands.cts), cmdInitManager's is_active gate and cmdInitQuick's quick_id generation (init.cts), and reapStaleTempFiles (io.cts). The CLI-subprocess-pinned tests are expected RED until a follow-up commit routes those call sites through realClock so GSD_TEST_MODE+GSD_NOW_MS can reach them. * refactor(#3314): route CLI-subprocess clock reads through realClock cmdCurrentTimestamp, cmdInitManager's is_active gate, and cmdInitQuick's quick_id generation read Date directly, which the GSD_TEST_MODE+GSD_NOW_MS subprocess pin cannot reach (it only fires inside realClock.now()). Behavior-preserving: realClock.now() falls through to Date.now() whenever GSD_TEST_MODE is unset, which is every real invocation. * docs(#3314): amend ADR-456 with reachability-based clock-control rule ADR-456 §(a) documented one mechanism (injected {clock=Date} + t.mock.timers). Adds the two this repo already relies on: t.mock.timers for in-process direct-Date reads, and the GSD_TEST_MODE+GSD_NOW_MS subprocess pin (routed through realClock) for CLI-spawned code. Updates TESTING-STANDARDS.md's matching passages, which already referenced this issue by number as the no-elapsed-assertion promotion precondition. * fix(#3314): address orthogonal review findings Spec-axis findings: file and link the no-elapsed-assertion promotion follow-up (#3331) instead of leaving TESTING-STANDARDS.md pointing at a dead #1885, and ship the module-by-module audit table in the ADR itself rather than only in a gitignored phase artifact. Standards-axis finding: pin the "hour-old file = not active" test via GSD_TEST_MODE+GSD_NOW_MS for consistency with the reachability rule this PR's own ADR amendment now documents. --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -968,6 +968,56 @@ describe('current-timestamp command', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// cmdCurrentTimestamp exact-value tests (#3314 — ADR-456 subprocess clock pin)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe('current-timestamp command — exact value under GSD_NOW_MS pin', () => {
|
||||
let tmpDir;
|
||||
// Pinned instant with a non-zero millisecond fraction so the 'full' format
|
||||
// assertion can't accidentally pass against a truncated value.
|
||||
const PINNED_MS = 1_700_000_000_123; // 2023-11-14T22:13:20.123Z
|
||||
const PIN_ENV = { GSD_TEST_MODE: '1', GSD_NOW_MS: String(PINNED_MS) };
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = createTempProject();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup(tmpDir);
|
||||
});
|
||||
|
||||
test('date format: exact value for pinned instant', () => {
|
||||
const result = runGsdTools('current-timestamp date', tmpDir, PIN_ENV);
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
const expected = new Date(PINNED_MS).toISOString().split('T')[0];
|
||||
assert.strictEqual(output.timestamp, expected);
|
||||
});
|
||||
|
||||
test('filename format: exact value for pinned instant', () => {
|
||||
const result = runGsdTools('current-timestamp filename', tmpDir, PIN_ENV);
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
const expected = new Date(PINNED_MS).toISOString().replace(/:/g, '-').replace(/\..+/, '');
|
||||
assert.strictEqual(output.timestamp, expected);
|
||||
});
|
||||
|
||||
test('full format: exact value for pinned instant', () => {
|
||||
const result = runGsdTools('current-timestamp full', tmpDir, PIN_ENV);
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.timestamp, new Date(PINNED_MS).toISOString());
|
||||
});
|
||||
|
||||
test('default format: exact value for pinned instant', () => {
|
||||
const result = runGsdTools('current-timestamp', tmpDir, PIN_ENV);
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.timestamp, new Date(PINNED_MS).toISOString());
|
||||
});
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// cmdListTodos tests (CMD-02)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -2476,17 +2526,48 @@ describe('_wsParseRetryAfter (#308)', () => {
|
||||
assert.strictEqual(_wsParseRetryAfter('120000'), 60000);
|
||||
});
|
||||
|
||||
test('future HTTP-date → value in (0, 60000]', () => {
|
||||
const futureDate = new Date(Date.now() + 5000).toUTCString();
|
||||
const v = _wsParseRetryAfter(futureDate);
|
||||
assert.ok(typeof v === 'number' && v > 0 && v <= 60000, `expected (0,60000], got ${v}`);
|
||||
// ADR-456 §(a) reachability rule: this function is required directly
|
||||
// (in-process), so t.mock.timers reaches it without any production change —
|
||||
// it patches the global `Date` that `Date.now()` reads from regardless of
|
||||
// whether the SUT goes through realClock. Fixed, second-aligned pin so the
|
||||
// HTTP-date's whole-second precision doesn't round the expected value away.
|
||||
const PINNED_MS = 1_700_000_000_000; // 2023-11-14T22:13:20.000Z
|
||||
|
||||
test('future HTTP-date 5s ahead → exactly 5000 (deterministic)', (t) => {
|
||||
t.mock.timers.enable(['Date']);
|
||||
t.mock.timers.setTime(PINNED_MS);
|
||||
const futureDate = new Date(PINNED_MS + 5000).toUTCString();
|
||||
assert.strictEqual(_wsParseRetryAfter(futureDate), 5000);
|
||||
});
|
||||
|
||||
test('past HTTP-date → 0', () => {
|
||||
const pastDate = new Date(Date.now() - 5000).toUTCString();
|
||||
test('past HTTP-date 5s behind → exactly 0 (deterministic)', (t) => {
|
||||
t.mock.timers.enable(['Date']);
|
||||
t.mock.timers.setTime(PINNED_MS);
|
||||
const pastDate = new Date(PINNED_MS - 5000).toUTCString();
|
||||
assert.strictEqual(_wsParseRetryAfter(pastDate), 0);
|
||||
});
|
||||
|
||||
test('boundary: HTTP-date 59s ahead → 59000, not clamped', (t) => {
|
||||
t.mock.timers.enable(['Date']);
|
||||
t.mock.timers.setTime(PINNED_MS);
|
||||
const d = new Date(PINNED_MS + 59_000).toUTCString();
|
||||
assert.strictEqual(_wsParseRetryAfter(d), 59_000);
|
||||
});
|
||||
|
||||
test('boundary: HTTP-date 60s ahead → 60000, at cap exactly', (t) => {
|
||||
t.mock.timers.enable(['Date']);
|
||||
t.mock.timers.setTime(PINNED_MS);
|
||||
const d = new Date(PINNED_MS + 60_000).toUTCString();
|
||||
assert.strictEqual(_wsParseRetryAfter(d), 60_000);
|
||||
});
|
||||
|
||||
test('boundary: HTTP-date 61s ahead → clamped to 60000', (t) => {
|
||||
t.mock.timers.enable(['Date']);
|
||||
t.mock.timers.setTime(PINNED_MS);
|
||||
const d = new Date(PINNED_MS + 61_000).toUTCString();
|
||||
assert.strictEqual(_wsParseRetryAfter(d), 60_000);
|
||||
});
|
||||
|
||||
test('"garbage" → null', () => {
|
||||
assert.strictEqual(_wsParseRetryAfter('garbage'), null);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user