Skip to content
Tracon

IdempotencyStoreContract

Namespace Tracon.Testing.Contracts.Storage · Assembly Tracon.Testing.Contracts.Xunit.dll

Behavior tests for the IIdempotencyStore contract.

public abstract class IdempotencyStoreContract : StoreCancellationContract<IIdempotencyStore>, IAsyncLifetime, IAsyncDisposable
Inheritance
object ← StoreCancellationContract<IIdempotencyStore> ← IdempotencyStoreContract
Implements
IAsyncLifetime, IAsyncDisposable
Inherited Members
StoreCancellationContract<IIdempotencyStore>.CreateStoreAsync(), StoreCancellationContract<IIdempotencyStore>.InitializeAsync(), StoreCancellationContract<IIdempotencyStore>.DisposeAsync(), StoreCancellationContract<IIdempotencyStore>.OnDisposeAsync(), StoreCancellationContract<IIdempotencyStore>.CancellableReadAsync(CancellationToken), StoreCancellationContract<IIdempotencyStore>.CancellableWriteAsync(CancellationToken), StoreCancellationContract<IIdempotencyStore>.WroteAnythingAsync(), StoreCancellationContract<IIdempotencyStore>.Canceled_token_throws_on_read(), StoreCancellationContract<IIdempotencyStore>.The_write_this_contract_checks_can_be_read_back(), StoreCancellationContract<IIdempotencyStore>.Canceled_token_throws_on_write_and_leaves_no_trace(), StoreCancellationContract<IIdempotencyStore>.Store, object.GetType(), object.MemberwiseClone(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

The in-memory store and the three SQL providers must pass the same scenarios.

The tenant id is passed explicitly to every call (not through the ambient ITenantContext) — the contract therefore does not rely on the generic CRUD shape of Storage.TenantIsolationContract and derives from Storage.StoreCancellationContract directly; the same pattern as SingletonLeaseStoreContract.

protected IdempotencyStoreContract()

Calls one read method of the store with the given token.

protected override ValueTask CancellableReadAsync(CancellationToken cancellationToken)

cancellationToken CancellationToken

The token the store must observe.

ValueTask

The completion task; any result is discarded.

A reservation for a key that already exists is the read path: it reports the stored state instead of opening a new slot.

Calls one write method of the store with the given token.

protected override ValueTask CancellableWriteAsync(CancellationToken cancellationToken)

cancellationToken CancellationToken

The token the store must observe.

ValueTask

The completion task.

The write must be one StoreCancellationContract.WroteAnythingAsync can see. A write this contract cannot read back proves nothing about side effects, which is why StoreCancellationContract.The_write_this_contract_checks_can_be_read_back runs the same pair with a live token and requires the read to find it.

Completed_key_also_returns_the_stored_HTTP_headers()

Section titled “ Completed_key_also_returns_the_stored_HTTP_headers()”
[Fact]
public Task Completed_key_also_returns_the_stored_HTTP_headers()

Task

Completed_key_returns_an_empty_dictionary_when_there_are_NO_headers()

Section titled “ Completed_key_returns_an_empty_dictionary_when_there_are_NO_headers()”
[Fact]
public Task Completed_key_returns_an_empty_dictionary_when_there_are_NO_headers()

Task

Completed_key_returns_the_stored_response_with_the_same_fingerprint()

Section titled “ Completed_key_returns_the_stored_response_with_the_same_fingerprint()”
[Fact]
public Task Completed_key_returns_the_stored_response_with_the_same_fingerprint()

Task

Completed_key_with_a_DIFFERENT_fingerprint_returns_FingerprintMismatch()

Section titled “ Completed_key_with_a_DIFFERENT_fingerprint_returns_FingerprintMismatch()”
[Fact]
public Task Completed_key_with_a_DIFFERENT_fingerprint_returns_FingerprintMismatch()

Task

Completed_record_does_NOT_affect_another_tenant()

Section titled “ Completed_record_does_NOT_affect_another_tenant()”
[Fact]
public Task Completed_record_does_NOT_affect_another_tenant()

Task

Concurrent_reservation_of_the_same_key_only_one_gets_Reserved()

Section titled “ Concurrent_reservation_of_the_same_key_only_one_gets_Reserved()”
[Fact]
public Task Concurrent_reservation_of_the_same_key_only_one_gets_Reserved()

Task

Key_in_progress_returns_InProgress_on_second_reservation()

Section titled “ Key_in_progress_returns_InProgress_on_second_reservation()”
[Fact]
public Task Key_in_progress_returns_InProgress_on_second_reservation()

Task

[Fact]
public Task New_key_returns_Reserved()

Task

[Fact]
public Task Released_key_can_be_reserved_again()

Task

Same_key_lives_independently_in_two_tenants()

Section titled “ Same_key_lives_independently_in_two_tenants()”
[Fact]
public Task Same_key_lives_independently_in_two_tenants()

Task

Reports whether StoreCancellationContract.CancellableWriteAsync left anything behind.

protected override ValueTask<bool> WroteAnythingAsync()

ValueTask<bool>

true if the store holds any record the write would have created.

A key nothing ever reserved comes back IdempotencyState.Reserved – a fresh slot. Any other state means the cancelled call wrote a row.