using MongoDB.Driver; using StellaOps.AirGap.Controller.Domain; using StellaOps.AirGap.Controller.Stores; using StellaOps.AirGap.Time.Models; using StellaOps.Testing; using Xunit; namespace StellaOps.AirGap.Controller.Tests; public class MongoAirGapStateStoreTests : IDisposable { private readonly MongoRunnerFixture _mongo = new(); private readonly IMongoCollection _collection; private readonly MongoAirGapStateStore _store; public MongoAirGapStateStoreTests() { OpenSslAutoInit.Init(); var database = _mongo.Client.GetDatabase("airgap_tests"); _collection = MongoAirGapStateStore.EnsureCollection(database); _store = new MongoAirGapStateStore(_collection); } [Fact] public async Task Upsert_and_read_state_by_tenant() { var state = new AirGapState { TenantId = "tenant-x", Sealed = true, PolicyHash = "hash-1", TimeAnchor = new TimeAnchor(DateTimeOffset.UtcNow, "roughtime", "roughtime", "fp", "digest"), StalenessBudget = new StalenessBudget(10, 20), LastTransitionAt = DateTimeOffset.UtcNow }; await _store.SetAsync(state); var stored = await _store.GetAsync("tenant-x"); Assert.True(stored.Sealed); Assert.Equal("hash-1", stored.PolicyHash); Assert.Equal("tenant-x", stored.TenantId); Assert.Equal(state.TimeAnchor.TokenDigest, stored.TimeAnchor.TokenDigest); Assert.Equal(10, stored.StalenessBudget.WarningSeconds); } [Fact] public async Task Enforces_singleton_per_tenant() { var first = new AirGapState { TenantId = "tenant-y", Sealed = true, PolicyHash = "h1" }; var second = new AirGapState { TenantId = "tenant-y", Sealed = false, PolicyHash = "h2" }; await _store.SetAsync(first); await _store.SetAsync(second); var stored = await _store.GetAsync("tenant-y"); Assert.Equal("h2", stored.PolicyHash); Assert.False(stored.Sealed); } [Fact] public async Task Defaults_to_unknown_when_missing() { var stored = await _store.GetAsync("absent"); Assert.False(stored.Sealed); Assert.Equal("absent", stored.TenantId); } public void Dispose() { _mongo.Dispose(); } }