Skip to content

GH-4035: select the storage reset by its own marker instead of the durable-inbox one - #4038

Merged
jeremydmiller merged 1 commit into
mainfrom
gh-4035/storage-reset-selector
Aug 23, 2026
Merged

GH-4035: select the storage reset by its own marker instead of the durable-inbox one#4038
jeremydmiller merged 1 commit into
mainfrom
gh-4035/storage-reset-selector

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #4035. Follow-up to #4028 / #4031, which is merged and correct — this fixes a second-order consequence of it that CI could not see.

What broke

ClearAllWolverineStorageAsync() picked the queues it resets with .Where(x => x is IDatabaseBackedEndpoint), so an endpoint's inbox behaviour silently decided whether integration tests could reset it. #4031 correctly removed that marker from RedisStreamEndpoint — and thereby dropped Redis streams out of the reset entirely. All 38 checks stayed green, because there was no Redis implementation of ClearAllWolverineStorageCompliance and no Redis test called the helper.

The comment above the selector still claimed coverage of "PostgreSQL, SQL Server, MySQL, Oracle, SQLite, and Redis streams", and docs/guide/testing.md:835 presents the helper as the integration-test reset — so a Redis user following the docs started carrying stream entries between runs with no signal.

The fix

IStorageBackedQueue says what the reset actually means: a queue whose contents live in storage Wolverine provisions rather than in an external broker. Carried by the five database queues and by RedisStreamEndpoint, and independent of IDatabaseBackedEndpoint — an endpoint may be either, both, or neither. Both interfaces now carry <remarks> saying which job is which, since conflating them is what caused this.

A second bug, found by the new coverage

RedisStreamEndpoint.PurgeAsync() deleted the stream key but not the scheduled sorted set. So even once Redis was back in the reset path, a scheduled message survived a "reset" and fired into the next test. That sorted set is part of this queue's storage exactly as the scheduled-message table is on the database queues.

Compliance suite seams

Two, so a non-table transport can implement the suite honestly instead of reshaping its own surface to fit:

  • queueCountsAsync() is virtual — RedisStreamEndpoint.GetAttributesAsync() reports streamKey/messageCount/consumerGroup, not the database queues' Count/Scheduled. Overriding beats changing a diagnostic surface other things read.
  • TeardownMakesTheQueueUnwritable gates the missing-storage precondition in rebuilds_queue_tables_that_have_been_dropped. A Redis XADD silently recreates a deleted stream key, so there is no absent "table" to observe; the rest of that test still runs for Redis.

Verification

The new suite actually catches the regression — with the selector reverted to IDatabaseBackedEndpoint, 3 of its 5 tests fail. A regression test that passes either way would have been worse than none, so this was checked rather than assumed.

Result
dotnet build wolverine.slnx -c Release -f net9.0 clean, 0 warnings
Wolverine.Redis.Tests 152 / 152
CoreTests 2533, 0 failed, 2 skipped
SqliteTests.Transport.clear_all_wolverine_storage 5 / 5
PostgresqlTests.Transport.clear_all_wolverine_storage 5 / 5

The two existing provider suites are there to show the marker change didn't disturb them. All figures are from the current base (d9a68b9ae, including #4032).

🤖 Generated with Claude Code

…rable-inbox one

ClearAllWolverineStorageAsync() picked the queues it resets with
`.Where(x => x is IDatabaseBackedEndpoint)`, so an endpoint's *inbox* behaviour silently
decided whether integration tests could reset it. GH-4028 correctly removed that marker
from RedisStreamEndpoint -- and thereby dropped Redis streams out of the reset entirely,
with all 38 checks green, because no Redis implementation of the compliance suite existed.

IStorageBackedQueue now says what the reset actually means: a queue whose contents live in
storage Wolverine provisions rather than in an external broker. It is carried by the five
database queues and by RedisStreamEndpoint, and it is independent of IDatabaseBackedEndpoint
-- an endpoint may be either, both, or neither.

Also fixed, found by the new coverage:

* RedisStreamEndpoint.PurgeAsync() deleted the stream key but not the scheduled sorted set,
  so a scheduled message survived a "reset" and fired into the next test. The sorted set is
  part of this queue's storage exactly as the scheduled-message table is on the database
  queues.

The compliance suite gains two seams so a non-table transport can implement it honestly
rather than by bending its own surface to fit:

* queueCountsAsync() is virtual -- RedisStreamEndpoint.GetAttributesAsync() reports
  streamKey/messageCount/consumerGroup, not the database queues' Count/Scheduled.
* TeardownMakesTheQueueUnwritable gates the missing-storage precondition in
  rebuilds_queue_tables_that_have_been_dropped. A Redis XADD silently recreates a deleted
  stream key, so only the empties-it half of that scenario is observable there; the rest of
  the test still runs.

Verified the new suite actually catches the regression: with the selector reverted to
IDatabaseBackedEndpoint, 3 of its 5 tests fail.

wolverine.slnx -c Release -f net9.0 clean. Wolverine.Redis.Tests 152/152. CoreTests
2525 (0 failed, 2 skipped). Sqlite and Postgresql clear_all_wolverine_storage 5/5 each.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jeremydmiller
jeremydmiller merged commit fea30a7 into main Aug 23, 2026
38 of 39 checks passed
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.

ClearAllWolverineStorageAsync silently stopped resetting Redis streams after #4031 — IDatabaseBackedEndpoint was also the reset selector

1 participant