Skip to content

Refuse every homemade TimeProvider, not only one named FakeTimeProvider - #569

Merged
kirill-abblix merged 2 commits into
developfrom
feature/ban-homemade-clocks
Sep 24, 2026
Merged

kirill-abblix merged 2 commits into
developfrom
feature/ban-homemade-clocks

Conversation

@kirill-abblix

@kirill-abblix kirill-abblix commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

The check against homemade clocks looked only at the name FakeTimeProvider, so a test that wrote its own clock under another name passed. NoHomemadeClockTests now refuses any type in the built assemblies that derives from TimeProvider. A copy under any name, generic or file-local, is found. A second row proves the check itself recognizes a clock.

It found several test clocks, and they are all gone:

  • Each fixed or shifted clock is now a FakeTimeProvider started at the same moment. So are the fixed clocks that were built with Moq: a mock is created while the tests run, in an assembly no build writes, so the check cannot see it, and the class remark says so.
  • The key ring refresh tests used a clock that signalled when the loop armed its timer. They now advance the clock until a load arrives, with a cap on how many advances that takes, and then wait until the load count stops moving before the case begins. Each later advance still produces exactly one load. They also wait for the logged failures, not only for the loads, before counting them.

Continuous integration builds and tests each test project on its own, so the check could only see what the server unit tests depend on. That project now references every other project of the solution with ReferenceOutputAssembly="false". Building it alone therefore builds the whole solution first, without making any of it visible to the test code. A row fails if a project of Abblix.Oidc.slnx is not reached through those references, and the paths are compared case-sensitively, the way a Linux runner resolves them.

A comment in ClientAssertionMayTightenItselfTests no longer claims a reservation cannot be given back: the replay cache can release one, and this path simply never does.

A test that wrote its own clock under another name passed the check,
which looked only at the name. NoHomemadeClockTests now refuses any
type in the built assemblies that derives from TimeProvider, so a copy
under any name, generic or file-local, is found.

The clocks it found are gone. Every fixed or shifted clock becomes a
FakeTimeProvider instance, and the key ring tests that needed a signal
when the refresh loop armed its timer now advance the clock until a load
arrives and wait until the count settles, so each case still sees
exactly one load per advance.

A comment in ClientAssertionMayTightenItselfTests no longer says a
reservation cannot be given back; the replay cache can release one, and
it is this path that never does.
The server unit tests now reference every other project of the solution
without referencing their assemblies, so building them alone, as the
continuous integration shard does, builds everything the clock check
reads; a second row fails while a solution project is not reached. The
fixed clocks built with Moq, which a check over built assemblies cannot
see, are FakeTimeProvider instances, and the remark says what the check
misses. The check itself gets rows proving it recognizes a clock.

The key ring refresh tests cap how far they advance the clock while
arming the loop, and wait for the logged failures rather than only for
the loads before counting them.
@sonarqubecloud

Copy link
Copy Markdown

@kirill-abblix
kirill-abblix merged commit 2d5d79d into develop Sep 24, 2026
25 checks passed
@kirill-abblix
kirill-abblix deleted the feature/ban-homemade-clocks branch September 24, 2026 20:03
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.

1 participant