Index: third_party/grpc/src/csharp/Grpc.IntegrationTesting/InteropClient.cs |
diff --git a/third_party/grpc/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/third_party/grpc/src/csharp/Grpc.IntegrationTesting/InteropClient.cs |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b0e33e49f77eefabf6a80ada6e0b22e2ab6f2fae |
--- /dev/null |
+++ b/third_party/grpc/src/csharp/Grpc.IntegrationTesting/InteropClient.cs |
@@ -0,0 +1,619 @@ |
+#region Copyright notice and license |
+ |
+// Copyright 2015, Google Inc. |
+// All rights reserved. |
+// |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following disclaimer |
+// in the documentation and/or other materials provided with the |
+// distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived from |
+// this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+#endregion |
+ |
+using System; |
+using System.Collections.Generic; |
+using System.IO; |
+using System.Linq; |
+using System.Text.RegularExpressions; |
+using System.Threading; |
+using System.Threading.Tasks; |
+ |
+using CommandLine; |
+using CommandLine.Text; |
+using Google.Apis.Auth.OAuth2; |
+using Google.Protobuf; |
+using Grpc.Auth; |
+using Grpc.Core; |
+using Grpc.Core.Utils; |
+using Grpc.Testing; |
+using Newtonsoft.Json.Linq; |
+using NUnit.Framework; |
+ |
+namespace Grpc.IntegrationTesting |
+{ |
+ public class InteropClient |
+ { |
+ private class ClientOptions |
+ { |
+ [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; } |
+ |
+ // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls) |
+ [Option("use_tls", DefaultValue = false)] |
+ public bool? UseTls { get; set; } |
+ |
+ // Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca) |
+ [Option("use_test_ca", DefaultValue = false)] |
+ 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; |
+ |
+ private InteropClient(ClientOptions options) |
+ { |
+ this.options = options; |
+ } |
+ |
+ public static void Run(string[] args) |
+ { |
+ var options = new ClientOptions(); |
+ if (!Parser.Default.ParseArguments(args, options)) |
+ { |
+ Environment.Exit(1); |
+ } |
+ |
+ var interopClient = new InteropClient(options); |
+ interopClient.Run().Wait(); |
+ } |
+ |
+ private async Task Run() |
+ { |
+ var credentials = await CreateCredentialsAsync(); |
+ |
+ List<ChannelOption> channelOptions = null; |
+ if (!string.IsNullOrEmpty(options.ServerHostOverride)) |
+ { |
+ channelOptions = new List<ChannelOption> |
+ { |
+ new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) |
+ }; |
+ } |
+ var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); |
+ await RunTestCaseAsync(channel, options); |
+ await channel.ShutdownAsync(); |
+ } |
+ |
+ private async Task<ChannelCredentials> CreateCredentialsAsync() |
+ { |
+ var credentials = ChannelCredentials.Insecure; |
+ if (options.UseTls.Value) |
+ { |
+ credentials = options.UseTestCa.Value ? TestCredentials.CreateSslCredentials() : new SslCredentials(); |
+ } |
+ |
+ if (options.TestCase == "jwt_token_creds") |
+ { |
+ var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); |
+ Assert.IsTrue(googleCredential.IsCreateScopedRequired); |
+ credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); |
+ } |
+ |
+ if (options.TestCase == "compute_engine_creds") |
+ { |
+ var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); |
+ Assert.IsFalse(googleCredential.IsCreateScopedRequired); |
+ credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); |
+ } |
+ return credentials; |
+ } |
+ |
+ private async Task RunTestCaseAsync(Channel channel, ClientOptions options) |
+ { |
+ var client = new TestService.TestServiceClient(channel); |
+ switch (options.TestCase) |
+ { |
+ case "empty_unary": |
+ RunEmptyUnary(client); |
+ break; |
+ case "large_unary": |
+ RunLargeUnary(client); |
+ break; |
+ case "client_streaming": |
+ await RunClientStreamingAsync(client); |
+ break; |
+ case "server_streaming": |
+ await RunServerStreamingAsync(client); |
+ break; |
+ case "ping_pong": |
+ await RunPingPongAsync(client); |
+ break; |
+ case "empty_stream": |
+ await RunEmptyStreamAsync(client); |
+ break; |
+ case "compute_engine_creds": |
+ RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope); |
+ break; |
+ case "jwt_token_creds": |
+ RunJwtTokenCreds(client); |
+ break; |
+ case "oauth2_auth_token": |
+ await RunOAuth2AuthTokenAsync(client, options.OAuthScope); |
+ break; |
+ case "per_rpc_creds": |
+ await RunPerRpcCredsAsync(client, options.OAuthScope); |
+ break; |
+ case "cancel_after_begin": |
+ await RunCancelAfterBeginAsync(client); |
+ break; |
+ case "cancel_after_first_response": |
+ await RunCancelAfterFirstResponseAsync(client); |
+ break; |
+ case "timeout_on_sleeping_server": |
+ await RunTimeoutOnSleepingServerAsync(client); |
+ break; |
+ case "custom_metadata": |
+ await RunCustomMetadataAsync(client); |
+ break; |
+ case "status_code_and_message": |
+ await RunStatusCodeAndMessageAsync(client); |
+ break; |
+ case "unimplemented_method": |
+ RunUnimplementedMethod(new UnimplementedService.UnimplementedServiceClient(channel)); |
+ break; |
+ default: |
+ throw new ArgumentException("Unknown test case " + options.TestCase); |
+ } |
+ } |
+ |
+ public static void RunEmptyUnary(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running empty_unary"); |
+ var response = client.EmptyCall(new Empty()); |
+ Assert.IsNotNull(response); |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static void RunLargeUnary(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running large_unary"); |
+ var request = new SimpleRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseSize = 314159, |
+ Payload = CreateZerosPayload(271828) |
+ }; |
+ var response = client.UnaryCall(request); |
+ |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
+ Assert.AreEqual(314159, response.Payload.Body.Length); |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunClientStreamingAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running client_streaming"); |
+ |
+ var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) }); |
+ |
+ using (var call = client.StreamingInputCall()) |
+ { |
+ await call.RequestStream.WriteAllAsync(bodySizes); |
+ |
+ var response = await call.ResponseAsync; |
+ Assert.AreEqual(74922, response.AggregatedPayloadSize); |
+ } |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunServerStreamingAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running server_streaming"); |
+ |
+ var bodySizes = new List<int> { 31415, 9, 2653, 58979 }; |
+ |
+ var request = new StreamingOutputCallRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseParameters = { bodySizes.ConvertAll((size) => new ResponseParameters { Size = size }) } |
+ }; |
+ |
+ using (var call = client.StreamingOutputCall(request)) |
+ { |
+ var responseList = await call.ResponseStream.ToListAsync(); |
+ foreach (var res in responseList) |
+ { |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type); |
+ } |
+ CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length)); |
+ } |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunPingPongAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running ping_pong"); |
+ |
+ using (var call = client.FullDuplexCall()) |
+ { |
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseParameters = { new ResponseParameters { Size = 31415 } }, |
+ Payload = CreateZerosPayload(27182) |
+ }); |
+ |
+ Assert.IsTrue(await call.ResponseStream.MoveNext()); |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); |
+ Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); |
+ |
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseParameters = { new ResponseParameters { Size = 9 } }, |
+ Payload = CreateZerosPayload(8) |
+ }); |
+ |
+ Assert.IsTrue(await call.ResponseStream.MoveNext()); |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); |
+ Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length); |
+ |
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseParameters = { new ResponseParameters { Size = 2653 } }, |
+ Payload = CreateZerosPayload(1828) |
+ }); |
+ |
+ Assert.IsTrue(await call.ResponseStream.MoveNext()); |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); |
+ Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length); |
+ |
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseParameters = { new ResponseParameters { Size = 58979 } }, |
+ Payload = CreateZerosPayload(45904) |
+ }); |
+ |
+ Assert.IsTrue(await call.ResponseStream.MoveNext()); |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); |
+ Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length); |
+ |
+ await call.RequestStream.CompleteAsync(); |
+ |
+ Assert.IsFalse(await call.ResponseStream.MoveNext()); |
+ } |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunEmptyStreamAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running empty_stream"); |
+ using (var call = client.FullDuplexCall()) |
+ { |
+ await call.RequestStream.CompleteAsync(); |
+ |
+ var responseList = await call.ResponseStream.ToListAsync(); |
+ Assert.AreEqual(0, responseList.Count); |
+ } |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) |
+ { |
+ Console.WriteLine("running compute_engine_creds"); |
+ |
+ var request = new SimpleRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseSize = 314159, |
+ Payload = CreateZerosPayload(271828), |
+ FillUsername = true, |
+ FillOauthScope = true |
+ }; |
+ |
+ // not setting credentials here because they were set on channel already |
+ var response = client.UnaryCall(request); |
+ |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
+ Assert.AreEqual(314159, response.Payload.Body.Length); |
+ Assert.False(string.IsNullOrEmpty(response.OauthScope)); |
+ Assert.True(oauthScope.Contains(response.OauthScope)); |
+ Assert.AreEqual(defaultServiceAccount, response.Username); |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static void RunJwtTokenCreds(TestService.TestServiceClient client) |
+ { |
+ Console.WriteLine("running jwt_token_creds"); |
+ |
+ var request = new SimpleRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseSize = 314159, |
+ Payload = CreateZerosPayload(271828), |
+ FillUsername = true, |
+ }; |
+ |
+ // not setting credentials here because they were set on channel already |
+ var response = client.UnaryCall(request); |
+ |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
+ Assert.AreEqual(314159, response.Payload.Body.Length); |
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope) |
+ { |
+ Console.WriteLine("running oauth2_auth_token"); |
+ ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); |
+ string oauth2Token = await credential.GetAccessTokenForRequestAsync(); |
+ |
+ var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token); |
+ var request = new SimpleRequest |
+ { |
+ FillUsername = true, |
+ FillOauthScope = true |
+ }; |
+ |
+ var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); |
+ |
+ Assert.False(string.IsNullOrEmpty(response.OauthScope)); |
+ Assert.True(oauthScope.Contains(response.OauthScope)); |
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope) |
+ { |
+ Console.WriteLine("running per_rpc_creds"); |
+ ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); |
+ |
+ var credentials = googleCredential.ToCallCredentials(); |
+ var request = new SimpleRequest |
+ { |
+ FillUsername = true, |
+ }; |
+ |
+ var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); |
+ |
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunCancelAfterBeginAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running cancel_after_begin"); |
+ |
+ var cts = new CancellationTokenSource(); |
+ using (var call = client.StreamingInputCall(cancellationToken: cts.Token)) |
+ { |
+ // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. |
+ await Task.Delay(1000); |
+ cts.Cancel(); |
+ |
+ var ex = Assert.Throws<RpcException>(async () => await call.ResponseAsync); |
+ Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); |
+ } |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunCancelAfterFirstResponseAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running cancel_after_first_response"); |
+ |
+ var cts = new CancellationTokenSource(); |
+ using (var call = client.FullDuplexCall(cancellationToken: cts.Token)) |
+ { |
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseParameters = { new ResponseParameters { Size = 31415 } }, |
+ Payload = CreateZerosPayload(27182) |
+ }); |
+ |
+ Assert.IsTrue(await call.ResponseStream.MoveNext()); |
+ Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); |
+ Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); |
+ |
+ cts.Cancel(); |
+ |
+ var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.MoveNext()); |
+ Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); |
+ } |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunTimeoutOnSleepingServerAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running timeout_on_sleeping_server"); |
+ |
+ var deadline = DateTime.UtcNow.AddMilliseconds(1); |
+ using (var call = client.FullDuplexCall(deadline: deadline)) |
+ { |
+ try |
+ { |
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { Payload = CreateZerosPayload(27182) }); |
+ } |
+ catch (InvalidOperationException) |
+ { |
+ // Deadline was reached before write has started. Eat the exception and continue. |
+ } |
+ |
+ var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.MoveNext()); |
+ Assert.AreEqual(StatusCode.DeadlineExceeded, ex.Status.StatusCode); |
+ } |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunCustomMetadataAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running custom_metadata"); |
+ { |
+ // step 1: test unary call |
+ var request = new SimpleRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseSize = 314159, |
+ Payload = CreateZerosPayload(271828) |
+ }; |
+ |
+ var call = client.UnaryCallAsync(request, headers: CreateTestMetadata()); |
+ await call.ResponseAsync; |
+ |
+ var responseHeaders = await call.ResponseHeadersAsync; |
+ var responseTrailers = call.GetTrailers(); |
+ |
+ Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value); |
+ CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes); |
+ } |
+ |
+ { |
+ // step 2: test full duplex call |
+ var request = new StreamingOutputCallRequest |
+ { |
+ ResponseType = PayloadType.COMPRESSABLE, |
+ ResponseParameters = { new ResponseParameters { Size = 31415 } }, |
+ Payload = CreateZerosPayload(27182) |
+ }; |
+ |
+ var call = client.FullDuplexCall(headers: CreateTestMetadata()); |
+ var responseHeaders = await call.ResponseHeadersAsync; |
+ |
+ await call.RequestStream.WriteAsync(request); |
+ await call.RequestStream.CompleteAsync(); |
+ await call.ResponseStream.ToListAsync(); |
+ |
+ var responseTrailers = call.GetTrailers(); |
+ |
+ Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value); |
+ CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes); |
+ } |
+ |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static async Task RunStatusCodeAndMessageAsync(TestService.ITestServiceClient client) |
+ { |
+ Console.WriteLine("running status_code_and_message"); |
+ var echoStatus = new EchoStatus |
+ { |
+ Code = 2, |
+ Message = "test status message" |
+ }; |
+ |
+ { |
+ // step 1: test unary call |
+ var request = new SimpleRequest { ResponseStatus = echoStatus }; |
+ |
+ var e = Assert.Throws<RpcException>(() => client.UnaryCall(request)); |
+ Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); |
+ Assert.AreEqual(echoStatus.Message, e.Status.Detail); |
+ } |
+ |
+ { |
+ // step 2: test full duplex call |
+ var request = new StreamingOutputCallRequest { ResponseStatus = echoStatus }; |
+ |
+ var call = client.FullDuplexCall(); |
+ await call.RequestStream.WriteAsync(request); |
+ await call.RequestStream.CompleteAsync(); |
+ |
+ var e = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToListAsync()); |
+ Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); |
+ Assert.AreEqual(echoStatus.Message, e.Status.Detail); |
+ } |
+ |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ public static void RunUnimplementedMethod(UnimplementedService.IUnimplementedServiceClient client) |
+ { |
+ Console.WriteLine("running unimplemented_method"); |
+ var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(new Empty())); |
+ |
+ Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); |
+ Assert.AreEqual("", e.Status.Detail); |
+ Console.WriteLine("Passed!"); |
+ } |
+ |
+ private static Payload CreateZerosPayload(int size) |
+ { |
+ return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; |
+ } |
+ |
+ // extracts the client_email field from service account file used for auth test cases |
+ private static string GetEmailFromServiceAccountFile() |
+ { |
+ string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"); |
+ Assert.IsNotNull(keyFile); |
+ |
+ var jobject = JObject.Parse(File.ReadAllText(keyFile)); |
+ string email = jobject.GetValue("client_email").Value<string>(); |
+ Assert.IsTrue(email.Length > 0); // spec requires nonempty client email. |
+ return email; |
+ } |
+ |
+ private static Metadata CreateTestMetadata() |
+ { |
+ return new Metadata |
+ { |
+ {"x-grpc-test-echo-initial", "test_initial_metadata_value"}, |
+ {"x-grpc-test-echo-trailing-bin", new byte[] {0xab, 0xab, 0xab}} |
+ }; |
+ } |
+ } |
+} |