Skip to content

Add storage conformance suite - #110

Merged
viceroypenguin merged 7 commits into
mainfrom
feature/storage-conformance-suite
Aug 9, 2026
Merged

viceroypenguin merged 7 commits into
mainfrom
feature/storage-conformance-suite

Conversation

@dukesteen

@dukesteen dukesteen commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add a public, framework-neutral storage conformance suite selected by StorageCapabilities
  • resolve IJobStorage from an IServiceProvider and verify its advertised capabilities before each scenario
  • exercise in-memory, Redis, single-server, Entity Framework Core, and LinqToDB registrations through their public DI APIs
  • replace redundant provider tests with 48 reusable conformance cases while retaining provider-specific race, corruption, schema, topology, and execution-strategy coverage
  • consolidate provider, conformance, and storage implementation tests in Immediate.Jobs.StorageTests
  • keep portable in-memory conformance and suite infrastructure coverage on .NET 8, 9, 10, and 11 while limiting the container-backed matrix to .NET 10
  • keep scheduler and generated-job runtime behavior in Immediate.Jobs.FunctionalTests
  • document the storage contract and provider-author workflow

This PR is stacked on #109 and targets refactor/internalize-storage-providers.

Testing

  • dotnet build Immediate.Jobs.slnx --no-restore -v minimal
  • 105 functional tests passed on .NET 10
  • 561 storage tests passed across SQLite, PostgreSQL, SQL Server, and Redis on .NET 10
  • 248 portable storage conformance and infrastructure tests passed across .NET 8, 9, 10, and 11

InternalsVisibleTo follow-up

The conformance suite itself no longer requires InternalsVisibleTo: it uses public registration APIs, receives an IServiceProvider, and resolves IJobStorage from the built container.

Some existing friendships remain because the surviving provider-specific white-box tests directly instantiate internal RedisJobStorage, LinqToDBJobStorage, EntityFrameworkCoreJobStorage, InMemoryJobStorage, and SingleServerJobStorage implementations. Those tests cover cross-instance races, recovery, corruption, transaction behavior, and single-server internals that are deliberately outside the portable conformance contract.

Fully removing those test friendships is possible as a separate refactoring: the remaining fixtures would need to resolve public storage interfaces from independently built containers, and the single-server tests need a public composition seam for custom durable stores and proxies. The Immediate.Jobs.Shared friendship with Immediate.Jobs.Benchmarks is unrelated to storage conformance.

Summary by CodeRabbit

  • New Features

    • Added a framework-neutral storage-provider conformance catalog covering queues, recurring jobs, graphs, fair queues, and replicas.
    • Added capability detection and support indicators for fair-queue and replica functionality.
  • Bug Fixes

    • Improved duplicate recurring-job handling and schedule advancement.
    • Strengthened recurring schedule validation, cleanup, and materialization consistency.
  • Documentation

    • Added comprehensive storage conformance guidance and expanded Testing documentation.
  • Tests

    • Added conformance coverage across in-memory, relational, single-server, and Redis storage configurations.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@dukesteen, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 20 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 63c26b2f-00d9-43d9-863a-b0cd37d3390f

📥 Commits

Reviewing files that changed from the base of the PR and between 85cefe9 and 5ed2982.

📒 Files selected for processing (8)
  • docs/storage-capabilities.md
  • docs/storage-tests.md
  • src/Immediate.Jobs.Shared/Storage/InMemoryJobStorage.cs
  • tests/Immediate.Jobs.FunctionalTests/StorageCapabilityTests.cs
  • tests/Immediate.Jobs.StorageTests/InMemoryStorageConformanceTests.cs
  • tests/Immediate.Jobs.StorageTests/JobExecutionStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/SingleServerJobStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/StorageConformanceInfrastructureTests.cs
📝 Walkthrough

Walkthrough

The change adds a framework-neutral storage conformance catalog, capability detection, provider fixtures, shared queue/recurring/graph/fair-queue/replica cases, provider fixes, and migrated storage tests.

Changes

Storage contracts and conformance API

