uts: define normative fake-time semantics (ADVANCE_TIME guarantee, hard-gate vs advisory, authoring rule) - #518
Open
sacOO7 wants to merge 1 commit into
Open
Conversation
Three SDKs implemented ADVANCE_TIME with silently different semantics: ably-cocoa and ably-js hard-gate virtual time, while ably-java is advisory because its ConnectionManager blocks in a real timed wait that the mock clock cannot fully intercept. This ambiguity caused a real CI flake in ably-java (ably/ably-java#1231): a "no retry before advance" assertion was unassertable on the advisory model. This strengthens mock_websocket.md §Timer Mocking with: - Guarantee: after ADVANCE_TIME(ms) returns, virtual time has advanced by ms and every unit of due scheduled work has run to quiescence, including cascades scheduled by that work that are themselves due within the interval. - Hard gate vs. advisory latitude: hard gate is RECOMMENDED; advisory is PERMITTED where the SDK blocks in a real timed wait. Implementations MUST document which model they provide; advisory still honors the Guarantee. - Authoring rule (normative for spec tests): tests MUST NOT assert the absence of timer-driven behavior before the corresponding ADVANCE_TIME, since that is only valid under a hard gate and is therefore non-portable. Includes Disallowed (negative, pre-advance) and Allowed (cross-boundary, own the event) examples. Also reconciles respond_with_success(connected_message?: ProtocolMessage) to an optional arg, matching the doc's own no-arg example at L267. mock_http.md gains a one-line cross-reference so HTTP timeout tests inherit the same normative fake-time contract.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem statement
ADVANCE_TIME(ms)is the single knob UTS timer tests use to drive time-dependent behavior, but three SDKs implemented it with silently different semantics:ADVANCE_TIMEmoves virtual time past the due point.ConnectionManagerblocks in a real, timed monitor wait that the mock clock cannot fully intercept, soADVANCE_TIMEaccelerates the wait but the same work will also fire once real time elapses.This ambiguity caused a real CI flake in ably-java (ably/ably-java#1231): a spec-shaped "no retry before advance" assertion — asserting the absence of timer-driven behavior before an advance — was simply unassertable on the advisory model, because the advisory model cannot guarantee that scheduled work has not yet run.
What this changes
Three normative additions to
mock_websocket.md§Timer Mocking (new### Fake-time semantics (normative)), plus a self-consistency fix:ADVANCE_TIME(ms)returns, virtual time has advanced byms, and every unit of scheduled work whose due time is at or before the new virtual time has been run to quiescence (including work scheduled by that work, provided it too is due within the advanced interval)." This is the only timing behavior tests may rely on.ADVANCE_TIME; such negative "nothing has happened yet" assertions are valid only under a hard gate and are therefore non-portable. Includes a Disallowed (negative, pre-advance) example and an Allowed (cross the boundary, then own the resulting event) example.respond_with_success(connected_message?: ProtocolMessage)self-consistency fix. The signature is reconciled to an optional argument, matching the doc's own no-arg example at L267.This is a STRENGTHENING, not a behavior change. The Guarantee is satisfied by all three SDKs today — ably-java's
FakeClockgained a run-to-quiescence loop in the same ably-java PR — and no existing green test is invalidated.What this deliberately does NOT do
It does not remediate the existing spec tests that violate the new authoring rule:
heartbeat_test.md(L245/247/336/349/778/866/879/886) andrealtime_timeouts.md(L257-259). Those pass on hard-gate SDKs today and are tracked as a follow-up hygiene task.Cross-SDK context
Companion mock-infra changes are landing alongside this:
respondWithDelayheaders + fake-timer routing,readyStatelock)Review guide
Read
uts/realtime/unit/helpers/mock_websocket.md§"Fake-time semantics (normative)" (the three subsections: Guarantee, Hard gate vs. advisory, Authoring rule) plus therespond_with_successsignature at L76.uts/rest/unit/helpers/mock_http.mdgains only a one-line cross-reference. The diff is additive and normative-clarifying — no existing normative statement is weakened or removed.