[AZ-1074] [AZ-1075] gRPC tile stream tests and shared proto
ci/woodpecker/push/01-test Pipeline failed
ci/woodpecker/push/02-build-push unknown status

Extract tile_provision.proto into GrpcContracts, add integration
tests and validation hardening for DeliverRouteTiles streaming.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-06-25 10:04:41 +03:00
parent 275ee1b554
commit 7633134a8a
20 changed files with 725 additions and 26 deletions
+1
View File
@@ -6,6 +6,7 @@ EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["SatelliteProvider.Api/SatelliteProvider.Api.csproj", "SatelliteProvider.Api/"]
COPY ["SatelliteProvider.GrpcContracts/SatelliteProvider.GrpcContracts.csproj", "SatelliteProvider.GrpcContracts/"]
COPY ["SatelliteProvider.Common/SatelliteProvider.Common.csproj", "SatelliteProvider.Common/"]
COPY ["SatelliteProvider.DataAccess/SatelliteProvider.DataAccess.csproj", "SatelliteProvider.DataAccess/"]
COPY ["SatelliteProvider.Services.TileDownloader/SatelliteProvider.Services.TileDownloader.csproj", "SatelliteProvider.Services.TileDownloader/"]
@@ -27,14 +27,12 @@ public sealed class RouteTileDeliveryGrpcService : RouteTileDelivery.RouteTileDe
{
if (request.Route is null)
{
await WriteErrorAsync(responseStream, "INVALID_REQUEST", "route is required", retryable: false, context.CancellationToken);
return;
throw new RpcException(new Status(StatusCode.InvalidArgument, "route is required"));
}
if (!Guid.TryParse(request.Route.RouteId, out var routeId))
{
await WriteErrorAsync(responseStream, "INVALID_REQUEST", "route_id must be a UUID", retryable: false, context.CancellationToken);
return;
throw new RpcException(new Status(StatusCode.InvalidArgument, "route_id must be a UUID"));
}
var job = MapJob(request, routeId);
@@ -47,7 +45,7 @@ public sealed class RouteTileDeliveryGrpcService : RouteTileDelivery.RouteTileDe
catch (ArgumentException ex)
{
_logger.LogWarning(ex, "Invalid route tile delivery request for route {RouteId}", routeId);
await WriteErrorAsync(responseStream, "INVALID_REQUEST", ex.Message, retryable: false, context.CancellationToken);
throw new RpcException(new Status(StatusCode.InvalidArgument, ex.Message));
}
catch (OperationCanceledException) when (context.CancellationToken.IsCancellationRequested)
{
@@ -1,95 +0,0 @@
syntax = "proto3";
package satellite.v1;
import "google/protobuf/timestamp.proto";
option csharp_namespace = "Satellite.V1";
service RouteTileDelivery {
rpc DeliverRouteTiles(DeliverRouteTilesRequest) returns (stream RouteTileEvent);
}
message DeliverRouteTilesRequest {
RouteSpec route = 1;
repeated ClientTileRecord client_tiles = 2;
}
message RouteSpec {
string route_id = 1;
repeated Waypoint waypoints = 2;
double region_size_meters = 3;
int32 zoom = 4;
repeated GeofencePolygon geofences = 5;
bool include_geofence_tiles = 6;
}
message Waypoint {
double lat = 1;
double lon = 2;
}
message GeofencePolygon {
repeated Waypoint vertices = 1;
}
message ClientTileRecord {
int32 z = 1;
int32 x = 2;
int32 y = 3;
double resolution_m_per_px = 4;
google.protobuf.Timestamp captured_at = 5;
optional string source = 6;
bytes content_sha256 = 7;
}
message RouteTileEvent {
oneof payload {
RouteManifest manifest = 1;
TileBatch batch = 2;
ProgressUpdate progress = 3;
DeliveryComplete complete = 4;
DeliveryError error = 5;
}
}
message RouteManifest {
uint32 total_candidates = 1;
uint32 skipped_by_client = 2;
uint32 to_deliver = 3;
}
message TileBatch {
uint32 batch_seq = 1;
repeated TilePayload tiles = 2;
}
message TilePayload {
int32 z = 1;
int32 x = 2;
int32 y = 3;
double resolution_m_per_px = 4;
google.protobuf.Timestamp captured_at = 5;
string source = 6;
bytes jpeg = 7;
bytes content_sha256 = 8;
uint32 route_priority = 9;
}
message ProgressUpdate {
uint32 delivered = 1;
uint32 total = 2;
uint32 downloading = 3;
}
message DeliveryComplete {
uint32 delivered = 1;
uint32 skipped_client = 2;
uint32 skipped_server_filter = 3;
}
message DeliveryError {
string code = 1;
string message = 2;
bool retryable = 3;
}
@@ -20,6 +20,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SatelliteProvider.GrpcContracts\SatelliteProvider.GrpcContracts.csproj" />
<ProjectReference Include="..\SatelliteProvider.Common\SatelliteProvider.Common.csproj" />
<ProjectReference Include="..\SatelliteProvider.DataAccess\SatelliteProvider.DataAccess.csproj" />
<ProjectReference Include="..\SatelliteProvider.Services.TileDownloader\SatelliteProvider.Services.TileDownloader.csproj" />
@@ -27,8 +28,4 @@
<ProjectReference Include="..\SatelliteProvider.Services.RouteManagement\SatelliteProvider.Services.RouteManagement.csproj" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\tile_provision.proto" GrpcServices="Server" />
</ItemGroup>
</Project>