.NET API
JobStoreContract
Tracon.Testing.Contracts.Xunit.dllBehavior tests for the IJobStore contract.
public abstract class JobStoreContract : TenantIsolationContract<IJobStore>, IAsyncLifetime, IAsyncDisposableInheritance
Section titled “Inheritance”object ← TenantIsolationContract<IJobStore> ← JobStoreContract
Implements
Section titled “Implements”IAsyncLifetime, IAsyncDisposable
Inherited Members
Section titled “Inherited Members”TenantIsolationContract<IJobStore>.TenantA, TenantIsolationContract<IJobStore>.TenantB, TenantIsolationContract<IJobStore>.CreateStoreAsync(), TenantIsolationContract<IJobStore>.UseAmbientTenant(MutableTenantContext), TenantIsolationContract<IJobStore>.InitializeAsync(), TenantIsolationContract<IJobStore>.DisposeAsync(), TenantIsolationContract<IJobStore>.OnDisposeAsync(), TenantIsolationContract<IJobStore>.SeedAsync(string, string), TenantIsolationContract<IJobStore>.ExistsAsync(string, object), TenantIsolationContract<IJobStore>.CountAsync(string), TenantIsolationContract<IJobStore>.TryDeleteAsync(string, object), TenantIsolationContract<IJobStore>.TryOverwriteAsync(string, string), TenantIsolationContract<IJobStore>.Tenant_cannot_read_another_tenants_record(), TenantIsolationContract<IJobStore>.Tenant_reads_its_own_record(), TenantIsolationContract<IJobStore>.Tenant_does_not_see_another_tenants_record_in_the_list(), TenantIsolationContract<IJobStore>.Tenant_cannot_delete_another_tenants_record(), TenantIsolationContract<IJobStore>.Same_name_lives_independently_across_two_tenants(), TenantIsolationContract<IJobStore>.AmbientTenant, TenantIsolationContract<IJobStore>.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 in-memory store and the PostgreSQL store must pass the same scenarios. The lease-expiry test runs against real time (a short lease + a short wait): the PostgreSQL implementation does not take its clock through an injectable TimeProvider, so fake time cannot be used here.
Constructors
Section titled “Constructors”JobStoreContract()
Section titled “ JobStoreContract()”protected JobStoreContract()Methods
Section titled “Methods”CancelAsync_does_not_affect_another_tenants_job()
Section titled “ CancelAsync_does_not_affect_another_tenants_job()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 196)]public Task CancelAsync_does_not_affect_another_tenants_job()Returns
Section titled “Returns”CancelAsync_works_only_in_eligible_states(JobStatus, bool)
Section titled “ CancelAsync_works_only_in_eligible_states(JobStatus, bool)”[Theory("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 180)][InlineData(new object?[] { JobStatus.Pending, true })][InlineData(new object?[] { JobStatus.Completed, false })][InlineData(new object?[] { JobStatus.Failed, false })]public Task CancelAsync_works_only_in_eligible_states(JobStatus status, bool expected)Parameters
Section titled “Parameters”status JobStatus
expected bool
Returns
Section titled “Returns”CompleteAsync_releases_the_lease()
Section titled “ CompleteAsync_releases_the_lease()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 144)]public Task CompleteAsync_releases_the_lease()Returns
Section titled “Returns”CountAsync(string)
Section titled “ CountAsync(string)”Reports how many records the given tenant sees through the listing endpoint.
protected override ValueTask<int> CountAsync(string tenantId)Parameters
Section titled “Parameters”tenantId string
The reading tenant.
Returns
Section titled “Returns”The number of records seen.
Enqueued_job_defaults_to_the_default_lane()
Section titled “ Enqueued_job_defaults_to_the_default_lane()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 262)]public Task Enqueued_job_defaults_to_the_default_lane()Returns
Section titled “Returns”Enqueued_job_starts_pending_and_creates_items()
Section titled “ Enqueued_job_starts_pending_and_creates_items()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 36)]public Task Enqueued_job_starts_pending_and_creates_items()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.
GetAsync_returns_null_for_another_tenant()
Section titled “ GetAsync_returns_null_for_another_tenant()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 207)]public Task GetAsync_returns_null_for_another_tenant()Returns
Section titled “Returns”Job_can_be_re_leased_once_the_lease_expires()
Section titled “ Job_can_be_re_leased_once_the_lease_expires()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 84)]public Task Job_can_be_re_leased_once_the_lease_expires()Returns
Section titled “Returns”Job_not_yet_due_cannot_be_leased()
Section titled “ Job_not_yet_due_cannot_be_leased()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 52)]public Task Job_not_yet_due_cannot_be_leased()Returns
Section titled “Returns”Lease_with_a_lane_filter_never_returns_a_job_from_an_unlisted_lane()
Section titled “ Lease_with_a_lane_filter_never_returns_a_job_from_an_unlisted_lane()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 283)]public Task Lease_with_a_lane_filter_never_returns_a_job_from_an_unlisted_lane()Returns
Section titled “Returns”Lease_with_a_lane_filter_only_returns_a_job_in_that_lane()
Section titled “ Lease_with_a_lane_filter_only_returns_a_job_in_that_lane()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 270)]public Task Lease_with_a_lane_filter_only_returns_a_job_in_that_lane()Returns
Section titled “Returns”Lease_with_an_empty_lanes_list_applies_no_filter()
Section titled “ Lease_with_an_empty_lanes_list_applies_no_filter()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 299)]public Task Lease_with_an_empty_lanes_list_applies_no_filter()Returns
Section titled “Returns”Lease_with_null_lanes_applies_no_filter()
Section titled “ Lease_with_null_lanes_applies_no_filter()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 291)]public Task Lease_with_null_lanes_applies_no_filter()Returns
Section titled “Returns”Leased_job_is_not_given_to_another_worker_before_expiry()
Section titled “ Leased_job_is_not_given_to_another_worker_before_expiry()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 75)]public Task Leased_job_is_not_given_to_another_worker_before_expiry()Returns
Section titled “Returns”Leasing_marks_Leased_and_increments_the_attempt()
Section titled “ Leasing_marks_Leased_and_increments_the_attempt()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 60)]public Task Leasing_marks_Leased_and_increments_the_attempt()Returns
Section titled “Returns”MarkRunningAsync_works_only_for_the_real_owner()
Section titled “ MarkRunningAsync_works_only_for_the_real_owner()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 99)]public Task MarkRunningAsync_works_only_for_the_real_owner()Returns
Section titled “Returns”QueryAsync_filters_by_handler_key()
Section titled “ QueryAsync_filters_by_handler_key()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 227)]public Task QueryAsync_filters_by_handler_key()Returns
Section titled “Returns”QueryAsync_filters_by_lane()
Section titled “ QueryAsync_filters_by_lane()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 331)]public Task QueryAsync_filters_by_lane()Returns
Section titled “Returns”QueryAsync_filters_by_tenant()
Section titled “ QueryAsync_filters_by_tenant()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 215)]public Task QueryAsync_filters_by_tenant()Returns
Section titled “Returns”QueryAsync_lane_filter_does_not_leak_another_tenants_job()
Section titled “ QueryAsync_lane_filter_does_not_leak_another_tenants_job()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 319)]public Task QueryAsync_lane_filter_does_not_leak_another_tenants_job()Returns
Section titled “Returns”QueryAsync_returns_nothing_for_a_handler_key_no_job_uses()
Section titled “ QueryAsync_returns_nothing_for_a_handler_key_no_job_uses()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 242)]public Task QueryAsync_returns_nothing_for_a_handler_key_no_job_uses()Returns
Section titled “Returns”QueryAsync_treats_an_empty_handler_key_as_a_filter_that_matches_nothing()
Section titled “ QueryAsync_treats_an_empty_handler_key_as_a_filter_that_matches_nothing()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 250)]public Task QueryAsync_treats_an_empty_handler_key_as_a_filter_that_matches_nothing()Returns
Section titled “Returns”Queue_depth_counts_a_job_released_for_retry_as_pending_again()
Section titled “ Queue_depth_counts_a_job_released_for_retry_as_pending_again()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 434)]public Task Queue_depth_counts_a_job_released_for_retry_as_pending_again()Returns
Section titled “Returns”Queue_depth_counts_every_tenants_jobs_together()
Section titled “ Queue_depth_counts_every_tenants_jobs_together()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 405)]public Task Queue_depth_counts_every_tenants_jobs_together()Returns
Section titled “Returns”Queue_depth_drops_a_lane_once_its_last_job_finishes()
Section titled “ Queue_depth_drops_a_lane_once_its_last_job_finishes()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 418)]public Task Queue_depth_drops_a_lane_once_its_last_job_finishes()Returns
Section titled “Returns”Queue_depth_groups_pending_jobs_by_lane()
Section titled “ Queue_depth_groups_pending_jobs_by_lane()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 347)]public Task Queue_depth_groups_pending_jobs_by_lane()Returns
Section titled “Returns”Queue_depth_is_empty_when_no_job_is_open()
Section titled “ Queue_depth_is_empty_when_no_job_is_open()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 343)]public Task Queue_depth_is_empty_when_no_job_is_open()Returns
Section titled “Returns”Queue_depth_never_counts_a_terminal_status()
Section titled “ Queue_depth_never_counts_a_terminal_status()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 382)]public Task Queue_depth_never_counts_a_terminal_status()Returns
Section titled “Returns”Queue_depth_separates_the_open_statuses()
Section titled “ Queue_depth_separates_the_open_statuses()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 360)]public Task Queue_depth_separates_the_open_statuses()Returns
Section titled “Returns”ReleaseForRetryAsync_returns_to_pending_without_resetting_the_attempt()
Section titled “ ReleaseForRetryAsync_returns_to_pending_without_resetting_the_attempt()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 164)]public Task ReleaseForRetryAsync_returns_to_pending_without_resetting_the_attempt()Returns
Section titled “Returns”ReportItemAsync_counts_successful_and_failed_items_separately()
Section titled “ ReportItemAsync_counts_successful_and_failed_items_separately()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 127)]public Task ReportItemAsync_counts_successful_and_failed_items_separately()Returns
Section titled “Returns”ReportItemAsync_is_idempotent()
Section titled “ ReportItemAsync_is_idempotent()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 113)]public Task ReportItemAsync_is_idempotent()Returns
Section titled “Returns”Retry_preserves_the_jobs_lane()
Section titled “ Retry_preserves_the_jobs_lane()”[Fact("/Users/farukatasoy/Desktop/projects/Tracon/src/Tracon.Testing.Contracts.Xunit/Contracts/JobStoreContract.cs", 307)]public Task Retry_preserves_the_jobs_lane()Returns
Section titled “Returns”SeedAsync(string, string)
Section titled “ SeedAsync(string, string)”Writes a sample record for the given tenant.
protected override ValueTask<object> SeedAsync(string tenantId, string name)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.
Returns
Section titled “Returns”The key to use for reading the record back.
TryDeleteAsync(string, object)
Section titled “ TryDeleteAsync(string, object)”Attempts to delete the record on behalf of the given tenant.
protected override ValueTask<bool?> TryDeleteAsync(string tenantId, object key)Parameters
Section titled “Parameters”tenantId string
The tenant attempting the delete.
key object
The key returned by TenantIsolationContract.SeedAsync.
Returns
Section titled “Returns”true if the delete succeeded, false if the record was not found; null if the store does not offer deletion.
Remarks
Section titled “Remarks”There is no delete in the job queue; the only destructive operation available to a tenant is cancel.