mirror of
https://github.com/azaion/missions.git
synced 2026-06-21 23:01:07 +00:00
3398ec49a0
ci/woodpecker/push/build-arm Pipeline was successful
- Updated Azaion.Missions.csproj to exclude test sources from service compilation, preventing build failures due to test project dependencies. - Modified docker-compose.test.yml to preload the pg_stat_statements extension for testing and adjusted JWT refresh intervals for better test execution timing. - Enhanced Dockerfile to install wget for health checks and ensure proper initialization of the container. - Introduced a test-only endpoint for JWKS refresh to facilitate end-to-end testing without relying on the default refresh intervals. - Updated DTOs in ApiDtos.cs to reflect camelCase naming conventions for consistency with service responses. - Improved test cases to handle JWKS rotation and refresh scenarios effectively, ensuring robust validation of JWT handling. This commit lays the groundwork for more reliable and efficient testing of the Azaion.Missions project.
96 lines
4.7 KiB
C#
96 lines
4.7 KiB
C#
using System.Net;
|
|
using System.Net.Http.Headers;
|
|
using System.Text.Json;
|
|
using Azaion.Missions.E2E.Fixtures;
|
|
using Azaion.Missions.E2E.Helpers;
|
|
using Xunit;
|
|
|
|
namespace Azaion.Missions.E2E.Tests.Missions;
|
|
|
|
/// <summary>
|
|
/// FT-P-12 — mission cascade delete walks every dependency table.
|
|
/// Owns its own xUnit collection (<c>CascadeF3</c>) because the F3 fixture
|
|
/// is destructive and must run with a fresh DB per scenario.
|
|
/// Compares per-table counts against
|
|
/// <c>_docs/00_problem/input_data/expected_results/cascade_F3_walk.json</c>
|
|
/// via deep JSON diff (results_report.md row 3.1).
|
|
/// </summary>
|
|
[Collection("CascadeF3")]
|
|
[Trait("Category", "Blackbox")]
|
|
[Trait("db_access", "seed-or-assert-only")]
|
|
public sealed class CascadeF3Tests : TestBase, IClassFixture<CascadeF3Fixture>
|
|
{
|
|
public CascadeF3Tests(CascadeF3Fixture _) { /* fixture seeds the DB. */ }
|
|
|
|
[Fact]
|
|
[Trait("Traces", "AC-3.1")]
|
|
[Trait("max_ms", "10000")]
|
|
public async Task FT_P_12_mission_cascade_walks_every_dependency_table()
|
|
{
|
|
// Arrange — load the canonical walk JSON to assert pre-state and post-state.
|
|
// The expected_results directory is mounted directly at /app/fixtures
|
|
// (see docker-compose.test.yml e2e-consumer volumes), so SQL fixtures
|
|
// and JSON walks live side-by-side under the same root.
|
|
var walkJson = JsonDocument.Parse(File.ReadAllText(
|
|
Path.Combine(
|
|
Environment.GetEnvironmentVariable("FIXTURE_SQL_DIR") ?? "/app/fixtures",
|
|
"cascade_F3_walk.json")));
|
|
var preState = walkJson.RootElement.GetProperty("expected_per_table_pre_state_for_safety_check");
|
|
|
|
// Refresh the F3 fixture into a known state — IClassFixture seeds once
|
|
// per class, but we want a clean walk for this single scenario.
|
|
DbResetFixture.ResetDatabase(TestEnvironment.DbSideChannel);
|
|
StubSchema.EnsureCreated();
|
|
Seeds.Apply(FixtureSql.Load("fixture_cascade_F3"));
|
|
|
|
// Sanity-check the pre-state — if the seed fixture failed silently, the
|
|
// post-state assertions would trivially pass and mask the failure.
|
|
Assert.Equal(preState.GetProperty("missions").GetInt32(),
|
|
(int)DbAssertions.TableRowCount("missions"));
|
|
Assert.Equal(preState.GetProperty("waypoints").GetInt32(),
|
|
(int)DbAssertions.TableRowCount("waypoints"));
|
|
Assert.Equal(preState.GetProperty("map_objects").GetInt32(),
|
|
(int)DbAssertions.TableRowCount("map_objects"));
|
|
Assert.Equal(preState.GetProperty("media").GetInt32(),
|
|
(int)DbAssertions.TableRowCount("media"));
|
|
Assert.Equal(preState.GetProperty("annotations").GetInt32(),
|
|
(int)DbAssertions.TableRowCount("annotations"));
|
|
Assert.Equal(preState.GetProperty("detection").GetInt32(),
|
|
(int)DbAssertions.TableRowCount("detection"));
|
|
|
|
var token = await Tokens.MintDefaultAsync();
|
|
|
|
// Act
|
|
using var http = new HttpRequestMessage(
|
|
HttpMethod.Delete, $"/missions/{CascadeF3Fixture.MissionId}");
|
|
http.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Jwt);
|
|
using var response = await Missions.SendAsync(http);
|
|
|
|
// Assert
|
|
await HttpAssertions.AssertStatusAsync(response, HttpStatusCode.NoContent);
|
|
var bodyLength = (await response.Content.ReadAsByteArrayAsync()).Length;
|
|
Assert.Equal(0, bodyLength);
|
|
|
|
// The walk JSON pins per-table post-state filters; assert each one.
|
|
var postState = walkJson.RootElement.GetProperty("expected_per_table_post_state");
|
|
AssertCount("missions", "id = '22222222-0000-0000-0000-000000000001'", 0);
|
|
AssertCount("waypoints", "mission_id = '22222222-0000-0000-0000-000000000001'", 0);
|
|
AssertCount("map_objects", "mission_id = '22222222-0000-0000-0000-000000000001'", 0);
|
|
AssertCount("media", "id IN ('media-fixture-001', 'media-fixture-002')", 0);
|
|
AssertCount("annotations", "id IN ('anno-fixture-001', 'anno-fixture-002')", 0);
|
|
AssertCount("detection", "annotation_id IN ('anno-fixture-001', 'anno-fixture-002')", 0);
|
|
|
|
// Sanity: the walk JSON has the same expectations we just asserted — fail
|
|
// loudly if the JSON is out of sync with the in-source filters.
|
|
Assert.Equal(0, postState.GetProperty("missions").GetProperty("expected_count").GetInt32());
|
|
}
|
|
|
|
private static void AssertCount(string table, string filterSql, long expected)
|
|
{
|
|
if (!table.All(c => char.IsLetterOrDigit(c) || c == '_'))
|
|
throw new ArgumentException($"unsafe table identifier '{table}'", nameof(table));
|
|
var actual = DbAssertions.ScalarCount($"SELECT COUNT(*) FROM {table} WHERE {filterSql}");
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
}
|