using FinalFactory.Rendezvous.Contracts; using FinalFactory.Rendezvous.Server.State; namespace FinalFactory.Rendezvous.Tests.State; public sealed class InMemoryEphemeralRendezvousStoreTests { [Fact] public void IdempotencyRetentionMustCoverResourceLifetimes() { ManualRendezvousClock clock = new(); Assert.Throws(() => new InMemoryEphemeralRendezvousStore( new EphemeralStoreOptions { IdempotencyLifetime = TimeSpan.FromSeconds(5) }, clock, clock)); } [Fact] public void DuplicateRegistrationIsIdempotentButChangedRequestConflicts() { EphemeralStateFixture fixture = new(); CreateListingCommand command = fixture.ListingCommand(); StoreResult first = fixture.Store.CreateListing(command); StoreResult duplicate = fixture.Store.CreateListing(command); StoreResult changed = fixture.Store.CreateListing(command with { RequestFingerprint = "different" }); Assert.True(first.Succeeded); Assert.True(duplicate.Succeeded); Assert.True(duplicate.IsIdempotentReplay); Assert.Equal(first.Value!.Definition.ListingId, duplicate.Value!.Definition.ListingId); Assert.Equal(StoreResultCode.Conflict, changed.Code); } [Fact] public void LeaseAndPresenceExpiryUseMonotonicTime() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out _); fixture.Clock.Advance(TimeSpan.FromSeconds(20)); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(listing.Definition.ListingId, true).Code); Assert.True(fixture.Store.GetListing(listing.Definition.ListingId, false).Succeeded); fixture.Clock.Advance(TimeSpan.FromSeconds(40)); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(listing.Definition.ListingId, false).Code); } [Fact] public void WallClockMovementDoesNotExpireOrExtendLease() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out CreateListingCommand command); fixture.Clock.MoveWall(TimeSpan.FromDays(30)); Assert.True(fixture.Store.GetListing(listing.Definition.ListingId, false).Succeeded); fixture.Clock.Advance(TimeSpan.FromSeconds(1)); StoreResult renewed = fixture.Store.RenewLease(new( listing.Definition.ListingId, listing.Definition.LeaseId, listing.Definition.LeaseFingerprint, listing.Definition.OwnerSubject, listing.Version)); Assert.Equal(new DateTimeOffset(2026, 7, 16, 0, 1, 1, TimeSpan.Zero), renewed.Value!.LeaseExpiresAt); fixture.Clock.MoveWall(TimeSpan.FromDays(-60)); fixture.Clock.Advance(TimeSpan.FromSeconds(59)); Assert.True(fixture.Store.GetListing(listing.Definition.ListingId, false).Succeeded); fixture.Clock.Advance(TimeSpan.FromSeconds(1)); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(command.Listing.ListingId, false).Code); } [Fact] public async Task RenewDeleteRaceIsAtomicAndDeleteAlwaysWinsEventually() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out CreateListingCommand command); using ManualResetEventSlim start = new(false); Task> renew = Task.Run(() => { start.Wait(); return fixture.Store.RenewLease(new( listing.Definition.ListingId, listing.Definition.LeaseId, listing.Definition.LeaseFingerprint, listing.Definition.OwnerSubject, listing.Version)); }); Task> delete = Task.Run(() => { start.Wait(); return fixture.Store.DeleteListing(new( command.Listing.ListingId, command.Listing.LeaseId, command.Listing.LeaseFingerprint, command.Listing.OwnerSubject)); }); start.Set(); await Task.WhenAll(renew, delete); StoreResult renewResult = await renew; StoreResult deleteResult = await delete; Assert.True(deleteResult.Succeeded); Assert.Contains(renewResult.Code, new[] { StoreResultCode.Success, StoreResultCode.NotFound }); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(command.Listing.ListingId, false).Code); } [Fact] public void CompareAndSwapPreventsStaleRenewal() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out _); RenewLeaseCommand command = new( listing.Definition.ListingId, listing.Definition.LeaseId, listing.Definition.LeaseFingerprint, listing.Definition.OwnerSubject, listing.Version); StoreResult first = fixture.Store.RenewLease(command); StoreResult stale = fixture.Store.RenewLease(command); Assert.Equal(2, first.Value!.Version); Assert.Equal(StoreResultCode.Conflict, stale.Code); Assert.Equal(2, stale.Value!.Version); } [Fact] public void JoinRequiresExactScopeProtocolAndFreshHostPresence() { EphemeralStateFixture fixture = new(); CreateListingCommand listingCommand = fixture.ListingCommand(); StoredListing listing = fixture.Store.CreateListing(listingCommand).Value!; CreateJoinAttemptCommand attempt = fixture.AttemptCommand(listing); Assert.Equal(StoreResultCode.NotFound, fixture.Store.CreateJoinAttempt(attempt).Code); fixture.Store.BindHostPresence(new( listingCommand.Listing.HostPresenceHandle, listingCommand.Listing.HostPresenceFingerprint, EphemeralStateFixture.PublicEndpoint(40_000), null)); Assert.Equal(StoreResultCode.NotFound, fixture.Store.CreateJoinAttempt(attempt with { ProtocolVersion = 8 }).Code); Assert.Equal(StoreResultCode.NotFound, fixture.Store.CreateJoinAttempt(attempt with { Scope = new(new("other-game"), new("test")), }).Code); Assert.True(fixture.Store.CreateJoinAttempt(attempt).Succeeded); } [Fact] public void DuplicateJoinIsIdempotentAndDoesNotAllocateTwice() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out _); CreateJoinAttemptCommand command = fixture.AttemptCommand(listing); StoreResult first = fixture.Store.CreateJoinAttempt(command); StoreResult duplicate = fixture.Store.CreateJoinAttempt(command); Assert.True(first.Succeeded); Assert.True(duplicate.Succeeded); Assert.True(duplicate.IsIdempotentReplay); Assert.Equal(first.Value!.AttemptId, duplicate.Value!.AttemptId); } [Fact] public void BrowseReturnsOnlyFreshPublicCompatibleListingsInStableOrder() { EphemeralStateFixture fixture = new(); StoredListing visible = fixture.CreateVisibleListing(out _); CreateListingCommand staleCommand = fixture.ListingCommand(); fixture.Store.CreateListing(staleCommand); CreateListingCommand unlistedCommand = fixture.ListingCommand(); unlistedCommand = unlistedCommand with { Listing = unlistedCommand.Listing with { Visibility = ListingVisibility.Unlisted }, }; fixture.Store.CreateListing(unlistedCommand); fixture.Store.BindHostPresence(new( unlistedCommand.Listing.HostPresenceHandle, unlistedCommand.Listing.HostPresenceFingerprint, EphemeralStateFixture.PublicEndpoint(40_099), null)); StoreResult> result = fixture.Store.BrowseVisibleListings(new( fixture.Scope, visible.Definition.ProtocolVersion, visible.Definition.RegionId)); Assert.True(result.Succeeded); Assert.Collection(result.Value!, item => Assert.Equal(visible.Definition.ListingId, item.Definition.ListingId)); } [Fact] public async Task ConcurrentEndpointBindingAcceptsOneCompleteEndpointOnly() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out _); CreateJoinAttemptCommand command = fixture.AttemptCommand(listing); fixture.Store.CreateJoinAttempt(command); BindAttemptEndpointCommand first = new( command.MediationHandle, AttemptPeerRole.Client, command.ClientCapabilityFingerprint, EphemeralStateFixture.PublicEndpoint(40_001), EphemeralStateFixture.LocalEndpoint(40_001)); BindAttemptEndpointCommand second = first with { PublicEndpoint = EphemeralStateFixture.OtherPublicEndpoint(50_001), LocalEndpoint = null, }; using ManualResetEventSlim start = new(false); Task> left = Task.Run(() => { start.Wait(); return fixture.Store.BindAttemptEndpoint(first); }); Task> right = Task.Run(() => { start.Wait(); return fixture.Store.BindAttemptEndpoint(second); }); start.Set(); await Task.WhenAll(left, right); StoreResult leftResult = await left; StoreResult rightResult = await right; Assert.Equal(1, new[] { leftResult, rightResult }.Count(static result => result.Succeeded)); Assert.Equal(1, new[] { leftResult, rightResult }.Count(static result => result.Code == StoreResultCode.ReplayRejected)); } [Fact] public void AttemptCapabilitiesAndIntroductionAreOneTime() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out _); CreateJoinAttemptCommand command = fixture.AttemptCommand(listing); fixture.Store.CreateJoinAttempt(command); BindAttemptEndpointCommand host = new( command.MediationHandle, AttemptPeerRole.Host, command.HostCapabilityFingerprint, EphemeralStateFixture.PublicEndpoint(40_010), null); BindAttemptEndpointCommand client = new( command.MediationHandle, AttemptPeerRole.Client, command.ClientCapabilityFingerprint, EphemeralStateFixture.OtherPublicEndpoint(40_020), null); Assert.True(fixture.Store.BindAttemptEndpoint(host).Succeeded); Assert.True(fixture.Store.BindAttemptEndpoint(client).Succeeded); Assert.True(fixture.Store.BindAttemptEndpoint(client).IsIdempotentReplay); Assert.True(fixture.Store.ConsumeIntroduction(command.MediationHandle).Succeeded); Assert.Equal(StoreResultCode.ReplayRejected, fixture.Store.ConsumeIntroduction(command.MediationHandle).Code); Assert.Equal(StoreResultCode.ReplayRejected, fixture.Store.BindAttemptEndpoint(client with { PublicEndpoint = EphemeralStateFixture.OtherPublicEndpoint(40_021), }).Code); } [Fact] public void ExpiredAttemptCannotBeObservedBoundOrConsumed() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out _); CreateJoinAttemptCommand command = fixture.AttemptCommand(listing); fixture.Store.CreateJoinAttempt(command); fixture.Clock.Advance(TimeSpan.FromSeconds(30)); Assert.Equal(StoreResultCode.NotFound, fixture.Store.BindAttemptEndpoint(new( command.MediationHandle, AttemptPeerRole.Client, command.ClientCapabilityFingerprint, EphemeralStateFixture.PublicEndpoint(40_050), null)).Code); Assert.Equal(StoreResultCode.NotFound, fixture.Store.ConsumeIntroduction(command.MediationHandle).Code); } [Fact] public void GenericReplayConsumptionIsBoundedAndExpires() { EphemeralStoreOptions options = new() { MaxReplayEntries = 1 }; EphemeralStateFixture fixture = new(options); Assert.True(fixture.Store.ConsumeReplay(new("ticket", "one")).Succeeded); Assert.Equal(StoreResultCode.ReplayRejected, fixture.Store.ConsumeReplay(new("ticket", "one")).Code); Assert.Equal(StoreResultCode.CapacityExceeded, fixture.Store.ConsumeReplay(new("ticket", "two")).Code); fixture.Clock.Advance(options.ReplayLifetime); Assert.True(fixture.Store.ConsumeReplay(new("ticket", "two")).Succeeded); } [Fact] public void PresenceAttemptAndRevocationPoolsShedWithoutPartialMutation() { EphemeralStoreOptions options = new() { MaxPresenceBindings = 1, MaxJoinAttempts = 1, MaxRevocations = 1, }; EphemeralStateFixture fixture = new(options); StoredListing first = fixture.CreateVisibleListing(out CreateListingCommand firstCommand); CreateListingCommand secondCommand = fixture.ListingCommand(owner: "publisher-2"); fixture.Store.CreateListing(secondCommand); Assert.Equal(StoreResultCode.CapacityExceeded, fixture.Store.BindHostPresence(new( secondCommand.Listing.HostPresenceHandle, secondCommand.Listing.HostPresenceFingerprint, EphemeralStateFixture.OtherPublicEndpoint(42_000), null)).Code); Assert.True(fixture.Store.CreateJoinAttempt(fixture.AttemptCommand(first)).Succeeded); Assert.Equal(StoreResultCode.CapacityExceeded, fixture.Store.CreateJoinAttempt(fixture.AttemptCommand(first, "client-2")).Code); Assert.True(fixture.Store.RevokePrincipal("unrelated", TimeSpan.FromMinutes(1)).Succeeded); Assert.Equal(StoreResultCode.CapacityExceeded, fixture.Store.RevokePrincipal(firstCommand.Listing.OwnerSubject, TimeSpan.FromMinutes(1)).Code); Assert.True(fixture.Store.GetListing(first.Definition.ListingId, true).Succeeded); Assert.True(fixture.Store.GetListing(secondCommand.Listing.ListingId, false).Succeeded); } [Fact] public void ExhaustionShedsNewListingWithoutMutatingExistingState() { EphemeralStoreOptions options = new() { MaxListings = 1 }; EphemeralStateFixture fixture = new(options); CreateListingCommand first = fixture.ListingCommand(); CreateListingCommand second = fixture.ListingCommand(); Assert.True(fixture.Store.CreateListing(first).Succeeded); Assert.Equal(StoreResultCode.CapacityExceeded, fixture.Store.CreateListing(second).Code); Assert.True(fixture.Store.GetListing(first.Listing.ListingId, false).Succeeded); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(second.Listing.ListingId, false).Code); } [Fact] public void IdempotencyPoolExhaustionDoesNotCreateUntrackedResource() { EphemeralStoreOptions options = new() { MaxListings = 2, MaxIdempotencyEntries = 1 }; EphemeralStateFixture fixture = new(options); CreateListingCommand first = fixture.ListingCommand(); CreateListingCommand second = fixture.ListingCommand(); Assert.True(fixture.Store.CreateListing(first).Succeeded); Assert.Equal(StoreResultCode.CapacityExceeded, fixture.Store.CreateListing(second).Code); Assert.True(fixture.Store.GetListing(first.Listing.ListingId, false).Succeeded); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(second.Listing.ListingId, false).Code); } [Fact] public void PolicyQuotasAreCheckedInsideAtomicCreation() { EphemeralStateFixture fixture = new(); CreateListingCommand first = fixture.ListingCommand(owner: "publisher-quota") with { OwnerListingLimit = 1 }; CreateListingCommand second = fixture.ListingCommand(owner: "publisher-quota") with { OwnerListingLimit = 1 }; Assert.True(fixture.Store.CreateListing(first).Succeeded); Assert.Equal(StoreResultCode.CapacityExceeded, fixture.Store.CreateListing(second).Code); fixture.Store.BindHostPresence(new( first.Listing.HostPresenceHandle, first.Listing.HostPresenceFingerprint, EphemeralStateFixture.PublicEndpoint(42_100), null)); StoredListing listing = fixture.Store.GetListing(first.Listing.ListingId, true).Value!; CreateJoinAttemptCommand attempt = fixture.AttemptCommand(listing) with { ScopeAttemptLimit = 1 }; Assert.True(fixture.Store.CreateJoinAttempt(attempt).Succeeded); Assert.Equal(StoreResultCode.CapacityExceeded, fixture.Store.CreateJoinAttempt( fixture.AttemptCommand(listing, "client-quota-2") with { ScopeAttemptLimit = 1 }).Code); } [Fact] public void InvalidDefaultSecurityValuesCannotEnterStore() { EphemeralStateFixture fixture = new(); CreateListingCommand command = fixture.ListingCommand(); Assert.Throws(() => fixture.Store.CreateListing(command with { Listing = command.Listing with { LeaseFingerprint = default }, })); } [Fact] public void RevocationRemovesEveryPathAndBlocksNewWorkAtomically() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out CreateListingCommand command); CreateJoinAttemptCommand attempt = fixture.AttemptCommand(listing, command.Listing.OwnerSubject); fixture.Store.CreateJoinAttempt(attempt); StoreResult revoked = fixture.Store.RevokePrincipal(command.Listing.OwnerSubject, TimeSpan.FromMinutes(1)); Assert.True(revoked.Succeeded); Assert.Equal(2, revoked.Value); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(listing.Definition.ListingId, false).Code); Assert.Equal(StoreResultCode.NotFound, fixture.Store.BindAttemptEndpoint(new( attempt.MediationHandle, AttemptPeerRole.Client, attempt.ClientCapabilityFingerprint, EphemeralStateFixture.PublicEndpoint(40_030), null)).Code); Assert.Equal(StoreResultCode.Revoked, fixture.Store.CreateListing(fixture.ListingCommand(owner: command.Listing.OwnerSubject)).Code); } [Fact] public void RestartHasNewGenerationAndNoEphemeralState() { EphemeralStateFixture before = new(); StoredListing listing = before.CreateVisibleListing(out _); EphemeralStateFixture after = new(); Assert.NotEqual(before.Store.InstanceId, after.Store.InstanceId); Assert.Equal(StoreResultCode.NotFound, after.Store.GetListing(listing.Definition.ListingId, false).Code); } [Fact] public void DrainRejectsNewWorkAllowsInflightCompletionThenClearsState() { EphemeralStoreOptions options = new() { GracefulDrainLifetime = TimeSpan.FromSeconds(5) }; EphemeralStateFixture fixture = new(options); StoredListing listing = fixture.CreateVisibleListing(out _); CreateJoinAttemptCommand attempt = fixture.AttemptCommand(listing); fixture.Store.CreateJoinAttempt(attempt); fixture.Store.BeginDrain(); Assert.Equal(StoreResultCode.Draining, fixture.Store.CreateListing(fixture.ListingCommand()).Code); Assert.Equal(StoreResultCode.Draining, fixture.Store.CreateJoinAttempt(fixture.AttemptCommand(listing)).Code); Assert.True(fixture.Store.BindAttemptEndpoint(new( attempt.MediationHandle, AttemptPeerRole.Client, attempt.ClientCapabilityFingerprint, EphemeralStateFixture.PublicEndpoint(41_000), null)).Succeeded); fixture.Clock.Advance(options.GracefulDrainLifetime); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(listing.Definition.ListingId, false).Code); Assert.Equal(StoreResultCode.NotFound, fixture.Store.BindAttemptEndpoint(new( attempt.MediationHandle, AttemptPeerRole.Host, attempt.HostCapabilityFingerprint, EphemeralStateFixture.PublicEndpoint(41_001), null)).Code); } [Fact] public void PrecancelledOperationHasNoPartialEffect() { EphemeralStateFixture fixture = new(); CreateListingCommand command = fixture.ListingCommand(); using CancellationTokenSource cancellation = new(); cancellation.Cancel(); Assert.Throws(() => fixture.Store.CreateListing(command, cancellation.Token)); Assert.Equal(StoreResultCode.NotFound, fixture.Store.GetListing(command.Listing.ListingId, false).Code); } [Fact] public void UnavailableStoreFailsNewAuthorizationClosedAndErasesActiveState() { EphemeralStateFixture fixture = new(); StoredListing listing = fixture.CreateVisibleListing(out _); fixture.Store.MarkUnavailable(); Assert.Equal(StoreResultCode.ServiceUnavailable, fixture.Store.GetListing(listing.Definition.ListingId, false).Code); Assert.Equal(StoreResultCode.ServiceUnavailable, fixture.Store.CreateJoinAttempt(fixture.AttemptCommand(listing)).Code); } }