using System.Collections.Immutable; using System.Globalization; using System.Text.Json.Nodes; using StellaOps.Concelier.Models.Observations; using StellaOps.Concelier.RawModels; using StellaOps.Concelier.WebService.Services; using Xunit; namespace StellaOps.Concelier.WebService.Tests; public class AdvisoryChunkCacheKeyTests { [Fact] public void Create_NormalizesObservationOrdering() { var options = new AdvisoryChunkBuildOptions( "CVE-2025-0001", "fp", 10, 10, ImmutableHashSet.Create("workaround"), ImmutableHashSet.Empty, 8); var first = BuildObservation("obs-1", "sha256:one", "2025-11-18T00:00:00Z"); var second = BuildObservation("obs-2", "sha256:two", "2025-11-18T00:05:00Z"); var ordered = AdvisoryChunkCacheKey.Create("tenant-a", "CVE-2025-0001", options, new[] { first, second }, "fp"); var reversed = AdvisoryChunkCacheKey.Create("tenant-a", "CVE-2025-0001", options, new[] { second, first }, "fp"); Assert.Equal(ordered.Value, reversed.Value); } [Fact] public void Create_NormalizesFilterCasing() { var optionsLower = new AdvisoryChunkBuildOptions( "CVE-2025-0002", "fp", 5, 5, ImmutableHashSet.Create("workaround", "fix"), ImmutableHashSet.Create("ndjson"), 1); var optionsUpper = new AdvisoryChunkBuildOptions( "CVE-2025-0002", "fp", 5, 5, ImmutableHashSet.Create("WorkAround", "FIX"), ImmutableHashSet.Create("NDJSON"), 1); var observation = BuildObservation("obs-3", "sha256:three", "2025-11-18T00:10:00Z"); var lower = AdvisoryChunkCacheKey.Create("tenant-a", "CVE-2025-0002", optionsLower, new[] { observation }, "fp"); var upper = AdvisoryChunkCacheKey.Create("tenant-a", "CVE-2025-0002", optionsUpper, new[] { observation }, "fp"); Assert.Equal(lower.Value, upper.Value); } [Fact] public void Create_ChangesWhenContentHashDiffers() { var options = new AdvisoryChunkBuildOptions( "CVE-2025-0003", "fp", 5, 5, ImmutableHashSet.Empty, ImmutableHashSet.Empty, 1); var original = BuildObservation("obs-4", "sha256:orig", "2025-11-18T00:15:00Z"); var mutated = BuildObservation("obs-4", "sha256:mut", "2025-11-18T00:15:00Z"); var originalKey = AdvisoryChunkCacheKey.Create("tenant-a", "CVE-2025-0003", options, new[] { original }, "fp"); var mutatedKey = AdvisoryChunkCacheKey.Create("tenant-a", "CVE-2025-0003", options, new[] { mutated }, "fp"); Assert.NotEqual(originalKey.Value, mutatedKey.Value); } private static AdvisoryObservation BuildObservation(string id, string contentHash, string timestamp) { var createdAt = DateTimeOffset.Parse(timestamp, CultureInfo.InvariantCulture); return new AdvisoryObservation( id, tenant: "tenant-a", source: new AdvisoryObservationSource("nvd", "stream", "api"), upstream: new AdvisoryObservationUpstream( upstreamId: id, documentVersion: "1", fetchedAt: createdAt, receivedAt: createdAt, contentHash: contentHash, signature: new AdvisoryObservationSignature(false, null, null, null)), content: new AdvisoryObservationContent("csaf", "2.0", JsonNode.Parse("{}")!), linkset: new AdvisoryObservationLinkset(Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty()), rawLinkset: new RawLinkset(), createdAt: createdAt); } }