Frontend gaps fill work. Testing fixes work. Auditing in progress.

This commit is contained in:
StellaOps Bot
2025-12-30 01:22:58 +02:00
parent 1dc4bcbf10
commit 7a5210e2aa
928 changed files with 183942 additions and 3941 deletions

View File

@@ -56,12 +56,12 @@ public sealed class ScoringApiContractTests : IAsyncLifetime
_pactBuilder = pact.WithHttpInteractions();
}
public Task InitializeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => ValueTask.CompletedTask;
public Task DisposeAsync()
public ValueTask DisposeAsync()
{
// Pact files are generated when the builder disposes
return Task.CompletedTask;
return ValueTask.CompletedTask;
}
#region Scoring Input Contract Tests
@@ -384,8 +384,8 @@ public sealed class ProfileSpecificContractTests : IAsyncLifetime
_pactBuilder = pact.WithHttpInteractions();
}
public Task InitializeAsync() => Task.CompletedTask;
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Fact(DisplayName = "Consumer expects Simple profile to return Simple in scoringProfile")]
public async Task Consumer_Expects_SimpleProfile_InResponse()
@@ -427,3 +427,6 @@ public sealed class ProfileSpecificContractTests : IAsyncLifetime
});
}
}

View File

@@ -14,7 +14,7 @@
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Moq" />
<PackageReference Include="FsCheck" />
<PackageReference Include="FsCheck.Xunit" />
<PackageReference Include="FsCheck.Xunit.v3" />
<PackageReference Include="NSubstitute" />
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
</ItemGroup>
@@ -28,4 +28,6 @@
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
<ProjectReference Include="../../../Scanner/__Libraries/StellaOps.Scanner.Emit/StellaOps.Scanner.Emit.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -0,0 +1,397 @@
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.Testing;
using StellaOps.TestKit;
using Xunit;
using GatewayProgram = StellaOps.Policy.Gateway.Program;
namespace StellaOps.Policy.Gateway.Tests;
/// <summary>
/// Tests for governance endpoints (GOV-018).
/// </summary>
public sealed class GovernanceEndpointsTests : IClassFixture<WebApplicationFactory<GatewayProgram>>
{
private readonly HttpClient _client;
private readonly WebApplicationFactory<GatewayProgram> _factory;
public GovernanceEndpointsTests(WebApplicationFactory<GatewayProgram> factory)
{
_factory = factory.WithWebHostBuilder(builder =>
{
builder.UseSetting("Environment", "Testing");
});
_client = _factory.CreateClient();
_client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", "test-tenant");
}
#region Sealed Mode Tests
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetSealedModeStatus_ReturnsOk()
{
// Act
var response = await _client.GetAsync("/api/v1/governance/sealed-mode/status", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.True(result.TryGetProperty("isSealed", out _));
Assert.True(result.TryGetProperty("tenantId", out _));
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetSealedModeStatus_ReturnsBadRequest_WhenTenantMissing()
{
// Arrange
var clientWithoutTenant = _factory.CreateClient();
// Act
var response = await clientWithoutTenant.GetAsync("/api/v1/governance/sealed-mode/status", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ToggleSealedMode_ReturnsOk()
{
// Arrange
var request = new { enable = true, reason = "Test seal" };
// Act
var response = await _client.PostAsJsonAsync("/api/v1/governance/sealed-mode/toggle", request, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.True(result.GetProperty("isSealed").GetBoolean());
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetSealedModeOverrides_ReturnsOk()
{
// Act
var response = await _client.GetAsync("/api/v1/governance/sealed-mode/overrides", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.True(result.TryGetProperty("overrides", out _));
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateSealedModeOverride_ReturnsCreated()
{
// Arrange
var request = new
{
overrideType = "PolicyUpdate",
reason = "Emergency hotfix",
durationMinutes = 60,
actor = "admin@example.com"
};
// Act
var response = await _client.PostAsJsonAsync("/api/v1/governance/sealed-mode/overrides", request, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.True(result.TryGetProperty("overrideId", out _));
Assert.Equal("PolicyUpdate", result.GetProperty("overrideType").GetString());
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task RevokeSealedModeOverride_ReturnsNotFound_WhenOverrideNotExists()
{
// Act
var response = await _client.PostAsJsonAsync("/api/v1/governance/sealed-mode/overrides/nonexistent/revoke", new { }, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
#endregion
#region Risk Profile Tests
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ListRiskProfiles_ReturnsOk()
{
// Act
var response = await _client.GetAsync("/api/v1/governance/risk-profiles", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.True(result.TryGetProperty("profiles", out _));
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateRiskProfile_ReturnsCreated()
{
// Arrange
var profileId = $"test-profile-{Guid.NewGuid():N}";
var request = new
{
profileId = profileId,
name = "Test Profile",
description = "Test profile for unit tests",
maxCriticalFindings = 0,
maxHighFindings = 5,
maxRiskScore = 7500
};
// Act
var response = await _client.PostAsJsonAsync("/api/v1/governance/risk-profiles", request, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.Equal(profileId, result.GetProperty("profileId").GetString());
Assert.Equal("Test Profile", result.GetProperty("name").GetString());
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetRiskProfile_ReturnsNotFound_WhenProfileNotExists()
{
// Act
var response = await _client.GetAsync("/api/v1/governance/risk-profiles/nonexistent-profile", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateAndGetRiskProfile_RoundTrip()
{
// Arrange
var profileId = $"roundtrip-{Guid.NewGuid():N}";
var createRequest = new
{
profileId = profileId,
name = "Roundtrip Profile",
description = "Profile for roundtrip test",
maxCriticalFindings = 1,
maxHighFindings = 10,
maxRiskScore = 5000
};
// Act - Create
var createResponse = await _client.PostAsJsonAsync("/api/v1/governance/risk-profiles", createRequest, cancellationToken: CancellationToken.None);
Assert.Equal(HttpStatusCode.Created, createResponse.StatusCode);
// Act - Get
var getResponse = await _client.GetAsync($"/api/v1/governance/risk-profiles/{profileId}", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.OK, getResponse.StatusCode);
var result = await getResponse.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.Equal(profileId, result.GetProperty("profileId").GetString());
Assert.Equal("Roundtrip Profile", result.GetProperty("name").GetString());
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task UpdateRiskProfile_ReturnsNotFound_WhenProfileNotExists()
{
// Arrange
var request = new
{
name = "Updated Profile",
description = "Updated description",
maxCriticalFindings = 2,
maxHighFindings = 20,
maxRiskScore = 10000
};
// Act
var response = await _client.PutAsJsonAsync("/api/v1/governance/risk-profiles/nonexistent", request, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeleteRiskProfile_ReturnsNotFound_WhenProfileNotExists()
{
// Act
var response = await _client.DeleteAsync("/api/v1/governance/risk-profiles/nonexistent", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task CreateUpdateDeleteRiskProfile_FullLifecycle()
{
// Arrange
var profileId = $"lifecycle-{Guid.NewGuid():N}";
// Act - Create
var createRequest = new
{
profileId = profileId,
name = "Lifecycle Profile",
description = "Profile for lifecycle test",
maxCriticalFindings = 0,
maxHighFindings = 5,
maxRiskScore = 7500
};
var createResponse = await _client.PostAsJsonAsync("/api/v1/governance/risk-profiles", createRequest, cancellationToken: CancellationToken.None);
Assert.Equal(HttpStatusCode.Created, createResponse.StatusCode);
// Act - Update
var updateRequest = new
{
name = "Updated Lifecycle Profile",
description = "Updated description",
maxCriticalFindings = 1,
maxHighFindings = 10,
maxRiskScore = 10000
};
var updateResponse = await _client.PutAsJsonAsync($"/api/v1/governance/risk-profiles/{profileId}", updateRequest, cancellationToken: CancellationToken.None);
Assert.Equal(HttpStatusCode.OK, updateResponse.StatusCode);
// Verify update
var getResponse = await _client.GetAsync($"/api/v1/governance/risk-profiles/{profileId}", CancellationToken.None);
var profile = await getResponse.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.Equal("Updated Lifecycle Profile", profile.GetProperty("name").GetString());
// Act - Delete
var deleteResponse = await _client.DeleteAsync($"/api/v1/governance/risk-profiles/{profileId}", CancellationToken.None);
Assert.Equal(HttpStatusCode.NoContent, deleteResponse.StatusCode);
// Verify deletion
var getAfterDeleteResponse = await _client.GetAsync($"/api/v1/governance/risk-profiles/{profileId}", CancellationToken.None);
Assert.Equal(HttpStatusCode.NotFound, getAfterDeleteResponse.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ActivateRiskProfile_ReturnsNotFound_WhenProfileNotExists()
{
// Act
var response = await _client.PostAsJsonAsync("/api/v1/governance/risk-profiles/nonexistent/activate", new { }, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task DeprecateRiskProfile_ReturnsNotFound_WhenProfileNotExists()
{
// Act
var response = await _client.PostAsJsonAsync("/api/v1/governance/risk-profiles/nonexistent/deprecate", new { }, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ValidateRiskProfile_ReturnsValidationResult()
{
// Arrange
var request = new
{
name = "Valid Profile",
description = "Test description",
maxCriticalFindings = 0,
maxHighFindings = 5,
maxRiskScore = 7500
};
// Act
var response = await _client.PostAsJsonAsync("/api/v1/governance/risk-profiles/validate", request, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.True(result.TryGetProperty("isValid", out _));
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ValidateRiskProfile_ReturnsInvalid_WithNegativeValues()
{
// Arrange
var request = new
{
name = "",
maxCriticalFindings = -1,
maxHighFindings = -1,
maxRiskScore = -1
};
// Act
var response = await _client.PostAsJsonAsync("/api/v1/governance/risk-profiles/validate", request, cancellationToken: CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.False(result.GetProperty("isValid").GetBoolean());
Assert.True(result.TryGetProperty("errors", out var errors));
Assert.True(errors.GetArrayLength() > 0);
}
#endregion
#region Audit Tests
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetAuditEvents_ReturnsOk()
{
// Act
var response = await _client.GetAsync("/api/v1/governance/audit/events", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
Assert.True(result.TryGetProperty("events", out _));
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetAuditEvent_ReturnsNotFound_WhenEventNotExists()
{
// Act
var response = await _client.GetAsync("/api/v1/governance/audit/events/nonexistent-event", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetAuditEvents_ReturnsBadRequest_WhenTenantMissing()
{
// Arrange
var clientWithoutTenant = _factory.CreateClient();
// Act
var response = await clientWithoutTenant.GetAsync("/api/v1/governance/audit/events", CancellationToken.None);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
#endregion
}

View File

@@ -53,14 +53,14 @@ public sealed class PolicyGatewayIntegrationTests : IAsyncLifetime
ActivitySource.AddActivityListener(_activityListener);
}
public Task InitializeAsync()
public ValueTask InitializeAsync()
{
_factory = new PolicyGatewayTestFactory();
_client = _factory.CreateClient();
return Task.CompletedTask;
return ValueTask.CompletedTask;
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
_activityListener.Dispose();
_client.Dispose();
@@ -483,3 +483,6 @@ public sealed record CreateExceptionRequest
}
#endregion

View File

@@ -32,7 +32,7 @@ public sealed class EvaluationRunRepositoryTests : IAsyncLifetime
_repository = new EvaluationRunRepository(dataSource, NullLogger<EvaluationRunRepository>.Instance);
}
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await _fixture.TruncateAllTablesAsync();
@@ -62,7 +62,7 @@ public sealed class EvaluationRunRepositoryTests : IAsyncLifetime
};
await _packVersionRepository.CreateAsync(packVersion);
}
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -300,3 +300,6 @@ public sealed class EvaluationRunRepositoryTests : IAsyncLifetime
Status = EvaluationStatus.Pending
};
}

View File

@@ -31,8 +31,8 @@ public sealed class ExceptionObjectRepositoryTests : IAsyncLifetime
_repository = new PostgresExceptionObjectRepository(dataSource, NullLogger<PostgresExceptionObjectRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -485,3 +485,6 @@ public sealed class ExceptionObjectRepositoryTests : IAsyncLifetime
#endregion
}

View File

@@ -26,8 +26,8 @@ public sealed class ExceptionRepositoryTests : IAsyncLifetime
_repository = new ExceptionRepository(dataSource, NullLogger<ExceptionRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -289,3 +289,6 @@ public sealed class ExceptionRepositoryTests : IAsyncLifetime
Status = ExceptionStatus.Active
};
}

View File

@@ -28,8 +28,8 @@ public sealed class PackRepositoryTests : IAsyncLifetime
_packVersionRepository = new PackVersionRepository(dataSource, NullLogger<PackVersionRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -283,3 +283,6 @@ public sealed class PackRepositoryTests : IAsyncLifetime
return created;
}
}

View File

@@ -36,8 +36,8 @@ public sealed class PackVersioningWorkflowTests : IAsyncLifetime
_ruleRepository = new RuleRepository(dataSource, NullLogger<RuleRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -290,3 +290,6 @@ public sealed class PackVersioningWorkflowTests : IAsyncLifetime
updated.IsBuiltin.Should().BeTrue();
}
}

View File

@@ -26,8 +26,8 @@ public sealed class PolicyAuditRepositoryTests : IAsyncLifetime
_repository = new PolicyAuditRepository(dataSource, NullLogger<PolicyAuditRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -200,3 +200,6 @@ public sealed class PolicyAuditRepositoryTests : IAsyncLifetime
ResourceId = Guid.NewGuid().ToString()
};
}

View File

@@ -29,7 +29,7 @@ public sealed class PolicyMigrationTests : IAsyncLifetime
{
private PostgreSqlContainer _container = null!;
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
_container = new PostgreSqlBuilder()
.WithImage("postgres:16-alpine")
@@ -41,7 +41,7 @@ public sealed class PolicyMigrationTests : IAsyncLifetime
await _container.StartAsync();
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
await _container.DisposeAsync();
}
@@ -320,3 +320,6 @@ public sealed class PolicyMigrationTests : IAsyncLifetime
return reader.ReadToEnd();
}
}

View File

@@ -51,7 +51,7 @@ public sealed class PolicyTestKitPostgresFixture : IAsyncLifetime
public TestKitPostgresFixture Fixture => _fixture;
public string ConnectionString => _fixture.ConnectionString;
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
_fixture = new TestKitPostgresFixture();
_fixture.IsolationMode = TestKitPostgresIsolationMode.Truncation;
@@ -59,7 +59,7 @@ public sealed class PolicyTestKitPostgresFixture : IAsyncLifetime
await _fixture.ApplyMigrationsFromAssemblyAsync(MigrationAssembly, "public");
}
public Task DisposeAsync() => _fixture.DisposeAsync();
public ValueTask DisposeAsync() => _fixture.DisposeAsync();
public Task TruncateAllTablesAsync() => _fixture.TruncateAllTablesAsync();
}
@@ -72,3 +72,6 @@ public sealed class PolicyTestKitPostgresCollection : ICollectionFixture<PolicyT
{
public const string Name = "PolicyTestKitPostgres";
}

View File

@@ -42,7 +42,7 @@ public sealed class PolicyQueryDeterminismTests : IAsyncLifetime
_fixture = fixture;
}
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await _fixture.TruncateAllTablesAsync();
@@ -56,7 +56,7 @@ public sealed class PolicyQueryDeterminismTests : IAsyncLifetime
_auditRepository = new PolicyAuditRepository(_dataSource, NullLogger<PolicyAuditRepository>.Instance);
}
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Fact]
public async Task GetAllPacks_MultipleQueries_ReturnsDeterministicOrder()
@@ -410,3 +410,6 @@ public sealed class PolicyQueryDeterminismTests : IAsyncLifetime
return await _auditRepository.CreateAsync(audit);
}
}

View File

@@ -40,7 +40,7 @@ public sealed class PolicyVersioningImmutabilityTests : IAsyncLifetime
_fixture = fixture;
}
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await _fixture.TruncateAllTablesAsync();
@@ -52,7 +52,7 @@ public sealed class PolicyVersioningImmutabilityTests : IAsyncLifetime
_ruleRepository = new RuleRepository(_dataSource, NullLogger<RuleRepository>.Instance);
}
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Fact]
public async Task PublishedVersion_CannotBeDeleted()
@@ -302,3 +302,6 @@ public sealed class PolicyVersioningImmutabilityTests : IAsyncLifetime
return created;
}
}

View File

@@ -36,7 +36,7 @@ public sealed class PostgresExceptionApplicationRepositoryTests : IAsyncLifetime
_repository = new PostgresExceptionApplicationRepository(_dataSource);
}
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await _fixture.TruncateAllTablesAsync();
@@ -46,7 +46,7 @@ public sealed class PostgresExceptionApplicationRepositoryTests : IAsyncLifetime
await cmd.ExecuteNonQueryAsync();
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
await _dataSource.DisposeAsync();
}
@@ -175,3 +175,6 @@ public sealed class PostgresExceptionApplicationRepositoryTests : IAsyncLifetime
string eff = "suppress") =>
ExceptionApplication.Create(_tenantId, excId, findId, "affected", "not_affected", "test", eff, vulnId);
}

View File

@@ -32,8 +32,8 @@ public sealed class PostgresExceptionObjectRepositoryTests : IAsyncLifetime
_repository = new PostgresExceptionObjectRepository(dataSource, NullLogger<PostgresExceptionObjectRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
#region Create Tests
@@ -569,3 +569,6 @@ public sealed class PostgresExceptionObjectRepositoryTests : IAsyncLifetime
#endregion
}

View File

@@ -30,8 +30,8 @@ public sealed class PostgresReceiptRepositoryTests : IAsyncLifetime
_repository = new PostgresReceiptRepository(dataSource, NullLogger<PostgresReceiptRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -110,3 +110,6 @@ public sealed class PostgresReceiptRepositoryTests : IAsyncLifetime
};
}
}

View File

@@ -25,9 +25,9 @@ public sealed class RecheckEvidenceMigrationTests : IAsyncLifetime
_dataSource = new PolicyDataSource(Options.Create(options), NullLogger<PolicyDataSource>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -48,3 +48,6 @@ public sealed class RecheckEvidenceMigrationTests : IAsyncLifetime
result.Should().NotBeNull($"{tableName} should exist after migrations");
}
}

View File

@@ -26,8 +26,8 @@ public sealed class RiskProfileRepositoryTests : IAsyncLifetime
_repository = new RiskProfileRepository(dataSource, NullLogger<RiskProfileRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -360,3 +360,6 @@ public sealed class RiskProfileRepositoryTests : IAsyncLifetime
ScoringWeights = scoringWeights ?? "{}"
};
}

View File

@@ -35,8 +35,8 @@ public sealed class RiskProfileVersionHistoryTests : IAsyncLifetime
_repository = new RiskProfileRepository(dataSource, NullLogger<RiskProfileRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -485,3 +485,6 @@ public sealed class RiskProfileVersionHistoryTests : IAsyncLifetime
afterUpdate.UpdatedAt.Should().BeOnOrAfter(createTime); // UpdatedAt should progress
}
}

View File

@@ -33,7 +33,7 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
_repository = new RuleRepository(dataSource, NullLogger<RuleRepository>.Instance);
}
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await _fixture.TruncateAllTablesAsync();
@@ -67,7 +67,7 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
await _packVersionRepository.CreateAsync(packVersion);
}
public Task DisposeAsync() => Task.CompletedTask;
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -279,3 +279,6 @@ public sealed class RuleRepositoryTests : IAsyncLifetime
ContentHash = Guid.NewGuid().ToString()
};
}

View File

@@ -27,8 +27,8 @@ public sealed class UnknownsRepositoryTests : IAsyncLifetime
_dataSource = new PolicyDataSource(Options.Create(options), NullLogger<PolicyDataSource>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
public async Task DisposeAsync() => await _dataSource.DisposeAsync();
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public async ValueTask DisposeAsync() => await _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]
@@ -123,3 +123,6 @@ public sealed class UnknownsRepositoryTests : IAsyncLifetime
UpdatedAt = timestamp
};
}

View File

@@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="FluentAssertions" />
<PackageReference Include="FsCheck" />
<PackageReference Include="FsCheck.Xunit" />
<PackageReference Include="FsCheck.Xunit.v3" />
<PackageReference Include="Moq" />
</ItemGroup>
<ItemGroup>
@@ -21,4 +21,6 @@
<ProjectReference Include="../../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="FluentAssertions" />
<PackageReference Include="FsCheck" />
<PackageReference Include="FsCheck.Xunit" />
<PackageReference Include="FsCheck.Xunit.v3" />
</ItemGroup>
<ItemGroup>
@@ -25,4 +25,6 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
</Project>