Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using StellaOps.SbomService.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.SbomService.Tests;
|
||||
|
||||
public sealed class SbomLedgerEndpointsTests : IClassFixture<WebApplicationFactory<Program>>
|
||||
{
|
||||
private readonly WebApplicationFactory<Program> _factory;
|
||||
|
||||
public SbomLedgerEndpointsTests(WebApplicationFactory<Program> factory)
|
||||
{
|
||||
_factory = factory.WithWebHostBuilder(_ => { });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Upload_accepts_cyclonedx_and_returns_analysis_job()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
var request = CreateUploadRequest("acme/app:1.0", CycloneDxSample());
|
||||
|
||||
var response = await client.PostAsJsonAsync("/sbom/upload", request);
|
||||
response.StatusCode.Should().Be(HttpStatusCode.Accepted);
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<SbomUploadResponse>();
|
||||
payload.Should().NotBeNull();
|
||||
payload!.ArtifactRef.Should().Be("acme/app:1.0");
|
||||
payload.ValidationResult.Valid.Should().BeTrue();
|
||||
payload.ValidationResult.ComponentCount.Should().Be(1);
|
||||
payload.AnalysisJobId.Should().NotBeNullOrWhiteSpace();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Upload_accepts_spdx_and_records_history()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
var artifact = "acme/worker:2.0";
|
||||
|
||||
var first = await client.PostAsJsonAsync("/sbom/upload", CreateUploadRequest(artifact, SpdxSample("4.17.21")));
|
||||
first.StatusCode.Should().Be(HttpStatusCode.Accepted);
|
||||
var firstPayload = await first.Content.ReadFromJsonAsync<SbomUploadResponse>();
|
||||
firstPayload.Should().NotBeNull();
|
||||
|
||||
var second = await client.PostAsJsonAsync("/sbom/upload", CreateUploadRequest(artifact, SpdxSample("4.17.22")));
|
||||
second.StatusCode.Should().Be(HttpStatusCode.Accepted);
|
||||
var secondPayload = await second.Content.ReadFromJsonAsync<SbomUploadResponse>();
|
||||
secondPayload.Should().NotBeNull();
|
||||
|
||||
var history = await client.GetAsync($"/sbom/ledger/history?artifact={Uri.EscapeDataString(artifact)}&limit=5");
|
||||
history.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var historyPayload = await history.Content.ReadFromJsonAsync<SbomVersionHistoryResult>();
|
||||
historyPayload.Should().NotBeNull();
|
||||
historyPayload!.Versions.Should().HaveCount(2);
|
||||
|
||||
var diff = await client.GetAsync($"/sbom/ledger/diff?before={firstPayload!.SbomId}&after={secondPayload!.SbomId}");
|
||||
diff.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var diffPayload = await diff.Content.ReadFromJsonAsync<SbomDiffResult>();
|
||||
diffPayload.Should().NotBeNull();
|
||||
diffPayload!.Summary.VersionChangedCount.Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Lineage_includes_build_edges_for_shared_build_id()
|
||||
{
|
||||
var client = _factory.CreateClient();
|
||||
var artifact = "acme/build:1.0";
|
||||
|
||||
var first = await client.PostAsJsonAsync("/sbom/upload", CreateUploadRequest(artifact, SpdxSample("1.0.0")));
|
||||
first.StatusCode.Should().Be(HttpStatusCode.Accepted);
|
||||
|
||||
var second = await client.PostAsJsonAsync("/sbom/upload", CreateUploadRequest(artifact, SpdxSample("1.1.0")));
|
||||
second.StatusCode.Should().Be(HttpStatusCode.Accepted);
|
||||
|
||||
var lineage = await client.GetAsync($"/sbom/ledger/lineage?artifact={Uri.EscapeDataString(artifact)}");
|
||||
lineage.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var payload = await lineage.Content.ReadFromJsonAsync<SbomLineageResult>();
|
||||
payload.Should().NotBeNull();
|
||||
payload!.Edges.Should().Contain(e => e.Relationship == SbomLineageRelationships.Build);
|
||||
}
|
||||
|
||||
private static SbomUploadRequest CreateUploadRequest(string artifactRef, string sbomJson)
|
||||
{
|
||||
using var document = JsonDocument.Parse(sbomJson);
|
||||
return new SbomUploadRequest
|
||||
{
|
||||
ArtifactRef = artifactRef,
|
||||
Sbom = document.RootElement.Clone(),
|
||||
Source = new SbomUploadSource
|
||||
{
|
||||
Tool = "syft",
|
||||
Version = "1.0.0",
|
||||
CiContext = new SbomUploadCiContext
|
||||
{
|
||||
BuildId = "build-01",
|
||||
Repository = "github.com/acme/app"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static string CycloneDxSample()
|
||||
{
|
||||
return """
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.6",
|
||||
"version": 1,
|
||||
"components": [
|
||||
{
|
||||
"type": "library",
|
||||
"name": "lodash",
|
||||
"version": "4.17.21",
|
||||
"purl": "pkg:npm/lodash@4.17.21",
|
||||
"licenses": [
|
||||
{ "license": { "id": "MIT" } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
private static string SpdxSample(string version)
|
||||
{
|
||||
return $$"""
|
||||
{
|
||||
"spdxVersion": "SPDX-2.3",
|
||||
"SPDXID": "SPDXRef-DOCUMENT",
|
||||
"name": "sample",
|
||||
"dataLicense": "CC0-1.0",
|
||||
"packages": [
|
||||
{
|
||||
"SPDXID": "SPDXRef-Package-lodash",
|
||||
"name": "lodash",
|
||||
"versionInfo": "{{version}}",
|
||||
"licenseDeclared": "MIT",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceType": "purl",
|
||||
"referenceLocator": "pkg:npm/lodash@{{version}}",
|
||||
"referenceCategory": "PACKAGE-MANAGER"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user