Refactor code structure and optimize performance across multiple modules

This commit is contained in:
StellaOps Bot
2025-12-26 20:03:22 +02:00
parent c786faae84
commit b4fc66feb6
3353 changed files with 88254 additions and 1590657 deletions

View File

@@ -12,6 +12,7 @@ using StellaOps.Concelier.Core.Canonical;
using StellaOps.Concelier.SbomIntegration.Models;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Concelier.SbomIntegration.Tests;
public class SbomAdvisoryMatcherTests
@@ -29,7 +30,8 @@ public class SbomAdvisoryMatcherTests
#region Basic Matching Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_WithVulnerablePurl_ReturnsMatch()
{
// Arrange
@@ -55,7 +57,8 @@ public class SbomAdvisoryMatcherTests
result[0].Method.Should().Be(MatchMethod.ExactPurl);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_WithMultipleVulnerablePurls_ReturnsAllMatches()
{
// Arrange
@@ -88,7 +91,8 @@ public class SbomAdvisoryMatcherTests
result.Should().Contain(m => m.CanonicalId == canonicalId2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_WithSafePurl_ReturnsNoMatches()
{
// Arrange
@@ -106,7 +110,8 @@ public class SbomAdvisoryMatcherTests
result.Should().BeEmpty();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_PurlAffectedByMultipleAdvisories_ReturnsMultipleMatches()
{
// Arrange
@@ -135,7 +140,8 @@ public class SbomAdvisoryMatcherTests
#region Reachability Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_WithReachabilityMap_SetsIsReachable()
{
// Arrange
@@ -161,7 +167,8 @@ public class SbomAdvisoryMatcherTests
result[0].IsReachable.Should().BeTrue();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_WithDeploymentMap_SetsIsDeployed()
{
// Arrange
@@ -187,7 +194,8 @@ public class SbomAdvisoryMatcherTests
result[0].IsDeployed.Should().BeTrue();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_PurlNotInReachabilityMap_DefaultsToFalse()
{
// Arrange
@@ -216,7 +224,8 @@ public class SbomAdvisoryMatcherTests
#region Ecosystem Coverage Tests
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("pkg:npm/lodash@4.17.20", "npm")]
[InlineData("pkg:pypi/requests@2.27.0", "pypi")]
[InlineData("pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1", "maven")]
@@ -244,7 +253,8 @@ public class SbomAdvisoryMatcherTests
result[0].Purl.Should().Be(purl);
}
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("pkg:deb/debian/openssl@1.1.1n-0+deb11u3")]
[InlineData("pkg:rpm/fedora/kernel@5.19.0-43.fc37")]
[InlineData("pkg:apk/alpine/openssl@1.1.1q-r0")]
@@ -271,7 +281,8 @@ public class SbomAdvisoryMatcherTests
#region Edge Cases
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_EmptyPurlList_ReturnsEmpty()
{
// Arrange
@@ -284,7 +295,8 @@ public class SbomAdvisoryMatcherTests
result.Should().BeEmpty();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_ServiceThrowsException_LogsAndContinues()
{
// Arrange
@@ -314,7 +326,8 @@ public class SbomAdvisoryMatcherTests
result[0].Purl.Should().Be("pkg:npm/succeeding@1.0.0");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_LargePurlList_ProcessesEfficiently()
{
// Arrange
@@ -337,7 +350,8 @@ public class SbomAdvisoryMatcherTests
sw.ElapsedMilliseconds.Should().BeLessThan(5000); // Reasonable timeout
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task MatchAsync_SetsMatchedAtTimestamp()
{
// Arrange
@@ -365,7 +379,8 @@ public class SbomAdvisoryMatcherTests
#region FindAffectingCanonicalIdsAsync Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FindAffectingCanonicalIdsAsync_ReturnsDistinctIds()
{
// Arrange
@@ -389,7 +404,8 @@ public class SbomAdvisoryMatcherTests
result.Should().Contain(canonicalId2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task FindAffectingCanonicalIdsAsync_EmptyPurl_ReturnsEmpty()
{
// Act
@@ -403,7 +419,8 @@ public class SbomAdvisoryMatcherTests
#region CheckMatchAsync Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckMatchAsync_AffectedPurl_ReturnsMatch()
{
// Arrange
@@ -425,7 +442,8 @@ public class SbomAdvisoryMatcherTests
result.Purl.Should().Be(purl);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckMatchAsync_AdvisoryNotFound_ReturnsNull()
{
// Arrange
@@ -442,7 +460,8 @@ public class SbomAdvisoryMatcherTests
result.Should().BeNull();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CheckMatchAsync_EmptyPurl_ReturnsNull()
{
// Arrange

View File

@@ -14,6 +14,8 @@ using StellaOps.Concelier.SbomIntegration.Models;
using StellaOps.Concelier.SbomIntegration.Parsing;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Concelier.SbomIntegration.Tests;
public class SbomParserTests
@@ -28,7 +30,8 @@ public class SbomParserTests
#region CycloneDX Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_CycloneDX_ExtractsPurls()
{
// Arrange
@@ -75,7 +78,8 @@ public class SbomParserTests
result.Purls.Should().Contain("pkg:npm/express@4.18.2");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_CycloneDX_HandlesNestedComponents()
{
// Arrange
@@ -112,7 +116,8 @@ public class SbomParserTests
result.Purls.Should().Contain("pkg:npm/child@2.0.0");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_CycloneDX_SkipsComponentsWithoutPurl()
{
// Arrange
@@ -148,7 +153,8 @@ public class SbomParserTests
result.UnresolvedComponents[0].Name.Should().Be("without-purl");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_CycloneDX_DeduplicatesPurls()
{
// Arrange
@@ -178,7 +184,8 @@ public class SbomParserTests
result.Purls.Should().HaveCount(1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_CycloneDX17_ExtractsPurls()
{
// Arrange - CycloneDX 1.7 format
@@ -220,7 +227,8 @@ public class SbomParserTests
#region SPDX Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_SPDX_ExtractsPurls()
{
// Arrange
@@ -269,7 +277,8 @@ public class SbomParserTests
result.Purls.Should().Contain("pkg:npm/express@4.18.2");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_SPDX_IgnoresNonPurlExternalRefs()
{
// Arrange
@@ -313,7 +322,8 @@ public class SbomParserTests
#region Format Detection Tests
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("1.4")]
[InlineData("1.5")]
[InlineData("1.6")]
@@ -340,7 +350,8 @@ public class SbomParserTests
result.SpecVersion.Should().Be(specVersion);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DetectFormatAsync_SPDX2_DetectsFormat()
{
// Arrange
@@ -362,7 +373,8 @@ public class SbomParserTests
result.SpecVersion.Should().Be("SPDX-2.3");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DetectFormatAsync_UnknownFormat_ReturnsNotDetected()
{
// Arrange
@@ -381,7 +393,8 @@ public class SbomParserTests
result.IsDetected.Should().BeFalse();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DetectFormatAsync_InvalidJson_ReturnsNotDetected()
{
// Arrange
@@ -400,7 +413,8 @@ public class SbomParserTests
#region PURL Ecosystem Tests
[Theory]
[Trait("Category", TestCategories.Unit)]
[Theory]
[InlineData("pkg:npm/lodash@4.17.21")]
[InlineData("pkg:pypi/requests@2.28.0")]
[InlineData("pkg:maven/org.apache.commons/commons-lang3@3.12.0")]
@@ -440,7 +454,8 @@ public class SbomParserTests
#region Edge Cases
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_EmptyComponents_ReturnsEmptyPurls()
{
// Arrange
@@ -462,7 +477,8 @@ public class SbomParserTests
result.TotalComponents.Should().Be(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_NullStream_ThrowsArgumentNullException()
{
// Act & Assert
@@ -470,7 +486,8 @@ public class SbomParserTests
_parser.ParseAsync(null!, SbomFormat.CycloneDX));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ParseAsync_ExtractsCpes()
{
// Arrange

View File

@@ -15,6 +15,7 @@ using StellaOps.Messaging;
using StellaOps.Messaging.Abstractions;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Concelier.SbomIntegration.Tests;
public class SbomRegistryServiceTests
@@ -44,7 +45,8 @@ public class SbomRegistryServiceTests
#region RegisterSbomAsync Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RegisterSbomAsync_NewSbom_CreatesRegistration()
{
// Arrange
@@ -84,7 +86,8 @@ public class SbomRegistryServiceTests
_repositoryMock.Verify(r => r.SaveAsync(It.IsAny<SbomRegistration>(), It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RegisterSbomAsync_ExistingSbom_ReturnsExisting()
{
// Arrange
@@ -122,7 +125,8 @@ public class SbomRegistryServiceTests
_repositoryMock.Verify(r => r.SaveAsync(It.IsAny<SbomRegistration>(), It.IsAny<CancellationToken>()), Times.Never);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RegisterSbomAsync_NullInput_ThrowsArgumentNullException()
{
// Act & Assert
@@ -134,7 +138,8 @@ public class SbomRegistryServiceTests
#region LearnSbomAsync Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbomAsync_MatchesAndUpdatesScores()
{
// Arrange
@@ -223,7 +228,8 @@ public class SbomRegistryServiceTests
Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbomAsync_NoMatches_ReturnsEmptyMatches()
{
// Arrange
@@ -258,7 +264,8 @@ public class SbomRegistryServiceTests
result.ScoresUpdated.Should().Be(0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbomAsync_EmitsEvent()
{
// Arrange
@@ -303,7 +310,8 @@ public class SbomRegistryServiceTests
#region RematchSbomAsync Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RematchSbomAsync_ExistingSbom_RematcesSuccessfully()
{
// Arrange
@@ -368,7 +376,8 @@ public class SbomRegistryServiceTests
Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RematchSbomAsync_NonExistentSbom_ThrowsInvalidOperation()
{
// Arrange
@@ -385,7 +394,8 @@ public class SbomRegistryServiceTests
#region UpdateSbomDeltaAsync Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task UpdateSbomDeltaAsync_AddsPurls()
{
// Arrange
@@ -441,7 +451,8 @@ public class SbomRegistryServiceTests
Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task UpdateSbomDeltaAsync_NonExistentSbom_ThrowsInvalidOperation()
{
// Arrange
@@ -460,7 +471,8 @@ public class SbomRegistryServiceTests
#region UnregisterAsync Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task UnregisterAsync_ExistingSbom_DeletesRegistrationAndMatches()
{
// Arrange

View File

@@ -16,6 +16,7 @@ using StellaOps.Concelier.SbomIntegration.Models;
using StellaOps.Messaging.Abstractions;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Concelier.SbomIntegration.Tests;
/// <summary>
@@ -43,7 +44,8 @@ public class SbomScoreIntegrationTests
#region SBOM Score Update Flow Tests (Task 17)
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbom_WithMatches_UpdatesInterestScores()
{
// Arrange
@@ -99,7 +101,8 @@ public class SbomScoreIntegrationTests
Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbom_MultipleMatchesSameCanonical_UpdatesScoreOnce()
{
// Arrange
@@ -156,7 +159,8 @@ public class SbomScoreIntegrationTests
Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbom_NoMatches_NoScoreUpdates()
{
// Arrange
@@ -210,7 +214,8 @@ public class SbomScoreIntegrationTests
Times.Never);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbom_ScoringServiceFails_ContinuesWithOtherMatches()
{
// Arrange
@@ -289,7 +294,8 @@ public class SbomScoreIntegrationTests
#region Reachability-Aware Scoring Tests (Task 21)
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbom_WithReachability_PassesReachabilityToScoring()
{
// Arrange
@@ -348,7 +354,8 @@ public class SbomScoreIntegrationTests
Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbom_WithDeployment_PassesDeploymentToScoring()
{
// Arrange
@@ -407,7 +414,8 @@ public class SbomScoreIntegrationTests
Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbom_FullReachabilityChain_PassesBothFlags()
{
// Arrange
@@ -471,7 +479,8 @@ public class SbomScoreIntegrationTests
Times.Once);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task LearnSbom_MixedReachability_CorrectFlagsPerMatch()
{
// Arrange
@@ -545,7 +554,8 @@ public class SbomScoreIntegrationTests
#region Score Calculation Verification
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void InterestScoreCalculator_WithSbomMatch_AddsSbomFactor()
{
// Arrange
@@ -572,7 +582,8 @@ public class SbomScoreIntegrationTests
result.Score.Should().BeGreaterThan(0.30); // in_sbom weight + no_vex_na
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void InterestScoreCalculator_WithReachableMatch_AddsReachableFactor()
{
// Arrange
@@ -601,7 +612,8 @@ public class SbomScoreIntegrationTests
result.Score.Should().BeGreaterThan(0.55); // in_sbom + reachable + no_vex_na
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void InterestScoreCalculator_WithDeployedMatch_AddsDeployedFactor()
{
// Arrange
@@ -630,7 +642,8 @@ public class SbomScoreIntegrationTests
result.Score.Should().BeGreaterThan(0.50); // in_sbom + deployed + no_vex_na
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void InterestScoreCalculator_FullReachabilityChain_MaximizesScore()
{
// Arrange

View File

@@ -27,6 +27,7 @@
<ProjectReference Include="..\..\__Libraries\StellaOps.Concelier.SbomIntegration\StellaOps.Concelier.SbomIntegration.csproj" />
<ProjectReference Include="..\..\__Libraries\StellaOps.Concelier.Interest\StellaOps.Concelier.Interest.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Messaging\StellaOps.Messaging.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
</ItemGroup>
</Project>