• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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