# ToolInvocationContract

> 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.toolinvocationcontract/
> Summary: ToolInvocationContract: Behavior tests for the IRunStore tool-invocation contract.

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

Behavior tests for the [IRunStore](/api/tracon.irunstore/) tool-invocation contract.

```csharp
public abstract class ToolInvocationContract : TenantIsolationContract<IRunStore>, 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;IRunStore&gt;</a> ← <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/">TenantIsolationContract&lt;IRunStore&gt;</a> ← <a href="/api/tracon.testing.contracts.storage.toolinvocationcontract/">ToolInvocationContract</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.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_TenantA">TenantIsolationContract&lt;IRunStore&gt;.TenantA</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_TenantB">TenantIsolationContract&lt;IRunStore&gt;.TenantB</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_UseAmbientTenant_Tracon_Testing_Contracts_Storage_MutableTenantContext_">TenantIsolationContract&lt;IRunStore&gt;.UseAmbientTenant(MutableTenantContext)</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_SeedAsync_System_String_System_String_System_Threading_CancellationToken_">TenantIsolationContract&lt;IRunStore&gt;.SeedAsync(string, string, CancellationToken)</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_ExistsAsync_System_String_System_Object_">TenantIsolationContract&lt;IRunStore&gt;.ExistsAsync(string, object)</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_CountAsync_System_String_System_Threading_CancellationToken_">TenantIsolationContract&lt;IRunStore&gt;.CountAsync(string, CancellationToken)</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_TryDeleteAsync_System_String_System_Object_">TenantIsolationContract&lt;IRunStore&gt;.TryDeleteAsync(string, object)</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_TryOverwriteAsync_System_String_System_String_">TenantIsolationContract&lt;IRunStore&gt;.TryOverwriteAsync(string, string)</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_CancellableReadAsync_System_Threading_CancellationToken_">TenantIsolationContract&lt;IRunStore&gt;.CancellableReadAsync(CancellationToken)</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_CancellableWriteAsync_System_Threading_CancellationToken_">TenantIsolationContract&lt;IRunStore&gt;.CancellableWriteAsync(CancellationToken)</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_WroteAnythingAsync">TenantIsolationContract&lt;IRunStore&gt;.WroteAnythingAsync()</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_Tenant_cannot_read_another_tenants_record">TenantIsolationContract&lt;IRunStore&gt;.Tenant_cannot_read_another_tenants_record()</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_Tenant_reads_its_own_record">TenantIsolationContract&lt;IRunStore&gt;.Tenant_reads_its_own_record()</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_Tenant_does_not_see_another_tenants_record_in_the_list">TenantIsolationContract&lt;IRunStore&gt;.Tenant_does_not_see_another_tenants_record_in_the_list()</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_Tenant_cannot_delete_another_tenants_record">TenantIsolationContract&lt;IRunStore&gt;.Tenant_cannot_delete_another_tenants_record()</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_Same_name_lives_independently_across_two_tenants">TenantIsolationContract&lt;IRunStore&gt;.Same_name_lives_independently_across_two_tenants()</a>, <a href="/api/tracon.testing.contracts.storage.tenantisolationcontract-1/#Tracon_Testing_Contracts_Storage_TenantIsolationContract_1_AmbientTenant">TenantIsolationContract&lt;IRunStore&gt;.AmbientTenant</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_CreateStoreAsync">StoreCancellationContract&lt;IRunStore&gt;.CreateStoreAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_InitializeAsync">StoreCancellationContract&lt;IRunStore&gt;.InitializeAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_DisposeAsync">StoreCancellationContract&lt;IRunStore&gt;.DisposeAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_OnDisposeAsync">StoreCancellationContract&lt;IRunStore&gt;.OnDisposeAsync()</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_CancellableReadAsync_System_Threading_CancellationToken_">StoreCancellationContract&lt;IRunStore&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;IRunStore&gt;.CancellableWriteAsync(CancellationToken)</a>, <a href="/api/tracon.testing.contracts.storage.storecancellationcontract-1/#Tracon_Testing_Contracts_Storage_StoreCancellationContract_1_WroteAnythingAsync">StoreCancellationContract&lt;IRunStore&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;IRunStore&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;IRunStore&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;IRunStore&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;IRunStore&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

Every implementation must pass the same scenarios; the summary is
computed *in the store itself*, not by fetching rows and
aggregating them in memory.

## Constructors

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract__ctor"></a> ToolInvocationContract\(\)

```csharp
protected ToolInvocationContract()
```

## Methods

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_A_late_settlement_does_not_count_as_a_second_call"></a> A\_late\_settlement\_does\_not\_count\_as\_a\_second\_call\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_A_late_settlement_never_erases_a_measurement_the_row_already_carries"></a> A\_late\_settlement\_never\_erases\_a\_measurement\_the\_row\_already\_carries\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_A_measurement_that_names_no_provider_or_model_comes_back_with_none"></a> A\_measurement\_that\_names\_no\_provider\_or\_model\_comes\_back\_with\_none\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_A_second_late_settlement_for_the_same_call_changes_nothing"></a> A\_second\_late\_settlement\_for\_the\_same\_call\_changes\_nothing\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_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_ToolInvocationContract_CountAsync_System_String_System_Threading_CancellationToken_"></a> CountAsync\(string, CancellationToken\)

Reports how many records the given tenant sees through the listing endpoint.

```csharp
protected override ValueTask<int> CountAsync(string tenantId, CancellationToken cancellationToken)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)

