# IdempotencyStoreContract

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.testing.contracts.storage.idempotencystorecontract/
> Summary: IdempotencyStoreContract: Behavior tests for the IIdempotencyStore contract.

<div class="api-provenance">Namespace Tracon.Testing.Contracts.Storage · Assembly <code>Tracon.Testing.Contracts.Xunit.dll</code></div>

Behavior tests for the [IIdempotencyStore](/api/tracon.iidempotencystore/) contract.

```csharp
public abstract class IdempotencyStoreContract : StoreCancellationContract<IIdempotencyStore>, IAsyncLifetime, IAsyncDisposable
```

<dl class="api-relations"><dt>Inheritance</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object">object</a> ← <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/">StoreCancellationContract&lt;IIdempotencyStore&gt;</a> ← <a href="/api/tracon.testing.contracts.storage.idempotencystorecontract/">IdempotencyStoreContract</a></dd><dt>Implements</dt><dd>IAsyncLifetime, <a href="https://learn.microsoft.com/dotnet/api/system.iasyncdisposable">IAsyncDisposable</a></dd><dt>Inherited Members</dt><dd><a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_CreateStoreAsync">StoreCancellationContract&lt;IIdempotencyStore&gt;.CreateStoreAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_InitializeAsync">StoreCancellationContract&lt;IIdempotencyStore&gt;.InitializeAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_DisposeAsync">StoreCancellationContract&lt;IIdempotencyStore&gt;.DisposeAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_OnDisposeAsync">StoreCancellationContract&lt;IIdempotencyStore&gt;.OnDisposeAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_CancellableReadAsync_System_Threading_CancellationToken_">StoreCancellationContract&lt;IIdempotencyStore&gt;.CancellableReadAsync(CancellationToken)</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_CancellableWriteAsync_System_Threading_CancellationToken_">StoreCancellationContract&lt;IIdempotencyStore&gt;.CancellableWriteAsync(CancellationToken)</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_WroteAnythingAsync">StoreCancellationContract&lt;IIdempotencyStore&gt;.WroteAnythingAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_Canceled_token_throws_on_read">StoreCancellationContract&lt;IIdempotencyStore&gt;.Canceled_token_throws_on_read()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_The_write_this_contract_checks_can_be_read_back">StoreCancellationContract&lt;IIdempotencyStore&gt;.The_write_this_contract_checks_can_be_read_back()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_Canceled_token_throws_on_write_and_leaves_no_trace">StoreCancellationContract&lt;IIdempotencyStore&gt;.Canceled_token_throws_on_write_and_leaves_no_trace()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_Store">StoreCancellationContract&lt;IIdempotencyStore&gt;.Store</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.gettype">object.GetType()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone">object.MemberwiseClone()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.tostring">object.ToString()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a></dd></dl>

## Remarks

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](/api/tracon.itenantcontext/)) — the contract therefore does
not rely on the generic CRUD shape of
[Storage.TenantIsolationContract](/api/tracon.testing.contracts.storage/) and derives from
[Storage.StoreCancellationContract](/api/tracon.testing.contracts.storage/) directly; the same pattern
as `SingletonLeaseStoreContract`.

## Constructors

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract__ctor"></a> IdempotencyStoreContract\(\)

```csharp
protected IdempotencyStoreContract()
```

## Methods

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_CancellableReadAsync_System_Threading_CancellationToken_"></a> CancellableReadAsync\(CancellationToken\)

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

```csharp
protected override ValueTask CancellableReadAsync(CancellationToken cancellationToken)
```

#### Parameters

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The token the store must observe.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask)

The completion task; any result is discarded.

#### Remarks

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

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_CancellableWriteAsync_System_Threading_CancellationToken_"></a> CancellableWriteAsync\(CancellationToken\)

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

```csharp
protected override ValueTask CancellableWriteAsync(CancellationToken cancellationToken)
```

#### Parameters

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The token the store must observe.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask)

The completion task.

#### Remarks

The write must be one [StoreCancellationContract.WroteAnythingAsync](/api/tracon.testing.contracts.storage/) 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](/api/tracon.testing.contracts.storage/)
runs the same pair with a live token and requires the read to find it.

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Completed_key_also_returns_the_stored_HTTP_headers"></a> Completed\_key\_also\_returns\_the\_stored\_HTTP\_headers\(\)

```csharp
[Fact]
public Task Completed_key_also_returns_the_stored_HTTP_headers()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Completed_key_returns_an_empty_dictionary_when_there_are_NO_headers"></a> Completed\_key\_returns\_an\_empty\_dictionary\_when\_there\_are\_NO\_headers\(\)

```csharp
[Fact]
public Task Completed_key_returns_an_empty_dictionary_when_there_are_NO_headers()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Completed_key_returns_the_stored_response_with_the_same_fingerprint"></a> Completed\_key\_returns\_the\_stored\_response\_with\_the\_same\_fingerprint\(\)

```csharp
[Fact]
public Task Completed_key_returns_the_stored_response_with_the_same_fingerprint()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Completed_key_with_a_DIFFERENT_fingerprint_returns_FingerprintMismatch"></a> Completed\_key\_with\_a\_DIFFERENT\_fingerprint\_returns\_FingerprintMismatch\(\)

```csharp
[Fact]
public Task Completed_key_with_a_DIFFERENT_fingerprint_returns_FingerprintMismatch()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Completed_record_does_NOT_affect_another_tenant"></a> Completed\_record\_does\_NOT\_affect\_another\_tenant\(\)

```csharp
[Fact]
public Task Completed_record_does_NOT_affect_another_tenant()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Concurrent_reservation_of_the_same_key_only_one_gets_Reserved"></a> Concurrent\_reservation\_of\_the\_same\_key\_only\_one\_gets\_Reserved\(\)

```csharp
[Fact]
public Task Concurrent_reservation_of_the_same_key_only_one_gets_Reserved()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Key_in_progress_returns_InProgress_on_second_reservation"></a> Key\_in\_progress\_returns\_InProgress\_on\_second\_reservation\(\)

```csharp
[Fact]
public Task Key_in_progress_returns_InProgress_on_second_reservation()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_New_key_returns_Reserved"></a> New\_key\_returns\_Reserved\(\)

```csharp
[Fact]
public Task New_key_returns_Reserved()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Released_key_can_be_reserved_again"></a> Released\_key\_can\_be\_reserved\_again\(\)

```csharp
[Fact]
public Task Released_key_can_be_reserved_again()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_Same_key_lives_independently_in_two_tenants"></a> Same\_key\_lives\_independently\_in\_two\_tenants\(\)

```csharp
[Fact]
public Task Same_key_lives_independently_in_two_tenants()
```

#### Returns

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_IdempotencyStoreContract_WroteAnythingAsync"></a> WroteAnythingAsync\(\)

Reports whether [StoreCancellationContract.CancellableWriteAsync](/api/tracon.testing.contracts.storage/) left anything
behind.

```csharp
protected override ValueTask<bool> WroteAnythingAsync()
```

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[bool](https://learn.microsoft.com/dotnet/api/system.boolean)\>

[true](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool) if the store holds any record the write would have created.

#### Remarks

A key nothing ever reserved comes back [IdempotencyState.Reserved](/api/tracon.idempotencystate/)
-- a fresh slot. Any other state means the cancelled call wrote a row.
