Skip to content

Three wall-clock-dependent tests fail intermittently across all three CI legs #92

Description

@dborgards

Observed over four CI runs of #91 — a branch containing no .cs changes at all, so none of these are caused by the code under test changing. Each failed exactly once and passed on a later run of the same or newer commit.

Test Leg Commit Symptom
IsoTpStminTimingTests.Sender_Paces_Consecutive_Frames_According_To_Peer_Stmin macOS ff7012a IsoTpTimeoutException: N_Cr timer expired waiting for next Consecutive Frame
J1939NodeTests.StartPeriodicSend_MultiFrame_KeepsFixedRate_Without_SendTime_Drift macOS ff7012a gap off-grid by 196.9 ms against a 180 ms tolerance (30 % of the 600 ms period)
UdsClientTests.TimedOut_Request_Does_Not_Poison_Next_Same_Service_Transaction Windows 0a8812d Expected a <UdsTimeoutException> to be thrown, but no exception was thrown

The cost is not the individual failure. It is that a green pull request can go red on the next run without anything changing, which makes "is CI red because of my change?" a question nobody can answer by looking.

Two of them are tolerance problems

J1939 measures the gap between periodic emissions with Stopwatch and asserts it sits within 30 % of a 600 ms period. 196.9 ms is over that. Worth noting before anyone reaches for a wider tolerance: the drift hypothesis the test guards against lands at half a period (~300 ms) off-grid, so widening to, say, 40 % would not blind it. But a tolerance picked to survive the slowest runner ever observed is a number that gets widened again the next time, and the test would stop meaning anything long before it stops failing.

ISO-TP measures CF-to-CF spacing against an advertised STmin of 5 ms with FastOptions(), and the receiver's N_Cr expired. Its own README already concedes the limit: "the effective CF spacing is STmin + OS scheduling latency … with no hard real-time guarantee under load". The test asserts a property the code cannot promise on a shared runner.

For both, the durable fix is to stop measuring wall-clock time: drive the actor's DeadlineScheduler from a virtual clock the test advances, so pacing and timeout behaviour are asserted deterministically. The real-time behaviour that genuinely depends on the host stays worth checking, but as a soft, non-gating observation rather than a build-breaking assertion.

The third one may not be a test problem at all

TimedOut_Request_Does_Not_Poison_Next_Same_Service_Transaction sets P2ClientMax = 80 ms and has the ECU double Thread.Sleep(250) before replying. A 170 ms margin is not tight, so "the runner was slow" does not explain it on its own — the response cannot arrive early.

What can produce the observed result is the opposite of slowness at the point that matters: if the actor loop is starved for longer than 250 ms, then by the time it runs again both the expired deadline and the response are waiting, and the response wins the race. The client returns data instead of throwing.

If that reading is right, the test caught something real: a deadline that has already expired losing to a response that arrived afterwards. That is the same shape as #24, where an expired pending send stays in the FIFO and swallows the next echo, and it is what the L2 deadline primitive was introduced to prevent — an expiry that is guaranteed to be checked.

This is a hypothesis from one log, not a diagnosis. It should be reproduced under deliberate actor starvation before anyone decides which side the bug is on. Doing that first also decides the fix: if the client is right and the test is racy, it joins the two above; if the client is wrong, widening a tolerance would have hidden a defect.

Suggested order

  1. Reproduce the UDS case under forced actor starvation, and settle whether the client or the test is at fault. This one first, because it is the only one that might be a product bug.
  2. Move the ISO-TP and J1939 assertions onto a virtual clock.
  3. Only then consider what, if anything, should still be measured against the wall clock, and make that non-gating.

Related: #52 covers the missing normative negative tests — a different gap in the same suite. This issue is about tests that exist and cannot be trusted.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: testsTest suite, coverage, API approvalstype: testsTest coverage — a missing, weak or flaky test

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions