doctor enhancements, setup, enhancements, ui functionality and design consolidation and , test projects fixes , product advisory attestation/rekor and delta verfications enhancements

This commit is contained in:
master
2026-01-19 09:02:59 +02:00
parent 8c4bf54aed
commit 17419ba7c4
809 changed files with 170738 additions and 12244 deletions

View File

@@ -0,0 +1,155 @@
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Time.Testing;
using StellaOps.Scanner.Reachability.Slices;
using Xunit;
namespace StellaOps.Scanner.Reachability.Tests.Slices;
/// <summary>
/// Unit tests for <see cref="InMemorySliceCache"/> with proper timer testing using FakeTimeProvider.
/// </summary>
[Trait("Category", "Unit")]
public sealed class InMemorySliceCacheTests : IDisposable
{
private readonly FakeTimeProvider _timeProvider;
private readonly InMemorySliceCache _cache;
public InMemorySliceCacheTests()
{
_timeProvider = new FakeTimeProvider(new DateTimeOffset(2026, 1, 18, 12, 0, 0, TimeSpan.Zero));
_cache = new InMemorySliceCache(
NullLogger<InMemorySliceCache>.Instance,
_timeProvider);
}
public void Dispose()
{
_cache.Dispose();
}
[Fact]
public async Task TryGetAsync_WithValidEntry_ReturnsValue()
{
// Arrange
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromHours(1));
// Act
var retrieved = await _cache.TryGetAsync("key1");
// Assert
retrieved.Should().NotBeNull();
retrieved!.SliceDigest.Should().Be("digest1");
}
[Fact]
public async Task TryGetAsync_WithExpiredEntry_ReturnsNull()
{
// Arrange
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromMinutes(30));
// Advance time past expiration
_timeProvider.Advance(TimeSpan.FromMinutes(31));
// Act
var retrieved = await _cache.TryGetAsync("key1");
// Assert
retrieved.Should().BeNull();
}
[Fact]
public async Task TryGetAsync_BeforeExpiration_ReturnsValue()
{
// Arrange
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromHours(1));
// Advance time but not past expiration
_timeProvider.Advance(TimeSpan.FromMinutes(59));
// Act
var retrieved = await _cache.TryGetAsync("key1");
// Assert
retrieved.Should().NotBeNull();
}
[Fact]
public async Task SetAsync_OverwritesExistingEntry()
{
// Arrange
var result1 = CreateTestResult("digest1");
var result2 = CreateTestResult("digest2");
await _cache.SetAsync("key1", result1, TimeSpan.FromHours(1));
// Act
await _cache.SetAsync("key1", result2, TimeSpan.FromHours(1));
var retrieved = await _cache.TryGetAsync("key1");
// Assert
retrieved.Should().NotBeNull();
retrieved!.SliceDigest.Should().Be("digest2");
}
[Fact]
public async Task TryGetAsync_NonExistentKey_ReturnsNull()
{
// Act
var retrieved = await _cache.TryGetAsync("nonexistent");
// Assert
retrieved.Should().BeNull();
}
[Fact]
public async Task GetStatistics_ReturnsAccurateStats()
{
// Arrange
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromHours(1));
// Act - hit
await _cache.TryGetAsync("key1");
// Act - miss
await _cache.TryGetAsync("nonexistent");
var stats = _cache.GetStatistics();
// Assert
stats.HitCount.Should().Be(1);
stats.MissCount.Should().Be(1);
stats.EntryCount.Should().Be(1);
}
[Fact]
public async Task EvictionTimer_AdvanceTime_EvictsExpiredEntries()
{
// Arrange - add entries with short TTL
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromSeconds(30));
// Advance time to trigger eviction timer (60 seconds interval)
_timeProvider.Advance(TimeSpan.FromSeconds(61));
// Allow the timer callback to complete
await Task.Delay(50);
// Act
var retrieved = await _cache.TryGetAsync("key1");
// Assert - should be evicted
retrieved.Should().BeNull();
}
private static CachedSliceResult CreateTestResult(string digest) => new()
{
SliceDigest = digest,
Verdict = "safe",
Confidence = 0.95,
PathWitnesses = new List<string> { "path1", "path2" },
CachedAt = DateTimeOffset.UtcNow
};
}

View File

