Files
Rendezvous/tests/FinalFactory.Rendezvous.Tests/Sessions/SessionLeaseTestData.cs
KyuubiYoru 49564c7e7e
quality-gate / quality (push) Successful in 55s
feat: add presence-gated session leases (#7)
Closes #7
2026-07-16 05:58:47 +02:00

94 lines
3.4 KiB
C#

using FinalFactory.Rendezvous.Contracts;
using FinalFactory.Rendezvous.Server.Provisioning;
using FinalFactory.Rendezvous.Server.Sessions;
using FinalFactory.Rendezvous.Server.State;
using FinalFactory.Rendezvous.Tests.Provisioning;
using FinalFactory.Rendezvous.Tests.State;
namespace FinalFactory.Rendezvous.Tests.Sessions;
internal sealed class SessionLeaseFixture : IDisposable
{
private int _sequence;
public SessionLeaseFixture(EphemeralStoreOptions? storeOptions = null)
{
StoreOptions = storeOptions ?? new EphemeralStoreOptions();
Clock = new();
Store = new(StoreOptions, Clock, Clock);
Capabilities = new();
GamePolicyRegistry policies = GamePolicyRegistry.Create([ProvisioningTestData.CreatePolicy()]);
Service = new(
new PublisherAuthorizationService(policies),
Store,
Capabilities,
SessionLeaseTiming.From(StoreOptions),
Clock);
Principal = Publisher("publisher-1");
}
public EphemeralStoreOptions StoreOptions { get; }
public ManualRendezvousClock Clock { get; }
public InMemoryEphemeralRendezvousStore Store { get; }
public EphemeralCapabilityIssuer Capabilities { get; }
public SessionLeaseService Service { get; }
public DedicatedPublisherPrincipal Principal { get; }
public TenantScope Scope { get; } = new(new("space-game"), new("production"));
public DedicatedPublisherPrincipal Publisher(string subject) => new(
subject,
Clock.UtcNow.AddMinutes(10),
Scope.GameId,
Scope.EnvironmentId,
new HashSet<RegionId> { new("eu-central") });
public RegisterSessionRequest Request(string? idempotencyKey = null) => new()
{
IdempotencyKey = idempotencyKey ?? $"register-{Interlocked.Increment(ref _sequence)}",
GameId = Scope.GameId,
EnvironmentId = Scope.EnvironmentId,
RegionId = new("eu-central"),
ProtocolVersion = 7,
BuildVersion = "1.4.2",
DisplayName = "Europa Relay",
Visibility = ListingVisibility.Public,
Capacity = new() { CurrentPlayers = 2, MaximumPlayers = 8 },
Metadata = new Dictionary<string, string>(StringComparer.Ordinal)
{
["mode"] = "co-op",
["map"] = "europa",
},
};
public RegisterSessionResponse Register(
RegisterSessionRequest? request = null,
DedicatedPublisherPrincipal? principal = null)
{
SessionServiceResult<RegisterSessionResponse> result = Service.Register(
principal ?? Principal,
request ?? Request());
Assert.True(result.Succeeded);
Assert.NotNull(result.Value);
return result.Value;
}
public StoreResult<StoredListing> BindPresence(RegisterSessionResponse registration)
{
Assert.True(Capabilities.TryFingerprint(
registration.HostPresenceCapability,
out SecretFingerprint fingerprint));
return Store.BindHostPresence(new(
registration.HostPresenceHandle,
fingerprint,
new(AddressFamilyKind.Ipv4, "203.0.113.50", 40_000),
new ObservedEndpoint(AddressFamilyKind.Ipv4, "192.168.1.50", 40_000)));
}
public IReadOnlyList<StoredListing> Browse() => Store.BrowseVisibleListings(new(
Scope,
7,
new RegionId("eu-central"))).Value!;
public void Dispose() => Capabilities.Dispose();
}