The reading tenant.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The token every store call inside the hook must be handed; see
[TenantIsolationContract.SeedAsync](/api/tracon.testing.contracts.storage/).

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[int](https://learn.microsoft.com/dotnet/api/system.int32)\>

The number of records seen.

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_ExistsAsync_System_String_System_Object_"></a> ExistsAsync\(string, object\)

Reports whether the record is visible from the given tenant's viewpoint.

```csharp
protected override ValueTask<bool> ExistsAsync(string tenantId, object key)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)

The reading tenant.

`key` [object](https://learn.microsoft.com/dotnet/api/system.object)

The key returned by [TenantIsolationContract.SeedAsync](/api/tracon.testing.contracts.storage/).

#### 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 record is visible.

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Failed_invocation_is_counted_as_unsuccessful"></a> Failed\_invocation\_is\_counted\_as\_unsuccessful\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Invocation_fields_round_trip"></a> Invocation\_fields\_round\_trip\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Invocation_with_no_reported_usage_comes_back_with_EMPTY_usage"></a> Invocation\_with\_no\_reported\_usage\_comes\_back\_with\_EMPTY\_usage\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Invocations_come_back_in_time_order"></a> Invocations\_come\_back\_in\_time\_order\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Late_settlement_fills_in_the_timed_out_record_without_rewriting_what_the_model_was_told"></a> Late\_settlement\_fills\_in\_the\_timed\_out\_record\_without\_rewriting\_what\_the\_model\_was\_told\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Late_settlement_for_an_unknown_call_reports_that_it_wrote_nothing"></a> Late\_settlement\_for\_an\_unknown\_call\_reports\_that\_it\_wrote\_nothing\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Late_settlement_from_the_wrong_tenant_writes_nothing"></a> Late\_settlement\_from\_the\_wrong\_tenant\_writes\_nothing\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Late_settlement_touches_only_the_call_it_names"></a> Late\_settlement\_touches\_only\_the\_call\_it\_names\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Non_token_measurement_round_trips"></a> Non\_token\_measurement\_round\_trips\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_SeedAsync_System_String_System_String_System_Threading_CancellationToken_"></a> SeedAsync\(string, string, CancellationToken\)

Writes a sample record for the given tenant.

```csharp
protected override ValueTask<object> SeedAsync(string tenantId, string name, CancellationToken cancellationToken)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)

The tenant that owns the record.

`name` [string](https://learn.microsoft.com/dotnet/api/system.string)

The name distinguishing the record. The same name may be used by two tenants.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The token every store call inside the hook must be handed. The
cancellation contract calls this hook with a token that is already
cancelled, so a hook that drops the token reports a store as sound
when it is not.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[object](https://learn.microsoft.com/dotnet/api/system.object)\>

The key to use for reading the record back.

#### Remarks

A tool invocation is attached to a run; isolation is established
through the run's tenant.

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Summary_does_not_count_another_tenants_invocations"></a> Summary\_does\_not\_count\_another\_tenants\_invocations\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Summary_is_aggregated_per_tool"></a> Summary\_is\_aggregated\_per\_tool\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Summary_is_ordered_by_call_count_and_limited"></a> Summary\_is\_ordered\_by\_call\_count\_and\_limited\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)

### <a id="Tracon_Testing_Contracts_Storage_ToolInvocationContract_Unknown_duration_stays_empty"></a> Unknown\_duration\_stays\_empty\(\)

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

 [Task](https://learn.microsoft.com/dotnet/api/system.threading.tasks.task)
