Files
git.stella-ops.org/src/AirGap/__Tests/StellaOps.AirGap.Time.Tests/SealedStartupValidatorTests.cs
StellaOps Bot f46bde5575 save progress
2026-01-02 15:52:55 +02:00

79 lines
3.1 KiB
C#

using StellaOps.AirGap.Time.Models;
using StellaOps.AirGap.Time.Services;
using StellaOps.AirGap.Time.Stores;
using StellaOps.TestKit;
namespace StellaOps.AirGap.Time.Tests;
public class SealedStartupValidatorTests
{
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FailsWhenAnchorMissing()
{
var validator = Build(out var statusService, DateTimeOffset.UnixEpoch);
var result = await validator.ValidateAsync("t1", StalenessBudget.Default, default);
Assert.False(result.IsValid);
Assert.Equal("time-anchor-missing", result.Reason);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FailsWhenBreach()
{
var now = DateTimeOffset.UnixEpoch.AddSeconds(25);
var validator = Build(out var statusService, now);
var anchor = new TimeAnchor(DateTimeOffset.UnixEpoch, "src", "fmt", "fp", "digest");
await statusService.SetAnchorAsync("t1", anchor, new StalenessBudget(10, 20));
var status = await statusService.GetStatusAsync("t1", now);
var result = status.Staleness.IsBreach;
Assert.True(result);
var validation = await validator.ValidateAsync("t1", new StalenessBudget(10, 20), default);
Assert.False(validation.IsValid);
Assert.Equal("time-anchor-stale", validation.Reason);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SucceedsWhenFresh()
{
var now = DateTimeOffset.UnixEpoch.AddSeconds(5);
var validator = Build(out var statusService, now);
var anchor = new TimeAnchor(now, "src", "fmt", "fp", "digest");
await statusService.SetAnchorAsync("t1", anchor, new StalenessBudget(10, 20));
var validation = await validator.ValidateAsync("t1", new StalenessBudget(10, 20), default);
Assert.True(validation.IsValid);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FailsOnBudgetMismatch()
{
var now = DateTimeOffset.UnixEpoch.AddSeconds(5);
var validator = Build(out var statusService, now);
var anchor = new TimeAnchor(now, "src", "fmt", "fp", "digest");
await statusService.SetAnchorAsync("t1", anchor, new StalenessBudget(10, 20));
var validation = await validator.ValidateAsync("t1", new StalenessBudget(5, 15), default);
Assert.False(validation.IsValid);
Assert.Equal("time-anchor-budget-mismatch", validation.Reason);
}
private static SealedStartupValidator Build(out TimeStatusService statusService, DateTimeOffset now)
{
var store = new InMemoryTimeAnchorStore();
statusService = new TimeStatusService(store, new StalenessCalculator(), new TimeTelemetry(), new TestOptionsMonitor<AirGapOptions>(new AirGapOptions()));
return new SealedStartupValidator(statusService, new FixedTimeProvider(now));
}
private sealed class FixedTimeProvider : TimeProvider
{
private readonly DateTimeOffset _now;
public FixedTimeProvider(DateTimeOffset now) => _now = now;
public override DateTimeOffset GetUtcNow() => _now;
}
}