Add unit tests for SBOM ingestion and transformation
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Implement `SbomIngestServiceCollectionExtensionsTests` to verify the SBOM ingestion pipeline exports snapshots correctly.
- Create `SbomIngestTransformerTests` to ensure the transformation produces expected nodes and edges, including deduplication of license nodes and normalization of timestamps.
- Add `SbomSnapshotExporterTests` to test the export functionality for manifest, adjacency, nodes, and edges.
- Introduce `VexOverlayTransformerTests` to validate the transformation of VEX nodes and edges.
- Set up project file for the test project with necessary dependencies and configurations.
- Include JSON fixture files for testing purposes.
This commit is contained in:
master
2025-11-04 07:49:39 +02:00
parent f72c5c513a
commit 2eb6852d34
491 changed files with 39445 additions and 3917 deletions

View File

@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using FluentAssertions;
using StellaOps.Graph.Indexer.Ingestion.Advisory;
using Xunit;
using Xunit.Abstractions;
namespace StellaOps.Graph.Indexer.Tests;
public sealed class AdvisoryLinksetTransformerTests
{
private readonly ITestOutputHelper _output;
public AdvisoryLinksetTransformerTests(ITestOutputHelper output)
{
_output = output;
}
private static readonly string FixturesRoot =
Path.Combine(AppContext.BaseDirectory, "Fixtures", "v1");
private static readonly HashSet<string> ExpectedNodeKinds = new(StringComparer.Ordinal)
{
"advisory"
};
private static readonly HashSet<string> ExpectedEdgeKinds = new(StringComparer.Ordinal)
{
"AFFECTED_BY"
};
[Fact]
public void Transform_projects_advisory_nodes_and_affected_by_edges()
{
var snapshot = LoadSnapshot("concelier-linkset.json");
var transformer = new AdvisoryLinksetTransformer();
var batch = transformer.Transform(snapshot);
var expectedNodes = LoadArray("nodes.json")
.Cast<JsonObject>()
.Where(node => ExpectedNodeKinds.Contains(node["kind"]!.GetValue<string>()))
.OrderBy(node => node["id"]!.GetValue<string>(), StringComparer.Ordinal)
.ToArray();
var expectedEdges = LoadArray("edges.json")
.Cast<JsonObject>()
.Where(edge => ExpectedEdgeKinds.Contains(edge["kind"]!.GetValue<string>()))
.OrderBy(edge => edge["id"]!.GetValue<string>(), StringComparer.Ordinal)
.ToArray();
var actualNodes = batch.Nodes
.Where(node => ExpectedNodeKinds.Contains(node["kind"]!.GetValue<string>()))
.OrderBy(node => node["id"]!.GetValue<string>(), StringComparer.Ordinal)
.ToArray();
var actualEdges = batch.Edges
.Where(edge => ExpectedEdgeKinds.Contains(edge["kind"]!.GetValue<string>()))
.OrderBy(edge => edge["id"]!.GetValue<string>(), StringComparer.Ordinal)
.ToArray();
actualNodes.Length.Should().Be(expectedNodes.Length);
actualEdges.Length.Should().Be(expectedEdges.Length);
for (var i = 0; i < expectedNodes.Length; i++)
{
if (!JsonNode.DeepEquals(expectedNodes[i], actualNodes[i]))
{
_output.WriteLine($"Expected Node: {expectedNodes[i]}");
_output.WriteLine($"Actual Node: {actualNodes[i]}");
}
JsonNode.DeepEquals(expectedNodes[i], actualNodes[i]).Should().BeTrue();
}
for (var i = 0; i < expectedEdges.Length; i++)
{
if (!JsonNode.DeepEquals(expectedEdges[i], actualEdges[i]))
{
_output.WriteLine($"Expected Edge: {expectedEdges[i]}");
_output.WriteLine($"Actual Edge: {actualEdges[i]}");
}
JsonNode.DeepEquals(expectedEdges[i], actualEdges[i]).Should().BeTrue();
}
}
private static AdvisoryLinksetSnapshot LoadSnapshot(string fileName)
{
var path = Path.Combine(FixturesRoot, fileName);
var json = File.ReadAllText(path);
return JsonSerializer.Deserialize<AdvisoryLinksetSnapshot>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
})!;
}
private static JsonArray LoadArray(string fileName)
{
var path = Path.Combine(FixturesRoot, fileName);
return (JsonArray)JsonNode.Parse(File.ReadAllText(path))!;
}
}