Frontend gaps fill work. Testing fixes work. Auditing in progress.
This commit is contained in:
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 ?? "{}"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user