1 #region Copyright notice and license 2 3 // Copyright 2015-2016 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #endregion 18 19 using System; 20 using System.Collections.Generic; 21 using System.IO; 22 using System.Linq; 23 using System.Text.RegularExpressions; 24 using System.Threading; 25 using System.Threading.Tasks; 26 27 using CommandLine; 28 using CommandLine.Text; 29 using Google.Apis.Auth.OAuth2; 30 using Google.Protobuf; 31 using Grpc.Auth; 32 using Grpc.Core; 33 using Grpc.Core.Logging; 34 using Grpc.Core.Utils; 35 using Grpc.Testing; 36 using Newtonsoft.Json.Linq; 37 using NUnit.Framework; 38 39 namespace Grpc.IntegrationTesting 40 { 41 public class InteropClient 42 { 43 private class ClientOptions 44 { 45 [Option("server_host", Default = "localhost")] 46 public string ServerHost { get; set; } 47 48 [Option("server_host_override", Default = TestCredentials.DefaultHostOverride)] 49 public string ServerHostOverride { get; set; } 50 51 [Option("server_port", Required = true)] 52 public int ServerPort { get; set; } 53 54 [Option("test_case", Default = "large_unary")] 55 public string TestCase { get; set; } 56 57 // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls) 58 [Option("use_tls", Default = false)] 59 public bool? UseTls { get; set; } 60 61 // Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca) 62 [Option("use_test_ca", Default = false)] 63 public bool? UseTestCa { get; set; } 64 65 [Option("default_service_account", Required = false)] 66 public string DefaultServiceAccount { get; set; } 67 68 [Option("oauth_scope", Required = false)] 69 public string OAuthScope { get; set; } 70 71 [Option("service_account_key_file", Required = false)] 72 public string ServiceAccountKeyFile { get; set; } 73 } 74 75 ClientOptions options; 76 InteropClient(ClientOptions options)77 private InteropClient(ClientOptions options) 78 { 79 this.options = options; 80 } 81 Run(string[] args)82 public static void Run(string[] args) 83 { 84 GrpcEnvironment.SetLogger(new ConsoleLogger()); 85 var parserResult = Parser.Default.ParseArguments<ClientOptions>(args) 86 .WithNotParsed(errors => Environment.Exit(1)) 87 .WithParsed(options => 88 { 89 var interopClient = new InteropClient(options); 90 interopClient.Run().Wait(); 91 }); 92 } 93 Run()94 private async Task Run() 95 { 96 var credentials = await CreateCredentialsAsync(); 97 98 List<ChannelOption> channelOptions = null; 99 if (!string.IsNullOrEmpty(options.ServerHostOverride)) 100 { 101 channelOptions = new List<ChannelOption> 102 { 103 new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) 104 }; 105 } 106 var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); 107 await RunTestCaseAsync(channel, options); 108 await channel.ShutdownAsync(); 109 } 110 CreateCredentialsAsync()111 private async Task<ChannelCredentials> CreateCredentialsAsync() 112 { 113 var credentials = ChannelCredentials.Insecure; 114 if (options.UseTls.Value) 115 { 116 credentials = options.UseTestCa.Value ? TestCredentials.CreateSslCredentials() : new SslCredentials(); 117 } 118 119 if (options.TestCase == "jwt_token_creds") 120 { 121 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); 122 Assert.IsTrue(googleCredential.IsCreateScopedRequired); 123 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); 124 } 125 126 if (options.TestCase == "compute_engine_creds") 127 { 128 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); 129 Assert.IsFalse(googleCredential.IsCreateScopedRequired); 130 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); 131 } 132 return credentials; 133 } 134 RunTestCaseAsync(Channel channel, ClientOptions options)135 private async Task RunTestCaseAsync(Channel channel, ClientOptions options) 136 { 137 var client = new TestService.TestServiceClient(channel); 138 switch (options.TestCase) 139 { 140 case "empty_unary": 141 RunEmptyUnary(client); 142 break; 143 case "large_unary": 144 RunLargeUnary(client); 145 break; 146 case "client_streaming": 147 await RunClientStreamingAsync(client); 148 break; 149 case "server_streaming": 150 await RunServerStreamingAsync(client); 151 break; 152 case "ping_pong": 153 await RunPingPongAsync(client); 154 break; 155 case "empty_stream": 156 await RunEmptyStreamAsync(client); 157 break; 158 case "compute_engine_creds": 159 RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope); 160 break; 161 case "jwt_token_creds": 162 RunJwtTokenCreds(client); 163 break; 164 case "oauth2_auth_token": 165 await RunOAuth2AuthTokenAsync(client, options.OAuthScope); 166 break; 167 case "per_rpc_creds": 168 await RunPerRpcCredsAsync(client, options.OAuthScope); 169 break; 170 case "cancel_after_begin": 171 await RunCancelAfterBeginAsync(client); 172 break; 173 case "cancel_after_first_response": 174 await RunCancelAfterFirstResponseAsync(client); 175 break; 176 case "timeout_on_sleeping_server": 177 await RunTimeoutOnSleepingServerAsync(client); 178 break; 179 case "custom_metadata": 180 await RunCustomMetadataAsync(client); 181 break; 182 case "status_code_and_message": 183 await RunStatusCodeAndMessageAsync(client); 184 break; 185 case "unimplemented_service": 186 RunUnimplementedService(new UnimplementedService.UnimplementedServiceClient(channel)); 187 break; 188 case "unimplemented_method": 189 RunUnimplementedMethod(client); 190 break; 191 case "client_compressed_unary": 192 RunClientCompressedUnary(client); 193 break; 194 case "client_compressed_streaming": 195 await RunClientCompressedStreamingAsync(client); 196 break; 197 default: 198 throw new ArgumentException("Unknown test case " + options.TestCase); 199 } 200 } 201 RunEmptyUnary(TestService.TestServiceClient client)202 public static void RunEmptyUnary(TestService.TestServiceClient client) 203 { 204 Console.WriteLine("running empty_unary"); 205 var response = client.EmptyCall(new Empty()); 206 Assert.IsNotNull(response); 207 Console.WriteLine("Passed!"); 208 } 209 RunLargeUnary(TestService.TestServiceClient client)210 public static void RunLargeUnary(TestService.TestServiceClient client) 211 { 212 Console.WriteLine("running large_unary"); 213 var request = new SimpleRequest 214 { 215 ResponseSize = 314159, 216 Payload = CreateZerosPayload(271828) 217 }; 218 var response = client.UnaryCall(request); 219 220 Assert.AreEqual(314159, response.Payload.Body.Length); 221 Console.WriteLine("Passed!"); 222 } 223 RunClientStreamingAsync(TestService.TestServiceClient client)224 public static async Task RunClientStreamingAsync(TestService.TestServiceClient client) 225 { 226 Console.WriteLine("running client_streaming"); 227 228 var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.Select((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) }); 229 230 using (var call = client.StreamingInputCall()) 231 { 232 await call.RequestStream.WriteAllAsync(bodySizes); 233 234 var response = await call.ResponseAsync; 235 Assert.AreEqual(74922, response.AggregatedPayloadSize); 236 } 237 Console.WriteLine("Passed!"); 238 } 239 RunServerStreamingAsync(TestService.TestServiceClient client)240 public static async Task RunServerStreamingAsync(TestService.TestServiceClient client) 241 { 242 Console.WriteLine("running server_streaming"); 243 244 var bodySizes = new List<int> { 31415, 9, 2653, 58979 }; 245 246 var request = new StreamingOutputCallRequest 247 { 248 ResponseParameters = { bodySizes.Select((size) => new ResponseParameters { Size = size }) } 249 }; 250 251 using (var call = client.StreamingOutputCall(request)) 252 { 253 var responseList = await call.ResponseStream.ToListAsync(); 254 CollectionAssert.AreEqual(bodySizes, responseList.Select((item) => item.Payload.Body.Length)); 255 } 256 Console.WriteLine("Passed!"); 257 } 258 RunPingPongAsync(TestService.TestServiceClient client)259 public static async Task RunPingPongAsync(TestService.TestServiceClient client) 260 { 261 Console.WriteLine("running ping_pong"); 262 263 using (var call = client.FullDuplexCall()) 264 { 265 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 266 { 267 ResponseParameters = { new ResponseParameters { Size = 31415 } }, 268 Payload = CreateZerosPayload(27182) 269 }); 270 271 Assert.IsTrue(await call.ResponseStream.MoveNext()); 272 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); 273 274 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 275 { 276 ResponseParameters = { new ResponseParameters { Size = 9 } }, 277 Payload = CreateZerosPayload(8) 278 }); 279 280 Assert.IsTrue(await call.ResponseStream.MoveNext()); 281 Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length); 282 283 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 284 { 285 ResponseParameters = { new ResponseParameters { Size = 2653 } }, 286 Payload = CreateZerosPayload(1828) 287 }); 288 289 Assert.IsTrue(await call.ResponseStream.MoveNext()); 290 Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length); 291 292 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 293 { 294 ResponseParameters = { new ResponseParameters { Size = 58979 } }, 295 Payload = CreateZerosPayload(45904) 296 }); 297 298 Assert.IsTrue(await call.ResponseStream.MoveNext()); 299 Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length); 300 301 await call.RequestStream.CompleteAsync(); 302 303 Assert.IsFalse(await call.ResponseStream.MoveNext()); 304 } 305 Console.WriteLine("Passed!"); 306 } 307 RunEmptyStreamAsync(TestService.TestServiceClient client)308 public static async Task RunEmptyStreamAsync(TestService.TestServiceClient client) 309 { 310 Console.WriteLine("running empty_stream"); 311 using (var call = client.FullDuplexCall()) 312 { 313 await call.RequestStream.CompleteAsync(); 314 315 var responseList = await call.ResponseStream.ToListAsync(); 316 Assert.AreEqual(0, responseList.Count); 317 } 318 Console.WriteLine("Passed!"); 319 } 320 RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)321 public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) 322 { 323 Console.WriteLine("running compute_engine_creds"); 324 325 var request = new SimpleRequest 326 { 327 ResponseSize = 314159, 328 Payload = CreateZerosPayload(271828), 329 FillUsername = true, 330 FillOauthScope = true 331 }; 332 333 // not setting credentials here because they were set on channel already 334 var response = client.UnaryCall(request); 335 336 Assert.AreEqual(314159, response.Payload.Body.Length); 337 Assert.False(string.IsNullOrEmpty(response.OauthScope)); 338 Assert.True(oauthScope.Contains(response.OauthScope)); 339 Assert.AreEqual(defaultServiceAccount, response.Username); 340 Console.WriteLine("Passed!"); 341 } 342 RunJwtTokenCreds(TestService.TestServiceClient client)343 public static void RunJwtTokenCreds(TestService.TestServiceClient client) 344 { 345 Console.WriteLine("running jwt_token_creds"); 346 347 var request = new SimpleRequest 348 { 349 ResponseSize = 314159, 350 Payload = CreateZerosPayload(271828), 351 FillUsername = true, 352 }; 353 354 // not setting credentials here because they were set on channel already 355 var response = client.UnaryCall(request); 356 357 Assert.AreEqual(314159, response.Payload.Body.Length); 358 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); 359 Console.WriteLine("Passed!"); 360 } 361 RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)362 public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope) 363 { 364 Console.WriteLine("running oauth2_auth_token"); 365 ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); 366 string oauth2Token = await credential.GetAccessTokenForRequestAsync(); 367 368 var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token); 369 var request = new SimpleRequest 370 { 371 FillUsername = true, 372 FillOauthScope = true 373 }; 374 375 var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); 376 377 Assert.False(string.IsNullOrEmpty(response.OauthScope)); 378 Assert.True(oauthScope.Contains(response.OauthScope)); 379 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); 380 Console.WriteLine("Passed!"); 381 } 382 RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)383 public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope) 384 { 385 Console.WriteLine("running per_rpc_creds"); 386 ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); 387 388 var credentials = googleCredential.ToCallCredentials(); 389 var request = new SimpleRequest 390 { 391 FillUsername = true, 392 }; 393 394 var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); 395 396 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); 397 Console.WriteLine("Passed!"); 398 } 399 RunCancelAfterBeginAsync(TestService.TestServiceClient client)400 public static async Task RunCancelAfterBeginAsync(TestService.TestServiceClient client) 401 { 402 Console.WriteLine("running cancel_after_begin"); 403 404 var cts = new CancellationTokenSource(); 405 using (var call = client.StreamingInputCall(cancellationToken: cts.Token)) 406 { 407 // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. 408 await Task.Delay(1000); 409 cts.Cancel(); 410 411 var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseAsync); 412 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); 413 } 414 Console.WriteLine("Passed!"); 415 } 416 RunCancelAfterFirstResponseAsync(TestService.TestServiceClient client)417 public static async Task RunCancelAfterFirstResponseAsync(TestService.TestServiceClient client) 418 { 419 Console.WriteLine("running cancel_after_first_response"); 420 421 var cts = new CancellationTokenSource(); 422 using (var call = client.FullDuplexCall(cancellationToken: cts.Token)) 423 { 424 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 425 { 426 ResponseParameters = { new ResponseParameters { Size = 31415 } }, 427 Payload = CreateZerosPayload(27182) 428 }); 429 430 Assert.IsTrue(await call.ResponseStream.MoveNext()); 431 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); 432 433 cts.Cancel(); 434 435 try 436 { 437 // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. 438 await call.ResponseStream.MoveNext(); 439 Assert.Fail(); 440 } 441 catch (RpcException ex) 442 { 443 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); 444 } 445 } 446 Console.WriteLine("Passed!"); 447 } 448 RunTimeoutOnSleepingServerAsync(TestService.TestServiceClient client)449 public static async Task RunTimeoutOnSleepingServerAsync(TestService.TestServiceClient client) 450 { 451 Console.WriteLine("running timeout_on_sleeping_server"); 452 453 var deadline = DateTime.UtcNow.AddMilliseconds(1); 454 using (var call = client.FullDuplexCall(deadline: deadline)) 455 { 456 try 457 { 458 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { Payload = CreateZerosPayload(27182) }); 459 } 460 catch (InvalidOperationException) 461 { 462 // Deadline was reached before write has started. Eat the exception and continue. 463 } 464 catch (RpcException) 465 { 466 // Deadline was reached before write has started. Eat the exception and continue. 467 } 468 469 try 470 { 471 await call.ResponseStream.MoveNext(); 472 Assert.Fail(); 473 } 474 catch (RpcException ex) 475 { 476 // We can't guarantee the status code always DeadlineExceeded. See issue #2685. 477 Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal }); 478 } 479 } 480 Console.WriteLine("Passed!"); 481 } 482 RunCustomMetadataAsync(TestService.TestServiceClient client)483 public static async Task RunCustomMetadataAsync(TestService.TestServiceClient client) 484 { 485 Console.WriteLine("running custom_metadata"); 486 { 487 // step 1: test unary call 488 var request = new SimpleRequest 489 { 490 ResponseSize = 314159, 491 Payload = CreateZerosPayload(271828) 492 }; 493 494 var call = client.UnaryCallAsync(request, headers: CreateTestMetadata()); 495 await call.ResponseAsync; 496 497 var responseHeaders = await call.ResponseHeadersAsync; 498 var responseTrailers = call.GetTrailers(); 499 500 Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value); 501 CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes); 502 } 503 504 { 505 // step 2: test full duplex call 506 var request = new StreamingOutputCallRequest 507 { 508 ResponseParameters = { new ResponseParameters { Size = 31415 } }, 509 Payload = CreateZerosPayload(27182) 510 }; 511 512 var call = client.FullDuplexCall(headers: CreateTestMetadata()); 513 514 await call.RequestStream.WriteAsync(request); 515 await call.RequestStream.CompleteAsync(); 516 await call.ResponseStream.ToListAsync(); 517 518 var responseHeaders = await call.ResponseHeadersAsync; 519 var responseTrailers = call.GetTrailers(); 520 521 Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value); 522 CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes); 523 } 524 525 Console.WriteLine("Passed!"); 526 } 527 RunStatusCodeAndMessageAsync(TestService.TestServiceClient client)528 public static async Task RunStatusCodeAndMessageAsync(TestService.TestServiceClient client) 529 { 530 Console.WriteLine("running status_code_and_message"); 531 var echoStatus = new EchoStatus 532 { 533 Code = 2, 534 Message = "test status message" 535 }; 536 537 { 538 // step 1: test unary call 539 var request = new SimpleRequest { ResponseStatus = echoStatus }; 540 541 var e = Assert.Throws<RpcException>(() => client.UnaryCall(request)); 542 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); 543 Assert.AreEqual(echoStatus.Message, e.Status.Detail); 544 } 545 546 { 547 // step 2: test full duplex call 548 var request = new StreamingOutputCallRequest { ResponseStatus = echoStatus }; 549 550 var call = client.FullDuplexCall(); 551 await call.RequestStream.WriteAsync(request); 552 await call.RequestStream.CompleteAsync(); 553 554 try 555 { 556 // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. 557 await call.ResponseStream.ToListAsync(); 558 Assert.Fail(); 559 } 560 catch (RpcException e) 561 { 562 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); 563 Assert.AreEqual(echoStatus.Message, e.Status.Detail); 564 } 565 } 566 567 Console.WriteLine("Passed!"); 568 } 569 RunUnimplementedService(UnimplementedService.UnimplementedServiceClient client)570 public static void RunUnimplementedService(UnimplementedService.UnimplementedServiceClient client) 571 { 572 Console.WriteLine("running unimplemented_service"); 573 var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(new Empty())); 574 575 Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); 576 Console.WriteLine("Passed!"); 577 } 578 RunUnimplementedMethod(TestService.TestServiceClient client)579 public static void RunUnimplementedMethod(TestService.TestServiceClient client) 580 { 581 Console.WriteLine("running unimplemented_method"); 582 var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(new Empty())); 583 584 Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); 585 Console.WriteLine("Passed!"); 586 } 587 RunClientCompressedUnary(TestService.TestServiceClient client)588 public static void RunClientCompressedUnary(TestService.TestServiceClient client) 589 { 590 Console.WriteLine("running client_compressed_unary"); 591 var probeRequest = new SimpleRequest 592 { 593 ExpectCompressed = new BoolValue 594 { 595 Value = true // lie about compression 596 }, 597 ResponseSize = 314159, 598 Payload = CreateZerosPayload(271828) 599 }; 600 var e = Assert.Throws<RpcException>(() => client.UnaryCall(probeRequest, CreateClientCompressionMetadata(false))); 601 Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode); 602 603 var compressedRequest = new SimpleRequest 604 { 605 ExpectCompressed = new BoolValue 606 { 607 Value = true 608 }, 609 ResponseSize = 314159, 610 Payload = CreateZerosPayload(271828) 611 }; 612 var response1 = client.UnaryCall(compressedRequest, CreateClientCompressionMetadata(true)); 613 Assert.AreEqual(314159, response1.Payload.Body.Length); 614 615 var uncompressedRequest = new SimpleRequest 616 { 617 ExpectCompressed = new BoolValue 618 { 619 Value = false 620 }, 621 ResponseSize = 314159, 622 Payload = CreateZerosPayload(271828) 623 }; 624 var response2 = client.UnaryCall(uncompressedRequest, CreateClientCompressionMetadata(false)); 625 Assert.AreEqual(314159, response2.Payload.Body.Length); 626 627 Console.WriteLine("Passed!"); 628 } 629 RunClientCompressedStreamingAsync(TestService.TestServiceClient client)630 public static async Task RunClientCompressedStreamingAsync(TestService.TestServiceClient client) 631 { 632 Console.WriteLine("running client_compressed_streaming"); 633 try 634 { 635 var probeCall = client.StreamingInputCall(CreateClientCompressionMetadata(false)); 636 await probeCall.RequestStream.WriteAsync(new StreamingInputCallRequest 637 { 638 ExpectCompressed = new BoolValue 639 { 640 Value = true 641 }, 642 Payload = CreateZerosPayload(27182) 643 }); 644 645 // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. 646 await probeCall; 647 Assert.Fail(); 648 } 649 catch (RpcException e) 650 { 651 Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode); 652 } 653 654 var call = client.StreamingInputCall(CreateClientCompressionMetadata(true)); 655 await call.RequestStream.WriteAsync(new StreamingInputCallRequest 656 { 657 ExpectCompressed = new BoolValue 658 { 659 Value = true 660 }, 661 Payload = CreateZerosPayload(27182) 662 }); 663 664 call.RequestStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress); 665 await call.RequestStream.WriteAsync(new StreamingInputCallRequest 666 { 667 ExpectCompressed = new BoolValue 668 { 669 Value = false 670 }, 671 Payload = CreateZerosPayload(45904) 672 }); 673 await call.RequestStream.CompleteAsync(); 674 675 var response = await call.ResponseAsync; 676 Assert.AreEqual(73086, response.AggregatedPayloadSize); 677 678 Console.WriteLine("Passed!"); 679 } 680 CreateZerosPayload(int size)681 private static Payload CreateZerosPayload(int size) 682 { 683 return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; 684 } 685 CreateClientCompressionMetadata(bool compressed)686 private static Metadata CreateClientCompressionMetadata(bool compressed) 687 { 688 var algorithmName = compressed ? "gzip" : "identity"; 689 return new Metadata 690 { 691 { new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, algorithmName) } 692 }; 693 } 694 695 // extracts the client_email field from service account file used for auth test cases GetEmailFromServiceAccountFile()696 private static string GetEmailFromServiceAccountFile() 697 { 698 string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"); 699 Assert.IsNotNull(keyFile); 700 var jobject = JObject.Parse(File.ReadAllText(keyFile)); 701 string email = jobject.GetValue("client_email").Value<string>(); 702 Assert.IsTrue(email.Length > 0); // spec requires nonempty client email. 703 return email; 704 } 705 CreateTestMetadata()706 private static Metadata CreateTestMetadata() 707 { 708 return new Metadata 709 { 710 {"x-grpc-test-echo-initial", "test_initial_metadata_value"}, 711 {"x-grpc-test-echo-trailing-bin", new byte[] {0xab, 0xab, 0xab}} 712 }; 713 } 714 } 715 } 716