.NET API
WorkflowRequestStoreContract
Tracon.Testing.Contracts.Xunit.dllBehavior tests for the IWorkflowRequestStore contract.
public abstract class WorkflowRequestStoreContract : TenantIsolationContract<IWorkflowRequestStore>, IAsyncLifetime, IAsyncDisposable- Inheritance
- object ← StoreCancellationContract<IWorkflowRequestStore> ← TenantIsolationContract<IWorkflowRequestStore> ← WorkflowRequestStoreContract
- Implements
- IAsyncLifetime, IAsyncDisposable
- Inherited Members
- TenantIsolationContract<IWorkflowRequestStore>.TenantA, TenantIsolationContract<IWorkflowRequestStore>.TenantB, TenantIsolationContract<IWorkflowRequestStore>.UseAmbientTenant(MutableTenantContext), TenantIsolationContract<IWorkflowRequestStore>.SeedAsync(string, string, CancellationToken), TenantIsolationContract<IWorkflowRequestStore>.ExistsAsync(string, object), TenantIsolationContract<IWorkflowRequestStore>.CountAsync(string, CancellationToken), TenantIsolationContract<IWorkflowRequestStore>.TryDeleteAsync(string, object), TenantIsolationContract<IWorkflowRequestStore>.TryOverwriteAsync(string, string), TenantIsolationContract<IWorkflowRequestStore>.CancellableReadAsync(CancellationToken), TenantIsolationContract<IWorkflowRequestStore>.CancellableWriteAsync(CancellationToken), TenantIsolationContract<IWorkflowRequestStore>.WroteAnythingAsync(), TenantIsolationContract<IWorkflowRequestStore>.Tenant_cannot_read_another_tenants_record(), TenantIsolationContract<IWorkflowRequestStore>.Tenant_reads_its_own_record(), TenantIsolationContract<IWorkflowRequestStore>.Tenant_does_not_see_another_tenants_record_in_the_list(), TenantIsolationContract<IWorkflowRequestStore>.Tenant_cannot_delete_another_tenants_record(), TenantIsolationContract<IWorkflowRequestStore>.Same_name_lives_independently_across_two_tenants(), TenantIsolationContract<IWorkflowRequestStore>.AmbientTenant, StoreCancellationContract<IWorkflowRequestStore>.CreateStoreAsync(), StoreCancellationContract<IWorkflowRequestStore>.InitializeAsync(), StoreCancellationContract<IWorkflowRequestStore>.DisposeAsync(), StoreCancellationContract<IWorkflowRequestStore>.OnDisposeAsync(), StoreCancellationContract<IWorkflowRequestStore>.CancellableReadAsync(CancellationToken), StoreCancellationContract<IWorkflowRequestStore>.CancellableWriteAsync(CancellationToken), StoreCancellationContract<IWorkflowRequestStore>.WroteAnythingAsync(), StoreCancellationContract<IWorkflowRequestStore>.Canceled_token_throws_on_read(), StoreCancellationContract<IWorkflowRequestStore>.The_write_this_contract_checks_can_be_read_back(), StoreCancellationContract<IWorkflowRequestStore>.Canceled_token_throws_on_write_and_leaves_no_trace(), StoreCancellationContract<IWorkflowRequestStore>.Store, object.GetType(), object.MemberwiseClone(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()
Remarks
Section titled “Remarks”The store is the authority of two decisions a unit test of the runner cannot prove: which row is THE open row of a logical request (the same request id in the same session held by several runs), and which of an answer and an expiry reaches a row first. The first is a listing question and the second is a race, so both are cases here.
The Storage.TenantIsolationContract hooks are wired to IWorkflowRequestStore.AddAsync and IWorkflowRequestStore.ListAsync; the store offers no delete, so another tenant’s chance to change a row is IWorkflowRequestStore.MarkAnsweredAsync, which has a case of its own.
Constructors
Section titled “Constructors”WorkflowRequestStoreContract()
Section titled “ WorkflowRequestStoreContract()”protected WorkflowRequestStoreContract()Methods
Section titled “Methods”A_closed_row_leaves_the_list_and_cannot_be_marked_answered()
Section titled “ A_closed_row_leaves_the_list_and_cannot_be_marked_answered()”[Fact]public Task A_closed_row_leaves_the_list_and_cannot_be_marked_answered()Returns
Section titled “Returns”A_logical_request_stays_listed_while_an_older_run_of_it_closes()
Section titled “ A_logical_request_stays_listed_while_an_older_run_of_it_closes()”[Fact]public Task A_logical_request_stays_listed_while_an_older_run_of_it_closes()Returns
Section titled “Returns”A_page_outside_the_range_is_cut_to_it()
Section titled “ A_page_outside_the_range_is_cut_to_it()”[Fact]public Task A_page_outside_the_range_is_cut_to_it()Returns
Section titled “Returns”A_row_expires_at_its_time_and_not_before()
Section titled “ A_row_expires_at_its_time_and_not_before()”[Fact]public Task A_row_expires_at_its_time_and_not_before()Returns
Section titled “Returns”A_row_is_closed_once()
Section titled “ A_row_is_closed_once()”[Fact]public Task A_row_is_closed_once()Returns
Section titled “Returns”A_row_without_a_time_limit_reads_back_without_one()
Section titled “ A_row_without_a_time_limit_reads_back_without_one()”[Fact]public Task A_row_without_a_time_limit_reads_back_without_one()Returns
Section titled “Returns”A_run_lists_its_requests_in_event_order()
Section titled “ A_run_lists_its_requests_in_event_order()”[Fact]public Task A_run_lists_its_requests_in_event_order()Returns
Section titled “Returns”A_run_that_is_closed_or_has_an_open_row_is_not_stranded()
Section titled “ A_run_that_is_closed_or_has_an_open_row_is_not_stranded()”[Fact]public Task A_run_that_is_closed_or_has_an_open_row_is_not_stranded()Returns
Section titled “Returns”A_run_that_still_waits_after_its_last_row_closed_is_listed_as_stranded()
Section titled “ A_run_that_still_waits_after_its_last_row_closed_is_listed_as_stranded()”[Fact]public Task A_run_that_still_waits_after_its_last_row_closed_is_listed_as_stranded()Returns
Section titled “Returns”A_second_answer_names_its_own_run_and_keeps_the_first_time()
Section titled “ A_second_answer_names_its_own_run_and_keeps_the_first_time()”[Fact]public Task A_second_answer_names_its_own_run_and_keeps_the_first_time()Returns
Section titled “Returns”A_written_row_is_read_back_with_every_field()
Section titled “ A_written_row_is_read_back_with_every_field()”[Fact]public Task A_written_row_is_read_back_with_every_field()Returns
Section titled “Returns”Another_tenant_cannot_mark_a_row_answered()
Section titled “ Another_tenant_cannot_mark_a_row_answered()”[Fact]public Task Another_tenant_cannot_mark_a_row_answered()Returns
Section titled “Returns”Concurrent_expiries_close_each_row_exactly_once()
Section titled “ Concurrent_expiries_close_each_row_exactly_once()”[Fact]public Task Concurrent_expiries_close_each_row_exactly_once()Returns
Section titled “Returns”CountAsync(string, CancellationToken)
Section titled “ CountAsync(string, CancellationToken)”Reports how many records the given tenant sees through the listing endpoint.
protected override ValueTask<int> CountAsync(string tenantId, CancellationToken cancellationToken)Parameters
Section titled “Parameters”tenantId string
The reading tenant.
cancellationToken CancellationToken
The token every store call inside the hook must be handed; see TenantIsolationContract.SeedAsync.
Returns
Section titled “Returns”The number of records seen.
EraseRunAsync(Guid, string)
Section titled “ EraseRunAsync(Guid, string)”Erases a run the way a data subject erasure does.
protected virtual ValueTask<bool> EraseRunAsync(Guid runId, string tenantId)Parameters
Section titled “Parameters”runId Guid
The run to erase.
tenantId string
The run’s tenant.
Returns
Section titled “Returns”true when the run was erased; false when the store under test has no run table to erase from, and the case does not apply.
Erasing_the_run_removes_its_rows()
Section titled “ Erasing_the_run_removes_its_rows()”[Fact]public Task Erasing_the_run_removes_its_rows()Returns
Section titled “Returns”ExistsAsync(string, object)
Section titled “ ExistsAsync(string, object)”Reports whether the record is visible from the given tenant’s viewpoint.
protected override ValueTask<bool> ExistsAsync(string tenantId, object key)Parameters
Section titled “Parameters”tenantId string
The reading tenant.
key object
The key returned by TenantIsolationContract.SeedAsync.
Returns
Section titled “Returns”true if the record is visible.
Expiry_closes_only_the_open_rows_whose_time_has_come_and_returns_them()
Section titled “ Expiry_closes_only_the_open_rows_whose_time_has_come_and_returns_them()”[Fact]public Task Expiry_closes_only_the_open_rows_whose_time_has_come_and_returns_them()Returns
Section titled “Returns”Expiry_closes_the_oldest_deadlines_first_and_no_more_than_max()
Section titled “ Expiry_closes_the_oldest_deadlines_first_and_no_more_than_max()”[Fact]public Task Expiry_closes_the_oldest_deadlines_first_and_no_more_than_max()Returns
Section titled “Returns”Expiry_closes_the_rows_of_every_tenant_and_keeps_the_answer_mark()
Section titled “ Expiry_closes_the_rows_of_every_tenant_and_keeps_the_answer_mark()”[Fact]public Task Expiry_closes_the_rows_of_every_tenant_and_keeps_the_answer_mark()Returns
Section titled “Returns”Marking_answered_marks_every_open_row_of_the_logical_request_and_no_other()
Section titled “ Marking_answered_marks_every_open_row_of_the_logical_request_and_no_other()”[Fact]public Task Marking_answered_marks_every_open_row_of_the_logical_request_and_no_other()Returns
Section titled “Returns”PrepareRunAsync(Guid, string, string)
Section titled “ PrepareRunAsync(Guid, string, string)”Opens the run row an inbox row points at.
protected virtual ValueTask PrepareRunAsync(Guid runId, string tenantId, string sessionId)Parameters
Section titled “Parameters”runId Guid
The run id.
tenantId string
The tenant id.
sessionId string
The run’s execution session.
Returns
Section titled “Returns”The completion task.
Remarks
Section titled “Remarks”In the SQL implementations workflow_requests.run_id is a foreign key into
runs; the in-memory implementation has no such link, and the hook does nothing.
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)Parameters
Section titled “Parameters”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.
Returns
Section titled “Returns”The key to use for reading the record back.
SetRunStatusAsync(Guid, string, RunStatus)
Section titled “ SetRunStatusAsync(Guid, string, RunStatus)”Gives a run the status a run has when it stops waiting, or starts to.
protected virtual ValueTask<bool> SetRunStatusAsync(Guid runId, string tenantId, RunStatus status)Parameters
Section titled “Parameters”runId Guid
The run, opened by WorkflowRequestStoreContract.PrepareRunAsync.
tenantId string
The run’s tenant.
status RunStatus
The status to give.
Returns
Section titled “Returns”true when the run now has the status; false when the store under test has no run table, and the cases that need a waiting run do not apply.
Stranded_runs_are_listed_oldest_closure_first_and_no_more_than_max()
Section titled “ Stranded_runs_are_listed_oldest_closure_first_and_no_more_than_max()”[Fact]public Task Stranded_runs_are_listed_oldest_closure_first_and_no_more_than_max()Returns
Section titled “Returns”The_list_can_be_limited_to_one_workflow()
Section titled “ The_list_can_be_limited_to_one_workflow()”[Fact]public Task The_list_can_be_limited_to_one_workflow()Returns
Section titled “Returns”The_list_is_oldest_first_and_pages_without_gaps_or_repeats()
Section titled “ The_list_is_oldest_first_and_pages_without_gaps_or_repeats()”[Fact]public Task The_list_is_oldest_first_and_pages_without_gaps_or_repeats()Returns
Section titled “Returns”The_same_request_id_in_two_sessions_is_two_requests()
Section titled “ The_same_request_id_in_two_sessions_is_two_requests()”[Fact]public Task The_same_request_id_in_two_sessions_is_two_requests()Returns
Section titled “Returns”The_same_request_of_a_session_is_listed_once_under_its_newest_open_run()
Section titled “ The_same_request_of_a_session_is_listed_once_under_its_newest_open_run()”[Fact]public Task The_same_request_of_a_session_is_listed_once_under_its_newest_open_run()Returns
Section titled “Returns”The_state_filter_runs_before_the_page_so_a_page_is_never_short()
Section titled “ The_state_filter_runs_before_the_page_so_a_page_is_never_short()”[Fact]public Task The_state_filter_runs_before_the_page_so_a_page_is_never_short()Returns
Section titled “Returns”Two_tenants_hold_the_same_session_and_request_without_seeing_each_other()
Section titled “ Two_tenants_hold_the_same_session_and_request_without_seeing_each_other()”[Fact]public Task Two_tenants_hold_the_same_session_and_request_without_seeing_each_other()Returns
Section titled “Returns”Writing_the_same_run_and_request_twice_keeps_the_first_row()
Section titled “ Writing_the_same_run_and_request_twice_keeps_the_first_row()”[Fact]public Task Writing_the_same_run_and_request_twice_keeps_the_first_row()