mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-04-22 09:06:38 +00:00
tests cleanup
This commit is contained in:
@@ -33,7 +33,7 @@
|
|||||||
},
|
},
|
||||||
"ProcessingConfig": {
|
"ProcessingConfig": {
|
||||||
"MaxConcurrentDownloads": 4,
|
"MaxConcurrentDownloads": 4,
|
||||||
"MaxConcurrentRegions": 3,
|
"MaxConcurrentRegions": 20,
|
||||||
"DefaultZoomLevel": 20,
|
"DefaultZoomLevel": 20,
|
||||||
"QueueCapacity": 1000,
|
"QueueCapacity": 1000,
|
||||||
"DelayBetweenRequestsMs": 50,
|
"DelayBetweenRequestsMs": 50,
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
using System.Net.Http.Json;
|
||||||
|
|
||||||
|
namespace SatelliteProvider.IntegrationTests;
|
||||||
|
|
||||||
|
public static class BasicRouteTests
|
||||||
|
{
|
||||||
|
public static async Task RunSimpleRouteTest(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
RouteTestHelpers.PrintSectionHeader("Test: Create Simple Route with Two Points");
|
||||||
|
|
||||||
|
var routeId = Guid.NewGuid();
|
||||||
|
var request = new CreateRouteRequest
|
||||||
|
{
|
||||||
|
Id = routeId,
|
||||||
|
Name = "Simple Test Route",
|
||||||
|
Description = "Test route with 2 points",
|
||||||
|
RegionSizeMeters = 500.0,
|
||||||
|
ZoomLevel = 18,
|
||||||
|
Points = new List<RoutePointInput>
|
||||||
|
{
|
||||||
|
new() { Lat = 48.276067180586544, Lon = 37.38445758819581 },
|
||||||
|
new() { Lat = 48.27074009522731, Lon = 37.374029159545906 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine($"Creating route with 2 points:");
|
||||||
|
Console.WriteLine($" Start: ({request.Points[0].Lat}, {request.Points[0].Lon})");
|
||||||
|
Console.WriteLine($" End: ({request.Points[1].Lat}, {request.Points[1].Lon})");
|
||||||
|
Console.WriteLine($" Region Size: {request.RegionSizeMeters}m");
|
||||||
|
Console.WriteLine($" Zoom Level: {request.ZoomLevel}");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var route = await RouteTestHelpers.CreateRoute(httpClient, request);
|
||||||
|
|
||||||
|
Console.WriteLine("Route Details:");
|
||||||
|
Console.WriteLine($" ID: {route.Id}");
|
||||||
|
Console.WriteLine($" Name: {route.Name}");
|
||||||
|
Console.WriteLine($" Total Points: {route.TotalPoints}");
|
||||||
|
Console.WriteLine($" Total Distance: {route.TotalDistanceMeters:F2}m");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintPointTypeDistribution(route);
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidatePointTypes(route, 1, 1, 0);
|
||||||
|
|
||||||
|
Console.WriteLine("Point spacing validation:");
|
||||||
|
for (int i = 1; i < route.Points.Count; i++)
|
||||||
|
{
|
||||||
|
var point = route.Points[i];
|
||||||
|
if (point.DistanceFromPrevious.HasValue)
|
||||||
|
{
|
||||||
|
if (point.DistanceFromPrevious.Value > 200.0)
|
||||||
|
{
|
||||||
|
throw new Exception($"Point {i} is {point.DistanceFromPrevious.Value:F2}m from previous, exceeds 200m limit");
|
||||||
|
}
|
||||||
|
Console.WriteLine($" Point {i} ({point.PointType}): {point.DistanceFromPrevious.Value:F2}m from previous");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
Console.WriteLine("Retrieving route by ID...");
|
||||||
|
var getResponse = await httpClient.GetAsync($"/api/satellite/route/{routeId}");
|
||||||
|
|
||||||
|
if (!getResponse.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new Exception($"Failed to retrieve route: {getResponse.StatusCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var retrievedRoute = await getResponse.Content.ReadFromJsonAsync<RouteResponseModel>(new System.Text.Json.JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (retrievedRoute == null || retrievedRoute.Id != routeId)
|
||||||
|
{
|
||||||
|
throw new Exception("Retrieved route does not match created route");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"✓ Route retrieved successfully");
|
||||||
|
Console.WriteLine($"✓ Retrieved {retrievedRoute.Points.Count} points");
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("✓ Route created successfully");
|
||||||
|
Console.WriteLine("✓ All point spacing validated (≤ 200m)");
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Simple Route Test: PASSED");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task RunRouteWithRegionProcessingAndStitching(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
RouteTestHelpers.PrintTestHeader("Test: Route with Region Processing and Full Map Stitching (Service-Level)");
|
||||||
|
|
||||||
|
var routeId = Guid.NewGuid();
|
||||||
|
var request = new CreateRouteRequest
|
||||||
|
{
|
||||||
|
Id = routeId,
|
||||||
|
Name = "Route with Region Processing",
|
||||||
|
Description = "Test route that processes regions for all points and stitches a full map",
|
||||||
|
RegionSizeMeters = 300.0,
|
||||||
|
ZoomLevel = 18,
|
||||||
|
RequestMaps = true,
|
||||||
|
Points = new List<RoutePointInput>
|
||||||
|
{
|
||||||
|
new() { Lat = 48.276067180586544, Lon = 37.38445758819581 },
|
||||||
|
new() { Lat = 48.27074009522731, Lon = 37.374029159545906 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine("Step 1: Creating route with RequestMaps=true");
|
||||||
|
Console.WriteLine($" Start: ({request.Points[0].Lat}, {request.Points[0].Lon})");
|
||||||
|
Console.WriteLine($" End: ({request.Points[1].Lat}, {request.Points[1].Lon})");
|
||||||
|
Console.WriteLine($" Region Size: {request.RegionSizeMeters}m");
|
||||||
|
Console.WriteLine($" Zoom Level: {request.ZoomLevel}");
|
||||||
|
Console.WriteLine($" Request Maps: {request.RequestMaps}");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var route = await RouteTestHelpers.CreateRoute(httpClient, request);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintRouteResponse(route);
|
||||||
|
RouteTestHelpers.ValidateRequestMaps(route, false);
|
||||||
|
|
||||||
|
Console.WriteLine("Step 2: Waiting for route maps to be ready");
|
||||||
|
Console.WriteLine(" (Service is processing regions SEQUENTIALLY to avoid API throttling)");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var finalRoute = await RouteTestHelpers.WaitForRouteReady(httpClient, routeId, 180, 3000);
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Step 3: Verifying generated files");
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidateFiles(finalRoute);
|
||||||
|
|
||||||
|
var uniqueTileCount = await RouteTestHelpers.GetUniqueTileCount(finalRoute.CsvFilePath!);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintGeneratedFiles(finalRoute, uniqueTileCount);
|
||||||
|
RouteTestHelpers.PrintRouteSummary(finalRoute, uniqueTileCount);
|
||||||
|
|
||||||
|
Console.WriteLine("✓ Route with Region Processing and Stitching Test: PASSED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
namespace SatelliteProvider.IntegrationTests;
|
||||||
|
|
||||||
|
public static class ComplexRouteTests
|
||||||
|
{
|
||||||
|
public static async Task RunComplexRouteWithStitching(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
RouteTestHelpers.PrintTestHeader("Test: Complex Route with 10 Points + 2 Geofences - Region Processing and Stitching");
|
||||||
|
|
||||||
|
var routeId = Guid.NewGuid();
|
||||||
|
var request = new CreateRouteRequest
|
||||||
|
{
|
||||||
|
Id = routeId,
|
||||||
|
Name = "Complex Route with 10 Points + 2 Geofences",
|
||||||
|
Description = "Test route with 10 action points and 2 geofence regions for complex map stitching",
|
||||||
|
RegionSizeMeters = 300.0,
|
||||||
|
ZoomLevel = 18,
|
||||||
|
RequestMaps = true,
|
||||||
|
Points = new List<RoutePointInput>
|
||||||
|
{
|
||||||
|
new() { Lat = 48.276067180586544, Lon = 37.38445758819581 },
|
||||||
|
new() { Lat = 48.27074009522731, Lon = 37.374029159545906 },
|
||||||
|
new() { Lat = 48.263312668696855, Lon = 37.37707614898682 },
|
||||||
|
new() { Lat = 48.26539817051818, Lon = 37.36587524414063 },
|
||||||
|
new() { Lat = 48.25851283439989, Lon = 37.35952377319337 },
|
||||||
|
new() { Lat = 48.254426906081555, Lon = 37.374801635742195 },
|
||||||
|
new() { Lat = 48.25914140977405, Lon = 37.39068031311036 },
|
||||||
|
new() { Lat = 48.25354110233028, Lon = 37.401752471923835 },
|
||||||
|
new() { Lat = 48.25902712391726, Lon = 37.416257858276374 },
|
||||||
|
new() { Lat = 48.26828345053738, Lon = 37.402009963989265 }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine("Step 1: Creating complex route with RequestMaps=true and 2 geofences");
|
||||||
|
Console.WriteLine($" Action Points: {request.Points.Count}");
|
||||||
|
Console.WriteLine($" NO Geofences Regions");
|
||||||
|
RouteTestHelpers.PrintRouteCreationDetails(request);
|
||||||
|
RouteTestHelpers.PrintRoutePoints(request.Points);
|
||||||
|
|
||||||
|
var route = await RouteTestHelpers.CreateRoute(httpClient, request);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintRouteResponse(route);
|
||||||
|
RouteTestHelpers.PrintPointTypeDistribution(route);
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidatePointTypes(route, 1, 1, 8);
|
||||||
|
RouteTestHelpers.ValidateRequestMaps(route, false);
|
||||||
|
|
||||||
|
Console.WriteLine("Step 2: Waiting for complex route maps to be ready");
|
||||||
|
Console.WriteLine(" (Processing route point regions + 2 geofence regions SEQUENTIALLY to avoid API throttling)");
|
||||||
|
Console.WriteLine(" (This will take several minutes as each region is processed one at a time)");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var finalRoute = await RouteTestHelpers.WaitForRouteReady(httpClient, routeId, 240, 3000);
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Step 3: Verifying generated files");
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidateFiles(finalRoute);
|
||||||
|
|
||||||
|
var uniqueTileCount = await RouteTestHelpers.GetUniqueTileCount(finalRoute.CsvFilePath!);
|
||||||
|
var stitchedInfo = new FileInfo(finalRoute.StitchedImagePath!);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintGeneratedFiles(finalRoute, uniqueTileCount);
|
||||||
|
RouteTestHelpers.PrintRouteSummary(finalRoute, uniqueTileCount, 2);
|
||||||
|
|
||||||
|
if (uniqueTileCount < 10)
|
||||||
|
{
|
||||||
|
throw new Exception($"Expected at least 10 unique tiles for complex route with geofences, got {uniqueTileCount}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stitchedInfo.Length < 1024)
|
||||||
|
{
|
||||||
|
throw new Exception($"Stitched image seems too small: {stitchedInfo.Length} bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("✓ Complex Route with 10 Points + 2 Geofences Test: PASSED");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task RunComplexRouteWithStitchingAndGeofences(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
RouteTestHelpers.PrintTestHeader("Test: Complex Route with 10 Points + 2 Geofences - Region Processing and Stitching");
|
||||||
|
|
||||||
|
var routeId = Guid.NewGuid();
|
||||||
|
var request = new CreateRouteRequest
|
||||||
|
{
|
||||||
|
Id = routeId,
|
||||||
|
Name = "Complex Route with 10 Points + 2 Geofences",
|
||||||
|
Description = "Test route with 10 action points and 2 geofence regions for complex map stitching",
|
||||||
|
RegionSizeMeters = 300.0,
|
||||||
|
ZoomLevel = 18,
|
||||||
|
RequestMaps = true,
|
||||||
|
Points = new List<RoutePointInput>
|
||||||
|
{
|
||||||
|
new() { Lat = 48.276067180586544, Lon = 37.38445758819581 },
|
||||||
|
new() { Lat = 48.27074009522731, Lon = 37.374029159545906 },
|
||||||
|
new() { Lat = 48.263312668696855, Lon = 37.37707614898682 },
|
||||||
|
new() { Lat = 48.26539817051818, Lon = 37.36587524414063 },
|
||||||
|
new() { Lat = 48.25851283439989, Lon = 37.35952377319337 },
|
||||||
|
new() { Lat = 48.254426906081555, Lon = 37.374801635742195 },
|
||||||
|
new() { Lat = 48.25914140977405, Lon = 37.39068031311036 },
|
||||||
|
new() { Lat = 48.25354110233028, Lon = 37.401752471923835 },
|
||||||
|
new() { Lat = 48.25902712391726, Lon = 37.416257858276374 },
|
||||||
|
new() { Lat = 48.26828345053738, Lon = 37.402009963989265 }
|
||||||
|
},
|
||||||
|
Geofences = new GeofencesInput
|
||||||
|
{
|
||||||
|
Polygons = new List<GeofencePolygonInput>
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
NorthWest = new GeoPointInput { Lat = 48.28022277841604, Lon = 37.37548828125001 },
|
||||||
|
SouthEast = new GeoPointInput { Lat = 48.2720540660028, Lon = 37.3901653289795 }
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
NorthWest = new GeoPointInput { Lat = 48.2614270732573, Lon = 37.35239982604981 },
|
||||||
|
SouthEast = new GeoPointInput { Lat = 48.24988342757033, Lon = 37.37943649291993 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine("Step 1: Creating complex route with RequestMaps=true and 2 geofences");
|
||||||
|
RouteTestHelpers.PrintRouteCreationDetails(request, true);
|
||||||
|
RouteTestHelpers.PrintGeofences(request.Geofences.Polygons);
|
||||||
|
RouteTestHelpers.PrintRoutePoints(request.Points);
|
||||||
|
|
||||||
|
var route = await RouteTestHelpers.CreateRoute(httpClient, request);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintRouteResponse(route);
|
||||||
|
RouteTestHelpers.PrintPointTypeDistribution(route);
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidatePointTypes(route, 1, 1, 8);
|
||||||
|
RouteTestHelpers.ValidateRequestMaps(route, false);
|
||||||
|
|
||||||
|
Console.WriteLine("Step 2: Waiting for complex route maps to be ready");
|
||||||
|
Console.WriteLine(" (Processing route point regions + 2 geofence regions SEQUENTIALLY to avoid API throttling)");
|
||||||
|
Console.WriteLine(" (This will take several minutes as each region is processed one at a time)");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var finalRoute = await RouteTestHelpers.WaitForRouteReady(httpClient, routeId, 240, 3000);
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Step 3: Verifying generated files");
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidateFiles(finalRoute);
|
||||||
|
|
||||||
|
var uniqueTileCount = await RouteTestHelpers.GetUniqueTileCount(finalRoute.CsvFilePath!);
|
||||||
|
var stitchedInfo = new FileInfo(finalRoute.StitchedImagePath!);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintGeneratedFiles(finalRoute, uniqueTileCount);
|
||||||
|
RouteTestHelpers.PrintRouteSummary(finalRoute, uniqueTileCount, 2);
|
||||||
|
|
||||||
|
if (uniqueTileCount < 10)
|
||||||
|
{
|
||||||
|
throw new Exception($"Expected at least 10 unique tiles for complex route with geofences, got {uniqueTileCount}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stitchedInfo.Length < 1024)
|
||||||
|
{
|
||||||
|
throw new Exception($"Stitched image seems too small: {stitchedInfo.Length} bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("✓ Complex Route with 10 Points + 2 Geofences Test: PASSED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
namespace SatelliteProvider.IntegrationTests;
|
||||||
|
|
||||||
|
public static class ExtendedRouteTests
|
||||||
|
{
|
||||||
|
public static async Task RunExtendedRouteEast(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
RouteTestHelpers.PrintTestHeader("Test: Extended Route with 20 Points - 10km East");
|
||||||
|
|
||||||
|
var routeId = Guid.NewGuid();
|
||||||
|
var request = new CreateRouteRequest
|
||||||
|
{
|
||||||
|
Id = routeId,
|
||||||
|
Name = "Extended Route with 20 Points (10km East)",
|
||||||
|
Description = "Test route with 20 action points, located 10km east of the complex route",
|
||||||
|
RegionSizeMeters = 300.0,
|
||||||
|
ZoomLevel = 18,
|
||||||
|
RequestMaps = true,
|
||||||
|
Points = new List<RoutePointInput>
|
||||||
|
{
|
||||||
|
new() { Lat = 48.276067180586544, Lon = 37.51945758819581 },
|
||||||
|
new() { Lat = 48.27074009522731, Lon = 37.509029159545906 },
|
||||||
|
new() { Lat = 48.263312668696855, Lon = 37.51207614898682 },
|
||||||
|
new() { Lat = 48.26539817051818, Lon = 37.50087524414063 },
|
||||||
|
new() { Lat = 48.25851283439989, Lon = 37.49452377319337 },
|
||||||
|
new() { Lat = 48.254426906081555, Lon = 37.509801635742195 },
|
||||||
|
new() { Lat = 48.25914140977405, Lon = 37.52568031311036 },
|
||||||
|
new() { Lat = 48.25354110233028, Lon = 37.536752471923835 },
|
||||||
|
new() { Lat = 48.25902712391726, Lon = 37.551257858276374 },
|
||||||
|
new() { Lat = 48.26828345053738, Lon = 37.537009963989265 },
|
||||||
|
new() { Lat = 48.27421563182974, Lon = 37.52345758819581 },
|
||||||
|
new() { Lat = 48.26889854647051, Lon = 37.513029159545906 },
|
||||||
|
new() { Lat = 48.26147111993905, Lon = 37.51607614898682 },
|
||||||
|
new() { Lat = 48.26355662176038, Lon = 37.50487524414063 },
|
||||||
|
new() { Lat = 48.25667128564209, Lon = 37.49852377319337 },
|
||||||
|
new() { Lat = 48.25258535732375, Lon = 37.513801635742195 },
|
||||||
|
new() { Lat = 48.25729986101625, Lon = 37.52968031311036 },
|
||||||
|
new() { Lat = 48.25169955357248, Lon = 37.540752471923835 },
|
||||||
|
new() { Lat = 48.25718557515946, Lon = 37.555257858276374 },
|
||||||
|
new() { Lat = 48.26644190177958, Lon = 37.541009963989265 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine("Step 1: Creating extended route with RequestMaps=true");
|
||||||
|
RouteTestHelpers.PrintRouteCreationDetails(request);
|
||||||
|
Console.WriteLine($" Location: ~10km east of original complex route");
|
||||||
|
Console.WriteLine();
|
||||||
|
RouteTestHelpers.PrintRoutePoints(request.Points, 5);
|
||||||
|
|
||||||
|
var route = await RouteTestHelpers.CreateRoute(httpClient, request);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintRouteResponse(route);
|
||||||
|
RouteTestHelpers.PrintPointTypeDistribution(route);
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidatePointTypes(route, 1, 1, 18);
|
||||||
|
RouteTestHelpers.ValidateRequestMaps(route, false);
|
||||||
|
|
||||||
|
Console.WriteLine("Step 2: Waiting for extended route maps to be ready");
|
||||||
|
Console.WriteLine(" (Processing regions SEQUENTIALLY to avoid API throttling)");
|
||||||
|
Console.WriteLine(" (This will take several minutes for 20 action points)");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var finalRoute = await RouteTestHelpers.WaitForRouteReady(httpClient, routeId, 360, 3000);
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Step 3: Verifying generated files");
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidateFiles(finalRoute);
|
||||||
|
|
||||||
|
var uniqueTileCount = await RouteTestHelpers.GetUniqueTileCount(finalRoute.CsvFilePath!);
|
||||||
|
var stitchedInfo = new FileInfo(finalRoute.StitchedImagePath!);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintGeneratedFiles(finalRoute, uniqueTileCount);
|
||||||
|
RouteTestHelpers.PrintRouteSummary(finalRoute, uniqueTileCount);
|
||||||
|
|
||||||
|
if (uniqueTileCount < 20)
|
||||||
|
{
|
||||||
|
throw new Exception($"Expected at least 20 unique tiles for extended route, got {uniqueTileCount}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stitchedInfo.Length < 1024)
|
||||||
|
{
|
||||||
|
throw new Exception($"Stitched image seems too small: {stitchedInfo.Length} bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("✓ Extended Route with 20 Points (10km East) Test: PASSED");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task RunRouteWithTilesZipTest(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
RouteTestHelpers.PrintTestHeader("Test: Route with Tiles ZIP File Creation");
|
||||||
|
|
||||||
|
var routeId = Guid.NewGuid();
|
||||||
|
var request = new CreateRouteRequest
|
||||||
|
{
|
||||||
|
Id = routeId,
|
||||||
|
Name = "Route with Tiles ZIP",
|
||||||
|
Description = "Test route with tiles zip file creation",
|
||||||
|
RegionSizeMeters = 500.0,
|
||||||
|
ZoomLevel = 18,
|
||||||
|
RequestMaps = true,
|
||||||
|
CreateTilesZip = true,
|
||||||
|
Points = new List<RoutePointInput>
|
||||||
|
{
|
||||||
|
new() { Lat = 48.276067180586544, Lon = 37.38445758819581 },
|
||||||
|
new() { Lat = 48.27074009522731, Lon = 37.374029159545906 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine($"Creating route with 2 points:");
|
||||||
|
Console.WriteLine($" Start: ({request.Points[0].Lat}, {request.Points[0].Lon})");
|
||||||
|
Console.WriteLine($" End: ({request.Points[1].Lat}, {request.Points[1].Lon})");
|
||||||
|
Console.WriteLine($" Region Size: {request.RegionSizeMeters}m");
|
||||||
|
Console.WriteLine($" Zoom Level: {request.ZoomLevel}");
|
||||||
|
Console.WriteLine($" Request Maps: {request.RequestMaps}");
|
||||||
|
Console.WriteLine($" Create Tiles ZIP: {request.CreateTilesZip}");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var route = await RouteTestHelpers.CreateRoute(httpClient, request);
|
||||||
|
|
||||||
|
Console.WriteLine("Route Details:");
|
||||||
|
Console.WriteLine($" ID: {route.Id}");
|
||||||
|
Console.WriteLine($" Name: {route.Name}");
|
||||||
|
Console.WriteLine($" Total Points: {route.TotalPoints}");
|
||||||
|
Console.WriteLine($" Total Distance: {route.TotalDistanceMeters:F2}m");
|
||||||
|
Console.WriteLine($" Request Maps: {route.RequestMaps}");
|
||||||
|
Console.WriteLine($" Maps Ready: {route.MapsReady}");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidateRequestMaps(route, false);
|
||||||
|
|
||||||
|
Console.WriteLine("Step 2: Waiting for route maps and zip file to be ready");
|
||||||
|
Console.WriteLine(" (Service is processing regions SEQUENTIALLY to avoid API throttling)");
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
var finalRoute = await RouteTestHelpers.WaitForRouteReady(httpClient, routeId, 180, 3000);
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Step 3: Verifying generated files including ZIP");
|
||||||
|
|
||||||
|
RouteTestHelpers.ValidateFiles(finalRoute, true);
|
||||||
|
|
||||||
|
var uniqueTileCount = await RouteTestHelpers.GetUniqueTileCount(finalRoute.CsvFilePath!);
|
||||||
|
var zipInfo = new FileInfo(finalRoute.TilesZipPath!);
|
||||||
|
|
||||||
|
RouteTestHelpers.PrintGeneratedFiles(finalRoute, uniqueTileCount, true);
|
||||||
|
|
||||||
|
Console.WriteLine("Verifying ZIP file contents:");
|
||||||
|
using (var zipArchive = System.IO.Compression.ZipFile.OpenRead(finalRoute.TilesZipPath!))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" ZIP contains {zipArchive.Entries.Count} files");
|
||||||
|
|
||||||
|
if (zipArchive.Entries.Count == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("ZIP file is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zipArchive.Entries.Count != uniqueTileCount)
|
||||||
|
{
|
||||||
|
throw new Exception($"ZIP contains {zipArchive.Entries.Count} files but CSV lists {uniqueTileCount} tiles");
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstEntry = zipArchive.Entries[0];
|
||||||
|
Console.WriteLine($" First entry: {firstEntry.Name} ({firstEntry.Length} bytes)");
|
||||||
|
|
||||||
|
if (firstEntry.Length == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("First entry in ZIP is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
RouteTestHelpers.PrintRouteSummary(finalRoute, uniqueTileCount, null, true);
|
||||||
|
|
||||||
|
if (zipInfo.Length < 1024)
|
||||||
|
{
|
||||||
|
throw new Exception($"ZIP file seems too small: {zipInfo.Length} bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("✓ Route with Tiles ZIP File Test: PASSED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -32,15 +32,15 @@ class Program
|
|||||||
|
|
||||||
await RegionTests.RunRegionProcessingTest_500m_Zoom18(httpClient);
|
await RegionTests.RunRegionProcessingTest_500m_Zoom18(httpClient);
|
||||||
|
|
||||||
await RouteTests.RunSimpleRouteTest(httpClient);
|
await BasicRouteTests.RunSimpleRouteTest(httpClient);
|
||||||
|
|
||||||
await RouteTests.RunRouteWithRegionProcessingAndStitching(httpClient);
|
await BasicRouteTests.RunRouteWithRegionProcessingAndStitching(httpClient);
|
||||||
|
|
||||||
await RouteTests.RunRouteWithTilesZipTest(httpClient);
|
await ExtendedRouteTests.RunRouteWithTilesZipTest(httpClient);
|
||||||
|
|
||||||
await RouteTests.RunComplexRouteWithStitching(httpClient);
|
await ComplexRouteTests.RunComplexRouteWithStitching(httpClient);
|
||||||
await RouteTests.RunComplexRouteWithStitchingAndGeofences(httpClient);
|
await ComplexRouteTests.RunComplexRouteWithStitchingAndGeofences(httpClient);
|
||||||
await RouteTests.RunExtendedRouteEast(httpClient);
|
await ExtendedRouteTests.RunExtendedRouteEast(httpClient);
|
||||||
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.WriteLine("=========================");
|
Console.WriteLine("=========================");
|
||||||
|
|||||||
@@ -0,0 +1,297 @@
|
|||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace SatelliteProvider.IntegrationTests;
|
||||||
|
|
||||||
|
public static class RouteTestHelpers
|
||||||
|
{
|
||||||
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions JsonWriteOptions = new()
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void PrintTestHeader(string title)
|
||||||
|
{
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine(title);
|
||||||
|
Console.WriteLine(new string('=', title.Length));
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintSectionHeader(string title)
|
||||||
|
{
|
||||||
|
Console.WriteLine(title);
|
||||||
|
Console.WriteLine(new string('-', title.Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintRouteCreationDetails(CreateRouteRequest request, bool includeGeofences = false)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Action Points: {request.Points.Count}");
|
||||||
|
if (includeGeofences && request.Geofences?.Polygons != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Geofence Regions: {request.Geofences.Polygons.Count}");
|
||||||
|
}
|
||||||
|
Console.WriteLine($" Region Size: {request.RegionSizeMeters}m");
|
||||||
|
Console.WriteLine($" Zoom Level: {request.ZoomLevel}");
|
||||||
|
Console.WriteLine($" Request Maps: {request.RequestMaps}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintRoutePoints(List<RoutePointInput> points, int maxPoints = 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Route Path:");
|
||||||
|
if (maxPoints > 0 && points.Count > maxPoints * 2)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < maxPoints; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {i + 1}. ({points[i].Lat}, {points[i].Lon})");
|
||||||
|
}
|
||||||
|
Console.WriteLine(" ...");
|
||||||
|
for (int i = points.Count - maxPoints; i < points.Count; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {i + 1}. ({points[i].Lat}, {points[i].Lon})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < points.Count; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {i + 1}. ({points[i].Lat}, {points[i].Lon})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintGeofences(List<GeofencePolygonInput> polygons)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Geofence Regions:");
|
||||||
|
for (int i = 0; i < polygons.Count; i++)
|
||||||
|
{
|
||||||
|
var polygon = polygons[i];
|
||||||
|
Console.WriteLine($" {i + 1}. NW: ({polygon.NorthWest?.Lat}, {polygon.NorthWest?.Lon}) -> SE: ({polygon.SouthEast?.Lat}, {polygon.SouthEast?.Lon})");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintRouteResponse(RouteResponseModel route)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"✓ Route created with {route.TotalPoints} total points");
|
||||||
|
Console.WriteLine($" Distance: {route.TotalDistanceMeters:F2}m");
|
||||||
|
Console.WriteLine($" Request Maps: {route.RequestMaps}");
|
||||||
|
Console.WriteLine($" Maps Ready: {route.MapsReady}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintPointTypeDistribution(RouteResponseModel route)
|
||||||
|
{
|
||||||
|
var startPoints = route.Points.Count(p => p.PointType == "start");
|
||||||
|
var endPoints = route.Points.Count(p => p.PointType == "end");
|
||||||
|
var actionPoints = route.Points.Count(p => p.PointType == "action");
|
||||||
|
var intermediatePoints = route.Points.Count(p => p.PointType == "intermediate");
|
||||||
|
|
||||||
|
Console.WriteLine("Point Type Distribution:");
|
||||||
|
Console.WriteLine($" Start: {startPoints}");
|
||||||
|
Console.WriteLine($" Action: {actionPoints}");
|
||||||
|
Console.WriteLine($" Intermediate: {intermediatePoints}");
|
||||||
|
Console.WriteLine($" End: {endPoints}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintGeneratedFiles(RouteResponseModel route, int uniqueTileCount, bool includeZip = false)
|
||||||
|
{
|
||||||
|
var stitchedInfo = new FileInfo(route.StitchedImagePath!);
|
||||||
|
|
||||||
|
Console.WriteLine("Files Generated:");
|
||||||
|
Console.WriteLine($" ✓ CSV: {Path.GetFileName(route.CsvFilePath)} ({uniqueTileCount} tiles)");
|
||||||
|
Console.WriteLine($" ✓ Summary: {Path.GetFileName(route.SummaryFilePath)}");
|
||||||
|
Console.WriteLine($" ✓ Stitched Map: {Path.GetFileName(route.StitchedImagePath)} ({stitchedInfo.Length / 1024:F2} KB)");
|
||||||
|
|
||||||
|
if (includeZip && !string.IsNullOrEmpty(route.TilesZipPath))
|
||||||
|
{
|
||||||
|
var zipInfo = new FileInfo(route.TilesZipPath);
|
||||||
|
Console.WriteLine($" ✓ Tiles ZIP: {Path.GetFileName(route.TilesZipPath)} ({zipInfo.Length / 1024:F2} KB)");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PrintRouteSummary(RouteResponseModel route, int uniqueTileCount, int? geofenceCount = null, bool includeZip = false)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Route Summary:");
|
||||||
|
Console.WriteLine($" Route ID: {route.Id}");
|
||||||
|
Console.WriteLine($" Total Points: {route.TotalPoints}");
|
||||||
|
Console.WriteLine($" Distance: {route.TotalDistanceMeters:F2}m");
|
||||||
|
|
||||||
|
if (geofenceCount.HasValue)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Geofence Regions: {geofenceCount.Value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($" Unique Tiles: {uniqueTileCount}");
|
||||||
|
|
||||||
|
if (includeZip && !string.IsNullOrEmpty(route.TilesZipPath))
|
||||||
|
{
|
||||||
|
var zipInfo = new FileInfo(route.TilesZipPath);
|
||||||
|
Console.WriteLine($" ZIP File Size: {zipInfo.Length / 1024:F2} KB");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($" Maps Ready: {route.MapsReady}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<RouteResponseModel> CreateRoute(HttpClient httpClient, CreateRouteRequest request)
|
||||||
|
{
|
||||||
|
var response = await httpClient.PostAsJsonAsync("/api/satellite/route", request, JsonWriteOptions);
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var errorContent = await response.Content.ReadAsStringAsync();
|
||||||
|
throw new Exception($"Route creation failed: {response.StatusCode} - {errorContent}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var route = await response.Content.ReadFromJsonAsync<RouteResponseModel>(JsonOptions);
|
||||||
|
|
||||||
|
if (route == null)
|
||||||
|
{
|
||||||
|
throw new Exception("No route data returned from API");
|
||||||
|
}
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<RouteResponseModel> WaitForRouteReady(
|
||||||
|
HttpClient httpClient,
|
||||||
|
Guid routeId,
|
||||||
|
int maxAttempts = 180,
|
||||||
|
int pollInterval = 3000)
|
||||||
|
{
|
||||||
|
for (int attempt = 0; attempt < maxAttempts; attempt++)
|
||||||
|
{
|
||||||
|
await Task.Delay(pollInterval);
|
||||||
|
|
||||||
|
var getResponse = await httpClient.GetAsync($"/api/satellite/route/{routeId}");
|
||||||
|
|
||||||
|
if (!getResponse.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new Exception($"Failed to get route status: {getResponse.StatusCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentRoute = await getResponse.Content.ReadFromJsonAsync<RouteResponseModel>(JsonOptions);
|
||||||
|
|
||||||
|
if (currentRoute == null)
|
||||||
|
{
|
||||||
|
throw new Exception("No route returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentRoute.MapsReady)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"✓ Route maps ready in approximately {attempt * pollInterval / 1000}s");
|
||||||
|
return currentRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt % 5 == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Waiting... (attempt {attempt + 1}/{maxAttempts})");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt == maxAttempts - 1)
|
||||||
|
{
|
||||||
|
throw new Exception($"Timeout: Route maps did not become ready in {maxAttempts * pollInterval / 1000}s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Failed to wait for route ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ValidateFiles(RouteResponseModel route, bool includeZip = false)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(route.CsvFilePath))
|
||||||
|
{
|
||||||
|
throw new Exception("CSV file path is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(route.SummaryFilePath))
|
||||||
|
{
|
||||||
|
throw new Exception("Summary file path is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(route.StitchedImagePath))
|
||||||
|
{
|
||||||
|
throw new Exception("Stitched image path is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(route.CsvFilePath))
|
||||||
|
{
|
||||||
|
throw new Exception($"CSV file not found: {route.CsvFilePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(route.SummaryFilePath))
|
||||||
|
{
|
||||||
|
throw new Exception($"Summary file not found: {route.SummaryFilePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(route.StitchedImagePath))
|
||||||
|
{
|
||||||
|
throw new Exception($"Stitched image not found: {route.StitchedImagePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includeZip)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(route.TilesZipPath))
|
||||||
|
{
|
||||||
|
throw new Exception("Tiles ZIP file path is null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(route.TilesZipPath))
|
||||||
|
{
|
||||||
|
throw new Exception($"Tiles ZIP file not found: {route.TilesZipPath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ValidatePointTypes(RouteResponseModel route, int expectedStart, int expectedEnd, int expectedAction)
|
||||||
|
{
|
||||||
|
var startPoints = route.Points.Count(p => p.PointType == "start");
|
||||||
|
var endPoints = route.Points.Count(p => p.PointType == "end");
|
||||||
|
var actionPoints = route.Points.Count(p => p.PointType == "action");
|
||||||
|
|
||||||
|
if (startPoints != expectedStart)
|
||||||
|
{
|
||||||
|
throw new Exception($"Expected {expectedStart} start point(s), got {startPoints}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endPoints != expectedEnd)
|
||||||
|
{
|
||||||
|
throw new Exception($"Expected {expectedEnd} end point(s), got {endPoints}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionPoints != expectedAction)
|
||||||
|
{
|
||||||
|
throw new Exception($"Expected {expectedAction} action point(s), got {actionPoints}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ValidateRequestMaps(RouteResponseModel route, bool shouldBeReady)
|
||||||
|
{
|
||||||
|
if (!route.RequestMaps)
|
||||||
|
{
|
||||||
|
throw new Exception("Expected RequestMaps to be true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.MapsReady != shouldBeReady)
|
||||||
|
{
|
||||||
|
throw new Exception($"Expected MapsReady to be {shouldBeReady}, got {route.MapsReady}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<int> GetUniqueTileCount(string csvFilePath)
|
||||||
|
{
|
||||||
|
var csvLines = await File.ReadAllLinesAsync(csvFilePath);
|
||||||
|
return csvLines.Length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user