@@ -0,0 +1,174 @@
using FluentAssertions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Time.Testing;
using StellaOps.Scanner.Reachability.Slices;
using Xunit;
namespace StellaOps.Scanner.Reachability.Tests.Slices;
/// <summary>
/// Unit tests for <see cref="SliceCache"/> with proper timer testing using FakeTimeProvider.
/// </summary>
[Trait("Category", "Unit")]
public sealed class SliceCacheTests : IDisposable
{
private readonly FakeTimeProvider _timeProvider;
private readonly SliceCache _cache;
public SliceCacheTests()
{
_timeProvider = new FakeTimeProvider(new DateTimeOffset(2026, 1, 18, 12, 0, 0, TimeSpan.Zero));
var options = Options.Create(new SliceCacheOptions
{
Enabled = true,
Ttl = TimeSpan.FromHours(1),
MaxItems = 100
});
_cache = new SliceCache(options, _timeProvider);
}
public void Dispose()
{
_cache.Dispose();
}
[Fact]
public async Task TryGetAsync_WithValidEntry_ReturnsValue()
{
// Arrange
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromHours(1));
// Act
var retrieved = await _cache.TryGetAsync("key1");
// Assert
retrieved.Should().NotBeNull();
retrieved!.SliceDigest.Should().Be("digest1");
}
[Fact]
public async Task TryGetAsync_WhenDisabled_ReturnsNull()
{
// Arrange
var options = Options.Create(new SliceCacheOptions { Enabled = false });
using var cache = new SliceCache(options, _timeProvider);
var result = CreateTestResult("digest1");
await cache.SetAsync("key1", result, TimeSpan.FromHours(1));
// Act
var retrieved = await cache.TryGetAsync("key1");
// Assert
retrieved.Should().BeNull();
}
[Fact]
public async Task TryGetAsync_WithExpiredEntry_ReturnsNull()
{
// Arrange
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromMinutes(30));
// Advance time past expiration
_timeProvider.Advance(TimeSpan.FromMinutes(31));
// Act
var retrieved = await _cache.TryGetAsync("key1");
// Assert
retrieved.Should().BeNull();
}
[Fact]
public async Task TryGetAsync_BeforeExpiration_ReturnsValue()
{
// Arrange
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromHours(1));
// Advance time but not past expiration
_timeProvider.Advance(TimeSpan.FromMinutes(59));
// Act
var retrieved = await _cache.TryGetAsync("key1");
// Assert
retrieved.Should().NotBeNull();
}
[Fact]
public async Task SetAsync_ExceedsMaxItems_EvictsOldest()
{
// Arrange - create cache with small max
var options = Options.Create(new SliceCacheOptions
{
Enabled = true,
MaxItems = 10,
Ttl = TimeSpan.FromHours(1)
});
using var cache = new SliceCache(options, _timeProvider);
// Add items up to max
for (int i = 0; i < 10; i++)
{
await cache.SetAsync($"key{i}", CreateTestResult($"digest{i}"), TimeSpan.FromHours(1));
_timeProvider.Advance(TimeSpan.FromSeconds(1)); // Ensure different access times
}
// Act - add one more, should trigger eviction
await cache.SetAsync("key_new", CreateTestResult("digest_new"), TimeSpan.FromHours(1));
// Assert - new item should be present
var retrieved = await cache.TryGetAsync("key_new");
retrieved.Should().NotBeNull();
}
[Fact]
public async Task EvictionTimer_AdvanceTime_EvictsExpiredEntries()
{
// Arrange - add entry with short TTL
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromSeconds(30));
// Advance time past eviction timer interval (1 minute)
_timeProvider.Advance(TimeSpan.FromMinutes(1.5));
// Allow timer callback to complete
await Task.Delay(50);
// Act
var retrieved = await _cache.TryGetAsync("key1");
// Assert - should be evicted
retrieved.Should().BeNull();
}
[Fact]
public async Task GetStatistics_ReturnsAccurateHitMissCount()
{
// Arrange
var result = CreateTestResult("digest1");
await _cache.SetAsync("key1", result, TimeSpan.FromHours(1));
// Act
await _cache.TryGetAsync("key1"); // hit
await _cache.TryGetAsync("key1"); // hit
await _cache.TryGetAsync("nonexistent"); // miss
var stats = _cache.GetStatistics();
// Assert
stats.HitCount.Should().Be(2);
stats.MissCount.Should().Be(1);
}
private static CachedSliceResult CreateTestResult(string digest) => new()
{
SliceDigest = digest,
Verdict = "safe",
Confidence = 0.95,
PathWitnesses = new List<string> { "path1", "path2" },
CachedAt = DateTimeOffset.UtcNow
};
}

View File

@@ -11,8 +11,9 @@
<PackageReference Include="FsCheck" />
<PackageReference Include="FsCheck.Xunit.v3" />
<PackageReference Include="JsonSchema.Net" />
<PackageReference Include="Moq" />
</ItemGroup>
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
<PackageReference Include="Moq" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\__Libraries\StellaOps.Scanner.Reachability\StellaOps.Scanner.Reachability.csproj" />