Skip to content

test(plugins): the update-status test raced the millisecond clock - #74

Merged
agnt-gg merged 1 commit into
agnt-gg:mainfrom
rimusz:fix/update-scheduler-timestamp-race
Aug 23, 2026
Merged

test(plugins): the update-status test raced the millisecond clock#74
agnt-gg merged 1 commit into
agnt-gg:mainfrom
rimusz:fix/update-scheduler-timestamp-race

Conversation

@rimusz

@rimusz rimusz commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

backend/src/plugins/UpdateScheduler.status.test.js > replaces the previous pass rather than accumulating has been intermittently red on main and on every PR opened today. This is the cause and the fix.

Standalone and independent — one test file, no production code, no overlap with #70, #71, #72 or #73.

The race

UpdateScheduler.tick() stamps its summary with a millisecond-resolution timestamp:

// UpdateScheduler.js:161
const summary = { checkedAt: new Date().toISOString(), ... };

The test runs two ticks back to back with nothing slow between them, and asserted only that the two timestamps differ:

await scheduler.tick();   const first  = await scheduler.getStatus();
await scheduler.tick();   const second = await scheduler.getStatus();

expect(second.checkedAt).not.toBe(first.checkedAt);

When both ticks start inside the same millisecond, the timestamps are identical:

AssertionError: expected '2026-08-22T11:43:29.404Z' not to be '2026-08-22T11:43:29.404Z'

On this machine the unmodified test fails 23 times out of 30 runs. It passes only when something happens to be slow enough between the two ticks.

The failure message is the part that makes this worth fixing rather than tolerating: it names no clock and reads like a logic bug in the scheduler, so anyone who hits it starts by investigating UpdateScheduler — which is fine.

The fix

Fake Date for that one test and stamp the two passes six hours apart.

  • Only Date is faked, not setTimeout/setInterval, so the scheduler's real async filesystem work is untouched and there is nothing to advance. useFakeTimers is already used in four other backend suites (rateLimit, remoteTokenVerifier, and both WorkflowProcessBridge suites), so this is house style.
  • The assertion gets stronger, not merely stable. With a controlled clock it pins both exact values instead of just their inequality:
expect(first.checkedAt).toBe(firstPassAt.toISOString());
expect(second.checkedAt).toBe(secondPassAt.toISOString());

That also catches a summary that carried the old timestamp forward, which not.toBe would have reported as a pass in the very case the test exists to detect.

  • afterEach restores real timers, so a failure inside this test cannot leak a frozen clock into the rest of the file.

Verification

result
unmodified test, 30 isolated runs 23 failed
fixed test, 15 consecutive runs 0 failed
full backend suite, run 1 290/290
full backend suite, run 2 290/290

Note

I previously described this as order-dependent, on the strength of a single isolated run that happened to pass. With a ~77% failure rate, one passing run is a 23% event — not evidence. Measuring it properly showed it fails in isolation too, and the real cause is the clock. Correcting that here so the record is right.

`UpdateScheduler.tick()` stamps its summary with

    checkedAt: new Date().toISOString()

which has millisecond resolution. "replaces the previous pass rather than
accumulating" runs two ticks back to back with nothing slow between them
and asserted only that the two timestamps DIFFER:

    expect(second.checkedAt).not.toBe(first.checkedAt);

When both ticks start inside the same millisecond the timestamps are
identical and the assertion fails:

    AssertionError: expected '2026-08-22T11:43:29.404Z'
                 not to be '2026-08-22T11:43:29.404Z'

On this machine the unmodified test fails 23 times out of 30 runs. It has
been red intermittently across every PR opened today, and the failure
carries no hint of a clock — it reads like a logic bug in the scheduler,
which is worse than a test that simply fails.

Fakes Date for that one test and stamps the two passes six hours apart.
Only Date is faked, not setTimeout/setInterval, so the scheduler's real
async filesystem work is untouched and there is nothing to advance.
useFakeTimers is already used in four other backend suites.

The assertion is now stronger, not merely stable: with a controlled clock
it can pin both exact values rather than just their inequality, so a
summary that carried the OLD timestamp forward also fails — which the
previous version would have missed.

Restores real timers in afterEach so a failure inside that test cannot
leak a frozen clock into the rest of the file.

Fixed: 15/15 runs green. Full backend suite: 290/290, twice.
Copilot AI lite review requested due to automatic review settings August 22, 2026 11:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants