Skip to content
Tracon

QuotaStoreContract

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

Behavior tests for the IQuotaStore contract.

public abstract class QuotaStoreContract : TenantIsolationContract<IQuotaStore>, IAsyncLifetime, IAsyncDisposable
Inheritance
object ← StoreCancellationContract<IQuotaStore> ← TenantIsolationContract<IQuotaStore> ← QuotaStoreContract
Implements
IAsyncLifetime, IAsyncDisposable
Inherited Members
TenantIsolationContract<IQuotaStore>.TenantA, TenantIsolationContract<IQuotaStore>.TenantB, TenantIsolationContract<IQuotaStore>.UseAmbientTenant(MutableTenantContext), TenantIsolationContract<IQuotaStore>.SeedAsync(string, string, CancellationToken), TenantIsolationContract<IQuotaStore>.ExistsAsync(string, object), TenantIsolationContract<IQuotaStore>.CountAsync(string, CancellationToken), TenantIsolationContract<IQuotaStore>.TryDeleteAsync(string, object), TenantIsolationContract<IQuotaStore>.TryOverwriteAsync(string, string), TenantIsolationContract<IQuotaStore>.CancellableReadAsync(CancellationToken), TenantIsolationContract<IQuotaStore>.CancellableWriteAsync(CancellationToken), TenantIsolationContract<IQuotaStore>.WroteAnythingAsync(), TenantIsolationContract<IQuotaStore>.Tenant_cannot_read_another_tenants_record(), TenantIsolationContract<IQuotaStore>.Tenant_reads_its_own_record(), TenantIsolationContract<IQuotaStore>.Tenant_does_not_see_another_tenants_record_in_the_list(), TenantIsolationContract<IQuotaStore>.Tenant_cannot_delete_another_tenants_record(), TenantIsolationContract<IQuotaStore>.Same_name_lives_independently_across_two_tenants(), TenantIsolationContract<IQuotaStore>.AmbientTenant, StoreCancellationContract<IQuotaStore>.CreateStoreAsync(), StoreCancellationContract<IQuotaStore>.InitializeAsync(), StoreCancellationContract<IQuotaStore>.DisposeAsync(), StoreCancellationContract<IQuotaStore>.OnDisposeAsync(), StoreCancellationContract<IQuotaStore>.CancellableReadAsync(CancellationToken), StoreCancellationContract<IQuotaStore>.CancellableWriteAsync(CancellationToken), StoreCancellationContract<IQuotaStore>.WroteAnythingAsync(), StoreCancellationContract<IQuotaStore>.Canceled_token_throws_on_read(), StoreCancellationContract<IQuotaStore>.The_write_this_contract_checks_can_be_read_back(), StoreCancellationContract<IQuotaStore>.Canceled_token_throws_on_write_and_leaves_no_trace(), StoreCancellationContract<IQuotaStore>.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 PostgreSQL store must pass the same scenarios. Two rules are especially critical: scope uniqueness (COALESCE(agent_name, '')) and the atomicity of usage increments (ON CONFLICT DO UPDATE).

protected QuotaStoreContract()
[Fact]
public Task A_different_metric_is_a_separate_claim()

Task

A_different_tenants_identically_shaped_claim_is_independent()

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

Task

A_different_threshold_percent_is_a_separate_claim()

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

Task

A_new_period_starts_with_no_claim_even_if_the_previous_period_already_has_one()

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

Task

A_period_left_out_of_the_period_starts_is_not_returned()

Section titled “ A_period_left_out_of_the_period_starts_is_not_returned()”

A period missing from QuotaUsageQuery.PeriodStarts returns no counters.

[Fact]
public Task A_period_left_out_of_the_period_starts_is_not_returned()

Task

A_threshold_already_claimed_in_this_period_is_not_claimed_again()

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

Task

[Fact]
public Task Another_tenants_rule_is_not_visible()

Task

[Fact]
public Task Another_tenants_usage_is_not_visible()

Task

Claim_fails_when_the_usage_row_does_not_exist_yet()

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

Task

Concurrent_claims_of_the_same_threshold_let_only_one_caller_win()

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

Task

Concurrent_increments_lose_no_increment()

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

Task

[Fact]
public Task Consecutive_usage_accumulates()

Task

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

protected override ValueTask<int> CountAsync(string tenantId, CancellationToken cancellationToken)

tenantId string

The reading tenant.

cancellationToken CancellationToken

The token every store call inside the hook must be handed; see TenantIsolationContract.SeedAsync.

ValueTask<int>

The number of records seen.

[Fact]
public Task Deleted_rule_is_not_read_back()

Task

Deleting_a_nonexistent_rule_returns_false()

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

Task

Different_agent_becomes_a_separate_rule()

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

Task

Different_period_becomes_a_separate_rule()

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

Task

[Fact]
public Task Empty_limits_are_preserved_as_null()

Task

An empty QuotaUsageQuery.PeriodStarts names no period and returns nothing.

[Fact]
public Task Empty_period_starts_return_no_counters()

Task

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

protected override ValueTask<bool> ExistsAsync(string tenantId, object key)

tenantId string

The reading tenant.

key object

The key returned by TenantIsolationContract.SeedAsync.

ValueTask<bool>

true if the record is visible.

[Fact]
public Task First_claim_of_a_threshold_succeeds()

Task

Period_starts_apply_together_with_the_other_filters()

Section titled “ Period_starts_apply_together_with_the_other_filters()”

The period filter applies together with the agent and period filters.

[Fact]
public Task Period_starts_apply_together_with_the_other_filters()

Task

[Fact]
public Task Saved_rule_is_read_back()

Task

Saving_the_same_scope_a_second_time_overwrites_it()

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

Task

SeedAsync(string, string, CancellationToken)

Section titled “ SeedAsync(string, string, CancellationToken)”

Writes a sample record for the given tenant.

protected override ValueTask<object> SeedAsync(string tenantId, string name, CancellationToken cancellationToken)

tenantId string

The tenant that owns the record.

name string

The name distinguishing the record. The same name may be used by two tenants.

cancellationToken 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.

ValueTask<object>

The key to use for reading the record back.

Separate_period_keeps_a_separate_counter()

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

Task

Attempts to delete the record on behalf of the given tenant.

protected override ValueTask<bool?> TryDeleteAsync(string tenantId, object key)

tenantId string

The tenant attempting the delete.

key object

The key returned by TenantIsolationContract.SeedAsync.

ValueTask<bool?>

true if the delete succeeded, false if the record was not found; null if the store does not offer deletion.

Usage_increments_both_the_agent_and_tenant_counters()

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

Task

[Fact]
public Task Usage_is_filtered_by_agent_name()

Task

[Fact]
public Task Usage_is_filtered_by_period()

Task

Usage_is_filtered_to_the_given_period_starts()

Section titled “ Usage_is_filtered_to_the_given_period_starts()”

QuotaUsageQuery.PeriodStarts returns only the counters of the named periods, each for its given first day. The admission check reads usage before every run; a store that ignores the filter returns the tenant’s whole history on each read.

[Fact]
public Task Usage_is_filtered_to_the_given_period_starts()

Task

Usage_that_adds_no_run_adds_its_tokens_and_cost_to_a_counter_that_does_not_exist_yet()

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

Task

Usage_that_adds_no_run_leaves_the_run_count_where_the_root_put_it()

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

Task

Usage_with_undefined_price_does_not_break_the_cost_total()

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

Task