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")] 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 "special_status_message": 189 await RunSpecialStatusMessageAsync(client); 190 break; 191 case "unimplemented_method": 192 RunUnimplementedMethod(client); 193 break; 194 case "client_compressed_unary": 195 RunClientCompressedUnary(client); 196 break; 197 case "client_compressed_streaming": 198 await RunClientCompressedStreamingAsync(client); 199 break; 200 default: 201 throw new ArgumentException("Unknown test case " + options.TestCase); 202 } 203 } 204 RunEmptyUnary(TestService.TestServiceClient client)205 public static void RunEmptyUnary(TestService.TestServiceClient client) 206 { 207 Console.WriteLine("running empty_unary"); 208 var response = client.EmptyCall(new Empty()); 209 Assert.IsNotNull(response); 210 Console.WriteLine("Passed!"); 211 } 212 RunLargeUnary(TestService.TestServiceClient client)213 public static void RunLargeUnary(TestService.TestServiceClient client) 214 { 215 Console.WriteLine("running large_unary"); 216 var request = new SimpleRequest 217 { 218 ResponseSize = 314159, 219 Payload = CreateZerosPayload(271828) 220 }; 221 var response = client.UnaryCall(request); 222 223 Assert.AreEqual(314159, response.Payload.Body.Length); 224 Console.WriteLine("Passed!"); 225 } 226 RunClientStreamingAsync(TestService.TestServiceClient client)227 public static async Task RunClientStreamingAsync(TestService.TestServiceClient client) 228 { 229 Console.WriteLine("running client_streaming"); 230 231 var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.Select((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) }); 232 233 using (var call = client.StreamingInputCall()) 234 { 235 await call.RequestStream.WriteAllAsync(bodySizes); 236 237 var response = await call.ResponseAsync; 238 Assert.AreEqual(74922, response.AggregatedPayloadSize); 239 } 240 Console.WriteLine("Passed!"); 241 } 242 RunServerStreamingAsync(TestService.TestServiceClient client)243 public static async Task RunServerStreamingAsync(TestService.TestServiceClient client) 244 { 245 Console.WriteLine("running server_streaming"); 246 247 var bodySizes = new List<int> { 31415, 9, 2653, 58979 }; 248 249 var request = new StreamingOutputCallRequest 250 { 251 ResponseParameters = { bodySizes.Select((size) => new ResponseParameters { Size = size }) } 252 }; 253 254 using (var call = client.StreamingOutputCall(request)) 255 { 256 var responseList = await call.ResponseStream.ToListAsync(); 257 CollectionAssert.AreEqual(bodySizes, responseList.Select((item) => item.Payload.Body.Length)); 258 } 259 Console.WriteLine("Passed!"); 260 } 261 RunPingPongAsync(TestService.TestServiceClient client)262 public static async Task RunPingPongAsync(TestService.TestServiceClient client) 263 { 264 Console.WriteLine("running ping_pong"); 265 266 using (var call = client.FullDuplexCall()) 267 { 268 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 269 { 270 ResponseParameters = { new ResponseParameters { Size = 31415 } }, 271 Payload = CreateZerosPayload(27182) 272 }); 273 274 Assert.IsTrue(await call.ResponseStream.MoveNext()); 275 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); 276 277 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 278 { 279 ResponseParameters = { new ResponseParameters { Size = 9 } }, 280 Payload = CreateZerosPayload(8) 281 }); 282 283 Assert.IsTrue(await call.ResponseStream.MoveNext()); 284 Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length); 285 286 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 287 { 288 ResponseParameters = { new ResponseParameters { Size = 2653 } }, 289 Payload = CreateZerosPayload(1828) 290 }); 291 292 Assert.IsTrue(await call.ResponseStream.MoveNext()); 293 Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length); 294 295 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 296 { 297 ResponseParameters = { new ResponseParameters { Size = 58979 } }, 298 Payload = CreateZerosPayload(45904) 299 }); 300 301 Assert.IsTrue(await call.ResponseStream.MoveNext()); 302 Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length); 303 304 await call.RequestStream.CompleteAsync(); 305 306 Assert.IsFalse(await call.ResponseStream.MoveNext()); 307 } 308 Console.WriteLine("Passed!"); 309 } 310 RunEmptyStreamAsync(TestService.TestServiceClient client)311 public static async Task RunEmptyStreamAsync(TestService.TestServiceClient client) 312 { 313 Console.WriteLine("running empty_stream"); 314 using (var call = client.FullDuplexCall()) 315 { 316 await call.RequestStream.CompleteAsync(); 317 318 var responseList = await call.ResponseStream.ToListAsync(); 319 Assert.AreEqual(0, responseList.Count); 320 } 321 Console.WriteLine("Passed!"); 322 } 323 RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)324 public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) 325 { 326 Console.WriteLine("running compute_engine_creds"); 327 328 var request = new SimpleRequest 329 { 330 ResponseSize = 314159, 331 Payload = CreateZerosPayload(271828), 332 FillUsername = true, 333 FillOauthScope = true 334 }; 335 336 // not setting credentials here because they were set on channel already 337 var response = client.UnaryCall(request); 338 339 Assert.AreEqual(314159, response.Payload.Body.Length); 340 Assert.False(string.IsNullOrEmpty(response.OauthScope)); 341 Assert.True(oauthScope.Contains(response.OauthScope)); 342 Assert.AreEqual(defaultServiceAccount, response.Username); 343 Console.WriteLine("Passed!"); 344 } 345 RunJwtTokenCreds(TestService.TestServiceClient client)346 public static void RunJwtTokenCreds(TestService.TestServiceClient client) 347 { 348 Console.WriteLine("running jwt_token_creds"); 349 350 var request = new SimpleRequest 351 { 352 ResponseSize = 314159, 353 Payload = CreateZerosPayload(271828), 354 FillUsername = true, 355 }; 356 357 // not setting credentials here because they were set on channel already 358 var response = client.UnaryCall(request); 359 360 Assert.AreEqual(314159, response.Payload.Body.Length); 361 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); 362 Console.WriteLine("Passed!"); 363 } 364 RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)365 public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope) 366 { 367 Console.WriteLine("running oauth2_auth_token"); 368 ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); 369 string oauth2Token = await credential.GetAccessTokenForRequestAsync(); 370 371 var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token); 372 var request = new SimpleRequest 373 { 374 FillUsername = true, 375 FillOauthScope = true 376 }; 377 378 var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); 379 380 Assert.False(string.IsNullOrEmpty(response.OauthScope)); 381 Assert.True(oauthScope.Contains(response.OauthScope)); 382 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); 383 Console.WriteLine("Passed!"); 384 } 385 RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)386 public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope) 387 { 388 Console.WriteLine("running per_rpc_creds"); 389 ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); 390 391 var credentials = googleCredential.ToCallCredentials(); 392 var request = new SimpleRequest 393 { 394 FillUsername = true, 395 }; 396 397 var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); 398 399 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); 400 Console.WriteLine("Passed!"); 401 } 402 RunCancelAfterBeginAsync(TestService.TestServiceClient client)403 public static async Task RunCancelAfterBeginAsync(TestService.TestServiceClient client) 404 { 405 Console.WriteLine("running cancel_after_begin"); 406 407 var cts = new CancellationTokenSource(); 408 using (var call = client.StreamingInputCall(cancellationToken: cts.Token)) 409 { 410 // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. 411 await Task.Delay(1000); 412 cts.Cancel(); 413 414 var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseAsync); 415 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); 416 } 417 Console.WriteLine("Passed!"); 418 } 419 RunCancelAfterFirstResponseAsync(TestService.TestServiceClient client)420 public static async Task RunCancelAfterFirstResponseAsync(TestService.TestServiceClient client) 421 { 422 Console.WriteLine("running cancel_after_first_response"); 423 424 var cts = new CancellationTokenSource(); 425 using (var call = client.FullDuplexCall(cancellationToken: cts.Token)) 426 { 427 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest 428 { 429 ResponseParameters = { new ResponseParameters { Size = 31415 } }, 430 Payload = CreateZerosPayload(27182) 431 }); 432 433 Assert.IsTrue(await call.ResponseStream.MoveNext()); 434 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); 435 436 cts.Cancel(); 437 438 try 439 { 440 // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. 441 await call.ResponseStream.MoveNext(); 442 Assert.Fail(); 443 } 444 catch (RpcException ex) 445 { 446 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); 447 } 448 } 449 Console.WriteLine("Passed!"); 450 } 451 RunTimeoutOnSleepingServerAsync(TestService.TestServiceClient client)452 public static async Task RunTimeoutOnSleepingServerAsync(TestService.TestServiceClient client) 453 { 454 Console.WriteLine("running timeout_on_sleeping_server"); 455 456 var deadline = DateTime.UtcNow.AddMilliseconds(1); 457 using (var call = client.FullDuplexCall(deadline: deadline)) 458 { 459 try 460 { 461 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { Payload = CreateZerosPayload(27182) }); 462 } 463 catch (InvalidOperationException) 464 { 465 // Deadline was reached before write has started. Eat the exception and continue. 466 } 467 catch (RpcException) 468 { 469 // Deadline was reached before write has started. Eat the exception and continue. 470 } 471 472 try 473 { 474 await call.ResponseStream.MoveNext(); 475 Assert.Fail(); 476 } 477 catch (RpcException ex) 478 { 479 Assert.AreEqual(StatusCode.DeadlineExceeded, ex.Status.StatusCode); 480 } 481 } 482 Console.WriteLine("Passed!"); 483 } 484 RunCustomMetadataAsync(TestService.TestServiceClient client)485 public static async Task RunCustomMetadataAsync(TestService.TestServiceClient client) 486 { 487 Console.WriteLine("running custom_metadata"); 488 { 489 // step 1: test unary call 490 var request = new SimpleRequest 491 { 492 ResponseSize = 314159, 493 Payload = CreateZerosPayload(271828) 494 }; 495 496 var call = client.UnaryCallAsync(request, headers: CreateTestMetadata()); 497 await call.ResponseAsync; 498 499 var responseHeaders = await call.ResponseHeadersAsync; 500 var responseTrailers = call.GetTrailers(); 501 502 Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value); 503 CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes); 504 } 505 506 { 507 // step 2: test full duplex call 508 var request = new StreamingOutputCallRequest 509 { 510 ResponseParameters = { new ResponseParameters { Size = 31415 } }, 511 Payload = CreateZerosPayload(27182) 512 }; 513 514 var call = client.FullDuplexCall(headers: CreateTestMetadata()); 515 516 await call.RequestStream.WriteAsync(request); 517 await call.RequestStream.CompleteAsync(); 518 await call.ResponseStream.ToListAsync(); 519 520 var responseHeaders = await call.ResponseHeadersAsync; 521 var responseTrailers = call.GetTrailers(); 522 523 Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value); 524 CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes); 525 } 526 527 Console.WriteLine("Passed!"); 528 } 529 RunStatusCodeAndMessageAsync(TestService.TestServiceClient client)530 public static async Task RunStatusCodeAndMessageAsync(TestService.TestServiceClient client) 531 { 532 Console.WriteLine("running status_code_and_message"); 533 var echoStatus = new EchoStatus 534 { 535 Code = 2, 536 Message = "test status message" 537 }; 538 539 { 540 // step 1: test unary call 541 var request = new SimpleRequest { ResponseStatus = echoStatus }; 542 543 var e = Assert.Throws<RpcException>(() => client.UnaryCall(request)); 544 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); 545 Assert.AreEqual(echoStatus.Message, e.Status.Detail); 546 } 547 548 { 549 // step 2: test full duplex call 550 var request = new StreamingOutputCallRequest { ResponseStatus = echoStatus }; 551 552 var call = client.FullDuplexCall(); 553 await call.RequestStream.WriteAsync(request); 554 await call.RequestStream.CompleteAsync(); 555 556 try 557 { 558 // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. 559 await call.ResponseStream.ToListAsync(); 560 Assert.Fail(); 561 } 562 catch (RpcException e) 563 { 564 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); 565 Assert.AreEqual(echoStatus.Message, e.Status.Detail); 566 } 567 } 568 569 Console.WriteLine("Passed!"); 570 } 571 RunSpecialStatusMessageAsync(TestService.TestServiceClient client)572 private static async Task RunSpecialStatusMessageAsync(TestService.TestServiceClient client) 573 { 574 Console.WriteLine("running special_status_message"); 575 576 var echoStatus = new EchoStatus 577 { 578 Code = 2, 579 Message = "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP \t\n" 580 }; 581 582 try 583 { 584 await client.UnaryCallAsync(new SimpleRequest 585 { 586 ResponseStatus = echoStatus 587 }); 588 Assert.Fail(); 589 } 590 catch (RpcException e) 591 { 592 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); 593 Assert.AreEqual(echoStatus.Message, e.Status.Detail); 594 } 595 596 Console.WriteLine("Passed!"); 597 } 598 RunUnimplementedService(UnimplementedService.UnimplementedServiceClient client)599 public static void RunUnimplementedService(UnimplementedService.UnimplementedServiceClient client) 600 { 601 Console.WriteLine("running unimplemented_service"); 602 var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(new Empty())); 603 604 Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); 605 Console.WriteLine("Passed!"); 606 } 607 RunUnimplementedMethod(TestService.TestServiceClient client)608 public static void RunUnimplementedMethod(TestService.TestServiceClient client) 609 { 610 Console.WriteLine("running unimplemented_method"); 611 var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(new Empty())); 612 613 Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); 614 Console.WriteLine("Passed!"); 615 } 616 RunClientCompressedUnary(TestService.TestServiceClient client)617 public static void RunClientCompressedUnary(TestService.TestServiceClient client) 618 { 619 Console.WriteLine("running client_compressed_unary"); 620 var probeRequest = new SimpleRequest 621 { 622 ExpectCompressed = new BoolValue 623 { 624 Value = true // lie about compression 625 }, 626 ResponseSize = 314159, 627 Payload = CreateZerosPayload(271828) 628 }; 629 var e = Assert.Throws<RpcException>(() => client.UnaryCall(probeRequest, CreateClientCompressionMetadata(false))); 630 Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode); 631 632 var compressedRequest = new SimpleRequest 633 { 634 ExpectCompressed = new BoolValue 635 { 636 Value = true 637 }, 638 ResponseSize = 314159, 639 Payload = CreateZerosPayload(271828) 640 }; 641 var response1 = client.UnaryCall(compressedRequest, CreateClientCompressionMetadata(true)); 642 Assert.AreEqual(314159, response1.Payload.Body.Length); 643 644 var uncompressedRequest = new SimpleRequest 645 { 646 ExpectCompressed = new BoolValue 647 { 648 Value = false 649 }, 650 ResponseSize = 314159, 651 Payload = CreateZerosPayload(271828) 652 }; 653 var response2 = client.UnaryCall(uncompressedRequest, CreateClientCompressionMetadata(false)); 654 Assert.AreEqual(314159, response2.Payload.Body.Length); 655 656 Console.WriteLine("Passed!"); 657 } 658 RunClientCompressedStreamingAsync(TestService.TestServiceClient client)659 public static async Task RunClientCompressedStreamingAsync(TestService.TestServiceClient client) 660 { 661 Console.WriteLine("running client_compressed_streaming"); 662 try 663 { 664 var probeCall = client.StreamingInputCall(CreateClientCompressionMetadata(false)); 665 await probeCall.RequestStream.WriteAsync(new StreamingInputCallRequest 666 { 667 ExpectCompressed = new BoolValue 668 { 669 Value = true 670 }, 671 Payload = CreateZerosPayload(27182) 672 }); 673 674 // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock. 675 await probeCall; 676 Assert.Fail(); 677 } 678 catch (RpcException e) 679 { 680 Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode); 681 } 682 683 var call = client.StreamingInputCall(CreateClientCompressionMetadata(true)); 684 await call.RequestStream.WriteAsync(new StreamingInputCallRequest 685 { 686 ExpectCompressed = new BoolValue 687 { 688 Value = true 689 }, 690 Payload = CreateZerosPayload(27182) 691 }); 692 693 call.RequestStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress); 694 await call.RequestStream.WriteAsync(new StreamingInputCallRequest 695 { 696 ExpectCompressed = new BoolValue 697 { 698 Value = false 699 }, 700 Payload = CreateZerosPayload(45904) 701 }); 702 await call.RequestStream.CompleteAsync(); 703 704 var response = await call.ResponseAsync; 705 Assert.AreEqual(73086, response.AggregatedPayloadSize); 706 707 Console.WriteLine("Passed!"); 708 } 709 CreateZerosPayload(int size)710 private static Payload CreateZerosPayload(int size) 711 { 712 return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; 713 } 714 CreateClientCompressionMetadata(bool compressed)715 private static Metadata CreateClientCompressionMetadata(bool compressed) 716 { 717 var algorithmName = compressed ? "gzip" : "identity"; 718 return new Metadata 719 { 720 { new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, algorithmName) } 721 }; 722 } 723 724 // extracts the client_email field from service account file used for auth test cases GetEmailFromServiceAccountFile()725 private static string GetEmailFromServiceAccountFile() 726 { 727 string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"); 728 Assert.IsNotNull(keyFile); 729 var jobject = JObject.Parse(File.ReadAllText(keyFile)); 730 string email = jobject.GetValue("client_email").Value<string>(); 731 Assert.IsTrue(email.Length > 0); // spec requires nonempty client email. 732 return email; 733 } 734 CreateTestMetadata()735 private static Metadata CreateTestMetadata() 736 { 737 return new Metadata 738 { 739 {"x-grpc-test-echo-initial", "test_initial_metadata_value"}, 740 {"x-grpc-test-echo-trailing-bin", new byte[] {0xab, 0xab, 0xab}} 741 }; 742 } 743 } 744 } 745