|
|
|
@ -37,6 +37,7 @@ using System.Text.RegularExpressions; |
|
|
|
|
using System.Threading; |
|
|
|
|
using System.Threading.Tasks; |
|
|
|
|
|
|
|
|
|
using CommandLine; |
|
|
|
|
using Google.Apis.Auth.OAuth2; |
|
|
|
|
using Google.Protobuf; |
|
|
|
|
using Grpc.Auth; |
|
|
|
@ -44,25 +45,54 @@ using Grpc.Core; |
|
|
|
|
using Grpc.Core.Utils; |
|
|
|
|
using Grpc.Testing; |
|
|
|
|
using NUnit.Framework; |
|
|
|
|
using CommandLine.Text; |
|
|
|
|
using System.IO; |
|
|
|
|
|
|
|
|
|
namespace Grpc.IntegrationTesting |
|
|
|
|
{ |
|
|
|
|
public class InteropClient |
|
|
|
|
{ |
|
|
|
|
private const string ServiceAccountUser = "155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk@developer.gserviceaccount.com"; |
|
|
|
|
private const string ComputeEngineUser = "155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel@developer.gserviceaccount.com"; |
|
|
|
|
private const string AuthScope = "https://www.googleapis.com/auth/xapi.zoo"; |
|
|
|
|
private const string AuthScopeResponse = "xapi.zoo"; |
|
|
|
|
|
|
|
|
|
private class ClientOptions |
|
|
|
|
{ |
|
|
|
|
public bool help; |
|
|
|
|
public string serverHost = "127.0.0.1"; |
|
|
|
|
public string serverHostOverride = TestCredentials.DefaultHostOverride; |
|
|
|
|
public int? serverPort; |
|
|
|
|
public string testCase = "large_unary"; |
|
|
|
|
public bool useTls; |
|
|
|
|
public bool useTestCa; |
|
|
|
|
[Option("server_host", DefaultValue = "127.0.0.1")] |
|
|
|
|
public string ServerHost { get; set; } |
|
|
|
|
|
|
|
|
|
[Option("server_host_override", DefaultValue = TestCredentials.DefaultHostOverride)] |
|
|
|
|
public string ServerHostOverride { get; set; } |
|
|
|
|
|
|
|
|
|
[Option("server_port", Required = true)] |
|
|
|
|
public int ServerPort { get; set; } |
|
|
|
|
|
|
|
|
|
[Option("test_case", DefaultValue = "large_unary")] |
|
|
|
|
public string TestCase { get; set; } |
|
|
|
|
|
|
|
|
|
[Option("use_tls")] |
|
|
|
|
public bool UseTls { get; set; } |
|
|
|
|
|
|
|
|
|
[Option("use_test_ca")] |
|
|
|
|
public bool UseTestCa { get; set; } |
|
|
|
|
|
|
|
|
|
[Option("default_service_account", Required = false)] |
|
|
|
|
public string DefaultServiceAccount { get; set; } |
|
|
|
|
|
|
|
|
|
[Option("oauth_scope", Required = false)] |
|
|
|
|
public string OAuthScope { get; set; } |
|
|
|
|
|
|
|
|
|
[Option("service_account_key_file", Required = false)] |
|
|
|
|
public string ServiceAccountKeyFile { get; set; } |
|
|
|
|
|
|
|
|
|
[HelpOption] |
|
|
|
|
public string GetUsage() |
|
|
|
|
{ |
|
|
|
|
var help = new HelpText |
|
|
|
|
{ |
|
|
|
|
Heading = "gRPC C# interop testing client", |
|
|
|
|
AddDashesToOption = true |
|
|
|
|
}; |
|
|
|
|
help.AddPreOptionsLine("Usage:"); |
|
|
|
|
help.AddOptions(this); |
|
|
|
|
return help; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ClientOptions options; |
|
|
|
@ -74,26 +104,9 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
|
|
|
|
|
public static void Run(string[] args) |
|
|
|
|
{ |
|
|
|
|
Console.WriteLine("gRPC C# interop testing client"); |
|
|
|
|
ClientOptions options = ParseArguments(args); |
|
|
|
|
|
|
|
|
|
if (options.serverHost == null || !options.serverPort.HasValue || options.testCase == null) |
|
|
|
|
{ |
|
|
|
|
Console.WriteLine("Missing required argument."); |
|
|
|
|
Console.WriteLine(); |
|
|
|
|
options.help = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (options.help) |
|
|
|
|
var options = new ClientOptions(); |
|
|
|
|
if (!Parser.Default.ParseArguments(args, options)) |
|
|
|
|
{ |
|
|
|
|
Console.WriteLine("Usage:"); |
|
|
|
|
Console.WriteLine(" --server_host=HOSTNAME"); |
|
|
|
|
Console.WriteLine(" --server_host_override=HOSTNAME"); |
|
|
|
|
Console.WriteLine(" --server_port=PORT"); |
|
|
|
|
Console.WriteLine(" --test_case=TESTCASE"); |
|
|
|
|
Console.WriteLine(" --use_tls=BOOLEAN"); |
|
|
|
|
Console.WriteLine(" --use_test_ca=BOOLEAN"); |
|
|
|
|
Console.WriteLine(); |
|
|
|
|
Environment.Exit(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -103,30 +116,27 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
|
|
|
|
|
private async Task Run() |
|
|
|
|
{ |
|
|
|
|
Credentials credentials = null; |
|
|
|
|
if (options.useTls) |
|
|
|
|
{ |
|
|
|
|
credentials = TestCredentials.CreateTestClientCredentials(options.useTestCa); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure; |
|
|
|
|
|
|
|
|
|
List<ChannelOption> channelOptions = null; |
|
|
|
|
if (!string.IsNullOrEmpty(options.serverHostOverride)) |
|
|
|
|
if (!string.IsNullOrEmpty(options.ServerHostOverride)) |
|
|
|
|
{ |
|
|
|
|
channelOptions = new List<ChannelOption> |
|
|
|
|
{ |
|
|
|
|
new ChannelOption(ChannelOptions.SslTargetNameOverride, options.serverHostOverride) |
|
|
|
|
new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions); |
|
|
|
|
Console.WriteLine(options.ServerHost); |
|
|
|
|
Console.WriteLine(options.ServerPort); |
|
|
|
|
var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); |
|
|
|
|
TestService.TestServiceClient client = new TestService.TestServiceClient(channel); |
|
|
|
|
await RunTestCaseAsync(options.testCase, client); |
|
|
|
|
await RunTestCaseAsync(client, options); |
|
|
|
|
channel.ShutdownAsync().Wait(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private async Task RunTestCaseAsync(string testCase, TestService.TestServiceClient client) |
|
|
|
|
private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options) |
|
|
|
|
{ |
|
|
|
|
switch (testCase) |
|
|
|
|
switch (options.TestCase) |
|
|
|
|
{ |
|
|
|
|
case "empty_unary": |
|
|
|
|
RunEmptyUnary(client); |
|
|
|
@ -146,20 +156,17 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
case "empty_stream": |
|
|
|
|
await RunEmptyStreamAsync(client); |
|
|
|
|
break; |
|
|
|
|
case "service_account_creds": |
|
|
|
|
await RunServiceAccountCredsAsync(client); |
|
|
|
|
break; |
|
|
|
|
case "compute_engine_creds": |
|
|
|
|
await RunComputeEngineCredsAsync(client); |
|
|
|
|
await RunComputeEngineCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope); |
|
|
|
|
break; |
|
|
|
|
case "jwt_token_creds": |
|
|
|
|
await RunJwtTokenCredsAsync(client); |
|
|
|
|
await RunJwtTokenCredsAsync(client, options.DefaultServiceAccount); |
|
|
|
|
break; |
|
|
|
|
case "oauth2_auth_token": |
|
|
|
|
await RunOAuth2AuthTokenAsync(client); |
|
|
|
|
await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope); |
|
|
|
|
break; |
|
|
|
|
case "per_rpc_creds": |
|
|
|
|
await RunPerRpcCredsAsync(client); |
|
|
|
|
await RunPerRpcCredsAsync(client, options.DefaultServiceAccount); |
|
|
|
|
break; |
|
|
|
|
case "cancel_after_begin": |
|
|
|
|
await RunCancelAfterBeginAsync(client); |
|
|
|
@ -174,7 +181,7 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
RunBenchmarkEmptyUnary(client); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
throw new ArgumentException("Unknown test case " + testCase); |
|
|
|
|
throw new ArgumentException("Unknown test case " + options.TestCase); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -313,32 +320,7 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
Console.WriteLine("Passed!"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static async Task RunServiceAccountCredsAsync(TestService.TestServiceClient client) |
|
|
|
|
{ |
|
|
|
|
Console.WriteLine("running service_account_creds"); |
|
|
|
|
var credential = await GoogleCredential.GetApplicationDefaultAsync(); |
|
|
|
|
credential = credential.CreateScoped(new[] { AuthScope }); |
|
|
|
|
client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); |
|
|
|
|
|
|
|
|
|
var request = new SimpleRequest |
|
|
|
|
{ |
|
|
|
|
ResponseType = PayloadType.COMPRESSABLE, |
|
|
|
|
ResponseSize = 314159, |
|
|
|
|
Payload = CreateZerosPayload(271828), |
|
|
|
|
FillUsername = true, |
|
|
|
|
FillOauthScope = true |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
var response = client.UnaryCall(request); |
|
|
|
|
|
|
|
|
|
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
|
|
|
|
Assert.AreEqual(314159, response.Payload.Body.Length); |
|
|
|
|
Assert.AreEqual(AuthScopeResponse, response.OauthScope); |
|
|
|
|
Assert.AreEqual(ServiceAccountUser, response.Username); |
|
|
|
|
Console.WriteLine("Passed!"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client) |
|
|
|
|
public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) |
|
|
|
|
{ |
|
|
|
|
Console.WriteLine("running compute_engine_creds"); |
|
|
|
|
var credential = await GoogleCredential.GetApplicationDefaultAsync(); |
|
|
|
@ -358,16 +340,16 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
|
|
|
|
|
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
|
|
|
|
Assert.AreEqual(314159, response.Payload.Body.Length); |
|
|
|
|
Assert.AreEqual(AuthScopeResponse, response.OauthScope); |
|
|
|
|
Assert.AreEqual(ComputeEngineUser, response.Username); |
|
|
|
|
Assert.False(string.IsNullOrEmpty(response.OauthScope)); |
|
|
|
|
Assert.True(oauthScope.Contains(response.OauthScope)); |
|
|
|
|
Assert.AreEqual(defaultServiceAccount, response.Username); |
|
|
|
|
Console.WriteLine("Passed!"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client) |
|
|
|
|
public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount) |
|
|
|
|
{ |
|
|
|
|
Console.WriteLine("running jwt_token_creds"); |
|
|
|
|
var credential = await GoogleCredential.GetApplicationDefaultAsync(); |
|
|
|
|
// check this a credential with scope support, but don't add the scope. |
|
|
|
|
Assert.IsTrue(credential.IsCreateScopedRequired); |
|
|
|
|
client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); |
|
|
|
|
|
|
|
|
@ -377,21 +359,20 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
ResponseSize = 314159, |
|
|
|
|
Payload = CreateZerosPayload(271828), |
|
|
|
|
FillUsername = true, |
|
|
|
|
FillOauthScope = true |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
var response = client.UnaryCall(request); |
|
|
|
|
|
|
|
|
|
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
|
|
|
|
Assert.AreEqual(314159, response.Payload.Body.Length); |
|
|
|
|
Assert.AreEqual(ServiceAccountUser, response.Username); |
|
|
|
|
Assert.AreEqual(defaultServiceAccount, response.Username); |
|
|
|
|
Console.WriteLine("Passed!"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client) |
|
|
|
|
public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) |
|
|
|
|
{ |
|
|
|
|
Console.WriteLine("running oauth2_auth_token"); |
|
|
|
|
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope }); |
|
|
|
|
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); |
|
|
|
|
string oauth2Token = await credential.GetAccessTokenForRequestAsync(); |
|
|
|
|
|
|
|
|
|
client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); |
|
|
|
@ -404,31 +385,30 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
|
|
|
|
|
var response = client.UnaryCall(request); |
|
|
|
|
|
|
|
|
|
Assert.AreEqual(AuthScopeResponse, response.OauthScope); |
|
|
|
|
Assert.AreEqual(ServiceAccountUser, response.Username); |
|
|
|
|
Assert.False(string.IsNullOrEmpty(response.OauthScope)); |
|
|
|
|
Assert.True(oauthScope.Contains(response.OauthScope)); |
|
|
|
|
Assert.AreEqual(defaultServiceAccount, response.Username); |
|
|
|
|
Console.WriteLine("Passed!"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client) |
|
|
|
|
public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount) |
|
|
|
|
{ |
|
|
|
|
Console.WriteLine("running per_rpc_creds"); |
|
|
|
|
|
|
|
|
|
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope }); |
|
|
|
|
string oauth2Token = await credential.GetAccessTokenForRequestAsync(); |
|
|
|
|
var headerInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); |
|
|
|
|
ITokenAccess credential = await GoogleCredential.GetApplicationDefaultAsync(); |
|
|
|
|
string accessToken = await credential.GetAccessTokenForRequestAsync(); |
|
|
|
|
var headerInterceptor = AuthInterceptors.FromAccessToken(accessToken); |
|
|
|
|
|
|
|
|
|
var request = new SimpleRequest |
|
|
|
|
{ |
|
|
|
|
FillUsername = true, |
|
|
|
|
FillOauthScope = true |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
var headers = new Metadata(); |
|
|
|
|
headerInterceptor(null, "", headers); |
|
|
|
|
var response = client.UnaryCall(request, headers: headers); |
|
|
|
|
|
|
|
|
|
Assert.AreEqual(AuthScopeResponse, response.OauthScope); |
|
|
|
|
Assert.AreEqual(ServiceAccountUser, response.Username); |
|
|
|
|
Assert.AreEqual(defaultServiceAccount, response.Username); |
|
|
|
|
Console.WriteLine("Passed!"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -508,68 +488,5 @@ namespace Grpc.IntegrationTesting |
|
|
|
|
{ |
|
|
|
|
return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static ClientOptions ParseArguments(string[] args) |
|
|
|
|
{ |
|
|
|
|
var options = new ClientOptions(); |
|
|
|
|
foreach (string arg in args) |
|
|
|
|
{ |
|
|
|
|
ParseArgument(arg, options); |
|
|
|
|
if (options.help) |
|
|
|
|
{ |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return options; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void ParseArgument(string arg, ClientOptions options) |
|
|
|
|
{ |
|
|
|
|
Match match; |
|
|
|
|
match = Regex.Match(arg, "--server_host=(.*)"); |
|
|
|
|
if (match.Success) |
|
|
|
|
{ |
|
|
|
|
options.serverHost = match.Groups[1].Value.Trim(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
match = Regex.Match(arg, "--server_host_override=(.*)"); |
|
|
|
|
if (match.Success) |
|
|
|
|
{ |
|
|
|
|
options.serverHostOverride = match.Groups[1].Value.Trim(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
match = Regex.Match(arg, "--server_port=(.*)"); |
|
|
|
|
if (match.Success) |
|
|
|
|
{ |
|
|
|
|
options.serverPort = int.Parse(match.Groups[1].Value.Trim()); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
match = Regex.Match(arg, "--test_case=(.*)"); |
|
|
|
|
if (match.Success) |
|
|
|
|
{ |
|
|
|
|
options.testCase = match.Groups[1].Value.Trim(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
match = Regex.Match(arg, "--use_tls=(.*)"); |
|
|
|
|
if (match.Success) |
|
|
|
|
{ |
|
|
|
|
options.useTls = bool.Parse(match.Groups[1].Value.Trim()); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
match = Regex.Match(arg, "--use_test_ca=(.*)"); |
|
|
|
|
if (match.Success) |
|
|
|
|
{ |
|
|
|
|
options.useTestCa = bool.Parse(match.Groups[1].Value.Trim()); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Console.WriteLine(string.Format("Unrecognized argument \"{0}\"", arg)); |
|
|
|
|
options.help = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|