using Grpc.Core; using Grpc.Net.Client; using Satellite.V1; namespace SatelliteProvider.IntegrationTests; public static class GrpcTestHelpers { public static GrpcChannel CreateChannel(string apiUrl) { return GrpcChannel.ForAddress(apiUrl, new GrpcChannelOptions { HttpHandler = new SocketsHttpHandler { EnableMultipleHttp2Connections = true, }, }); } public static RouteTileDelivery.RouteTileDeliveryClient CreateClient(string apiUrl, string jwtToken) { var channel = CreateChannel(apiUrl); var client = new RouteTileDelivery.RouteTileDeliveryClient(channel); return client; } public static Metadata AuthMetadata(string jwtToken) { return new Metadata { { "Authorization", $"Bearer {jwtToken}" } }; } public static DeliverRouteTilesRequest BuildValidRequest( Guid? routeId = null, double lat1 = 48.276067180586544, double lon1 = 37.38445758819581, double lat2 = 48.27074009522731, double lon2 = 37.374029159545906, double regionSizeMeters = 500, int zoom = 18) { return new DeliverRouteTilesRequest { Route = new RouteSpec { RouteId = (routeId ?? Guid.NewGuid()).ToString(), RegionSizeMeters = regionSizeMeters, Zoom = zoom, Waypoints = { new Waypoint { Lat = lat1, Lon = lon1 }, new Waypoint { Lat = lat2, Lon = lon2 }, }, }, }; } public static async Task<(RouteManifest? Manifest, List Tiles, DeliveryComplete? Complete, DeliveryError? Error)> CollectStreamAsync(AsyncServerStreamingCall call, int? delayMsBetweenEvents = null) { RouteManifest? manifest = null; var tiles = new List(); DeliveryComplete? complete = null; DeliveryError? error = null; await foreach (var evt in call.ResponseStream.ReadAllAsync()) { switch (evt.PayloadCase) { case RouteTileEvent.PayloadOneofCase.Manifest: manifest = evt.Manifest; break; case RouteTileEvent.PayloadOneofCase.Batch: tiles.AddRange(evt.Batch.Tiles); break; case RouteTileEvent.PayloadOneofCase.Complete: complete = evt.Complete; break; case RouteTileEvent.PayloadOneofCase.Error: error = evt.Error; break; } if (delayMsBetweenEvents.HasValue) { await Task.Delay(delayMsBetweenEvents.Value); } } return (manifest, tiles, complete, error); } public static async Task ExpectInvalidArgumentAsync(Func action, string context) { try { await action(); throw new Exception($"{context}: expected RpcException with InvalidArgument, but call succeeded"); } catch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument) { Console.WriteLine($" ✓ {context}: InvalidArgument — {ex.Status.Detail}"); } catch (RpcException ex) { throw new Exception($"{context}: expected InvalidArgument, got {ex.StatusCode} — {ex.Status.Detail}"); } } }