up
Some checks failed
api-governance / spectral-lint (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Some checks failed
api-governance / spectral-lint (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
using StellaOps.AirGap.Controller.Services;
|
||||
using StellaOps.AirGap.Controller.Stores;
|
||||
using StellaOps.AirGap.Time.Models;
|
||||
using StellaOps.AirGap.Time.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.AirGap.Controller.Tests;
|
||||
|
||||
public class AirGapStateServiceTests
|
||||
{
|
||||
private readonly AirGapStateService _service;
|
||||
private readonly InMemoryAirGapStateStore _store = new();
|
||||
private readonly StalenessCalculator _calculator = new();
|
||||
|
||||
public AirGapStateServiceTests()
|
||||
{
|
||||
_service = new AirGapStateService(_store, _calculator);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Seal_sets_state_and_computes_staleness()
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var anchor = new TimeAnchor(now.AddMinutes(-2), "roughtime", "roughtime", "fp", "digest");
|
||||
var budget = new StalenessBudget(60, 120);
|
||||
|
||||
await _service.SealAsync("tenant-a", "policy-1", anchor, budget, now);
|
||||
var status = await _service.GetStatusAsync("tenant-a", now);
|
||||
|
||||
Assert.True(status.State.Sealed);
|
||||
Assert.Equal("policy-1", status.State.PolicyHash);
|
||||
Assert.Equal("tenant-a", status.State.TenantId);
|
||||
Assert.True(status.Staleness.AgeSeconds > 0);
|
||||
Assert.True(status.Staleness.IsWarning);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Unseal_clears_sealed_flag_and_updates_timestamp()
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
await _service.SealAsync("default", "hash", TimeAnchor.Unknown, StalenessBudget.Default, now);
|
||||
|
||||
var later = now.AddMinutes(1);
|
||||
await _service.UnsealAsync("default", later);
|
||||
var status = await _service.GetStatusAsync("default", later);
|
||||
|
||||
Assert.False(status.State.Sealed);
|
||||
Assert.Equal(later, status.State.LastTransitionAt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
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<AirGapStateDocument> _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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../shared/Testing.Shared/Testing.Shared.csproj" />
|
||||
<ProjectReference Include="../../../src/AirGap/StellaOps.AirGap.Controller/StellaOps.AirGap.Controller.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user