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:
@@ -0,0 +1,176 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Scanner.Cache.Abstractions;
|
||||
using StellaOps.Scanner.Cache.LayerCache;
|
||||
using StellaOps.TestKit;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Scanner.Cache.Tests.LayerCache;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="LayerCacheStore"/> with FakeTimeProvider for deterministic TTL testing.
|
||||
/// </summary>
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
public sealed class LayerCacheStoreTimeProviderTests : IDisposable
|
||||
{
|
||||
private readonly FakeTimeProvider _timeProvider;
|
||||
private readonly LayerCacheStore _store;
|
||||
private readonly string _testCacheDir;
|
||||
|
||||
public LayerCacheStoreTimeProviderTests()
|
||||
{
|
||||
_timeProvider = new FakeTimeProvider(new DateTimeOffset(2026, 1, 18, 12, 0, 0, TimeSpan.Zero));
|
||||
|
||||
_testCacheDir = Path.Combine(Path.GetTempPath(), $"layer-cache-test-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(_testCacheDir);
|
||||
|
||||
var options = Options.Create(new ScannerCacheOptions
|
||||
{
|
||||
RootPath = _testCacheDir,
|
||||
LayerTtl = TimeSpan.FromHours(24)
|
||||
});
|
||||
|
||||
_store = new LayerCacheStore(
|
||||
options,
|
||||
NullLogger<LayerCacheStore>.Instance,
|
||||
_timeProvider);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Directory.Exists(_testCacheDir))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(_testCacheDir, recursive: true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore cleanup errors in tests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static LayerCachePutRequest CreatePutRequest(string layerDigest) =>
|
||||
new(
|
||||
layerDigest: layerDigest,
|
||||
architecture: "amd64",
|
||||
mediaType: "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
metadata: new Dictionary<string, string>(),
|
||||
artifacts: new List<LayerCacheArtifactContent>
|
||||
{
|
||||
new("sbom.json", new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }), "application/json")
|
||||
});
|
||||
|
||||
[Fact]
|
||||
public async Task TryGetAsync_NewEntry_ReturnsEntry()
|
||||
{
|
||||
// Arrange
|
||||
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
|
||||
var request = CreatePutRequest(layerDigest);
|
||||
await _store.PutAsync(request);
|
||||
|
||||
// Act
|
||||
var entry = await _store.TryGetAsync(layerDigest);
|
||||
|
||||
// Assert
|
||||
entry.Should().NotBeNull();
|
||||
entry!.LayerDigest.Should().Be(layerDigest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryGetAsync_AfterTtlExpires_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
|
||||
var request = CreatePutRequest(layerDigest);
|
||||
await _store.PutAsync(request);
|
||||
|
||||
// Verify entry exists
|
||||
var entryBefore = await _store.TryGetAsync(layerDigest);
|
||||
entryBefore.Should().NotBeNull();
|
||||
|
||||
// Act - advance time past TTL (24 hours + buffer)
|
||||
_timeProvider.Advance(TimeSpan.FromHours(25));
|
||||
|
||||
var entryAfter = await _store.TryGetAsync(layerDigest);
|
||||
|
||||
// Assert
|
||||
entryAfter.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryGetAsync_BeforeTtlExpires_ReturnsEntry()
|
||||
{
|
||||
// Arrange
|
||||
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
|
||||
var request = CreatePutRequest(layerDigest);
|
||||
await _store.PutAsync(request);
|
||||
|
||||
// Act - advance time but not past TTL
|
||||
_timeProvider.Advance(TimeSpan.FromHours(12));
|
||||
|
||||
var entry = await _store.TryGetAsync(layerDigest);
|
||||
|
||||
// Assert
|
||||
entry.Should().NotBeNull();
|
||||
entry!.LayerDigest.Should().Be(layerDigest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryGetAsync_AtExactTtl_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
|
||||
var request = CreatePutRequest(layerDigest);
|
||||
await _store.PutAsync(request);
|
||||
|
||||
// Act - advance time to exactly TTL + 1 second
|
||||
_timeProvider.Advance(TimeSpan.FromHours(24).Add(TimeSpan.FromSeconds(1)));
|
||||
|
||||
var entry = await _store.TryGetAsync(layerDigest);
|
||||
|
||||
// Assert
|
||||
entry.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryGetAsync_UpdatesLastAccessed()
|
||||
{
|
||||
// Arrange
|
||||
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
|
||||
var request = CreatePutRequest(layerDigest);
|
||||
await _store.PutAsync(request);
|
||||
|
||||
// First access
|
||||
await _store.TryGetAsync(layerDigest);
|
||||
var firstAccessTime = _timeProvider.GetUtcNow();
|
||||
|
||||
// Advance time
|
||||
_timeProvider.Advance(TimeSpan.FromHours(1));
|
||||
|
||||
// Second access
|
||||
var entry = await _store.TryGetAsync(layerDigest);
|
||||
|
||||
// Assert
|
||||
entry.Should().NotBeNull();
|
||||
entry!.LastAccessed.Should().BeAfter(firstAccessTime);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PutAsync_SetsCorrectCachedAt()
|
||||
{
|
||||
// Arrange
|
||||
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
|
||||
var request = CreatePutRequest(layerDigest);
|
||||
var expectedTime = _timeProvider.GetUtcNow();
|
||||
|
||||
// Act
|
||||
var entry = await _store.PutAsync(request);
|
||||
|
||||
// Assert
|
||||
entry.CachedAt.Should().Be(expectedTime);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
|
||||
<PackageReference Include="Moq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="..\StellaOps.Concelier.Tests.Shared\AssemblyInfo.cs" />
|
||||
|
||||
Reference in New Issue
Block a user