Skip to content

test: HowToSubscribeRealModel replayed earlier runs — LiteDbFactory left LiteDB's journal behind; in-memory assertion db + own-row bounded counts - #43

Merged
rafalmaciag merged 4 commits into
masterfrom
fix/howto-subscribe-realmodel-own-row
Oct 18, 2026
Merged

rafalmaciag merged 4 commits into
masterfrom
fix/howto-subscribe-realmodel-own-row

Conversation

@rafalmaciag

Copy link
Copy Markdown
Contributor

Card microplumberd-howto-subscribe-realmodel-absolute-count. HowTo.PlumberMethodsTests.HowToSubscribeRealModel failed on master:

The cause was not the shared event store; it was a LiteDB journal from EARLIER PROCESSES

LiteDbFactory.Get() made a "fresh" database by deleting ./test_{n}.db and opening it. LiteDB also writes a journal, ./test_{n}-log.db. The journal survived and was replayed on the next open, so each later test process started with every earlier run's reservations already in the model. The counts grew run on run (2, 6, 10), and the row passed only where the journal had been checkpointed away or the bin was clean.

The evidence:

  • The names. A mutant that restores the absolute count and lists what it counted gave 10: Golden Eye ×6 plus four Golden Eye <guid>. The plain "Golden Eye" rows can only come from the old test body in earlier processes: this branch's rows write unique names.
  • The files. The bin held test_3-log.db (200 KB) beside an 8 KB test_3.db.
  • The store is not the source. With the factory fixed, that same absolute-count mutant survives (13/13 green). The class-fixture KurrentDB contributed nothing: each row's StartInDocker restarts the in-memory store. The card's hypothesis (other rows' TicketReserved in the shared store) was ruled out by this mutant, not assumed.

The fix

  1. At the seam: LiteDbFactory.Get() returns an in-memory LiteDB (new LiteDatabase(new MemoryStream()); the file is already named InMemoryAssertionDb). Nothing is left on disk for a later run to replay. Its only callers are the two HowTo real-model rows.
  2. Both real-model rows (HowToSubscribeRealModel and its sibling …WithHost, which had the same shape and passed only by circumstance):
    • append a reservation under their own unique name and count that one;
    • wait bounded (≤ 15 s) for their own event folded, instead of a fixed Task.Delay(1000);
    • then settle 250 ms, so a duplicate delivery would still be counted ("folded exactly once").

Rows (Unit/LiteDbFactoryTests, new)

  • EachAssertionDb_StartsEmpty: a reservation written to one assertion db is not seen by the next.
  • AnAssertionDb_LeavesNoFileBehind_ForALaterRunToReplay: no new *.db file appears in the working directory. On a bin that already holds test_*.db files this row can't see the old factory (the files pre-exist); StartsEmpty is the one that discriminates there.

Mutants (messages read)

  • F1, the shipped file factory restored: EachAssertionDb_StartsEmpty red, "Expected next.Reservations().Count() to be 0, but found 11". The leftover journal was replayed into a "fresh" db: the defect, reproduced at its seam.
  • H1, the absolute count restored (the lead's named mutant):
    • before the factory fix it was red, ABSOLUTE 10: …, the names above;
    • after it, it survives. That's reported, not hidden: it's the evidence that the shared store was never the source. The own-row count stays as the robust shape, immune to anything else in the model.
  • H2, no wait at all (the fixed-delay class at its limit): both real-model rows red, "Expected … to be 1 because our event is folded exactly once, but found 0". The bounded wait carries weight.

Suite

MicroPlumberd.Tests at the tip (21af5dd): 193/199, 16 m 3 s, exit 1, no FATAL or crash, and no refused/409 line. It was the only MP process on the host. The 6 failures are exactly the long-standing set:

  • GrpcApiTests.ApiInvocationWithProcessorCorrelation, ApiHandingExceptionInvocation, ApiSuccessfulInvocation;
  • ProcessManagerSourceGenerationTests.CommandTypes;
  • SubscriptionRunnerStateTests.ThrowsWrongExpectedVersionExceptionWhenOnDoubleChange, …WhenStreamAlreadyExists.

HowToSubscribeRealModel passes.

🤖 Generated with Claude Code

rafalmaciag and others added 4 commits October 18, 2026 15:29
…teDbFactory left LiteDB's journal (test_N-log.db) behind and the next process replayed it; the assertion db is now in-memory, and both HowTo real-model rows count their own reservation after a bounded wait

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…; say why the own-row count stays (rev-reach 6646ada65)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…CLEAN bin (CI: the file factory creates test_1.db) and a DIRTY one (reused names, modified) (rev-reach 5d04e884e)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e no-file row guards both bins

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rafalmaciag
rafalmaciag merged commit 875ab10 into master Oct 18, 2026
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