feat: add presence-gated session leases (#7)
quality-gate / quality (push) Successful in 55s
quality-gate / quality (push) Successful in 55s
Closes #7
This commit is contained in:
@@ -5,7 +5,10 @@ namespace FinalFactory.Rendezvous.Tests.State;
|
||||
|
||||
internal sealed class ManualRendezvousClock : IWallClock, IMonotonicClock
|
||||
{
|
||||
public DateTimeOffset UtcNow { get; private set; } = new(2026, 7, 16, 0, 0, 0, TimeSpan.Zero);
|
||||
public ManualRendezvousClock(DateTimeOffset? utcNow = null) =>
|
||||
UtcNow = utcNow ?? new DateTimeOffset(2026, 7, 16, 0, 0, 0, TimeSpan.Zero);
|
||||
|
||||
public DateTimeOffset UtcNow { get; private set; }
|
||||
public TimeSpan Elapsed { get; private set; }
|
||||
|
||||
public void Advance(TimeSpan duration)
|
||||
@@ -58,6 +61,7 @@ internal sealed class EphemeralStateFixture
|
||||
LeaseFingerprint = Fingerprint($"lease-{sequence}"),
|
||||
HostPresenceHandle = NewHandle(),
|
||||
HostPresenceFingerprint = Fingerprint($"presence-{sequence}"),
|
||||
CapabilityDerivationSalt = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,16 @@ namespace FinalFactory.Rendezvous.Tests.State;
|
||||
|
||||
public sealed class InMemoryEphemeralRendezvousStoreTests
|
||||
{
|
||||
[Fact]
|
||||
public void IdempotencyRetentionMustCoverResourceLifetimes()
|
||||
{
|
||||
ManualRendezvousClock clock = new();
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new InMemoryEphemeralRendezvousStore(
|
||||
new EphemeralStoreOptions { IdempotencyLifetime = TimeSpan.FromSeconds(5) },
|
||||
clock,
|
||||
clock));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DuplicateRegistrationIsIdempotentButChangedRequestConflicts()
|
||||
{
|
||||
@@ -49,6 +59,7 @@ public sealed class InMemoryEphemeralRendezvousStoreTests
|
||||
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));
|
||||
@@ -72,6 +83,7 @@ public sealed class InMemoryEphemeralRendezvousStoreTests
|
||||
listing.Definition.ListingId,
|
||||
listing.Definition.LeaseId,
|
||||
listing.Definition.LeaseFingerprint,
|
||||
listing.Definition.OwnerSubject,
|
||||
listing.Version));
|
||||
});
|
||||
Task<StoreResult<bool>> delete = Task.Run(() =>
|
||||
@@ -80,7 +92,8 @@ public sealed class InMemoryEphemeralRendezvousStoreTests
|
||||
return fixture.Store.DeleteListing(new(
|
||||
command.Listing.ListingId,
|
||||
command.Listing.LeaseId,
|
||||
command.Listing.LeaseFingerprint));
|
||||
command.Listing.LeaseFingerprint,
|
||||
command.Listing.OwnerSubject));
|
||||
});
|
||||
|
||||
start.Set();
|
||||
@@ -102,6 +115,7 @@ public sealed class InMemoryEphemeralRendezvousStoreTests
|
||||
listing.Definition.ListingId,
|
||||
listing.Definition.LeaseId,
|
||||
listing.Definition.LeaseFingerprint,
|
||||
listing.Definition.OwnerSubject,
|
||||
listing.Version);
|
||||
|
||||
StoreResult<StoredListing> first = fixture.Store.RenewLease(command);
|
||||
|
||||
Reference in New Issue
Block a user