• 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", 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