Add tests for SBOM generation determinism across multiple formats
- Created `StellaOps.TestKit.Tests` project for unit tests related to determinism. - Implemented `DeterminismManifestTests` to validate deterministic output for canonical bytes and strings, file read/write operations, and error handling for invalid schema versions. - Added `SbomDeterminismTests` to ensure identical inputs produce consistent SBOMs across SPDX 3.0.1 and CycloneDX 1.6/1.7 formats, including parallel execution tests. - Updated project references in `StellaOps.Integration.Determinism` to include the new determinism testing library.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Connector.Common.Cursors;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Ghsa.Internal;
|
||||
@@ -36,15 +37,8 @@ internal sealed record GhsaCursor(
|
||||
document["lastUpdatedExclusive"] = LastUpdatedExclusive.Value.UtcDateTime;
|
||||
}
|
||||
|
||||
if (CurrentWindowStart.HasValue)
|
||||
{
|
||||
document["currentWindowStart"] = CurrentWindowStart.Value.UtcDateTime;
|
||||
}
|
||||
|
||||
if (CurrentWindowEnd.HasValue)
|
||||
{
|
||||
document["currentWindowEnd"] = CurrentWindowEnd.Value.UtcDateTime;
|
||||
}
|
||||
new TimeWindowCursorState(CurrentWindowStart, CurrentWindowEnd)
|
||||
.WriteTo(document, startField: "currentWindowStart", endField: "currentWindowEnd");
|
||||
|
||||
return document;
|
||||
}
|
||||
@@ -59,12 +53,7 @@ internal sealed record GhsaCursor(
|
||||
var lastUpdatedExclusive = document.TryGetValue("lastUpdatedExclusive", out var lastUpdated)
|
||||
? ParseDate(lastUpdated)
|
||||
: null;
|
||||
var windowStart = document.TryGetValue("currentWindowStart", out var windowStartValue)
|
||||
? ParseDate(windowStartValue)
|
||||
: null;
|
||||
var windowEnd = document.TryGetValue("currentWindowEnd", out var windowEndValue)
|
||||
? ParseDate(windowEndValue)
|
||||
: null;
|
||||
var window = TimeWindowCursorState.FromDocumentObject(document, startField: "currentWindowStart", endField: "currentWindowEnd");
|
||||
var nextPage = document.TryGetValue("nextPage", out var nextPageValue) && nextPageValue.IsInt32
|
||||
? Math.Max(1, nextPageValue.AsInt32)
|
||||
: 1;
|
||||
@@ -74,8 +63,8 @@ internal sealed record GhsaCursor(
|
||||
|
||||
return new GhsaCursor(
|
||||
lastUpdatedExclusive,
|
||||
windowStart,
|
||||
windowEnd,
|
||||
window.LastWindowStart,
|
||||
window.LastWindowEnd,
|
||||
nextPage,
|
||||
pendingDocuments,
|
||||
pendingMappings);
|
||||
|
||||
@@ -157,6 +157,42 @@ public sealed class GhsaConnectorTests : IAsyncLifetime
|
||||
Assert.Empty(pendingMappings.AsDocumentArray);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FetchAsync_ResumesFromPersistedCursorWindow()
|
||||
{
|
||||
var initialTime = new DateTimeOffset(2024, 10, 7, 0, 0, 0, TimeSpan.Zero);
|
||||
await EnsureHarnessAsync(initialTime);
|
||||
var harness = _harness!;
|
||||
|
||||
var since = initialTime - TimeSpan.FromDays(8);
|
||||
var until = initialTime - TimeSpan.FromDays(7);
|
||||
|
||||
var stateRepository = harness.ServiceProvider.GetRequiredService<ISourceStateRepository>();
|
||||
await stateRepository.UpdateCursorAsync(
|
||||
GhsaConnectorPlugin.SourceName,
|
||||
new DocumentObject
|
||||
{
|
||||
["currentWindowStart"] = since.UtcDateTime,
|
||||
["currentWindowEnd"] = until.UtcDateTime,
|
||||
["nextPage"] = 2,
|
||||
["pendingDocuments"] = new DocumentArray(),
|
||||
["pendingMappings"] = new DocumentArray(),
|
||||
},
|
||||
initialTime,
|
||||
CancellationToken.None);
|
||||
|
||||
var listUri = new Uri($"https://ghsa.test/security/advisories?updated_since={Uri.EscapeDataString(since.ToString("O"))}&updated_until={Uri.EscapeDataString(until.ToString("O"))}&page=2&per_page=5");
|
||||
harness.Handler.AddJsonResponse(listUri, """{"advisories":[],"pagination":{"page":2,"has_next_page":false}}""");
|
||||
harness.Handler.SetFallback(_ => new HttpResponseMessage(HttpStatusCode.NotFound));
|
||||
|
||||
var connector = new GhsaConnectorPlugin().Create(harness.ServiceProvider);
|
||||
await connector.FetchAsync(harness.ServiceProvider, CancellationToken.None);
|
||||
|
||||
var request = Assert.Single(harness.Handler.Requests);
|
||||
Assert.Equal(listUri, request.Uri);
|
||||
harness.Handler.AssertNoPendingResponses();
|
||||
}
|
||||
|
||||
private async Task EnsureHarnessAsync(DateTimeOffset initialTime)
|
||||
{
|
||||
if (_harness is not null)
|
||||
|
||||
Reference in New Issue
Block a user