mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-21 08:31:14 +00:00
fcd494f67e
Mirror of AZ-794 (inventory z/x/y rename). RequestRegionRequest.cs renames C#
props Latitude→Lat / Longitude→Lon and adds [JsonPropertyName("lat"/"lon")] so
the wire format is unambiguous under the AZ-795 strict-parsing stack
(UnmappedMemberHandling.Disallow → legacy {"latitude":..,"longitude":..} now
returns HTTP 400 instead of silently coercing).
Updates all in-repo consumers: API handler (Program.cs), integration tests
(Models.cs, RegionTests.cs, IdempotentPostTests.cs, SecurityTests.cs), the
performance harness (run-performance-tests.sh PT-03/04/05/07), and module
docs (common_dtos.md, api_program.md; system-flows.md F2 already used
lat/lon). New RegionFieldRenameTests.cs covers AC-4 both directions (new
format → 200, legacy format → 400). Smoke green; no regressions.
region-request.md contract doc not bumped here — AZ-808 publishes v1.0.0
directly with the post-rename names per AZ-812 coordination clause.
Batch 01 of cycle 8. PASS_WITH_WARNINGS (one Low DRY finding for follow-up
test-helper consolidation; details in
_docs/03_implementation/reviews/batch_01_cycle8_review.md).
Co-authored-by: Cursor <cursoragent@cursor.com>
112 lines
4.5 KiB
C#
112 lines
4.5 KiB
C#
using System.Net.Http.Json;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace SatelliteProvider.IntegrationTests;
|
|
|
|
// AZ-812: wire-format rename for POST /api/satellite/request.
|
|
// `RequestRegionRequest` now uses `lat`/`lon` (OSM convention) on the wire,
|
|
// replacing the previous verbose `latitude`/`longitude`. The strict-parsing
|
|
// infrastructure landed by AZ-795 (UnmappedMemberHandling.Disallow +
|
|
// GlobalExceptionHandler) means the old wire format must now be rejected
|
|
// explicitly, not silently coerced. AC-4 from the AZ-812 task spec.
|
|
public static class RegionFieldRenameTests
|
|
{
|
|
private const string RegionPath = "/api/satellite/request";
|
|
|
|
public static async Task RunAll(HttpClient httpClient)
|
|
{
|
|
RouteTestHelpers.PrintTestHeader("Test: Region endpoint OSM field-name rename (AZ-812)");
|
|
|
|
await NewLatLonFormat_Returns200(httpClient);
|
|
await OldLatitudeLongitudeFormat_Returns400(httpClient);
|
|
|
|
Console.WriteLine("✓ Region field-rename tests: PASSED");
|
|
}
|
|
|
|
private static async Task NewLatLonFormat_Returns200(HttpClient httpClient)
|
|
{
|
|
Console.WriteLine();
|
|
Console.WriteLine("AZ-812 AC-4 (positive): new {lat,lon} wire format → HTTP 200");
|
|
|
|
// Arrange
|
|
var regionId = Guid.NewGuid();
|
|
var body = $"{{\"id\":\"{regionId}\",\"lat\":47.461747,\"lon\":37.647063,\"sizeMeters\":200,\"zoomLevel\":18,\"stitchTiles\":false}}";
|
|
|
|
// Act
|
|
var response = await PostJsonAsync(httpClient, body);
|
|
var status = (int)response.StatusCode;
|
|
var responseBody = await response.Content.ReadAsStringAsync();
|
|
|
|
// Assert
|
|
if (status != 200)
|
|
{
|
|
throw new Exception($"AZ-812 AC-4 positive: expected HTTP 200 for {{lat,lon}} body, got {status}. Body: {responseBody}");
|
|
}
|
|
|
|
Console.WriteLine(" ✓ {lat,lon} body accepted with HTTP 200");
|
|
}
|
|
|
|
private static async Task OldLatitudeLongitudeFormat_Returns400(HttpClient httpClient)
|
|
{
|
|
Console.WriteLine();
|
|
Console.WriteLine("AZ-812 AC-4 (negative): legacy {latitude,longitude} wire format → HTTP 400 (UnmappedMemberHandling.Disallow)");
|
|
|
|
// Arrange — exact pre-AZ-812 wire format; must now fail explicitly instead
|
|
// of silently mapping to the renamed Lat/Lon properties.
|
|
var regionId = Guid.NewGuid();
|
|
var body = $"{{\"id\":\"{regionId}\",\"latitude\":47.461747,\"longitude\":37.647063,\"sizeMeters\":200,\"zoomLevel\":18,\"stitchTiles\":false}}";
|
|
|
|
// Act
|
|
var response = await PostJsonAsync(httpClient, body);
|
|
var problem = await ProblemDetailsAssertions.ReadProblemDetailsAsync(response, "AZ-812 legacy field names");
|
|
|
|
// Assert
|
|
ProblemDetailsAssertions.AssertValidationProblem(problem, expectedStatus: 400, label: "AZ-812 legacy field names");
|
|
AssertErrorsContainsMention(problem, expectedMention: "latitude", label: "AZ-812 legacy field names");
|
|
|
|
Console.WriteLine(" ✓ Legacy {latitude,longitude} body rejected with HTTP 400; errors map names the unknown field");
|
|
}
|
|
|
|
private static Task<HttpResponseMessage> PostJsonAsync(HttpClient httpClient, string body)
|
|
{
|
|
var content = new StringContent(body, Encoding.UTF8, "application/json");
|
|
return httpClient.PostAsync(RegionPath, content);
|
|
}
|
|
|
|
private static void AssertErrorsContainsMention(JsonElement problem, string expectedMention, string label)
|
|
{
|
|
if (!problem.TryGetProperty("errors", out var errorsEl) || errorsEl.ValueKind != JsonValueKind.Object)
|
|
{
|
|
throw new Exception($"{label}: expected 'errors' object in ProblemDetails body.");
|
|
}
|
|
|
|
var found = false;
|
|
foreach (var prop in errorsEl.EnumerateObject())
|
|
{
|
|
if (prop.Name.Contains(expectedMention, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
foreach (var msg in prop.Value.EnumerateArray())
|
|
{
|
|
if (msg.GetString()?.Contains(expectedMention, StringComparison.OrdinalIgnoreCase) == true)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found) break;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
var paths = string.Join(", ", errorsEl.EnumerateObject().Select(p => p.Name));
|
|
throw new Exception($"{label}: expected '{expectedMention}' to appear in errors keys or messages. Available paths: {paths}.");
|
|
}
|
|
}
|
|
}
|