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

@@ -11,6 +11,8 @@ using StellaOps.EvidenceLocker.Core.Domain;
using StellaOps.EvidenceLocker.Infrastructure.Db;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class DatabaseMigrationTests : IAsyncLifetime
@@ -33,7 +35,8 @@ public sealed class DatabaseMigrationTests : IAsyncLifetime
.Build();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ApplyAsync_CreatesExpectedSchemaAndPolicies()
{
if (_skipReason is not null)

View File

@@ -9,6 +9,7 @@ using StellaOps.EvidenceLocker.Core.Repositories;
using StellaOps.EvidenceLocker.Infrastructure.Builders;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class EvidenceBundleBuilderTests
@@ -21,7 +22,8 @@ public sealed class EvidenceBundleBuilderTests
_builder = new EvidenceBundleBuilder(_repository, new MerkleTreeCalculator());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task BuildAsync_ComputesDeterministicRootAndPersists()
{
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
@@ -51,7 +53,8 @@ public sealed class EvidenceBundleBuilderTests
result.Manifest.Entries.OrderBy(entry => entry.CanonicalPath, StringComparer.Ordinal)));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task BuildAsync_NormalizesSectionAndPath()
{
var request = new EvidenceBundleBuildRequest(

View File

@@ -10,6 +10,8 @@ using StellaOps.EvidenceLocker.Core.Repositories;
using StellaOps.EvidenceLocker.Core.Storage;
using StellaOps.EvidenceLocker.Infrastructure.Services;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class EvidenceBundlePackagingServiceTests
@@ -23,7 +25,8 @@ public sealed class EvidenceBundlePackagingServiceTests
new Guid("11111111-2222-3333-4444-555555555555"));
private static readonly DateTimeOffset CreatedAtForDeterminism = new(2025, 11, 10, 8, 0, 0, TimeSpan.Zero);
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePackageAsync_ReturnsCached_WhenPackageExists()
{
var repository = new FakeRepository(CreateSealedBundle(), CreateSignature());
@@ -38,7 +41,8 @@ public sealed class EvidenceBundlePackagingServiceTests
Assert.False(objectStore.Stored);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePackageAsync_Throws_WhenSignatureMissing()
{
var repository = new FakeRepository(CreateSealedBundle(), signature: null);
@@ -48,7 +52,8 @@ public sealed class EvidenceBundlePackagingServiceTests
await Assert.ThrowsAsync<InvalidOperationException>(() => service.EnsurePackageAsync(TenantId, BundleId, CancellationToken.None));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePackageAsync_CreatesPackageWithExpectedEntries()
{
var repository = new FakeRepository(
@@ -89,7 +94,8 @@ public sealed class EvidenceBundlePackagingServiceTests
Assert.True(repository.StorageKeyUpdated);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePackageAsync_ProducesDeterministicGzipHeader()
{
var repository = new FakeRepository(CreateSealedBundle(), CreateSignature());
@@ -110,7 +116,8 @@ public sealed class EvidenceBundlePackagingServiceTests
Assert.Equal(expectedSeconds, mtime);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePackageAsync_ProducesDeterministicTarEntryMetadata()
{
var repository = new FakeRepository(CreateSealedBundle(), CreateSignature());
@@ -137,7 +144,8 @@ public sealed class EvidenceBundlePackagingServiceTests
}
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePackageAsync_ProducesIdenticalBytesForSameInput()
{
// First run
@@ -163,7 +171,8 @@ public sealed class EvidenceBundlePackagingServiceTests
Assert.Equal(objectStore1.StoredBytes, objectStore2.StoredBytes);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePackageAsync_Throws_WhenManifestPayloadInvalid()
{
var signature = CreateSignature() with { Payload = "not-base64" };
@@ -175,7 +184,8 @@ public sealed class EvidenceBundlePackagingServiceTests
Assert.Contains("manifest payload", exception.Message, StringComparison.OrdinalIgnoreCase);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePackageAsync_Throws_WhenManifestPayloadNotJson()
{
var rawPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes("not-json"));

View File

@@ -14,6 +14,8 @@ using System.Text.Json;
using FluentAssertions;
using StellaOps.Auth.Abstractions;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
/// <summary>
@@ -34,7 +36,8 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
#region EVIDENCE-5100-007: Store Retrieve Verify Hash
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_ThenRetrieve_HashMatches()
{
// Arrange
@@ -94,7 +97,8 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
retrievedRootHash.Should().Be(storedRootHash, "Root hash should match between store and retrieve");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_ThenDownload_ContainsCorrectManifest()
{
// Arrange
@@ -133,7 +137,8 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
manifestDoc.RootElement.GetProperty("bundleId").GetString().Should().Be(bundleId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreMultipleArtifacts_EachHasUniqueHash()
{
// Arrange
@@ -180,7 +185,8 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
hashes.Should().OnlyHaveUniqueItems("Each bundle should have a unique root hash");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_SignatureIsValid()
{
// Arrange
@@ -207,7 +213,8 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
signature.TryGetProperty("timestampToken", out var timestampToken).Should().BeTrue();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_ThenRetrieve_MetadataPreserved()
{
// Arrange
@@ -266,7 +273,8 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
metadataDict["pipelineId"].Should().Be("pipe-123");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_TimelineEventEmitted()
{
// Arrange
@@ -296,7 +304,8 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
#region Portable Bundle Integration
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_PortableDownload_IsSanitized()
{
// Arrange

View File

@@ -14,6 +14,8 @@ using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using StellaOps.Auth.Abstractions;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
/// <summary>
@@ -40,7 +42,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
#region EVIDENCE-5100-004: Contract Tests (OpenAPI Snapshot)
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_Endpoint_Returns_Expected_Schema()
{
// Arrange
@@ -70,7 +73,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
signature.ValueKind.Should().Be(JsonValueKind.Object);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RetrieveArtifact_Endpoint_Returns_Expected_Schema()
{
// Arrange
@@ -104,7 +108,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
root.TryGetProperty("createdAt", out _).Should().BeTrue("createdAt should be present");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DownloadArtifact_Endpoint_Returns_GzipMediaType()
{
// Arrange
@@ -129,7 +134,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
response.Content.Headers.ContentType?.MediaType.Should().Be("application/gzip");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Contract_ErrorResponse_Schema_Is_Consistent()
{
// Arrange - No auth headers (should fail)
@@ -144,7 +150,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Contract_NotFound_Response_Schema()
{
// Arrange
@@ -163,7 +170,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
#region EVIDENCE-5100-005: Auth Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_Without_Auth_Returns_Unauthorized()
{
// Arrange - No auth headers
@@ -178,7 +186,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_Without_CreateScope_Returns_Forbidden()
{
// Arrange - Auth but no create scope
@@ -195,7 +204,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
response.StatusCode.Should().BeOneOf(HttpStatusCode.Forbidden, HttpStatusCode.Unauthorized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_With_CreateScope_Succeeds()
{
// Arrange
@@ -212,7 +222,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
response.StatusCode.Should().Be(HttpStatusCode.OK);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RetrieveArtifact_Without_ReadScope_Returns_Forbidden()
{
// Arrange - Create with proper scope
@@ -238,7 +249,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
response.StatusCode.Should().BeOneOf(HttpStatusCode.Forbidden, HttpStatusCode.Unauthorized);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CrossTenant_Access_Returns_NotFound_Or_Forbidden()
{
// Arrange - Create bundle as tenant A
@@ -265,7 +277,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
response.StatusCode.Should().BeOneOf(HttpStatusCode.NotFound, HttpStatusCode.Forbidden);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Download_Without_ReadScope_Returns_Forbidden()
{
// Arrange
@@ -295,7 +308,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
#region EVIDENCE-5100-006: OTel Trace Assertions
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_Emits_OTel_Trace_With_ArtifactId()
{
// Arrange
@@ -342,7 +356,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
listener.Dispose();
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreArtifact_Timeline_Contains_TenantId()
{
// Arrange
@@ -364,7 +379,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
// Note: Actual assertion depends on how tenant_id is encoded in timeline events
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RetrieveArtifact_Emits_Trace_With_BundleId()
{
// Arrange
@@ -391,7 +407,8 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
// Timeline events may or may not be emitted on read depending on configuration
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Error_Response_Does_Not_Leak_Internal_Details()
{
// Arrange

View File

@@ -20,11 +20,14 @@ using StellaOps.EvidenceLocker.Core.Configuration;
using StellaOps.EvidenceLocker.Core.Domain;
using StellaOps.EvidenceLocker.WebService.Contracts;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class EvidenceLockerWebServiceTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Snapshot_ReturnsSignatureAndEmitsTimeline()
{
using var factory = new EvidenceLockerWebApplicationFactory();
@@ -70,7 +73,8 @@ public sealed class EvidenceLockerWebServiceTests
Assert.Equal(snapshot.Signature.TimestampToken, bundle.Signature.TimestampToken);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Snapshot_WithIncidentModeActive_ExtendsRetentionAndCapturesDebugArtifact()
{
using var baseFactory = new EvidenceLockerWebApplicationFactory();
@@ -117,7 +121,8 @@ public sealed class EvidenceLockerWebServiceTests
Assert.Contains("enabled", timeline.IncidentEvents);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Download_ReturnsPackageStream()
{
using var factory = new EvidenceLockerWebApplicationFactory();
@@ -171,7 +176,8 @@ public sealed class EvidenceLockerWebServiceTests
Assert.NotEmpty(factory.ObjectStore.StoredObjects);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task PortableDownload_ReturnsSanitizedBundle()
{
using var factory = new EvidenceLockerWebApplicationFactory();
@@ -217,7 +223,8 @@ public sealed class EvidenceLockerWebServiceTests
Assert.Contains("stella evidence verify", script, StringComparison.Ordinal);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Snapshot_ReturnsValidationError_WhenQuotaExceeded()
{
using var factory = new EvidenceLockerWebApplicationFactory();
@@ -246,7 +253,8 @@ public sealed class EvidenceLockerWebServiceTests
Assert.Contains(messages, m => m.Contains("exceeds", StringComparison.OrdinalIgnoreCase));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Snapshot_ReturnsForbidden_WhenTenantMissing()
{
using var factory = new EvidenceLockerWebApplicationFactory();
@@ -270,7 +278,8 @@ public sealed class EvidenceLockerWebServiceTests
Assert.True(response.StatusCode == HttpStatusCode.Forbidden, $"Expected 403 but received {(int)response.StatusCode}: {responseContent}");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Hold_ReturnsConflict_WhenCaseAlreadyExists()
{
using var factory = new EvidenceLockerWebApplicationFactory();
@@ -297,7 +306,8 @@ public sealed class EvidenceLockerWebServiceTests
Assert.Contains(messages, m => m.IndexOf("already exists", StringComparison.OrdinalIgnoreCase) >= 0);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task Hold_CreatesTimelineEvent()
{
using var factory = new EvidenceLockerWebApplicationFactory();

View File

@@ -10,6 +10,8 @@ using StellaOps.EvidenceLocker.Core.Repositories;
using StellaOps.EvidenceLocker.Core.Storage;
using StellaOps.EvidenceLocker.Infrastructure.Services;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class EvidencePortableBundleServiceTests
@@ -18,7 +20,8 @@ public sealed class EvidencePortableBundleServiceTests
private static readonly EvidenceBundleId BundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
private static readonly DateTimeOffset CreatedAt = new(2025, 11, 4, 10, 30, 0, TimeSpan.Zero);
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePortablePackageAsync_ReturnsCached_WhenObjectExists()
{
var bundle = CreateSealedBundle(
@@ -37,7 +40,8 @@ public sealed class EvidencePortableBundleServiceTests
Assert.False(repository.PortableStorageKeyUpdated);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePortablePackageAsync_CreatesPortableArchiveWithRedactedMetadata()
{
var repository = new FakeRepository(CreateSealedBundle(), CreateSignature(includeTimestamp: true));
@@ -84,7 +88,8 @@ public sealed class EvidencePortableBundleServiceTests
Assert.Contains("stella evidence verify", script, StringComparison.Ordinal);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePortablePackageAsync_Throws_WhenSignatureMissing()
{
var repository = new FakeRepository(CreateSealedBundle(), signature: null);
@@ -94,7 +99,8 @@ public sealed class EvidencePortableBundleServiceTests
await Assert.ThrowsAsync<InvalidOperationException>(() => service.EnsurePortablePackageAsync(TenantId, BundleId, CancellationToken.None));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task EnsurePortablePackageAsync_ProducesDeterministicTarEntryMetadata()
{
var repository = new FakeRepository(CreateSealedBundle(), CreateSignature(includeTimestamp: true));

View File

@@ -16,13 +16,16 @@ using StellaOps.EvidenceLocker.Core.Signing;
using StellaOps.EvidenceLocker.Infrastructure.Signing;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class EvidenceSignatureServiceTests
{
private static readonly SigningKeyMaterialOptions TestKeyMaterial = CreateKeyMaterial();
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SignManifestAsync_SignsManifestWithoutTimestamp_WhenTimestampingDisabled()
{
var timestampClient = new FakeTimestampAuthorityClient();
@@ -46,7 +49,8 @@ public sealed class EvidenceSignatureServiceTests
Assert.Equal(0, timestampClient.CallCount);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SignManifestAsync_AttachesTimestamp_WhenAuthorityClientSucceeds()
{
var timestampClient = new FakeTimestampAuthorityClient
@@ -81,7 +85,8 @@ public sealed class EvidenceSignatureServiceTests
Assert.Equal(1, timestampClient.CallCount);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SignManifestAsync_Throws_WhenTimestampRequiredAndClientFails()
{
var timestampClient = new FakeTimestampAuthorityClient
@@ -107,7 +112,8 @@ public sealed class EvidenceSignatureServiceTests
CancellationToken.None));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SignManifestAsync_ProducesDeterministicPayload()
{
var timestampClient = new FakeTimestampAuthorityClient();

View File

@@ -16,6 +16,8 @@ using StellaOps.EvidenceLocker.Core.Storage;
using StellaOps.EvidenceLocker.Core.Timeline;
using StellaOps.EvidenceLocker.Infrastructure.Services;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class EvidenceSnapshotServiceTests
@@ -75,7 +77,8 @@ public sealed class EvidenceSnapshotServiceTests
NullLogger<EvidenceSnapshotService>.Instance);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateSnapshotAsync_PersistsBundleAndBuildsManifest()
{
var request = new EvidenceSnapshotRequest
@@ -109,7 +112,8 @@ public sealed class EvidenceSnapshotServiceTests
Assert.False(_timelinePublisher.BundleSealedPublished);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateSnapshotAsync_StoresSignature_WhenSignerReturnsEnvelope()
{
var tenantId = TenantId.FromGuid(Guid.NewGuid());
@@ -148,7 +152,8 @@ public sealed class EvidenceSnapshotServiceTests
Assert.Equal(_repository.LastCreatedBundleId?.Value ?? Guid.Empty, result.BundleId);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateSnapshotAsync_ThrowsWhenMaterialQuotaExceeded()
{
var request = new EvidenceSnapshotRequest
@@ -165,7 +170,8 @@ public sealed class EvidenceSnapshotServiceTests
_service.CreateSnapshotAsync(TenantId.FromGuid(Guid.NewGuid()), request, CancellationToken.None));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateHoldAsync_ReturnsHoldWhenValid()
{
var tenantId = TenantId.FromGuid(Guid.NewGuid());
@@ -188,7 +194,8 @@ public sealed class EvidenceSnapshotServiceTests
Assert.True(_timelinePublisher.HoldPublished);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateHoldAsyncThrowsWhenBundleMissing()
{
var tenantId = TenantId.FromGuid(Guid.NewGuid());
@@ -202,7 +209,8 @@ public sealed class EvidenceSnapshotServiceTests
}, CancellationToken.None));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateHoldAsyncThrowsWhenCaseAlreadyExists()
{
_repository.ThrowUniqueViolationForHolds = true;
@@ -215,7 +223,8 @@ public sealed class EvidenceSnapshotServiceTests
CancellationToken.None));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateSnapshotAsync_ExtendsRetentionAndCapturesIncidentArtifacts_WhenIncidentModeActive()
{
_incidentState.SetState(true, retentionExtensionDays: 45, captureSnapshot: true);

View File

@@ -5,6 +5,8 @@ using StellaOps.EvidenceLocker.Core.Domain;
using StellaOps.EvidenceLocker.Core.Storage;
using StellaOps.EvidenceLocker.Infrastructure.Storage;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class FileSystemEvidenceObjectStoreTests : IDisposable
@@ -16,7 +18,8 @@ public sealed class FileSystemEvidenceObjectStoreTests : IDisposable
_rootPath = Path.Combine(Path.GetTempPath(), $"evidence-locker-tests-{Guid.NewGuid():N}");
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreAsync_EnforcesWriteOnceWhenConfigured()
{
var cancellationToken = TestContext.Current.CancellationToken;
@@ -30,7 +33,8 @@ public sealed class FileSystemEvidenceObjectStoreTests : IDisposable
await Assert.ThrowsAsync<InvalidOperationException>(() => store.StoreAsync(second, options, cancellationToken));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreAsync_AllowsOverwriteWhenWriteOnceDisabled()
{
var cancellationToken = TestContext.Current.CancellationToken;

View File

@@ -4,13 +4,16 @@ using System.Text;
using System.Text.Json;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class GoldenFixturesTests
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void SealedBundle_Fixture_HashAndSubjectMatch()
{
var root = FixturePath("sealed");
@@ -35,7 +38,8 @@ public sealed class GoldenFixturesTests
Assert.Equal(rootFromChecksums, recomputedSubject);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void PortableBundle_Fixture_RedactionAndSubjectMatch()
{
var root = FixturePath("portable");
@@ -54,7 +58,8 @@ public sealed class GoldenFixturesTests
Assert.Equal(rootFromChecksums, recomputedSubject);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ReplayFixture_RecordDigestMatches()
{
var root = FixturePath("replay");

View File

@@ -12,11 +12,13 @@ using StellaOps.EvidenceLocker.Core.Signing;
using StellaOps.EvidenceLocker.Infrastructure.Signing;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class Rfc3161TimestampAuthorityClientTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RequestTimestampAsync_ReturnsNull_WhenAuthorityFailsAndTimestampOptional()
{
var handler = new StubHttpMessageHandler(_ => new HttpResponseMessage(HttpStatusCode.InternalServerError));
@@ -33,7 +35,8 @@ public sealed class Rfc3161TimestampAuthorityClientTests
Assert.Null(result);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RequestTimestampAsync_Throws_WhenAuthorityFailsAndTimestampRequired()
{
var handler = new StubHttpMessageHandler(_ => new HttpResponseMessage(HttpStatusCode.InternalServerError));

View File

@@ -11,11 +11,14 @@ using StellaOps.EvidenceLocker.Core.Domain;
using StellaOps.EvidenceLocker.Core.Storage;
using StellaOps.EvidenceLocker.Infrastructure.Storage;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class S3EvidenceObjectStoreTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreAsync_SetsIfNoneMatchAndMetadataWhenEnforcingWriteOnce()
{
var fakeClient = new FakeAmazonS3Client();
@@ -58,7 +61,8 @@ public sealed class S3EvidenceObjectStoreTests
Assert.Equal("\"etag\"", metadata.ETag);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task StoreAsync_DoesNotSetIfNoneMatchWhenWriteOnceDisabled()
{
var fakeClient = new FakeAmazonS3Client();

View File

@@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="DotNet.Testcontainers" Version="1.6.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0-preview.7.25380.108" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Npgsql" Version="9.0.3" />
<PackageReference Include="xunit.v3" Version="3.0.0" />
@@ -34,5 +34,6 @@
<ProjectReference Include="..\StellaOps.EvidenceLocker.Core\StellaOps.EvidenceLocker.Core.csproj" />
<ProjectReference Include="..\StellaOps.EvidenceLocker.Infrastructure\StellaOps.EvidenceLocker.Infrastructure.csproj" />
<ProjectReference Include="..\StellaOps.EvidenceLocker.WebService\StellaOps.EvidenceLocker.WebService.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
</ItemGroup>
</Project>

View File

@@ -10,11 +10,14 @@ using StellaOps.EvidenceLocker.Core.Configuration;
using StellaOps.EvidenceLocker.Core.Domain;
using StellaOps.EvidenceLocker.Infrastructure.Timeline;
using StellaOps.TestKit;
namespace StellaOps.EvidenceLocker.Tests;
public sealed class TimelineIndexerEvidenceTimelinePublisherTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task PublishBundleSealedAsync_SendsExpectedPayload()
{
var tenantId = TenantId.FromGuid(Guid.NewGuid());
@@ -92,7 +95,8 @@ public sealed class TimelineIndexerEvidenceTimelinePublisherTests
Assert.Equal("primary", entry.GetProperty("attributes").GetProperty("role").GetString());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task PublishHoldCreatedAsync_ProducesHoldPayload()
{
var tenantId = TenantId.FromGuid(Guid.NewGuid());