mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-27 08:31:13 +00:00
161 lines
5.2 KiB
C#
161 lines
5.2 KiB
C#
using System.Net.Security;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using Grpc.Core;
|
|
using Grpc.Net.Client;
|
|
using Satellite.V1;
|
|
|
|
namespace SatelliteProvider.IntegrationTests;
|
|
|
|
public static class GrpcTestHelpers
|
|
{
|
|
public static GrpcChannel CreateChannel(string apiUrl)
|
|
{
|
|
var handler = new SocketsHttpHandler
|
|
{
|
|
EnableMultipleHttp2Connections = true,
|
|
};
|
|
|
|
var caCertPath = ResolveCaCertPath();
|
|
if (!string.IsNullOrEmpty(caCertPath))
|
|
{
|
|
var caCert = X509Certificate2.CreateFromPemFile(caCertPath);
|
|
handler.SslOptions = new SslClientAuthenticationOptions
|
|
{
|
|
RemoteCertificateValidationCallback = (_, certificate, _, errors) =>
|
|
{
|
|
if (errors == SslPolicyErrors.None)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (certificate is null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
using var chain = new X509Chain();
|
|
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
|
|
chain.ChainPolicy.CustomTrustStore.Add(caCert);
|
|
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
|
|
return chain.Build(new X509Certificate2(certificate));
|
|
},
|
|
};
|
|
}
|
|
|
|
return GrpcChannel.ForAddress(apiUrl, new GrpcChannelOptions
|
|
{
|
|
HttpHandler = handler,
|
|
});
|
|
}
|
|
|
|
private static string? ResolveCaCertPath()
|
|
{
|
|
var explicitPath = Environment.GetEnvironmentVariable("PERF_CA_CERT");
|
|
if (!string.IsNullOrWhiteSpace(explicitPath) && File.Exists(explicitPath))
|
|
{
|
|
return explicitPath;
|
|
}
|
|
|
|
var projectRoot = Environment.GetEnvironmentVariable("PROJECT_ROOT");
|
|
if (!string.IsNullOrWhiteSpace(projectRoot))
|
|
{
|
|
var defaultPath = Path.Combine(projectRoot, "certs", "api.crt");
|
|
if (File.Exists(defaultPath))
|
|
{
|
|
return defaultPath;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
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<TilePayload> Tiles, DeliveryComplete? Complete, DeliveryError? Error)>
|
|
CollectStreamAsync(AsyncServerStreamingCall<RouteTileEvent> call, int? delayMsBetweenEvents = null)
|
|
{
|
|
RouteManifest? manifest = null;
|
|
var tiles = new List<TilePayload>();
|
|
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<Task> 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}");
|
|
}
|
|
}
|
|
}
|