Refactor code structure and optimize performance across multiple modules
This commit is contained in:
@@ -4,13 +4,15 @@ using StellaOps.Concelier.Merge.Identity;
|
||||
using StellaOps.Concelier.Models;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class AdvisoryIdentityResolverTests
|
||||
{
|
||||
private readonly AdvisoryIdentityResolver _resolver = new();
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Resolve_GroupsBySharedCveAlias()
|
||||
{
|
||||
var nvd = CreateAdvisory("CVE-2025-1234", aliases: new[] { "CVE-2025-1234" }, source: "nvd");
|
||||
@@ -24,7 +26,8 @@ public sealed class AdvisoryIdentityResolverTests
|
||||
Assert.True(cluster.Aliases.Any(alias => alias.Value == "CVE-2025-1234"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Resolve_PrefersPsirtAliasWhenNoCve()
|
||||
{
|
||||
var vendor = CreateAdvisory("VMSA-2025-0001", aliases: new[] { "VMSA-2025-0001" }, source: "vmware");
|
||||
@@ -38,7 +41,8 @@ public sealed class AdvisoryIdentityResolverTests
|
||||
Assert.True(cluster.Aliases.Any(alias => alias.Value == "VMSA-2025-0001"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Resolve_FallsBackToGhsaWhenOnlyGhsaPresent()
|
||||
{
|
||||
var ghsa = CreateAdvisory("GHSA-aaaa-bbbb-cccc", aliases: new[] { "GHSA-aaaa-bbbb-cccc" }, source: "ghsa");
|
||||
@@ -52,7 +56,8 @@ public sealed class AdvisoryIdentityResolverTests
|
||||
Assert.True(cluster.Aliases.Any(alias => alias.Value == "GHSA-aaaa-bbbb-cccc"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Resolve_GroupsByKeyWhenNoAliases()
|
||||
{
|
||||
var first = CreateAdvisory("custom-1", aliases: Array.Empty<string>(), source: "source-a");
|
||||
|
||||
@@ -15,11 +15,13 @@ using StellaOps.Concelier.Storage.Aliases;
|
||||
using StellaOps.Concelier.Storage.MergeEvents;
|
||||
using StellaOps.Provenance;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class AdvisoryMergeServiceTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task MergeAsync_AppliesCanonicalRulesAndPersistsDecisions()
|
||||
{
|
||||
var aliasStore = new FakeAliasStore();
|
||||
@@ -167,7 +169,8 @@ public sealed class AdvisoryMergeServiceTests
|
||||
provenance: new[] { provenance });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task MergeAsync_PersistsConflictSummariesWithHashes()
|
||||
{
|
||||
var aliasStore = new FakeAliasStore();
|
||||
|
||||
@@ -9,11 +9,14 @@ using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
using Xunit;
|
||||
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class AdvisoryPrecedenceMergerTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Merge_PrefersVendorPrecedenceOverNvd()
|
||||
{
|
||||
var timeProvider = new FakeTimeProvider(new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
@@ -59,7 +62,8 @@ public sealed class AdvisoryPrecedenceMergerTests
|
||||
Assert.Contains(severityConflict.Tags, tag => string.Equals(tag.Key, "type", StringComparison.Ordinal) && string.Equals(tag.Value?.ToString(), "severity", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Merge_KevOnlyTogglesExploitKnown()
|
||||
{
|
||||
var timeProvider = new FakeTimeProvider(new DateTimeOffset(2025, 2, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
@@ -128,7 +132,8 @@ public sealed class AdvisoryPrecedenceMergerTests
|
||||
Assert.Contains(merged.Provenance, provenance => provenance.Source == "merge");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Merge_UnionsCreditsFromSources()
|
||||
{
|
||||
var timeProvider = new FakeTimeProvider();
|
||||
@@ -231,7 +236,8 @@ public sealed class AdvisoryPrecedenceMergerTests
|
||||
Assert.Contains(merged.Credits, credit => credit.Provenance.Source == "osv");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Merge_AcscActsAsEnrichmentSource()
|
||||
{
|
||||
var timeProvider = new FakeTimeProvider(new DateTimeOffset(2025, 10, 12, 0, 0, 0, TimeSpan.Zero));
|
||||
@@ -333,7 +339,8 @@ public sealed class AdvisoryPrecedenceMergerTests
|
||||
Assert.Contains(merged.Provenance, provenance => provenance.Source == "merge" && (provenance.Value?.Contains("acsc", StringComparison.OrdinalIgnoreCase) ?? false));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Merge_RecordsNormalizedRuleMetrics()
|
||||
{
|
||||
var now = new DateTimeOffset(2025, 3, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
@@ -474,7 +481,8 @@ public sealed class AdvisoryPrecedenceMergerTests
|
||||
Assert.Contains(missingMeasurement.Tags, tag => string.Equals(tag.Key, "package_type", StringComparison.Ordinal) && string.Equals(tag.Value?.ToString(), "semver", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Merge_RespectsConfiguredPrecedenceOverrides()
|
||||
{
|
||||
var timeProvider = new FakeTimeProvider(new DateTimeOffset(2025, 3, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
|
||||
@@ -4,11 +4,13 @@ using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class AffectedPackagePrecedenceResolverTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Merge_PrefersRedHatOverNvdForSameCpe()
|
||||
{
|
||||
var redHat = new AffectedPackage(
|
||||
@@ -64,7 +66,8 @@ public sealed class AffectedPackagePrecedenceResolverTests
|
||||
Assert.Equal(1, rangeOverride.SuppressedRangeCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Merge_KeepsNvdWhenNoHigherPrecedence()
|
||||
{
|
||||
var nvd = new AffectedPackage(
|
||||
|
||||
@@ -6,11 +6,13 @@ using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Storage.Aliases;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class AliasGraphResolverTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_ReturnsCollisions_WhenAliasesOverlap()
|
||||
{
|
||||
var aliasStore = new AliasStore();
|
||||
@@ -39,7 +41,8 @@ public sealed class AliasGraphResolverTests
|
||||
Assert.Contains("ADV-2", collision.AdvisoryKeys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task BuildComponentAsync_TracesConnectedAdvisories()
|
||||
{
|
||||
var aliasStore = new AliasStore();
|
||||
@@ -73,7 +76,8 @@ public sealed class AliasGraphResolverTests
|
||||
Assert.Contains(component.AliasMap["ADV-B"], record => record.Scheme == "OSV" && record.Value == "OSV-2025-1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task BuildComponentAsync_LinksOsvAndGhsaAliases()
|
||||
{
|
||||
var aliasStore = new AliasStore();
|
||||
|
||||
@@ -4,18 +4,21 @@ using StellaOps.Concelier.Normalization.Distro;
|
||||
using StellaOps.VersionComparison;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class ApkVersionComparerTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComparatorType_Returns_Apk()
|
||||
{
|
||||
Assert.Equal(ComparatorType.Apk, ApkVersionComparer.Instance.ComparatorType);
|
||||
}
|
||||
public static TheoryData<string, string, int, string> ComparisonCases => BuildComparisonCases();
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[MemberData(nameof(ComparisonCases))]
|
||||
public void Compare_ApkVersions_ReturnsExpectedOrder(string left, string right, int expected, string note)
|
||||
{
|
||||
@@ -23,7 +26,8 @@ public sealed class ApkVersionComparerTests
|
||||
Assert.True(expected == actual, $"[{note}] '{left}' vs '{right}': expected {expected}, got {actual}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_ParsesApkVersionComponents()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.Compare(
|
||||
@@ -84,7 +88,8 @@ public sealed class ApkVersionComparerTests
|
||||
|
||||
#region CompareWithProof Tests (SPRINT_4000_0002_0001)
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_BothNull_ReturnsEqual()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof(null, null);
|
||||
@@ -94,7 +99,8 @@ public sealed class ApkVersionComparerTests
|
||||
Assert.Contains("null", result.ProofLines[0].ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_LeftNull_ReturnsLess()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof(null, "1.0-r0");
|
||||
@@ -103,7 +109,8 @@ public sealed class ApkVersionComparerTests
|
||||
Assert.Contains("null", result.ProofLines[0].ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_RightNull_ReturnsGreater()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof("1.0-r0", null);
|
||||
@@ -112,7 +119,8 @@ public sealed class ApkVersionComparerTests
|
||||
Assert.Contains("null", result.ProofLines[0].ToLower());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_EqualVersions_ReturnsEqualWithProof()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof("1.2.3-r1", "1.2.3-r1");
|
||||
@@ -122,7 +130,8 @@ public sealed class ApkVersionComparerTests
|
||||
Assert.Contains(result.ProofLines, line => line.Contains("equal"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_VersionDifference_ReturnsProofLines()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof("1.2.3-r0", "1.2.4-r0");
|
||||
@@ -133,7 +142,8 @@ public sealed class ApkVersionComparerTests
|
||||
line.Contains("Version") || line.Contains("older") || line.Contains("<"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_PkgRelDifference_ReturnsProofWithPkgRel()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof("1.2.3-r1", "1.2.3-r2");
|
||||
@@ -142,7 +152,8 @@ public sealed class ApkVersionComparerTests
|
||||
Assert.Contains(result.ProofLines, line => line.Contains("release") || line.Contains("-r"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_ImplicitVsExplicitPkgRel_ReturnsProofExplaining()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof("1.2.3", "1.2.3-r0");
|
||||
@@ -151,7 +162,8 @@ public sealed class ApkVersionComparerTests
|
||||
Assert.Contains(result.ProofLines, line => line.Contains("implicit") || line.Contains("explicit"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_NewerVersion_ReturnsGreaterThanOrEqual()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof("1.2.4-r0", "1.2.3-r0");
|
||||
@@ -160,7 +172,8 @@ public sealed class ApkVersionComparerTests
|
||||
Assert.True(result.IsGreaterThanOrEqual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_InvalidVersions_FallsBackToStringComparison()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof("", "");
|
||||
@@ -172,7 +185,8 @@ public sealed class ApkVersionComparerTests
|
||||
line.Contains("equal", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CompareWithProof_ReturnsCorrectComparatorType()
|
||||
{
|
||||
var result = ApkVersionComparer.Instance.CompareWithProof("1.0-r0", "1.0-r1");
|
||||
|
||||
@@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using StellaOps.Concelier.Merge.Backport;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
/// <summary>
|
||||
@@ -35,7 +36,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
|
||||
#region Tier 1: DistroAdvisory Evidence
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_Tier1DistroAdvisory_ExtractsEvidence()
|
||||
{
|
||||
// Arrange
|
||||
@@ -60,7 +62,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
evidence.DistroRelease.Should().Contain("debian");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_Tier1LowConfidence_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
@@ -83,7 +86,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
|
||||
#region Tier 2: ChangelogMention Evidence
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_Tier2ChangelogMention_ExtractsEvidence()
|
||||
{
|
||||
// Arrange
|
||||
@@ -108,7 +112,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
evidence.DistroRelease.Should().Contain("redhat");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_Tier2WithUpstreamCommit_ExtractsPatchLineage()
|
||||
{
|
||||
// Arrange
|
||||
@@ -144,7 +149,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
|
||||
#region Tier 3: PatchHeader Evidence
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_Tier3PatchHeader_ExtractsEvidence()
|
||||
{
|
||||
// Arrange
|
||||
@@ -168,7 +174,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
evidence.PatchOrigin.Should().Be(PatchOrigin.Upstream);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_Tier3DistroPatch_DetectsDistroOrigin()
|
||||
{
|
||||
// Arrange
|
||||
@@ -204,7 +211,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
|
||||
#region Tier 4: BinaryFingerprint Evidence
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_Tier4BinaryFingerprint_ExtractsEvidence()
|
||||
{
|
||||
// Arrange
|
||||
@@ -230,7 +238,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
|
||||
#region Tier Priority
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_MultipleTiers_SelectsHighestTier()
|
||||
{
|
||||
// Arrange: BinaryFingerprint (Tier 4) should be selected as highest
|
||||
@@ -256,7 +265,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
evidence!.Tier.Should().Be(BackportEvidenceTier.BinaryFingerprint);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_PatchHeaderVsChangelog_PrefersPatchHeader()
|
||||
{
|
||||
// Arrange: PatchHeader (Tier 3) > ChangelogMention (Tier 2)
|
||||
@@ -286,7 +296,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
|
||||
#region Distro Release Extraction
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData("pkg:deb/debian/curl@7.64.0-4+deb11u1", "debian:bullseye")]
|
||||
[InlineData("pkg:deb/debian/openssl@3.0.11-1~deb12u2", "debian:bookworm")]
|
||||
[InlineData("pkg:rpm/redhat/nginx@1.20.1-14.el9", "redhat:9")]
|
||||
@@ -314,7 +325,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
|
||||
#region Batch Resolution
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveBatchAsync_ResolvesMultiplePackages()
|
||||
{
|
||||
// Arrange
|
||||
@@ -350,7 +362,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
|
||||
#region Edge Cases
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_NullProof_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
@@ -365,7 +378,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
evidence.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_VeryLowConfidence_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
@@ -383,7 +397,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
evidence.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task HasEvidenceAsync_ReturnsTrueWhenEvidenceExists()
|
||||
{
|
||||
// Arrange
|
||||
@@ -401,7 +416,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
hasEvidence.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task HasEvidenceAsync_ReturnsFalseWhenNoEvidence()
|
||||
{
|
||||
// Arrange
|
||||
@@ -416,7 +432,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
hasEvidence.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_ThrowsOnNullCveId()
|
||||
{
|
||||
// Act & Assert
|
||||
@@ -424,7 +441,8 @@ public sealed class BackportEvidenceResolverTests
|
||||
() => _resolver.ResolveAsync(null!, "pkg:deb/debian/test@1.0"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ResolveAsync_ThrowsOnNullPurl()
|
||||
{
|
||||
// Act & Assert
|
||||
|
||||
@@ -15,6 +15,7 @@ using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Storage.MergeEvents;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
/// <summary>
|
||||
@@ -65,7 +66,8 @@ public sealed class BackportProvenanceE2ETests
|
||||
|
||||
#region E2E: Debian Backport Advisory Flow
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task E2E_IngestDebianAdvisoryWithBackport_CreatesProvenanceScope()
|
||||
{
|
||||
// Arrange: Simulate Debian security advisory for CVE-2024-1234
|
||||
@@ -129,7 +131,8 @@ public sealed class BackportProvenanceE2ETests
|
||||
capturedScope.PatchId.Should().Be(patchCommit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task E2E_IngestRhelAdvisoryWithBackport_CreatesProvenanceScopeWithDistroOrigin()
|
||||
{
|
||||
// Arrange: Simulate RHEL security advisory with distro-specific patch
|
||||
@@ -186,7 +189,8 @@ public sealed class BackportProvenanceE2ETests
|
||||
|
||||
#region E2E: Multiple Distro Backports for Same CVE
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task E2E_SameCveMultipleDistros_CreatesSeparateProvenanceScopes()
|
||||
{
|
||||
// Arrange: Same CVE with Debian and Ubuntu backports
|
||||
@@ -239,7 +243,8 @@ public sealed class BackportProvenanceE2ETests
|
||||
|
||||
#region E2E: Merge Event with Backport Evidence
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task E2E_MergeWithBackportEvidence_RecordsInAuditLog()
|
||||
{
|
||||
// Arrange
|
||||
@@ -296,7 +301,8 @@ public sealed class BackportProvenanceE2ETests
|
||||
|
||||
#region E2E: Evidence Tier Upgrade
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task E2E_EvidenceUpgrade_UpdatesProvenanceScope()
|
||||
{
|
||||
// Arrange: Start with low-tier evidence, then upgrade
|
||||
@@ -355,7 +361,8 @@ public sealed class BackportProvenanceE2ETests
|
||||
|
||||
#region E2E: Provenance Retrieval
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task E2E_RetrieveProvenanceForCanonical_ReturnsAllDistroScopes()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Linq;
|
||||
using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class CanonicalHashCalculatorTests
|
||||
@@ -41,7 +42,8 @@ public sealed class CanonicalHashCalculatorTests
|
||||
},
|
||||
provenance: new[] { AdvisoryProvenance.Empty });
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeHash_ReturnsDeterministicValue()
|
||||
{
|
||||
var calculator = new CanonicalHashCalculator();
|
||||
@@ -51,7 +53,8 @@ public sealed class CanonicalHashCalculatorTests
|
||||
Assert.Equal(first, second);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeHash_IgnoresOrderingDifferences()
|
||||
{
|
||||
var calculator = new CanonicalHashCalculator();
|
||||
@@ -77,7 +80,8 @@ public sealed class CanonicalHashCalculatorTests
|
||||
Assert.Equal(originalHash, reorderedHash);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeHash_NullReturnsEmpty()
|
||||
{
|
||||
var calculator = new CanonicalHashCalculator();
|
||||
|
||||
@@ -3,11 +3,13 @@ using StellaOps.Concelier.Merge.Comparers;
|
||||
using StellaOps.Concelier.Normalization.Distro;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class DebianEvrComparerTests
|
||||
{
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData("1:1.2.3-1", 1, "1.2.3", "1")]
|
||||
[InlineData("1.2.3-1", 0, "1.2.3", "1")]
|
||||
[InlineData("2:4.5", 2, "4.5", "")]
|
||||
@@ -24,7 +26,8 @@ public sealed class DebianEvrComparerTests
|
||||
Assert.Equal(input, evr.Original);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData(":1.0-1")]
|
||||
[InlineData("1:")]
|
||||
@@ -36,7 +39,8 @@ public sealed class DebianEvrComparerTests
|
||||
Assert.Null(evr);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_PrefersHigherEpoch()
|
||||
{
|
||||
var lower = "0:2.0-1";
|
||||
@@ -45,7 +49,8 @@ public sealed class DebianEvrComparerTests
|
||||
Assert.True(DebianEvrComparer.Instance.Compare(higher, lower) > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_UsesVersionOrdering()
|
||||
{
|
||||
var lower = "0:1.2.3-1";
|
||||
@@ -54,7 +59,8 @@ public sealed class DebianEvrComparerTests
|
||||
Assert.True(DebianEvrComparer.Instance.Compare(higher, lower) > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_TildeRanksEarlier()
|
||||
{
|
||||
var prerelease = "0:1.0~beta1-1";
|
||||
@@ -63,7 +69,8 @@ public sealed class DebianEvrComparerTests
|
||||
Assert.True(DebianEvrComparer.Instance.Compare(prerelease, stable) < 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_RevisionBreaksTies()
|
||||
{
|
||||
var first = "0:1.0-1";
|
||||
@@ -72,7 +79,8 @@ public sealed class DebianEvrComparerTests
|
||||
Assert.True(DebianEvrComparer.Instance.Compare(second, first) > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_FallsBackToOrdinalForInvalid()
|
||||
{
|
||||
var left = "not-an-evr";
|
||||
@@ -86,7 +94,8 @@ public sealed class DebianEvrComparerTests
|
||||
|
||||
public static TheoryData<string, string, int, string> ComparisonCases => BuildComparisonCases();
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[MemberData(nameof(ComparisonCases))]
|
||||
public void Compare_DebianEvr_ReturnsExpectedOrder(string left, string right, int expected, string note)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Text;
|
||||
using StellaOps.Concelier.Merge.Comparers;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class GoldenVersionComparisonTests
|
||||
@@ -16,7 +17,8 @@ public sealed class GoldenVersionComparisonTests
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData("rpm_version_comparison.golden.ndjson", "rpm")]
|
||||
[InlineData("deb_version_comparison.golden.ndjson", "deb")]
|
||||
[InlineData("apk_version_comparison.golden.ndjson", "apk")]
|
||||
|
||||
@@ -4,11 +4,13 @@ using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Storage.MergeEvents;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class MergeEventWriterTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task AppendAsync_WritesRecordWithComputedHashes()
|
||||
{
|
||||
var store = new InMemoryMergeEventStore();
|
||||
@@ -31,7 +33,8 @@ public sealed class MergeEventWriterTests
|
||||
Assert.Same(store.LastRecord, record);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task AppendAsync_NullBeforeUsesEmptyHash()
|
||||
{
|
||||
var store = new InMemoryMergeEventStore();
|
||||
|
||||
@@ -9,6 +9,7 @@ using FluentAssertions;
|
||||
using StellaOps.Concelier.Merge.Identity;
|
||||
using StellaOps.Concelier.Merge.Identity.Normalizers;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
/// <summary>
|
||||
@@ -26,7 +27,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
|
||||
#region Same Patch Lineage = Same Hash
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_SamePatchLineage_ProducesSameHash()
|
||||
{
|
||||
// Arrange
|
||||
@@ -56,7 +58,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
hash1.Should().Be(hash2, "same patch lineage should produce same hash");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_NoPatchLineage_ProducesSameHash()
|
||||
{
|
||||
// Arrange
|
||||
@@ -90,7 +93,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
|
||||
#region Different Patch Lineage = Different Hash
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_DifferentPatchLineage_ProducesDifferentHash()
|
||||
{
|
||||
// Arrange - Upstream fix vs distro-specific backport
|
||||
@@ -121,7 +125,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
"different patch lineage should produce different hash");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_WithVsWithoutPatchLineage_ProducesDifferentHash()
|
||||
{
|
||||
// Arrange
|
||||
@@ -152,7 +157,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
"advisory with patch lineage should differ from one without");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_DebianVsRhelBackport_ProducesDifferentHash()
|
||||
{
|
||||
// Arrange - Same CVE, different distro backports
|
||||
@@ -187,7 +193,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
|
||||
#region Patch Lineage Normalization
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData(
|
||||
"abc123def456abc123def456abc123def456abcd",
|
||||
"ABC123DEF456ABC123DEF456ABC123DEF456ABCD",
|
||||
@@ -230,7 +237,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
hash1.Should().Be(hash2, reason);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_AbbreviatedSha_DiffersFromFullSha()
|
||||
{
|
||||
// Abbreviated SHA is treated as different from a full different SHA
|
||||
@@ -265,7 +273,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
|
||||
#region Real-World Scenarios
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_GoldenCorpus_DebianBackportVsNvd()
|
||||
{
|
||||
// Golden corpus test case: CVE-2024-1234 with Debian backport
|
||||
@@ -300,7 +309,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
"NVD and Debian entries should produce different hashes due to package and version differences");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_GoldenCorpus_DistroSpecificFix()
|
||||
{
|
||||
// Golden corpus test case: Distro-specific fix different from upstream
|
||||
@@ -331,7 +341,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
"distro-specific fix should produce different hash from upstream");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_SameUpstreamBackported_ProducesSameHash()
|
||||
{
|
||||
// When two distros backport the SAME upstream patch, they should merge
|
||||
@@ -367,7 +378,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
|
||||
#region Edge Cases
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_EmptyPatchLineage_TreatedAsNull()
|
||||
{
|
||||
var emptyLineage = new MergeHashInput
|
||||
@@ -397,7 +409,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
"empty and null patch lineage should produce same hash");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_WhitespacePatchLineage_TreatedAsNull()
|
||||
{
|
||||
var whitespaceLineage = new MergeHashInput
|
||||
@@ -427,7 +440,8 @@ public sealed class MergeHashBackportDifferentiationTests
|
||||
"whitespace-only patch lineage should be treated as null");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ComputeMergeHash_IsDeterministic()
|
||||
{
|
||||
// Verify determinism across multiple calls
|
||||
|
||||
@@ -7,6 +7,7 @@ using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Storage.MergeEvents;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class MergePrecedenceIntegrationTests : IAsyncLifetime
|
||||
@@ -16,7 +17,8 @@ public sealed class MergePrecedenceIntegrationTests : IAsyncLifetime
|
||||
private AdvisoryPrecedenceMerger? _merger;
|
||||
private FakeTimeProvider? _timeProvider;
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task MergePipeline_PsirtOverridesNvd_AndKevOnlyTogglesExploitKnown()
|
||||
{
|
||||
await EnsureInitializedAsync();
|
||||
|
||||
@@ -3,11 +3,13 @@ using StellaOps.Concelier.Merge.Comparers;
|
||||
using StellaOps.Concelier.Normalization.Distro;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class NevraComparerTests
|
||||
{
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData("kernel-1:4.18.0-348.7.1.el8_5.x86_64", "kernel", 1, "4.18.0", "348.7.1.el8_5", "x86_64")]
|
||||
[InlineData("bash-5.1.8-2.fc35.x86_64", "bash", 0, "5.1.8", "2.fc35", "x86_64")]
|
||||
[InlineData("openssl-libs-1:1.1.1k-7.el8", "openssl-libs", 1, "1.1.1k", "7.el8", null)]
|
||||
@@ -28,7 +30,8 @@ public sealed class NevraComparerTests
|
||||
Assert.Equal(input, nevra.Original);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("kernel4.18.0-80.el8")]
|
||||
[InlineData("kernel-4.18.0")]
|
||||
@@ -40,7 +43,8 @@ public sealed class NevraComparerTests
|
||||
Assert.Null(nevra);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void TryParse_TrimsWhitespace()
|
||||
{
|
||||
var success = Nevra.TryParse(" kernel-0:4.18.0-80.el8.x86_64 ", out var nevra);
|
||||
@@ -51,7 +55,8 @@ public sealed class NevraComparerTests
|
||||
Assert.Equal("4.18.0", nevra.Version);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_PrefersHigherEpoch()
|
||||
{
|
||||
var older = "kernel-0:4.18.0-348.7.1.el8_5.x86_64";
|
||||
@@ -61,7 +66,8 @@ public sealed class NevraComparerTests
|
||||
Assert.True(NevraComparer.Instance.Compare(older, newer) < 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_UsesRpmVersionOrdering()
|
||||
{
|
||||
var lower = "kernel-0:4.18.0-80.el8.x86_64";
|
||||
@@ -70,7 +76,8 @@ public sealed class NevraComparerTests
|
||||
Assert.True(NevraComparer.Instance.Compare(higher, lower) > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_UsesReleaseOrdering()
|
||||
{
|
||||
var el8 = "bash-0:5.1.0-1.el8.x86_64";
|
||||
@@ -79,7 +86,8 @@ public sealed class NevraComparerTests
|
||||
Assert.True(NevraComparer.Instance.Compare(el9, el8) > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_TildeRanksEarlier()
|
||||
{
|
||||
var prerelease = "bash-0:5.1.0~beta-1.fc34.x86_64";
|
||||
@@ -88,7 +96,8 @@ public sealed class NevraComparerTests
|
||||
Assert.True(NevraComparer.Instance.Compare(prerelease, stable) < 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_ConsidersArchitecture()
|
||||
{
|
||||
var noarch = "pkg-0:1.0-1.noarch";
|
||||
@@ -97,7 +106,8 @@ public sealed class NevraComparerTests
|
||||
Assert.True(NevraComparer.Instance.Compare(noarch, arch) < 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_FallsBackToOrdinalForInvalid()
|
||||
{
|
||||
var left = "not-a-nevra";
|
||||
@@ -110,7 +120,8 @@ public sealed class NevraComparerTests
|
||||
|
||||
public static TheoryData<string, string, int, string> ComparisonCases => BuildComparisonCases();
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[MemberData(nameof(ComparisonCases))]
|
||||
public void Compare_NevraVersions_ReturnsExpectedOrder(string left, string right, int expected, string note)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using StellaOps.Concelier.Merge.Backport;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
/// <summary>
|
||||
@@ -34,7 +35,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
|
||||
#region CreateOrUpdateAsync Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task CreateOrUpdateAsync_NewScope_CreatesProvenanceScope()
|
||||
{
|
||||
// Arrange
|
||||
@@ -74,7 +76,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task CreateOrUpdateAsync_ExistingScope_UpdatesProvenanceScope()
|
||||
{
|
||||
// Arrange
|
||||
@@ -117,7 +120,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
result.ProvenanceScopeId.Should().Be(existingScopeId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task CreateOrUpdateAsync_WithEvidenceResolver_ResolvesEvidence()
|
||||
{
|
||||
// Arrange
|
||||
@@ -171,7 +175,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task CreateOrUpdateAsync_NonDistroSource_StillCreatesScope()
|
||||
{
|
||||
// Arrange
|
||||
@@ -204,7 +209,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
|
||||
#region UpdateFromEvidenceAsync Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task UpdateFromEvidenceAsync_NewEvidence_CreatesScope()
|
||||
{
|
||||
// Arrange
|
||||
@@ -246,7 +252,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task UpdateFromEvidenceAsync_BetterEvidence_UpdatesScope()
|
||||
{
|
||||
// Arrange
|
||||
@@ -300,7 +307,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task UpdateFromEvidenceAsync_LowerConfidenceEvidence_SkipsUpdate()
|
||||
{
|
||||
// Arrange
|
||||
@@ -352,7 +360,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
|
||||
#region LinkEvidenceRefAsync Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task LinkEvidenceRefAsync_LinksEvidenceToScope()
|
||||
{
|
||||
// Arrange
|
||||
@@ -374,7 +383,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
|
||||
#region GetByCanonicalIdAsync Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task GetByCanonicalIdAsync_ReturnsAllScopes()
|
||||
{
|
||||
// Arrange
|
||||
@@ -418,7 +428,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
|
||||
#region DeleteByCanonicalIdAsync Tests
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DeleteByCanonicalIdAsync_DeletesAllScopes()
|
||||
{
|
||||
// Arrange
|
||||
@@ -439,7 +450,8 @@ public sealed class ProvenanceScopeLifecycleTests
|
||||
|
||||
#region Distro Release Extraction Tests
|
||||
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData("pkg:deb/debian/curl@7.64.0-4+deb11u1", "debian", "debian:bullseye")]
|
||||
[InlineData("pkg:deb/debian/openssl@3.0.11-1~deb12u2", "debian", "debian:bookworm")]
|
||||
[InlineData("pkg:rpm/redhat/nginx@1.20.1-14.el9", "redhat", "redhat:9")]
|
||||
|
||||
@@ -2,11 +2,13 @@ using FluentAssertions;
|
||||
using StellaOps.Concelier.Merge.Comparers;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class SemanticVersionRangeResolverTests
|
||||
{
|
||||
[Theory]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Theory]
|
||||
[InlineData("1.2.3", true)]
|
||||
[InlineData("1.2.3-beta.1", true)]
|
||||
[InlineData("invalid", false)]
|
||||
@@ -19,14 +21,16 @@ public sealed class SemanticVersionRangeResolverTests
|
||||
Assert.Equal(expected, version is not null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_ParsesSemanticVersions()
|
||||
{
|
||||
Assert.True(SemanticVersionRangeResolver.Compare("1.2.3", "1.2.2") > 0);
|
||||
Assert.True(SemanticVersionRangeResolver.Compare("1.2.3-beta", "1.2.3") < 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Compare_UsesOrdinalFallbackForInvalid()
|
||||
{
|
||||
var left = "zzz";
|
||||
@@ -37,7 +41,8 @@ public sealed class SemanticVersionRangeResolverTests
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveWindows_WithFixedVersion_ComputesExclusiveUpper()
|
||||
{
|
||||
var (introduced, exclusive, inclusive) = SemanticVersionRangeResolver.ResolveWindows("1.0.0", "1.2.0", null);
|
||||
@@ -47,7 +52,8 @@ public sealed class SemanticVersionRangeResolverTests
|
||||
Assert.Null(inclusive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveWindows_WithLastAffectedOnly_ComputesInclusiveAndExclusive()
|
||||
{
|
||||
var (introduced, exclusive, inclusive) = SemanticVersionRangeResolver.ResolveWindows("1.0.0", null, "1.1.5");
|
||||
@@ -57,7 +63,8 @@ public sealed class SemanticVersionRangeResolverTests
|
||||
Assert.Equal(SemanticVersionRangeResolver.Parse("1.1.5"), inclusive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void ResolveWindows_WithNeither_ReturnsNullBounds()
|
||||
{
|
||||
var (introduced, exclusive, inclusive) = SemanticVersionRangeResolver.ResolveWindows(null, null, null);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Concelier.Normalization/StellaOps.Concelier.Normalization.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Canonical.Json/StellaOps.Canonical.Json.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
|
||||
Reference in New Issue
Block a user