Restore policy simulation history compatibility
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using StellaOps.TestKit;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Policy.Gateway.Tests;
|
||||
|
||||
public sealed class PolicySimulationEndpointsTests : IClassFixture<TestPolicyGatewayFactory>
|
||||
{
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public PolicySimulationEndpointsTests(TestPolicyGatewayFactory factory)
|
||||
{
|
||||
_client = factory.CreateClient();
|
||||
_client.DefaultRequestHeaders.Add("X-StellaOps-Tenant", "test-tenant");
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public async Task ShadowConfig_ReturnsDeterministicCompatibilityShape()
|
||||
{
|
||||
var response = await _client.GetAsync("/policy/shadow/config", TestContext.Current.CancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
Assert.True(payload.TryGetProperty("enabled", out _));
|
||||
Assert.Equal("policy-pack-shadow-001", payload.GetProperty("shadowPackId").GetString());
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public async Task EnableShadowMode_UpdatesConfigAndResults()
|
||||
{
|
||||
var enableResponse = await _client.PostAsJsonAsync(
|
||||
"/policy/shadow/enable",
|
||||
new
|
||||
{
|
||||
enabled = true,
|
||||
shadowPackId = "policy-pack-shadow-qa",
|
||||
shadowVersion = 7,
|
||||
trafficPercentage = 40
|
||||
},
|
||||
TestContext.Current.CancellationToken);
|
||||
enableResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var resultsResponse = await _client.GetAsync("/policy/shadow/results?limit=5", TestContext.Current.CancellationToken);
|
||||
resultsResponse.EnsureSuccessStatusCode();
|
||||
var payload = await resultsResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.True(payload.GetProperty("config").GetProperty("enabled").GetBoolean());
|
||||
Assert.Equal(5, payload.GetProperty("comparisons").GetArrayLength());
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public async Task SimulationLifecycle_CreateListGetCancel()
|
||||
{
|
||||
var createResponse = await _client.PostAsJsonAsync(
|
||||
"/policy/simulations",
|
||||
new
|
||||
{
|
||||
policyPackId = "policy-pack-qa",
|
||||
policyVersion = 4,
|
||||
includeExplain = true,
|
||||
diffAgainstActive = true
|
||||
},
|
||||
TestContext.Current.CancellationToken);
|
||||
createResponse.EnsureSuccessStatusCode();
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var simulationId = created.GetProperty("simulationId").GetString();
|
||||
Assert.False(string.IsNullOrWhiteSpace(simulationId));
|
||||
|
||||
var listResponse = await _client.GetAsync("/policy/simulations?limit=10", TestContext.Current.CancellationToken);
|
||||
listResponse.EnsureSuccessStatusCode();
|
||||
var list = await listResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
Assert.True(list.GetProperty("items").EnumerateArray().Any(item => item.GetProperty("simulationId").GetString() == simulationId));
|
||||
|
||||
var getResponse = await _client.GetAsync($"/policy/simulations/{simulationId}", TestContext.Current.CancellationToken);
|
||||
getResponse.EnsureSuccessStatusCode();
|
||||
var detail = await getResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
Assert.Equal("completed", detail.GetProperty("status").GetString());
|
||||
|
||||
var cancelResponse = await _client.PostAsJsonAsync($"/policy/simulations/{simulationId}/cancel", new { }, TestContext.Current.CancellationToken);
|
||||
cancelResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var cancelledResponse = await _client.GetAsync($"/policy/simulations/{simulationId}", TestContext.Current.CancellationToken);
|
||||
cancelledResponse.EnsureSuccessStatusCode();
|
||||
var cancelled = await cancelledResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
Assert.Equal("cancelled", cancelled.GetProperty("status").GetString());
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public async Task SimulationHistory_ReturnsCompatibilityEntriesAndSupportsPinnedFilter()
|
||||
{
|
||||
var response = await _client.GetAsync("/policy/simulations/history?page=1&pageSize=20", TestContext.Current.CancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var items = payload.GetProperty("items");
|
||||
Assert.True(items.GetArrayLength() >= 3);
|
||||
Assert.Equal("sim-001", items[0].GetProperty("simulationId").GetString());
|
||||
Assert.Equal("sha256:abc123def456789", items[0].GetProperty("resultHash").GetString());
|
||||
Assert.True(items[0].GetProperty("pinned").GetBoolean());
|
||||
|
||||
var pinnedResponse = await _client.GetAsync("/policy/simulations/history?pinnedOnly=true&page=1&pageSize=20", TestContext.Current.CancellationToken);
|
||||
pinnedResponse.EnsureSuccessStatusCode();
|
||||
var pinnedPayload = await pinnedResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var pinnedItems = pinnedPayload.GetProperty("items");
|
||||
Assert.All(pinnedItems.EnumerateArray(), item => Assert.True(item.GetProperty("pinned").GetBoolean()));
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public async Task SimulationCompare_ReturnsDeterministicDiffShape()
|
||||
{
|
||||
var response = await _client.GetAsync("/policy/simulations/compare?baseId=sim-001&compareId=sim-002", TestContext.Current.CancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
Assert.Equal("sim-001", payload.GetProperty("baseSimulationId").GetString());
|
||||
Assert.Equal("sim-002", payload.GetProperty("compareSimulationId").GetString());
|
||||
Assert.False(payload.GetProperty("resultsMatch").GetBoolean());
|
||||
Assert.NotEmpty(payload.GetProperty("changed").EnumerateArray());
|
||||
Assert.True(payload.GetProperty("matchPercentage").GetDouble() < 100);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Integration)]
|
||||
[Fact]
|
||||
public async Task SimulationVerifyAndPin_PreserveHistoryActions()
|
||||
{
|
||||
var verifyResponse = await _client.PostAsJsonAsync("/policy/simulations/sim-001/verify", new { }, TestContext.Current.CancellationToken);
|
||||
verifyResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var verifyPayload = await verifyResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
Assert.True(verifyPayload.GetProperty("isReproducible").GetBoolean());
|
||||
Assert.Equal(
|
||||
verifyPayload.GetProperty("originalHash").GetString(),
|
||||
verifyPayload.GetProperty("replayHash").GetString());
|
||||
|
||||
using var patchRequest = new HttpRequestMessage(HttpMethod.Patch, "/policy/simulations/sim-002")
|
||||
{
|
||||
Content = JsonContent.Create(new { pinned = true })
|
||||
};
|
||||
|
||||
var patchResponse = await _client.SendAsync(patchRequest, TestContext.Current.CancellationToken);
|
||||
patchResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var historyResponse = await _client.GetAsync("/policy/simulations/history?pinnedOnly=true&page=1&pageSize=20", TestContext.Current.CancellationToken);
|
||||
historyResponse.EnsureSuccessStatusCode();
|
||||
var historyPayload = await historyResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
Assert.Contains(
|
||||
historyPayload.GetProperty("items").EnumerateArray().Select(item => item.GetProperty("simulationId").GetString()),
|
||||
simulationId => string.Equals(simulationId, "sim-002", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user