Layer / File(s) Summary
Capabilities and provider contracts
src/Immediate.Jobs.Shared/..., src/Immediate.Jobs.*/*, docs/storage-tests.md, readme.md
Adds FairQueues and Replica capabilities, IFairQueueStorage, capability detection, provider visibility changes, provider behavior updates, and conformance documentation.
Conformance runner and assertions
src/Immediate.Jobs.Testing/Storage/*
Adds capability-based case selection, runtime capability validation, cancellation handling, failure wrapping, stable names, and assertion utilities.
Shared behavioral catalogs
src/Immediate.Jobs.Testing/Storage/*Conformance.cs
Adds queue, recurring, graph, fair-queue, and replica conformance cases for persistence, acquisition, leases, concurrency, continuations, fairness, and recovery.
Provider fixtures and migration
tests/Immediate.Jobs.StorageTests/*, tests/Immediate.Jobs.StorageTests/*.csproj
Adds isolated relational, single-server, Redis, and in-memory conformance execution with fake time and provider-specific cleanup.
Provider behavior and supporting tests
src/Immediate.Jobs.Shared/Storage/*, src/Immediate.Jobs.EntityFrameworkCore/*, src/Immediate.Jobs.LinqToDB/*, tests/Immediate.Jobs.FunctionalTests/*
Updates recurring deduplication, single-server materialization, recurring-key cleanup, functional scheduling coverage, controllable storage testing, and focused in-memory batch and execution-history coverage. Existing provider-specific tests are removed or reduced where shared conformance cases replace them.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TestRunner
  participant JobStorageConformanceSuite
  participant IServiceProvider
  participant StorageProvider
  participant ConformanceCase

  TestRunner->>JobStorageConformanceSuite: GetCases(capabilities)
  JobStorageConformanceSuite->>TestRunner: Return required cases
  TestRunner->>IServiceProvider: Build isolated provider
  TestRunner->>ConformanceCase: RunAsync(provider, cancellation)
  ConformanceCase->>IServiceProvider: Resolve storage
  ConformanceCase->>StorageProvider: Verify capabilities and run scenario
  StorageProvider->>ConformanceCase: Return persisted state and results
Loading

Possibly related PRs

Suggested reviewers: viceroypenguin

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.93% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the pull request's primary change: adding a storage conformance suite.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/storage-conformance-suite

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@viceroypenguin
viceroypenguin changed the base branch from refactor/internalize-storage-providers to main August 8, 2026 00:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (8)
src/Immediate.Jobs.Testing/Storage/QueueStorageConformance.cs (2)

114-118: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the method name with the case name.

The case constant is Queue.Acquisition.ExcludesFutureJobs, and the body enqueues only a due record and a future record. The method name ExcludesFutureAndParkedAsync implies parked-state coverage that the case does not exercise.

♻️ Proposed rename
-	private static async ValueTask ExcludesFutureAndParkedAsync(
+	private static async ValueTask ExcludesFutureJobsAsync(

Update the reference on line 33 as well:

-		new(DueName, StorageCapabilities.Queue, ExcludesFutureAndParkedAsync),
+		new(DueName, StorageCapabilities.Queue, ExcludesFutureJobsAsync),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Testing/Storage/QueueStorageConformance.cs` around lines
114 - 118, Rename ExcludesFutureAndParkedAsync to ExcludesFutureJobsAsync to
match the Queue.Acquisition.ExcludesFutureJobs case and its covered records, and
update the reference to this method at the existing call site.

458-468: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document that this case disposes the container-owned storage.

DisposesIdempotentlyAsync calls DisposeAsync on the IJobStorage instance that the service provider owns and will dispose again. Every host in this PR builds a fresh provider per case, so the suite passes today. If a provider author reuses one service provider for all cases, the disposal case leaves a disposed singleton for later cases, and failures depend on case order.

State this requirement in the provider-author documentation, or resolve a dedicated storage instance for this case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Testing/Storage/QueueStorageConformance.cs` around lines
458 - 468, Document in the provider-author guidance that
DisposesIdempotentlyAsync disposes the service-provider-owned IJobStorage
instance and therefore requires a provider created specifically for this case;
alternatively, change the test to resolve a dedicated storage instance before
disposing it. Preserve the idempotent disposal assertions.
src/Immediate.Jobs.Testing/Storage/RecurringStorageConformance.cs (1)

425-430: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use GetService so a missing TimeProvider produces a conformance message.

QueueStorageConformance.GetClock (lines 500-508) calls GetService<TimeProvider>() and lets ConformanceAssert.IsAssignableFrom report the missing registration with the case name. This helper calls GetRequiredService<TimeProvider>(), so a provider author who forgets the registration gets an InvalidOperationException that the runner wraps as an unexpected scenario failure. Align both catalogs on the clearer diagnostic.

♻️ Proposed change
 	private static FakeTimeProvider Clock(IServiceProvider serviceProvider, string caseName) =>
 		ConformanceAssert.IsAssignableFrom<FakeTimeProvider>(
-			serviceProvider.GetRequiredService<TimeProvider>(),
+			serviceProvider.GetService<TimeProvider>(),
 			caseName,
 			"time-dependent conformance cases require the registered TimeProvider to be a FakeTimeProvider"
 		);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Testing/Storage/RecurringStorageConformance.cs` around
lines 425 - 430, Update the Clock helper to resolve TimeProvider with GetService
rather than GetRequiredService, allowing ConformanceAssert.IsAssignableFrom to
handle missing registrations and report the case name consistently with
QueueStorageConformance.GetClock.
tests/Immediate.Jobs.StorageTests/StorageConformanceTests.cs (1)

29-63: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Consider sharing one fixture per provider combination.

RelationalStorageConforms creates a fixture for every theory row. The row count is 3 databases × 2 adapters × the full conformance case count, and each row creates and drops a schema, or creates and deletes a SQLite file. This multiplies container round trips and CI time.

Per-case isolation is the safest default, so this is a trade-off rather than a defect. If the suite runtime becomes a problem, group cases by provider combination and reset only the data between cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Immediate.Jobs.StorageTests/StorageConformanceTests.cs` around lines 29
- 63, Consider refactoring RelationalStorageConforms to reuse one
RelationalConformanceFixture for each database and adapter combination, while
resetting only test data between JobStorageConformanceTestCase executions.
Preserve per-case isolation and ensure each provider fixture is disposed after
all its cases complete.
src/Immediate.Jobs.Testing/Storage/GraphStorageConformance.cs (2)

475-476: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the setup acquisition before you complete the job.

The code discards the acquisition result. If AcquireDueJobsAsync returns no job, the later CompleteWithContinuationsAsync call fails with an unrelated message, which hides the real cause. Assert the acquired job and reuse its Attempt value.

♻️ Proposed refactor
-		_ = await graph.AcquireDueJobsAsync(CreateRequest("dynamic-worker", current.JobName), cancellationToken)
-			.ConfigureAwait(false);
+		var acquiredCurrent = ConformanceAssert.NotNull(
+			(await graph.AcquireDueJobsAsync(CreateRequest("dynamic-worker", current.JobName), cancellationToken)
+				.ConfigureAwait(false)).SingleOrDefault(),
+			DynamicName,
+			"the dynamic batch root must be acquirable"
+		);
 		var inserted = CreateJob("dynamic-inserted", batchId: "dynamic-batch");
 		await graph.CompleteWithContinuationsAsync(
 			current.Id,
-			1,
+			acquiredCurrent.Attempt,
 			"dynamic-worker",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Testing/Storage/GraphStorageConformance.cs` around lines
475 - 476, Update the setup acquisition in the conformance test to capture and
assert the result of AcquireDueJobsAsync before completing the job, then reuse
the asserted acquired job’s Attempt value in CompleteWithContinuationsAsync
instead of relying on the existing current job state.

587-595: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Share one default-queue-name helper instead of duplicating the dummy JobRecord probe. Both catalogs construct a throwaway JobRecord only to read its computed QueueName. Extract this into a single internal helper in the conformance package, then use it in both files. If a public accessor for the default queue name already exists, prefer it over the probe.

  • src/Immediate.Jobs.Testing/Storage/GraphStorageConformance.cs#L587-L595: replace the inline probe with the shared helper, and stop rebuilding the record on every CreateRequest call.
  • src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs#L448-L456: delete the local DefaultQueueName probe and reference the shared helper.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Testing/Storage/GraphStorageConformance.cs` around lines
587 - 595, Create one internal default-queue-name helper in the conformance
package, or reuse an existing public accessor if available, instead of
constructing dummy JobRecord probes. In
src/Immediate.Jobs.Testing/Storage/GraphStorageConformance.cs lines 587-595,
replace the inline probe with the shared helper so it is not rebuilt for each
CreateRequest call; in
src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs lines 448-456,
remove the local DefaultQueueName probe and reference the same helper.
src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs (1)

431-440: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Document the acquisition ordering contract.

Queue acquisition orders jobs by DueAt, then CreatedAt, then Id; fair acquisition uses the CreatedAt tie-breaker before comparing candidate fairness. Add this contract to the storage/provider conformance docs so new providers do not implement another deterministic order.

Also mention that enqueue records can have CreatedAt after DueAt for queued delayed jobs, since providers may inspect that field.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs` around
lines 431 - 440, Update the storage/provider conformance documentation around
the enqueue fixture to explicitly define acquisition ordering: sort by DueAt,
then CreatedAt, then Id; for fair acquisition, apply CreatedAt as the
tie-breaker before comparing candidate fairness. Also document that queued
delayed jobs may have CreatedAt later than DueAt, and providers must inspect and
preserve this field.
src/Immediate.Jobs.Testing/Storage/ReplicaStorageConformance.cs (1)

465-465: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Make the expected attempt a parameter of AssertAcquired.

The message says "must increment the attempt", but the assertion requires the absolute value 1. The single current caller acquires the job once, so the check passes today. A later caller that asserts a reclaimed acquisition would get a misleading failure.

♻️ Proposed refactor
 	private static void AssertAcquired(
 		JobRecord expected,
 		JobRecord actual,
 		string workerId,
 		DateTimeOffset leaseExpiresAt,
-		string caseName
+		string caseName,
+		int expectedAttempt = 1
 	)
 	{
-		ConformanceAssert.Equal(1, actual.Attempt, caseName, "exact acquisition must increment the attempt");
+		ConformanceAssert.Equal(expectedAttempt, actual.Attempt, caseName, "exact acquisition must increment the attempt");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Immediate.Jobs.Testing/Storage/ReplicaStorageConformance.cs` at line 465,
Update AssertAcquired to accept an expected attempt parameter and compare
actual.Attempt against it instead of hardcoding 1. Pass the appropriate expected
attempt from each caller, including the existing single-acquisition case, while
preserving the current assertion message and behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Immediate.Jobs.EntityFrameworkCore/EntityFrameworkCoreJobStorage.cs`:
- Around line 15-18: Restore public accessibility for
EntityFrameworkCoreJobStorage<TContext> in
src/Immediate.Jobs.EntityFrameworkCore/EntityFrameworkCoreJobStorage.cs:15-18,
LinqToDBJobStorage in src/Immediate.Jobs.LinqToDB/LinqToDBJobStorage.cs:14, and
RedisJobStorage in src/Immediate.Jobs.Redis/RedisJobStorage.cs:16 so existing
consumers and public factory methods retain access to these storage
implementations.

In `@src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs`:
- Around line 375-383: Update the concurrent acquisition assertions in the test
around Task.WhenAll: remove the requirement that the two parallel claims
immediately return exactly 12 IDs, while retaining the invariant that IDs are
distinct. Then either drain remaining eligible jobs after the concurrent calls
and verify all 12 are eventually claimed, or assert the collected ID count does
not exceed 12.

In `@src/Immediate.Jobs.Testing/Storage/JobStorageConformanceTestCase.cs`:
- Line 61: Update the setup in the conformance test case to resolve all
registrations through GetServices<IJobStorage>() and require exactly one result
before assigning the storage used by the scenario. Replace the current
GetRequiredService<IJobStorage>() resolution while preserving the existing
failure behavior for invalid service configuration.

In `@src/Immediate.Jobs.Testing/Storage/ReplicaStorageConformance.cs`:
- Around line 258-268: Update the clock advancement immediately before the
second AcquireJobsAsync call in the stale-worker lease test to move beyond the
first lease’s expiry instant, rather than exactly one minute. Preserve the
existing reclaimability assertion and use a small additional duration sufficient
to avoid provider-specific expiry-boundary behavior.

In `@tests/Immediate.Jobs.StorageTests/StorageConformanceTests.cs`:
- Around line 199-241: Update the fixture-construction method containing
ConformanceDbContextFactory and serviceCollection so schema creation and
BuildServiceProvider occur inside a try/catch after constructing the fixture. On
any failure from CreateImmediateJobsSchemaAsync, ExecuteSqlRawAsync, or provider
validation, call the fixture’s DisposeAsync cleanup before rethrowing, matching
the existing MatrixFixture pattern in RelationalStorageMatrixTests.

---

Nitpick comments:
In `@src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs`:
- Around line 431-440: Update the storage/provider conformance documentation
around the enqueue fixture to explicitly define acquisition ordering: sort by
DueAt, then CreatedAt, then Id; for fair acquisition, apply CreatedAt as the
tie-breaker before comparing candidate fairness. Also document that queued
delayed jobs may have CreatedAt later than DueAt, and providers must inspect and
preserve this field.

In `@src/Immediate.Jobs.Testing/Storage/GraphStorageConformance.cs`:
- Around line 475-476: Update the setup acquisition in the conformance test to
capture and assert the result of AcquireDueJobsAsync before completing the job,
then reuse the asserted acquired job’s Attempt value in
CompleteWithContinuationsAsync instead of relying on the existing current job
state.
- Around line 587-595: Create one internal default-queue-name helper in the
conformance package, or reuse an existing public accessor if available, instead
of constructing dummy JobRecord probes. In
src/Immediate.Jobs.Testing/Storage/GraphStorageConformance.cs lines 587-595,
replace the inline probe with the shared helper so it is not rebuilt for each
CreateRequest call; in
src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs lines 448-456,
remove the local DefaultQueueName probe and reference the same helper.

In `@src/Immediate.Jobs.Testing/Storage/QueueStorageConformance.cs`:
- Around line 114-118: Rename ExcludesFutureAndParkedAsync to
ExcludesFutureJobsAsync to match the Queue.Acquisition.ExcludesFutureJobs case
and its covered records, and update the reference to this method at the existing
call site.
- Around line 458-468: Document in the provider-author guidance that
DisposesIdempotentlyAsync disposes the service-provider-owned IJobStorage
instance and therefore requires a provider created specifically for this case;
alternatively, change the test to resolve a dedicated storage instance before
disposing it. Preserve the idempotent disposal assertions.

In `@src/Immediate.Jobs.Testing/Storage/RecurringStorageConformance.cs`:
- Around line 425-430: Update the Clock helper to resolve TimeProvider with
GetService rather than GetRequiredService, allowing
ConformanceAssert.IsAssignableFrom to handle missing registrations and report
the case name consistently with QueueStorageConformance.GetClock.

In `@src/Immediate.Jobs.Testing/Storage/ReplicaStorageConformance.cs`:
- Line 465: Update AssertAcquired to accept an expected attempt parameter and
compare actual.Attempt against it instead of hardcoding 1. Pass the appropriate
expected attempt from each caller, including the existing single-acquisition
case, while preserving the current assertion message and behavior.

In `@tests/Immediate.Jobs.StorageTests/StorageConformanceTests.cs`:
- Around line 29-63: Consider refactoring RelationalStorageConforms to reuse one
RelationalConformanceFixture for each database and adapter combination, while
resetting only test data between JobStorageConformanceTestCase executions.
Preserve per-case isolation and ensure each provider fixture is disposed after
all its cases complete.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: defcebd9-1028-4f5f-8eb0-5ffaa227cba4

📥 Commits

Reviewing files that changed from the base of the PR and between 3d0c723 and e0de719.

📒 Files selected for processing (38)
  • docs/storage-tests.md
  • readme.md
  • src/Immediate.Jobs.EntityFrameworkCore/EntityFrameworkCoreJobStorage.cs
  • src/Immediate.Jobs.EntityFrameworkCore/Immediate.Jobs.EntityFrameworkCore.csproj
  • src/Immediate.Jobs.EntityFrameworkCore/ImmediateJobsModelBuilderExtensions.cs
  • src/Immediate.Jobs.LinqToDB/Immediate.Jobs.LinqToDB.csproj
  • src/Immediate.Jobs.LinqToDB/LinqToDBJobStorage.cs
  • src/Immediate.Jobs.Redis/Immediate.Jobs.Redis.csproj
  • src/Immediate.Jobs.Redis/RedisJobStorage.cs
  • src/Immediate.Jobs.Shared/Immediate.Jobs.Shared.csproj
  • src/Immediate.Jobs.Shared/Storage/IFairQueueStorage.cs
  • src/Immediate.Jobs.Shared/Storage/InMemoryJobStorage.cs
  • src/Immediate.Jobs.Shared/Storage/SingleServerJobStorage.cs
  • src/Immediate.Jobs.Shared/Storage/StorageCapabilities.cs
  • src/Immediate.Jobs.Testing/Immediate.Jobs.Testing.csproj
  • src/Immediate.Jobs.Testing/Storage/ConformanceAssert.cs
  • src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs
  • src/Immediate.Jobs.Testing/Storage/GraphStorageConformance.cs
  • src/Immediate.Jobs.Testing/Storage/JobStorageConformanceScenario.cs
  • src/Immediate.Jobs.Testing/Storage/JobStorageConformanceSuite.cs
  • src/Immediate.Jobs.Testing/Storage/JobStorageConformanceTestCase.cs
  • src/Immediate.Jobs.Testing/Storage/QueueStorageConformance.cs
  • src/Immediate.Jobs.Testing/Storage/RecurringStorageConformance.cs
  • src/Immediate.Jobs.Testing/Storage/ReplicaStorageConformance.cs
  • tests/Immediate.Jobs.FunctionalTests/Packages/InMemoryStorageConformanceTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Packages/StorageConformanceInfrastructureTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/EntityFrameworkCoreJobStorageTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/InMemoryFairQueueTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/InMemoryJobStorageBatchTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/JobExecutionStorageTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/QueueStorageTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/SingleServerJobStorageTests.cs
  • tests/Immediate.Jobs.FunctionalTests/StorageCapabilityTests.cs
  • tests/Immediate.Jobs.StorageTests/Immediate.Jobs.StorageTests.csproj
  • tests/Immediate.Jobs.StorageTests/LinqToDBSqliteStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/RedisStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/RelationalStorageMatrixTests.cs
  • tests/Immediate.Jobs.StorageTests/StorageConformanceTests.cs
💤 Files with no reviewable changes (6)
  • tests/Immediate.Jobs.FunctionalTests/Storage/InMemoryJobStorageBatchTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/QueueStorageTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/InMemoryFairQueueTests.cs
  • tests/Immediate.Jobs.FunctionalTests/Storage/JobExecutionStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/RedisStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/LinqToDBSqliteStorageTests.cs

Comment thread src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs
Comment thread src/Immediate.Jobs.Testing/Storage/JobStorageConformanceTestCase.cs Outdated
Comment thread src/Immediate.Jobs.Testing/Storage/ReplicaStorageConformance.cs
Comment thread tests/Immediate.Jobs.StorageTests/StorageConformanceTests.cs
@dukesteen
dukesteen changed the base branch from main to refactor/internalize-storage-providers August 8, 2026 20:44
@coveralls

coveralls commented Aug 8, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 31316266018

Coverage increased (+6.6%) to 90.508%

Details

  • Coverage increased (+6.6%) from the base build.
  • Patch coverage: 63 uncovered changes across 6 files (2142 of 2205 lines covered, 97.14%).
  • 11 coverage regressions across 4 files.

Uncovered Changes

File Changed Covered %
src/Immediate.Jobs.Testing/Storage/ConformanceAssert.cs 88 38 43.18%
src/Immediate.Jobs.Testing/Storage/JobStorageConformanceTestCase.cs 46 39 84.78%
src/Immediate.Jobs.Shared/Storage/SingleServerJobStorage.cs 24 21 87.5%
src/Immediate.Jobs.Shared/Storage/InMemoryJobStorage.cs 11 10 90.91%
src/Immediate.Jobs.Testing/Storage/RecurringStorageConformance.cs 371 370 99.73%
src/Immediate.Jobs.Testing/Storage/ReplicaStorageConformance.cs 360 359 99.72%
Total (14 files) 2205 2142 97.14%

Coverage Regressions

11 previously-covered lines in 4 files lost coverage.

File Lines Losing Coverage Coverage
src/Immediate.Jobs.EntityFrameworkCore/EntityFrameworkCoreJobStorage.cs 5 91.78%
src/Immediate.Jobs.Shared/Storage/SingleServerJobStorage.cs 4 84.31%
src/Immediate.Jobs.LinqToDB/LinqToDBJobStorage.cs 1 87.81%
src/Immediate.Jobs.Redis/RedisJobStorage.cs 1 96.93%

Coverage Stats

Coverage Status
Relevant Lines: 12095
Covered Lines: 10947
Line Coverage: 90.51%
Coverage Strength: 2.61 hits per line

💛 - Coveralls

@viceroypenguin
viceroypenguin force-pushed the feature/storage-conformance-suite branch from f35fced to 71f7024 Compare August 8, 2026 22:31
@viceroypenguin
viceroypenguin deleted the branch main August 8, 2026 22:34
@viceroypenguin viceroypenguin reopened this Aug 8, 2026
@viceroypenguin
viceroypenguin changed the base branch from refactor/internalize-storage-providers to main August 8, 2026 23:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/Immediate.Jobs.StorageTests/JobExecutionStorageTests.cs`:
- Around line 15-16: Update the legacy job fixture in JobExecutionStorageTests
so CreateJob’s CreatedAt value is at least two minutes earlier than completedAt,
while preserving the existing execution timestamps and test flow.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0f0be227-01e1-4896-b298-2873df8fac28

📥 Commits

Reviewing files that changed from the base of the PR and between 0c541f4 and 85cefe9.

📒 Files selected for processing (15)
  • src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs
  • src/Immediate.Jobs.Testing/Storage/JobStorageConformanceTestCase.cs
  • tests/Immediate.Jobs.FunctionalTests/BatchesAndContinuationsTests.cs
  • tests/Immediate.Jobs.FunctionalTests/ControllableJobStorageProxy.cs
  • tests/Immediate.Jobs.FunctionalTests/JobSchedulingServiceTests.cs
  • tests/Immediate.Jobs.StorageTests/EntityFrameworkCoreJobStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/InMemoryJobStorageBatchTests.cs
  • tests/Immediate.Jobs.StorageTests/InMemoryStorageConformanceTests.cs
  • tests/Immediate.Jobs.StorageTests/JobExecutionStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/LinqToDBSqliteStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/RedisStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/RelationalStorageMatrixTests.cs
  • tests/Immediate.Jobs.StorageTests/SingleServerJobStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/StorageConformanceInfrastructureTests.cs
  • tests/Immediate.Jobs.StorageTests/StorageConformanceTests.cs
💤 Files with no reviewable changes (2)
  • tests/Immediate.Jobs.StorageTests/RedisStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/LinqToDBSqliteStorageTests.cs
🚧 Files skipped from review as they are similar to previous changes (11)
  • tests/Immediate.Jobs.StorageTests/InMemoryStorageConformanceTests.cs
  • tests/Immediate.Jobs.FunctionalTests/JobSchedulingServiceTests.cs
  • src/Immediate.Jobs.Testing/Storage/FairQueueStorageConformance.cs
  • src/Immediate.Jobs.Testing/Storage/JobStorageConformanceTestCase.cs
  • tests/Immediate.Jobs.StorageTests/EntityFrameworkCoreJobStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/StorageConformanceTests.cs
  • tests/Immediate.Jobs.StorageTests/StorageConformanceInfrastructureTests.cs
  • tests/Immediate.Jobs.FunctionalTests/BatchesAndContinuationsTests.cs
  • tests/Immediate.Jobs.StorageTests/SingleServerJobStorageTests.cs
  • tests/Immediate.Jobs.StorageTests/InMemoryJobStorageBatchTests.cs
  • tests/Immediate.Jobs.StorageTests/RelationalStorageMatrixTests.cs

Comment thread tests/Immediate.Jobs.StorageTests/JobExecutionStorageTests.cs Outdated
@viceroypenguin
viceroypenguin enabled auto-merge (squash) August 9, 2026 13:41
@viceroypenguin
viceroypenguin merged commit d3c1e04 into main Aug 9, 2026
3 checks passed
@viceroypenguin
viceroypenguin deleted the feature/storage-conformance-suite branch August 9, 2026 13:45
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.

3 participants