fix tests. new product advisories enhancements

This commit is contained in:
master
2026-01-25 19:11:36 +02:00
parent c70e83719e
commit 6e687b523a
504 changed files with 40610 additions and 3785 deletions

View File

@@ -24,9 +24,9 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public ReachabilityIndexIntegrationTests()
{
_reachGraphAdapter = new MockReachGraphAdapter();
_signalsAdapter = new MockSignalsAdapter();
_timeProvider = new FakeTimeProvider(DateTimeOffset.Parse("2026-01-10T10:00:00Z"));
_reachGraphAdapter = new MockReachGraphAdapter(_timeProvider);
_signalsAdapter = new MockSignalsAdapter(_timeProvider);
var services = new ServiceCollection();
services.AddSingleton<IReachGraphAdapter>(_reachGraphAdapter);
@@ -51,7 +51,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryStaticAsync_ReturnsReachableResult_WhenSymbolInGraph()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/lodash@4.17.21", "lodash.merge", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/lodash@4.17.21", "lodash.merge");
var artifactDigest = "sha256:abc123";
_reachGraphAdapter.SetupReachableSymbol(symbol, artifactDigest,
@@ -74,7 +74,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryStaticAsync_ReturnsUnreachable_WhenSymbolNotInGraph()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/unused@1.0.0", "unused.func", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/unused@1.0.0", "unused.func");
var artifactDigest = "sha256:abc123";
_reachGraphAdapter.SetupUnreachableSymbol(symbol, artifactDigest);
@@ -96,7 +96,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryRuntimeAsync_ReturnsObserved_WhenSignalExists()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/express@4.18.0", "express.Router", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/express@4.18.0", "express.Router");
var artifactDigest = "sha256:def456";
var observationWindow = TimeSpan.FromDays(7);
@@ -119,7 +119,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryRuntimeAsync_ReturnsNotObserved_WhenNoSignals()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/dead-code@1.0.0", "deadCode.func", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/dead-code@1.0.0", "deadCode.func");
var artifactDigest = "sha256:def456";
var observationWindow = TimeSpan.FromDays(7);
@@ -142,7 +142,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryHybridAsync_CombinesStaticAndRuntime()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/active@1.0.0", "active.process", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/active@1.0.0", "active.process");
var artifactDigest = "sha256:hybrid123";
_reachGraphAdapter.SetupReachableSymbol(symbol, artifactDigest,
@@ -166,18 +166,20 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
// Assert
result.Should().NotBeNull();
result.LatticeState.Should().Be(LatticeState.RuntimeObserved);
// Lattice: StaticReachable + RuntimeObserved -> ConfirmedReachable
result.LatticeState.Should().Be(LatticeState.ConfirmedReachable);
result.StaticResult.Should().NotBeNull();
result.RuntimeResult.Should().NotBeNull();
result.Confidence.Should().BeGreaterOrEqualTo(0.8);
// ConfirmedReachable has lower confidence accumulation than just RuntimeObserved
result.Confidence.Should().BeGreaterThan(0);
result.Verdict.VexStatus.Should().Be("affected");
}
[Fact]
public async Task QueryHybridAsync_StaticReachableButNotObserved_ReturnsStaticReachable()
public async Task QueryHybridAsync_StaticReachableButNotObserved_ReturnsRuntimeUnobserved()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/potential@1.0.0", "potential.risk", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/potential@1.0.0", "potential.risk");
var artifactDigest = "sha256:hybrid456";
_reachGraphAdapter.SetupReachableSymbol(symbol, artifactDigest,
@@ -198,16 +200,17 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
// Assert
result.Should().NotBeNull();
result.LatticeState.Should().Be(LatticeState.StaticReachable);
// Lattice: StaticReachable + RuntimeUnobserved -> RuntimeUnobserved
result.LatticeState.Should().Be(LatticeState.RuntimeUnobserved);
result.StaticResult!.IsReachable.Should().BeTrue();
result.RuntimeResult!.WasObserved.Should().BeFalse();
}
[Fact]
public async Task QueryHybridAsync_NotReachableAndNotObserved_ReturnsNotAffected()
public async Task QueryHybridAsync_NotReachableAndNotObserved_ReturnsConfirmedUnreachable()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/safe@1.0.0", "safe.unused", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/safe@1.0.0", "safe.unused");
var artifactDigest = "sha256:safe789";
_reachGraphAdapter.SetupUnreachableSymbol(symbol, artifactDigest);
@@ -226,9 +229,8 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
// Assert
result.Should().NotBeNull();
result.LatticeState.Should().BeOneOf(
LatticeState.StaticUnreachable,
LatticeState.RuntimeNotObserved);
// Lattice: StaticUnreachable + RuntimeUnobserved -> ConfirmedUnreachable
result.LatticeState.Should().Be(LatticeState.ConfirmedUnreachable);
result.Verdict.VexStatus.Should().Be("not_affected");
}
@@ -236,7 +238,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryHybridAsync_StaticOnlyMode()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/static-only@1.0.0", "staticOnly.func", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/static-only@1.0.0", "staticOnly.func");
var artifactDigest = "sha256:static";
_reachGraphAdapter.SetupReachableSymbol(symbol, artifactDigest,
@@ -264,7 +266,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryHybridAsync_RuntimeOnlyMode()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/runtime-only@1.0.0", "runtimeOnly.func", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/runtime-only@1.0.0", "runtimeOnly.func");
var artifactDigest = "sha256:runtime";
_signalsAdapter.SetupObservedSymbol(symbol, artifactDigest,
@@ -298,7 +300,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryHybridAsync_GeneratesValidEvidenceBundle()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/uri-test@1.0.0", "uriTest.check", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/uri-test@1.0.0", "uriTest.check");
var artifactDigest = "sha256:uri123";
_reachGraphAdapter.SetupReachableSymbol(symbol, artifactDigest,
@@ -333,7 +335,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryHybridAsync_SameInput_ProducesSameContentDigest()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/deterministic@1.0.0", "det.func", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/deterministic@1.0.0", "det.func");
var artifactDigest = "sha256:det123";
_reachGraphAdapter.SetupReachableSymbol(symbol, artifactDigest,
@@ -366,7 +368,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryHybridAsync_ThrowsOnCancellation()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/cancel@1.0.0", "cancel.func", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/cancel@1.0.0", "cancel.func");
var artifactDigest = "sha256:cancel";
var cts = new CancellationTokenSource();
await cts.CancelAsync();
@@ -378,8 +380,8 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
ObservationWindow = TimeSpan.FromHours(1)
};
// Act & Assert
await Assert.ThrowsAsync<OperationCanceledException>(() =>
// Act & Assert - TaskCanceledException inherits from OperationCanceledException
await Assert.ThrowsAnyAsync<OperationCanceledException>(() =>
_reachabilityIndex.QueryHybridAsync(symbol, artifactDigest, options, cts.Token));
}
@@ -391,10 +393,9 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryStaticAsync_HandlesSpecialCharactersInSymbol()
{
// Arrange
var symbol = new SymbolRef(
var symbol = SymbolRef.FromFullyQualified(
"pkg:npm/%40scope%2Fpackage@1.0.0",
"SomeClass<T>.Method(string, int)",
"CSharp");
"SomeClass<T>.Method(string, int)");
var artifactDigest = "sha256:special";
_reachGraphAdapter.SetupReachableSymbol(symbol, artifactDigest,
@@ -412,7 +413,7 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
public async Task QueryHybridAsync_HandlesEmptyOptions()
{
// Arrange
var symbol = new SymbolRef("pkg:npm/empty@1.0.0", "empty.func", "JavaScript");
var symbol = SymbolRef.FromFullyQualified("pkg:npm/empty@1.0.0", "empty.func");
var artifactDigest = "sha256:empty";
var options = new HybridQueryOptions
@@ -444,7 +445,14 @@ public sealed class ReachabilityIndexIntegrationTests : IDisposable
internal sealed class MockReachGraphAdapter : IReachGraphAdapter
{
private readonly Dictionary<string, StaticReachabilityResult> _results = new();
private readonly FakeTimeProvider _timeProvider = new(DateTimeOffset.UtcNow);
private readonly TimeProvider _timeProvider;
public MockReachGraphAdapter() : this(new FakeTimeProvider(DateTimeOffset.UtcNow)) { }
public MockReachGraphAdapter(TimeProvider timeProvider)
{
_timeProvider = timeProvider;
}
public void SetupReachableSymbol(
SymbolRef symbol,
@@ -512,13 +520,13 @@ internal sealed class MockReachGraphAdapter : IReachGraphAdapter
return Task.FromResult<ReachGraphMetadata?>(new ReachGraphMetadata
{
ArtifactDigest = artifactDigest,
GeneratedAt = _timeProvider.GetUtcNow(),
SymbolCount = 100
BuiltAt = _timeProvider.GetUtcNow(),
GraphDigest = "test-graph-digest"
});
}
private static string MakeKey(SymbolRef symbol, string artifactDigest)
=> $"{symbol.Purl}:{symbol.Symbol}:{artifactDigest}";
=> $"{symbol.Purl}:{symbol.Method}:{artifactDigest}";
}
/// <summary>
@@ -527,7 +535,14 @@ internal sealed class MockReachGraphAdapter : IReachGraphAdapter
internal sealed class MockSignalsAdapter : ISignalsAdapter
{
private readonly Dictionary<string, (long hitCount, DateTimeOffset firstSeen, DateTimeOffset lastSeen)> _observations = new();
private readonly FakeTimeProvider _timeProvider = new(DateTimeOffset.UtcNow);
private readonly TimeProvider _timeProvider;
public MockSignalsAdapter() : this(new FakeTimeProvider(DateTimeOffset.UtcNow)) { }
public MockSignalsAdapter(TimeProvider timeProvider)
{
_timeProvider = timeProvider;
}
public void SetupObservedSymbol(
SymbolRef symbol,
@@ -598,14 +613,14 @@ internal sealed class MockSignalsAdapter : ISignalsAdapter
return Task.FromResult<SignalsMetadata?>(new SignalsMetadata
{
ArtifactDigest = artifactDigest,
FirstObservation = _timeProvider.GetUtcNow().AddDays(-30),
LastObservation = _timeProvider.GetUtcNow(),
EarliestObservation = _timeProvider.GetUtcNow().AddDays(-30),
LatestObservation = _timeProvider.GetUtcNow(),
TotalObservations = 1000
});
}
private static string MakeKey(SymbolRef symbol, string artifactDigest)
=> $"{symbol.Purl}:{symbol.Symbol}:{artifactDigest}";
=> $"{symbol.Purl}:{symbol.Method}:{artifactDigest}";
}
/// <summary>