using System.Net; using FinalFactory.Rendezvous.Contracts; using FinalFactory.Rendezvous.Server.JoinAttempts; using FinalFactory.Rendezvous.Server.Provisioning; using FinalFactory.Rendezvous.Server.State; using FinalFactory.Rendezvous.Tests.Provisioning; using FinalFactory.Rendezvous.Tests.Sessions; namespace FinalFactory.Rendezvous.Tests.JoinAttempts; internal sealed class JoinAttemptFixture : IDisposable { private int _sequence; public JoinAttemptFixture( EphemeralStoreOptions? options = null, GamePolicyOptions? joinPolicy = null) { Sessions = new(options); Cursors = new(); GamePolicyRegistry policies = GamePolicyRegistry.Create([ joinPolicy ?? ProvisioningTestData.CreatePolicy(), ]); Service = new(policies, Sessions.Store, Sessions.Capabilities, Cursors, Sessions.Clock); ClientSubject = Service.CreateAnonymousClientSubject(IPAddress.Parse("198.51.100.40")); } public SessionLeaseFixture Sessions { get; } public JoinAttemptCursorCodec Cursors { get; } public JoinAttemptService Service { get; } public string ClientSubject { get; } public (RegisterSessionResponse Registration, StoredListing Listing) CreateHost(bool bindPresence = true) { RegisterSessionResponse registration = Sessions.Register(); if (bindPresence) { Assert.True(Sessions.BindPresence(registration).Succeeded); } StoredListing listing = Sessions.Store.GetListing(registration.ListingId, false).Value!; return (registration, listing); } public CreateJoinAttemptRequest Request( SessionListingId listingId, string? idempotencyKey = null) => new() { IdempotencyKey = idempotencyKey ?? $"join-{Interlocked.Increment(ref _sequence)}", GameId = Sessions.Scope.GameId, EnvironmentId = Sessions.Scope.EnvironmentId, ListingId = listingId, ProtocolVersion = 7, }; public CreateJoinAttemptResponse Create( SessionListingId listingId, string? idempotencyKey = null) { JoinAttemptServiceResult result = Service.Create( ClientSubject, Request(listingId, idempotencyKey)); Assert.True(result.Succeeded); return Assert.IsType(result.Value); } public StoredJoinAttempt GetAttempt( RegisterSessionResponse registration, JoinAttemptId attemptId) { Assert.True(Sessions.Capabilities.TryFingerprint( registration.LeaseToken, out SecretFingerprint leaseFingerprint)); IReadOnlyList attempts = Sessions.Store.BrowseHostJoinAttempts(new( registration.ListingId, leaseFingerprint, ContractLimits.BrowserPageMaxItems)).Value!; return attempts.Single(attempt => attempt.AttemptId == attemptId); } public IntroductionEndpoints Introduce( RegisterSessionResponse registration, CreateJoinAttemptResponse created) { StoredJoinAttempt attempt = GetAttempt(registration, created.AttemptId); HostJoinAttempt host = Service.BrowseForHost( registration.ListingId, ContractLimits.ContractVersion, registration.LeaseToken, ContractLimits.BrowserPageMaxItems, null).Value!.Items.Single(item => item.AttemptId == created.AttemptId); Assert.True(Sessions.Capabilities.TryFingerprint( host.HostPunchCapability, out SecretFingerprint hostFingerprint)); Assert.True(Sessions.Capabilities.TryFingerprint( created.ClientPunchCapability, out SecretFingerprint clientFingerprint)); Assert.True(Sessions.Store.BindAttemptEndpoint(new( attempt.MediationHandle, AttemptPeerRole.Host, hostFingerprint, new(AddressFamilyKind.Ipv4, "203.0.113.20", 41_000), null)).Succeeded); Assert.True(Sessions.Store.BindAttemptEndpoint(new( attempt.MediationHandle, AttemptPeerRole.Client, clientFingerprint, new(AddressFamilyKind.Ipv4, "198.51.100.40", 42_000), null)).Succeeded); StoreResult introduced = Sessions.Store.ConsumeIntroduction( attempt.MediationHandle); Assert.True(introduced.Succeeded); return introduced.Value!; } public void Dispose() { Cursors.Dispose(); Sessions.Dispose(); } }