blob: cff85086310711a3b2a88fad410f250552fe0cc5 [file] [log] [blame]
Jan Tattermuscha7fff862015-02-13 11:08:08 -08001#region Copyright notice and license
2
Jan Tattermuschacb842c2016-03-25 16:54:14 -07003// Copyright 2015-2016, Google Inc.
Jan Tattermuscha7fff862015-02-13 11:08:08 -08004// All rights reserved.
Craig Tiller190d3602015-02-18 09:23:38 -08005//
Jan Tattermuscha7fff862015-02-13 11:08:08 -08006// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
Craig Tiller190d3602015-02-18 09:23:38 -08009//
Jan Tattermuscha7fff862015-02-13 11:08:08 -080010// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
Craig Tiller190d3602015-02-18 09:23:38 -080019//
Jan Tattermuscha7fff862015-02-13 11:08:08 -080020// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32#endregion
33
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -080034using System;
Jan Tattermuschd233d3a2015-02-06 14:15:00 -080035using System.Collections.Generic;
Jan Tattermusch74f39e12015-09-23 20:14:56 -070036using System.IO;
Jan Tattermusch0ed73152015-12-09 18:21:11 -080037using System.Linq;
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -080038using System.Text.RegularExpressions;
Jan Tattermusche5c44602015-05-01 11:12:34 -070039using System.Threading;
Jan Tattermuscha5272b62015-04-30 11:56:46 -070040using System.Threading.Tasks;
Jan Tattermusch1ca56b92015-04-27 11:03:06 -070041
Jan Tattermuschb26972f2015-09-03 17:47:14 -070042using CommandLine;
Jan Tattermusch74f39e12015-09-23 20:14:56 -070043using CommandLine.Text;
Jan Tattermusch67c45872015-08-27 18:12:39 -070044using Google.Apis.Auth.OAuth2;
45using Google.Protobuf;
Jan Tattermuschdca6e882015-04-22 16:56:27 -070046using Grpc.Auth;
Jan Tattermusch30868622015-02-19 09:22:33 -080047using Grpc.Core;
48using Grpc.Core.Utils;
Jan Tattermusch8644aea2015-08-03 10:21:18 -070049using Grpc.Testing;
Jan Tattermusch64d7c242015-10-08 08:02:27 -070050using Newtonsoft.Json.Linq;
Jan Tattermusch30868622015-02-19 09:22:33 -080051using NUnit.Framework;
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -080052
Jan Tattermusch8b86b152015-02-19 21:01:05 -080053namespace Grpc.IntegrationTesting
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -080054{
Jan Tattermusch503bbac2015-02-26 18:19:47 -080055 public class InteropClient
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -080056 {
57 private class ClientOptions
58 {
Jan Tattermuschb26972f2015-09-03 17:47:14 -070059 [Option("server_host", DefaultValue = "127.0.0.1")]
60 public string ServerHost { get; set; }
61
62 [Option("server_host_override", DefaultValue = TestCredentials.DefaultHostOverride)]
63 public string ServerHostOverride { get; set; }
64
65 [Option("server_port", Required = true)]
66 public int ServerPort { get; set; }
67
68 [Option("test_case", DefaultValue = "large_unary")]
69 public string TestCase { get; set; }
70
Jan Tattermusch7828e812015-10-07 17:27:48 -070071 // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
72 [Option("use_tls", DefaultValue = false)]
73 public bool? UseTls { get; set; }
Jan Tattermuschb26972f2015-09-03 17:47:14 -070074
Jan Tattermusch7828e812015-10-07 17:27:48 -070075 // Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca)
76 [Option("use_test_ca", DefaultValue = false)]
77 public bool? UseTestCa { get; set; }
Jan Tattermuschb26972f2015-09-03 17:47:14 -070078
79 [Option("default_service_account", Required = false)]
80 public string DefaultServiceAccount { get; set; }
81
82 [Option("oauth_scope", Required = false)]
83 public string OAuthScope { get; set; }
84
85 [Option("service_account_key_file", Required = false)]
86 public string ServiceAccountKeyFile { get; set; }
87
88 [HelpOption]
89 public string GetUsage()
90 {
91 var help = new HelpText
92 {
93 Heading = "gRPC C# interop testing client",
94 AddDashesToOption = true
95 };
96 help.AddPreOptionsLine("Usage:");
97 help.AddOptions(this);
98 return help;
99 }
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800100 }
101
102 ClientOptions options;
103
Jan Tattermusch503bbac2015-02-26 18:19:47 -0800104 private InteropClient(ClientOptions options)
Jan Tattermusch392d1e02015-02-09 11:13:51 -0800105 {
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800106 this.options = options;
107 }
108
Jan Tattermusch503bbac2015-02-26 18:19:47 -0800109 public static void Run(string[] args)
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800110 {
Jan Tattermuschb26972f2015-09-03 17:47:14 -0700111 var options = new ClientOptions();
112 if (!Parser.Default.ParseArguments(args, options))
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800113 {
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800114 Environment.Exit(1);
115 }
116
Jan Tattermusch503bbac2015-02-26 18:19:47 -0800117 var interopClient = new InteropClient(options);
Jan Tattermusch0c140a82015-08-02 00:54:02 -0700118 interopClient.Run().Wait();
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800119 }
120
Jan Tattermusch0c140a82015-08-02 00:54:02 -0700121 private async Task Run()
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800122 {
Jan Tattermusch9e5e7e92015-09-24 10:34:05 -0700123 var credentials = await CreateCredentialsAsync();
124
125 List<ChannelOption> channelOptions = null;
126 if (!string.IsNullOrEmpty(options.ServerHostOverride))
127 {
128 channelOptions = new List<ChannelOption>
129 {
130 new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride)
131 };
132 }
133 var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions);
Jan Tattermuschfa20ebc2015-12-09 18:38:10 -0800134 await RunTestCaseAsync(channel, options);
Jan Tattermusch9e5e7e92015-09-24 10:34:05 -0700135 await channel.ShutdownAsync();
136 }
137
Jan Tattermusch5bd70052015-10-06 16:47:49 -0700138 private async Task<ChannelCredentials> CreateCredentialsAsync()
Jan Tattermusch9e5e7e92015-09-24 10:34:05 -0700139 {
Jan Tattermuschbeffc772015-10-22 13:28:22 -0700140 var credentials = ChannelCredentials.Insecure;
141 if (options.UseTls.Value)
142 {
143 credentials = options.UseTestCa.Value ? TestCredentials.CreateSslCredentials() : new SslCredentials();
144 }
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700145
146 if (options.TestCase == "jwt_token_creds")
147 {
148 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
149 Assert.IsTrue(googleCredential.IsCreateScopedRequired);
Jan Tattermusch18729a02015-10-08 18:40:00 -0700150 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700151 }
152
153 if (options.TestCase == "compute_engine_creds")
154 {
155 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
156 Assert.IsFalse(googleCredential.IsCreateScopedRequired);
Jan Tattermusch18729a02015-10-08 18:40:00 -0700157 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700158 }
Jan Tattermusch9e5e7e92015-09-24 10:34:05 -0700159 return credentials;
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800160 }
161
Jan Tattermuschfa20ebc2015-12-09 18:38:10 -0800162 private async Task RunTestCaseAsync(Channel channel, ClientOptions options)
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800163 {
Jan Tattermuschfa20ebc2015-12-09 18:38:10 -0800164 var client = new TestService.TestServiceClient(channel);
Jan Tattermuschb26972f2015-09-03 17:47:14 -0700165 switch (options.TestCase)
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800166 {
167 case "empty_unary":
168 RunEmptyUnary(client);
169 break;
170 case "large_unary":
171 RunLargeUnary(client);
172 break;
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800173 case "client_streaming":
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700174 await RunClientStreamingAsync(client);
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800175 break;
176 case "server_streaming":
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700177 await RunServerStreamingAsync(client);
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800178 break;
179 case "ping_pong":
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700180 await RunPingPongAsync(client);
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800181 break;
182 case "empty_stream":
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700183 await RunEmptyStreamAsync(client);
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800184 break;
Jan Tattermusch0bbfa382015-04-27 16:11:59 -0700185 case "compute_engine_creds":
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700186 RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope);
Jan Tattermusch0c140a82015-08-02 00:54:02 -0700187 break;
188 case "jwt_token_creds":
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700189 RunJwtTokenCreds(client);
Jan Tattermusch0bbfa382015-04-27 16:11:59 -0700190 break;
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700191 case "oauth2_auth_token":
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700192 await RunOAuth2AuthTokenAsync(client, options.OAuthScope);
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700193 break;
194 case "per_rpc_creds":
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700195 await RunPerRpcCredsAsync(client, options.OAuthScope);
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700196 break;
Jan Tattermusche5c44602015-05-01 11:12:34 -0700197 case "cancel_after_begin":
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700198 await RunCancelAfterBeginAsync(client);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700199 break;
200 case "cancel_after_first_response":
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700201 await RunCancelAfterFirstResponseAsync(client);
Jan Tattermusche5c44602015-05-01 11:12:34 -0700202 break;
Jan Tattermusche4134dd2015-08-12 14:54:40 -0700203 case "timeout_on_sleeping_server":
204 await RunTimeoutOnSleepingServerAsync(client);
205 break;
Jan Tattermusch0ed73152015-12-09 18:21:11 -0800206 case "custom_metadata":
207 await RunCustomMetadataAsync(client);
208 break;
209 case "status_code_and_message":
210 await RunStatusCodeAndMessageAsync(client);
Jan Tattermusch50faa8f2015-02-21 17:51:52 -0800211 break;
Jan Tattermuschfa20ebc2015-12-09 18:38:10 -0800212 case "unimplemented_method":
213 RunUnimplementedMethod(new UnimplementedService.UnimplementedServiceClient(channel));
214 break;
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800215 default:
Jan Tattermuschb26972f2015-09-03 17:47:14 -0700216 throw new ArgumentException("Unknown test case " + options.TestCase);
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800217 }
218 }
219
Jan Tattermusch809148d2016-03-22 15:09:41 -0700220 public static void RunEmptyUnary(TestService.TestServiceClient client)
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800221 {
222 Console.WriteLine("running empty_unary");
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700223 var response = client.EmptyCall(new Empty());
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800224 Assert.IsNotNull(response);
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800225 Console.WriteLine("Passed!");
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800226 }
227
Jan Tattermusch809148d2016-03-22 15:09:41 -0700228 public static void RunLargeUnary(TestService.TestServiceClient client)
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800229 {
230 Console.WriteLine("running large_unary");
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700231 var request = new SimpleRequest
232 {
233 ResponseType = PayloadType.COMPRESSABLE,
234 ResponseSize = 314159,
235 Payload = CreateZerosPayload(271828)
236 };
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800237 var response = client.UnaryCall(request);
238
239 Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
240 Assert.AreEqual(314159, response.Payload.Body.Length);
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800241 Console.WriteLine("Passed!");
242 }
243
Jan Tattermusch809148d2016-03-22 15:09:41 -0700244 public static async Task RunClientStreamingAsync(TestService.TestServiceClient client)
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800245 {
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700246 Console.WriteLine("running client_streaming");
247
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700248 var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) });
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700249
250 using (var call = client.StreamingInputCall())
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800251 {
Jan Tattermuschf22abfb2015-08-09 16:15:34 -0700252 await call.RequestStream.WriteAllAsync(bodySizes);
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800253
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700254 var response = await call.ResponseAsync;
255 Assert.AreEqual(74922, response.AggregatedPayloadSize);
256 }
257 Console.WriteLine("Passed!");
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800258 }
259
Jan Tattermusch809148d2016-03-22 15:09:41 -0700260 public static async Task RunServerStreamingAsync(TestService.TestServiceClient client)
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800261 {
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700262 Console.WriteLine("running server_streaming");
263
264 var bodySizes = new List<int> { 31415, 9, 2653, 58979 };
265
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700266 var request = new StreamingOutputCallRequest
267 {
268 ResponseType = PayloadType.COMPRESSABLE,
269 ResponseParameters = { bodySizes.ConvertAll((size) => new ResponseParameters { Size = size }) }
270 };
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700271
272 using (var call = client.StreamingOutputCall(request))
Jan Tattermuscha5272b62015-04-30 11:56:46 -0700273 {
Jan Tattermuschf22abfb2015-08-09 16:15:34 -0700274 var responseList = await call.ResponseStream.ToListAsync();
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700275 foreach (var res in responseList)
276 {
277 Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type);
278 }
279 CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length));
280 }
281 Console.WriteLine("Passed!");
282 }
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800283
Jan Tattermusch809148d2016-03-22 15:09:41 -0700284 public static async Task RunPingPongAsync(TestService.TestServiceClient client)
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700285 {
286 Console.WriteLine("running ping_pong");
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800287
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700288 using (var call = client.FullDuplexCall())
289 {
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700290 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
291 {
292 ResponseType = PayloadType.COMPRESSABLE,
293 ResponseParameters = { new ResponseParameters { Size = 31415 } },
294 Payload = CreateZerosPayload(27182)
295 });
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800296
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700297 Assert.IsTrue(await call.ResponseStream.MoveNext());
298 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
299 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
300
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700301 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
302 {
303 ResponseType = PayloadType.COMPRESSABLE,
304 ResponseParameters = { new ResponseParameters { Size = 9 } },
305 Payload = CreateZerosPayload(8)
306 });
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700307
308 Assert.IsTrue(await call.ResponseStream.MoveNext());
309 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
310 Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
311
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700312 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
313 {
314 ResponseType = PayloadType.COMPRESSABLE,
315 ResponseParameters = { new ResponseParameters { Size = 2653 } },
316 Payload = CreateZerosPayload(1828)
317 });
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700318
319 Assert.IsTrue(await call.ResponseStream.MoveNext());
320 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
321 Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
322
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700323 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
324 {
325 ResponseType = PayloadType.COMPRESSABLE,
326 ResponseParameters = { new ResponseParameters { Size = 58979 } },
327 Payload = CreateZerosPayload(45904)
328 });
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700329
330 Assert.IsTrue(await call.ResponseStream.MoveNext());
331 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
332 Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length);
333
334 await call.RequestStream.CompleteAsync();
335
336 Assert.IsFalse(await call.ResponseStream.MoveNext());
337 }
338 Console.WriteLine("Passed!");
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800339 }
340
Jan Tattermusch809148d2016-03-22 15:09:41 -0700341 public static async Task RunEmptyStreamAsync(TestService.TestServiceClient client)
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800342 {
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700343 Console.WriteLine("running empty_stream");
344 using (var call = client.FullDuplexCall())
Jan Tattermuscha5272b62015-04-30 11:56:46 -0700345 {
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700346 await call.RequestStream.CompleteAsync();
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800347
Jan Tattermuschf22abfb2015-08-09 16:15:34 -0700348 var responseList = await call.ResponseStream.ToListAsync();
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700349 Assert.AreEqual(0, responseList.Count);
350 }
351 Console.WriteLine("Passed!");
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800352 }
353
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700354 public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
Jan Tattermusch0bbfa382015-04-27 16:11:59 -0700355 {
356 Console.WriteLine("running compute_engine_creds");
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700357
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700358 var request = new SimpleRequest
359 {
360 ResponseType = PayloadType.COMPRESSABLE,
361 ResponseSize = 314159,
362 Payload = CreateZerosPayload(271828),
363 FillUsername = true,
364 FillOauthScope = true
365 };
Jan Tattermusch0bbfa382015-04-27 16:11:59 -0700366
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700367 // not setting credentials here because they were set on channel already
Jan Tattermusch0bbfa382015-04-27 16:11:59 -0700368 var response = client.UnaryCall(request);
369
370 Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
371 Assert.AreEqual(314159, response.Payload.Body.Length);
Jan Tattermuschb26972f2015-09-03 17:47:14 -0700372 Assert.False(string.IsNullOrEmpty(response.OauthScope));
373 Assert.True(oauthScope.Contains(response.OauthScope));
374 Assert.AreEqual(defaultServiceAccount, response.Username);
Jan Tattermusch0bbfa382015-04-27 16:11:59 -0700375 Console.WriteLine("Passed!");
376 }
377
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700378 public static void RunJwtTokenCreds(TestService.TestServiceClient client)
Jan Tattermusch0c140a82015-08-02 00:54:02 -0700379 {
380 Console.WriteLine("running jwt_token_creds");
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700381
Jan Tattermusch46e85b02015-08-13 10:31:05 -0700382 var request = new SimpleRequest
383 {
384 ResponseType = PayloadType.COMPRESSABLE,
385 ResponseSize = 314159,
386 Payload = CreateZerosPayload(271828),
387 FillUsername = true,
Jan Tattermusch46e85b02015-08-13 10:31:05 -0700388 };
Jan Tattermusch0c140a82015-08-02 00:54:02 -0700389
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700390 // not setting credentials here because they were set on channel already
Jan Tattermusch0c140a82015-08-02 00:54:02 -0700391 var response = client.UnaryCall(request);
392
393 Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
394 Assert.AreEqual(314159, response.Payload.Body.Length);
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700395 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Jan Tattermusch0c140a82015-08-02 00:54:02 -0700396 Console.WriteLine("Passed!");
397 }
398
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700399 public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700400 {
401 Console.WriteLine("running oauth2_auth_token");
Jan Tattermuschb26972f2015-09-03 17:47:14 -0700402 ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
Jan Tattermusch0c140a82015-08-02 00:54:02 -0700403 string oauth2Token = await credential.GetAccessTokenForRequestAsync();
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700404
Jan Tattermusch18729a02015-10-08 18:40:00 -0700405 var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token);
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700406 var request = new SimpleRequest
407 {
408 FillUsername = true,
409 FillOauthScope = true
410 };
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700411
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700412 var response = client.UnaryCall(request, new CallOptions(credentials: credentials));
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700413
Jan Tattermuschb26972f2015-09-03 17:47:14 -0700414 Assert.False(string.IsNullOrEmpty(response.OauthScope));
415 Assert.True(oauthScope.Contains(response.OauthScope));
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700416 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700417 Console.WriteLine("Passed!");
418 }
419
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700420 public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700421 {
422 Console.WriteLine("running per_rpc_creds");
Jan Tattermuschcf72a3a2015-10-08 08:44:20 -0700423 ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700424
Jan Tattermusch18729a02015-10-08 18:40:00 -0700425 var credentials = googleCredential.ToCallCredentials();
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700426 var request = new SimpleRequest
427 {
428 FillUsername = true,
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700429 };
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700430
Jan Tattermusch74f39e12015-09-23 20:14:56 -0700431 var response = client.UnaryCall(request, new CallOptions(credentials: credentials));
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700432
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700433 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Jan Tattermusch7b4a31f2015-07-20 17:08:13 -0700434 Console.WriteLine("Passed!");
435 }
436
Jan Tattermusch809148d2016-03-22 15:09:41 -0700437 public static async Task RunCancelAfterBeginAsync(TestService.TestServiceClient client)
Jan Tattermusche5c44602015-05-01 11:12:34 -0700438 {
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700439 Console.WriteLine("running cancel_after_begin");
440
441 var cts = new CancellationTokenSource();
442 using (var call = client.StreamingInputCall(cancellationToken: cts.Token))
Jan Tattermusche5c44602015-05-01 11:12:34 -0700443 {
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700444 // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
445 await Task.Delay(1000);
446 cts.Cancel();
Jan Tattermusche5c44602015-05-01 11:12:34 -0700447
Jan Tattermusch9f19bd32016-04-08 13:32:30 -0700448 var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseAsync);
Jan Tattermuschc8d7b842015-08-07 20:52:21 -0700449 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700450 }
451 Console.WriteLine("Passed!");
Jan Tattermusche5c44602015-05-01 11:12:34 -0700452 }
453
Jan Tattermusch809148d2016-03-22 15:09:41 -0700454 public static async Task RunCancelAfterFirstResponseAsync(TestService.TestServiceClient client)
Jan Tattermusche5c44602015-05-01 11:12:34 -0700455 {
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700456 Console.WriteLine("running cancel_after_first_response");
457
458 var cts = new CancellationTokenSource();
459 using (var call = client.FullDuplexCall(cancellationToken: cts.Token))
Jan Tattermusche5c44602015-05-01 11:12:34 -0700460 {
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700461 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
462 {
463 ResponseType = PayloadType.COMPRESSABLE,
464 ResponseParameters = { new ResponseParameters { Size = 31415 } },
465 Payload = CreateZerosPayload(27182)
466 });
Jan Tattermusche5c44602015-05-01 11:12:34 -0700467
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700468 Assert.IsTrue(await call.ResponseStream.MoveNext());
469 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
470 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
471
472 cts.Cancel();
473
Jan Tattermusch9f19bd32016-04-08 13:32:30 -0700474 var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
Jan Tattermuschc8d7b842015-08-07 20:52:21 -0700475 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
Jan Tattermuschb98e1dd2015-07-24 21:30:14 -0700476 }
477 Console.WriteLine("Passed!");
Jan Tattermusche5c44602015-05-01 11:12:34 -0700478 }
479
Jan Tattermusch809148d2016-03-22 15:09:41 -0700480 public static async Task RunTimeoutOnSleepingServerAsync(TestService.TestServiceClient client)
Jan Tattermusche4134dd2015-08-12 14:54:40 -0700481 {
482 Console.WriteLine("running timeout_on_sleeping_server");
483
484 var deadline = DateTime.UtcNow.AddMilliseconds(1);
485 using (var call = client.FullDuplexCall(deadline: deadline))
486 {
487 try
488 {
Jan Tattermusch0608a002015-08-26 08:50:19 -0700489 await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { Payload = CreateZerosPayload(27182) });
Jan Tattermusche4134dd2015-08-12 14:54:40 -0700490 }
491 catch (InvalidOperationException)
492 {
493 // Deadline was reached before write has started. Eat the exception and continue.
494 }
Jan Tattermuscha46d21d2016-05-10 09:57:51 -0700495 catch (RpcException)
496 {
497 // Deadline was reached before write has started. Eat the exception and continue.
498 }
Jan Tattermusche4134dd2015-08-12 14:54:40 -0700499
Jan Tattermusch9f19bd32016-04-08 13:32:30 -0700500 var ex = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.MoveNext());
Jan Tattermusch85c3ab02016-04-26 17:17:02 -0700501 // We can't guarantee the status code always DeadlineExceeded. See issue #2685.
502 Assert.Contains(ex.Status.StatusCode, new[] { StatusCode.DeadlineExceeded, StatusCode.Internal });
Jan Tattermusche4134dd2015-08-12 14:54:40 -0700503 }
504 Console.WriteLine("Passed!");
505 }
506
Jan Tattermusch809148d2016-03-22 15:09:41 -0700507 public static async Task RunCustomMetadataAsync(TestService.TestServiceClient client)
Jan Tattermusch50faa8f2015-02-21 17:51:52 -0800508 {
Jan Tattermusch0ed73152015-12-09 18:21:11 -0800509 Console.WriteLine("running custom_metadata");
510 {
511 // step 1: test unary call
512 var request = new SimpleRequest
513 {
514 ResponseType = PayloadType.COMPRESSABLE,
515 ResponseSize = 314159,
516 Payload = CreateZerosPayload(271828)
517 };
518
519 var call = client.UnaryCallAsync(request, headers: CreateTestMetadata());
520 await call.ResponseAsync;
521
522 var responseHeaders = await call.ResponseHeadersAsync;
523 var responseTrailers = call.GetTrailers();
524
525 Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value);
526 CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes);
527 }
528
529 {
530 // step 2: test full duplex call
531 var request = new StreamingOutputCallRequest
532 {
533 ResponseType = PayloadType.COMPRESSABLE,
534 ResponseParameters = { new ResponseParameters { Size = 31415 } },
535 Payload = CreateZerosPayload(27182)
536 };
537
538 var call = client.FullDuplexCall(headers: CreateTestMetadata());
539 var responseHeaders = await call.ResponseHeadersAsync;
540
541 await call.RequestStream.WriteAsync(request);
542 await call.RequestStream.CompleteAsync();
543 await call.ResponseStream.ToListAsync();
544
545 var responseTrailers = call.GetTrailers();
546
547 Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value);
548 CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes);
549 }
550
551 Console.WriteLine("Passed!");
552 }
553
Jan Tattermusch809148d2016-03-22 15:09:41 -0700554 public static async Task RunStatusCodeAndMessageAsync(TestService.TestServiceClient client)
Jan Tattermusch0ed73152015-12-09 18:21:11 -0800555 {
556 Console.WriteLine("running status_code_and_message");
557 var echoStatus = new EchoStatus
558 {
559 Code = 2,
560 Message = "test status message"
561 };
562
563 {
564 // step 1: test unary call
565 var request = new SimpleRequest { ResponseStatus = echoStatus };
566
567 var e = Assert.Throws<RpcException>(() => client.UnaryCall(request));
568 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
569 Assert.AreEqual(echoStatus.Message, e.Status.Detail);
570 }
571
572 {
573 // step 2: test full duplex call
574 var request = new StreamingOutputCallRequest { ResponseStatus = echoStatus };
575
576 var call = client.FullDuplexCall();
577 await call.RequestStream.WriteAsync(request);
578 await call.RequestStream.CompleteAsync();
579
Jan Tattermusch9f19bd32016-04-08 13:32:30 -0700580 var e = Assert.ThrowsAsync<RpcException>(async () => await call.ResponseStream.ToListAsync());
Jan Tattermusch0ed73152015-12-09 18:21:11 -0800581 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
582 Assert.AreEqual(echoStatus.Message, e.Status.Detail);
583 }
584
585 Console.WriteLine("Passed!");
Jan Tattermusch50faa8f2015-02-21 17:51:52 -0800586 }
Jan Tattermuschd233d3a2015-02-06 14:15:00 -0800587
Jan Tattermusch809148d2016-03-22 15:09:41 -0700588 public static void RunUnimplementedMethod(UnimplementedService.UnimplementedServiceClient client)
Jan Tattermuschfa20ebc2015-12-09 18:38:10 -0800589 {
590 Console.WriteLine("running unimplemented_method");
591 var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(new Empty()));
592
593 Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode);
594 Assert.AreEqual("", e.Status.Detail);
595 Console.WriteLine("Passed!");
596 }
597
Jan Tattermusch075dde42015-03-11 18:21:00 -0700598 private static Payload CreateZerosPayload(int size)
599 {
Jan Tattermusch8644aea2015-08-03 10:21:18 -0700600 return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800601 }
Jan Tattermusch64d7c242015-10-08 08:02:27 -0700602
603 // extracts the client_email field from service account file used for auth test cases
604 private static string GetEmailFromServiceAccountFile()
605 {
606 string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
607 Assert.IsNotNull(keyFile);
608
609 var jobject = JObject.Parse(File.ReadAllText(keyFile));
610 string email = jobject.GetValue("client_email").Value<string>();
611 Assert.IsTrue(email.Length > 0); // spec requires nonempty client email.
612 return email;
613 }
Jan Tattermusch0ed73152015-12-09 18:21:11 -0800614
615 private static Metadata CreateTestMetadata()
616 {
617 return new Metadata
618 {
619 {"x-grpc-test-echo-initial", "test_initial_metadata_value"},
620 {"x-grpc-test-echo-trailing-bin", new byte[] {0xab, 0xab, 0xab}}
621 };
622 }
Jan Tattermuscheb3e76e2015-02-06 11:43:13 -0800623 }
624}