using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using StellaOps.Messaging.Testing.Fixtures; using StellaOps.Scanner.CallGraph; using StellaOps.Scanner.CallGraph.Caching; using Xunit; namespace StellaOps.Scanner.CallGraph.Tests; [Collection(nameof(ValkeyFixtureCollection))] public class ValkeyCallGraphCacheServiceTests : IAsyncLifetime { private readonly ValkeyFixture _fixture; private ValkeyCallGraphCacheService _cache = null!; public ValkeyCallGraphCacheServiceTests(ValkeyFixture fixture) { _fixture = fixture; } public Task InitializeAsync() { var options = Options.Create(new CallGraphCacheConfig { Enabled = true, ConnectionString = _fixture.ConnectionString, KeyPrefix = "test:callgraph:", TtlSeconds = 60, EnableGzip = true, CircuitBreaker = new CircuitBreakerConfig { FailureThreshold = 3, TimeoutSeconds = 30, HalfOpenTimeout = 10 } }); _cache = new ValkeyCallGraphCacheService(options, NullLogger.Instance); return Task.CompletedTask; } public async Task DisposeAsync() { await _cache.DisposeAsync(); } [Fact] public async Task SetThenGet_CallGraph_RoundTrips() { var nodeId = CallGraphNodeIds.Compute("dotnet:test:entry"); var snapshot = new CallGraphSnapshot( ScanId: "scan-cache-1", GraphDigest: "sha256:cg", Language: "dotnet", ExtractedAt: DateTimeOffset.UtcNow, Nodes: [new CallGraphNode(nodeId, "Entry", "file.cs", 1, "app", Visibility.Public, true, EntrypointType.HttpHandler, false, null)], Edges: [], EntrypointIds: [nodeId], SinkIds: []); await _cache.SetCallGraphAsync(snapshot); var loaded = await _cache.TryGetCallGraphAsync("scan-cache-1", "dotnet"); Assert.NotNull(loaded); Assert.Equal(snapshot.ScanId, loaded!.ScanId); Assert.Equal(snapshot.Language, loaded.Language); Assert.Equal(snapshot.GraphDigest, loaded.GraphDigest); } [Fact] public async Task SetThenGet_ReachabilityResult_RoundTrips() { var result = new ReachabilityAnalysisResult( ScanId: "scan-cache-2", GraphDigest: "sha256:cg", Language: "dotnet", ComputedAt: DateTimeOffset.UtcNow, ReachableNodeIds: [], ReachableSinkIds: [], Paths: [], ResultDigest: "sha256:r"); await _cache.SetReachabilityResultAsync(result); var loaded = await _cache.TryGetReachabilityResultAsync("scan-cache-2", "dotnet"); Assert.NotNull(loaded); Assert.Equal(result.ResultDigest, loaded!.ResultDigest); } }