Files
missions/tests/Azaion.Missions.E2E.Tests/Fixtures/Seeds.cs
T
Oleksandr Bezdieniezhnykh 6b2c2d998e [AZ-577] [AZ-578] [AZ-579] [AZ-580] Implement E2E test batch 2
Adds 26 blackbox tests (FT-P-01..18, FT-N-01..08) covering full AC
matrices for Vehicles/Missions/Waypoints/Health/Errors. Three
spec-vs-code carry-forwards documented in batch_02_report.md and
pinned with [Trait("carry_forward", ...)].

Shared scaffolding: ApiDtos.cs, AssertProblemEnvelopeAsync helper,
Seeds.cs, StubSchema.cs, CascadeF3/F4 fixtures, PostgresStopStart
fixture (gated by COMPOSE_RESTART_ENABLED). Removes the 4 placeholder
Sanity.cs files (now superseded). docker-compose.test.yml gains the
expected_results volume mount + FIXTURE_SQL_DIR for the consumer.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 08:28:37 +03:00

171 lines
7.7 KiB
C#

using Npgsql;
namespace Azaion.Missions.E2E.Fixtures;
/// <summary>
/// Inline seed-data definitions referenced by name from
/// <c>_docs/02_document/tests/test-data.md § Seed Data Sets</c>. Each seed
/// is idempotent against a freshly-reset DB (callers must run
/// <see cref="DbResetFixture.ResetDatabase(string)"/> first; the
/// <see cref="DbSeedFixture{TSeed}"/> base does this automatically).
/// </summary>
/// <remarks>
/// UUIDs are deterministic so assertions can reference them directly without
/// having to first read them back. Seeds insert rows that satisfy every
/// schema constraint — including the partial unique index
/// <c>ux_vehicles_one_default</c> (a fixture cannot stage two
/// is_default=true rows even though the test name suggests it).
/// </remarks>
public static class Seeds
{
/// <summary>seed_one_default_vehicle: a single Bayraktar with is_default=true.</summary>
public static class OneDefaultVehicle
{
public static readonly Guid Id =
Guid.Parse("11111111-1111-1111-1111-000000000001");
public const string Sql = """
INSERT INTO vehicles
(id, type, model, name, fuel_type, battery_capacity,
engine_consumption, engine_consumption_idle, is_default)
VALUES
('11111111-1111-1111-1111-000000000001',
0, 'Bayraktar', 'BR-default', 1, 0, 5, 1, true);
""";
}
/// <summary>
/// seed_3_vehicles_2_default — name-misleading: only ONE row is default
/// because the partial unique index <c>ux_vehicles_one_default</c> rejects
/// two. The "2" in the name historically referred to a pre-B12 variant
/// allowing two defaults; today only BR-01 carries the flag. This still
/// satisfies every consumer scenario (FT-P-04 ordering, FT-P-05 filter,
/// FT-N-01 no-match) — none of them require >1 default.
///
/// Insert order is reverse-alphabetic ([MQ-9, BR-02, BR-01]) so an
/// ordering bug in the SUT (missing OrderBy) would surface immediately
/// — see Risk #2 in _docs/tasks/done/AZ-577_test_vehicles_positive.md.
/// </summary>
public static class Three_BR01_BR02_MQ9
{
public static readonly Guid IdBr01 =
Guid.Parse("11111111-2222-3333-4444-000000000001");
public static readonly Guid IdBr02 =
Guid.Parse("11111111-2222-3333-4444-000000000002");
public static readonly Guid IdMq9 =
Guid.Parse("11111111-2222-3333-4444-000000000003");
public const string Sql = """
INSERT INTO vehicles
(id, type, model, name, fuel_type, battery_capacity,
engine_consumption, engine_consumption_idle, is_default)
VALUES
('11111111-2222-3333-4444-000000000003',
0, 'Bayraktar', 'MQ-9', 1, 0, 5, 1, false),
('11111111-2222-3333-4444-000000000002',
0, 'Bayraktar', 'BR-02', 1, 0, 5, 1, false),
('11111111-2222-3333-4444-000000000001',
0, 'Bayraktar', 'BR-01', 1, 0, 5, 1, true);
""";
}
/// <summary>
/// seed_25_missions: 5 in January 2026, 20 in February 2026; CreatedDate
/// values are spaced ≥ 1 second apart so DESC ordering is deterministic
/// (FT-P-08 risk #2). Names alternate between "Recon-N" and "OPS-N" so
/// the case-INSENSITIVE name=re filter returns >0 rows.
/// </summary>
public static class TwentyFiveMissions
{
public static readonly Guid VehicleId =
Guid.Parse("11111111-aaaa-aaaa-aaaa-000000000001");
// The 5 January CreatedDate values are 2026-01-15T10:00:[00..04]Z so
// every mission has a distinct, deterministic CreatedDate.
public static string Sql
{
get
{
var sb = new System.Text.StringBuilder();
sb.AppendLine("""
INSERT INTO vehicles
(id, type, model, name, fuel_type, battery_capacity,
engine_consumption, engine_consumption_idle, is_default)
VALUES
('11111111-aaaa-aaaa-aaaa-000000000001',
0, 'Bayraktar', 'BR-fixture-25', 1, 0, 5, 1, false);
""");
sb.AppendLine("INSERT INTO missions (id, created_date, name, vehicle_id) VALUES");
for (var i = 0; i < 25; i++)
{
var month = i < 5 ? "01" : "02";
var day = i < 5 ? (15 + i).ToString("D2") : (1 + (i - 5)).ToString("D2");
var second = (i % 60).ToString("D2");
var minute = ((i / 60) % 60).ToString("D2");
var name = (i % 2 == 0) ? $"Recon-{i:D2}" : $"OPS-{i:D2}";
var idHex = (i + 1).ToString("D12");
sb.Append("('22222222-bbbb-bbbb-bbbb-").Append(idHex).Append("', ");
sb.Append("'2026-").Append(month).Append('-').Append(day);
sb.Append('T').Append("10:").Append(minute).Append(':').Append(second).Append("Z', ");
sb.Append('\'').Append(name).Append("', ");
sb.Append("'11111111-aaaa-aaaa-aaaa-000000000001')");
sb.AppendLine(i == 24 ? ";" : ",");
}
return sb.ToString();
}
}
}
/// <summary>
/// seed_5_waypoints_unordered: 5 waypoints under one mission with
/// OrderNum values [3, 1, 2, 5, 4] inserted in that order. The shuffled
/// insert order forces FT-P-13 to fail loudly if the SUT forgets the
/// OrderBy(w => w.OrderNum) clause.
/// </summary>
public static class FiveWaypointsUnordered
{
public static readonly Guid VehicleId =
Guid.Parse("11111111-cccc-cccc-cccc-000000000001");
public static readonly Guid MissionId =
Guid.Parse("22222222-cccc-cccc-cccc-000000000001");
public const string Sql = """
INSERT INTO vehicles
(id, type, model, name, fuel_type, battery_capacity,
engine_consumption, engine_consumption_idle, is_default)
VALUES
('11111111-cccc-cccc-cccc-000000000001',
0, 'Bayraktar', 'BR-wp-fixture', 1, 0, 5, 1, false);
INSERT INTO missions (id, created_date, name, vehicle_id)
VALUES
('22222222-cccc-cccc-cccc-000000000001',
'2026-05-14T00:00:00Z', 'wp-fixture', '11111111-cccc-cccc-cccc-000000000001');
INSERT INTO waypoints
(id, mission_id, lat, lon, mgrs, waypoint_source,
waypoint_objective, order_num, height)
VALUES
('33333333-cccc-cccc-cccc-000000000001',
'22222222-cccc-cccc-cccc-000000000001', 50.45, 30.52, NULL, 0, 0, 3, 100),
('33333333-cccc-cccc-cccc-000000000002',
'22222222-cccc-cccc-cccc-000000000001', 50.46, 30.53, NULL, 0, 0, 1, 110),
('33333333-cccc-cccc-cccc-000000000003',
'22222222-cccc-cccc-cccc-000000000001', 50.47, 30.54, NULL, 0, 0, 2, 120),
('33333333-cccc-cccc-cccc-000000000004',
'22222222-cccc-cccc-cccc-000000000001', 50.48, 30.55, NULL, 0, 0, 5, 130),
('33333333-cccc-cccc-cccc-000000000005',
'22222222-cccc-cccc-cccc-000000000001', 50.49, 30.56, NULL, 0, 0, 4, 140);
""";
}
public static void Apply(string sql)
{
using var conn = new NpgsqlConnection(TestEnvironment.DbSideChannel);
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
}
}