OLD | NEW |
(Empty) | |
| 1 #region Copyright notice and license |
| 2 |
| 3 // Copyright 2015, Google Inc. |
| 4 // All rights reserved. |
| 5 // |
| 6 // Redistribution and use in source and binary forms, with or without |
| 7 // modification, are permitted provided that the following conditions are |
| 8 // met: |
| 9 // |
| 10 // * 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. |
| 19 // |
| 20 // 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 |
| 34 using System; |
| 35 using System.Collections.Generic; |
| 36 using System.IO; |
| 37 using System.Linq; |
| 38 using System.Text.RegularExpressions; |
| 39 using System.Threading; |
| 40 using System.Threading.Tasks; |
| 41 |
| 42 using CommandLine; |
| 43 using CommandLine.Text; |
| 44 using Google.Apis.Auth.OAuth2; |
| 45 using Google.Protobuf; |
| 46 using Grpc.Auth; |
| 47 using Grpc.Core; |
| 48 using Grpc.Core.Utils; |
| 49 using Grpc.Testing; |
| 50 using Newtonsoft.Json.Linq; |
| 51 using NUnit.Framework; |
| 52 |
| 53 namespace Grpc.IntegrationTesting |
| 54 { |
| 55 public class InteropClient |
| 56 { |
| 57 private class ClientOptions |
| 58 { |
| 59 [Option("server_host", DefaultValue = "127.0.0.1")] |
| 60 public string ServerHost { get; set; } |
| 61 |
| 62 [Option("server_host_override", DefaultValue = TestCredentials.Defau
ltHostOverride)] |
| 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 |
| 71 // Deliberately using nullable bool type to allow --use_tls=true syn
tax (as opposed to --use_tls) |
| 72 [Option("use_tls", DefaultValue = false)] |
| 73 public bool? UseTls { get; set; } |
| 74 |
| 75 // 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; } |
| 78 |
| 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 } |
| 100 } |
| 101 |
| 102 ClientOptions options; |
| 103 |
| 104 private InteropClient(ClientOptions options) |
| 105 { |
| 106 this.options = options; |
| 107 } |
| 108 |
| 109 public static void Run(string[] args) |
| 110 { |
| 111 var options = new ClientOptions(); |
| 112 if (!Parser.Default.ParseArguments(args, options)) |
| 113 { |
| 114 Environment.Exit(1); |
| 115 } |
| 116 |
| 117 var interopClient = new InteropClient(options); |
| 118 interopClient.Run().Wait(); |
| 119 } |
| 120 |
| 121 private async Task Run() |
| 122 { |
| 123 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, opti
ons.ServerHostOverride) |
| 131 }; |
| 132 } |
| 133 var channel = new Channel(options.ServerHost, options.ServerPort, cr
edentials, channelOptions); |
| 134 await RunTestCaseAsync(channel, options); |
| 135 await channel.ShutdownAsync(); |
| 136 } |
| 137 |
| 138 private async Task<ChannelCredentials> CreateCredentialsAsync() |
| 139 { |
| 140 var credentials = ChannelCredentials.Insecure; |
| 141 if (options.UseTls.Value) |
| 142 { |
| 143 credentials = options.UseTestCa.Value ? TestCredentials.CreateSs
lCredentials() : new SslCredentials(); |
| 144 } |
| 145 |
| 146 if (options.TestCase == "jwt_token_creds") |
| 147 { |
| 148 var googleCredential = await GoogleCredential.GetApplicationDefa
ultAsync(); |
| 149 Assert.IsTrue(googleCredential.IsCreateScopedRequired); |
| 150 credentials = ChannelCredentials.Create(credentials, googleCrede
ntial.ToCallCredentials()); |
| 151 } |
| 152 |
| 153 if (options.TestCase == "compute_engine_creds") |
| 154 { |
| 155 var googleCredential = await GoogleCredential.GetApplicationDefa
ultAsync(); |
| 156 Assert.IsFalse(googleCredential.IsCreateScopedRequired); |
| 157 credentials = ChannelCredentials.Create(credentials, googleCrede
ntial.ToCallCredentials()); |
| 158 } |
| 159 return credentials; |
| 160 } |
| 161 |
| 162 private async Task RunTestCaseAsync(Channel channel, ClientOptions optio
ns) |
| 163 { |
| 164 var client = new TestService.TestServiceClient(channel); |
| 165 switch (options.TestCase) |
| 166 { |
| 167 case "empty_unary": |
| 168 RunEmptyUnary(client); |
| 169 break; |
| 170 case "large_unary": |
| 171 RunLargeUnary(client); |
| 172 break; |
| 173 case "client_streaming": |
| 174 await RunClientStreamingAsync(client); |
| 175 break; |
| 176 case "server_streaming": |
| 177 await RunServerStreamingAsync(client); |
| 178 break; |
| 179 case "ping_pong": |
| 180 await RunPingPongAsync(client); |
| 181 break; |
| 182 case "empty_stream": |
| 183 await RunEmptyStreamAsync(client); |
| 184 break; |
| 185 case "compute_engine_creds": |
| 186 RunComputeEngineCreds(client, options.DefaultServiceAccount,
options.OAuthScope); |
| 187 break; |
| 188 case "jwt_token_creds": |
| 189 RunJwtTokenCreds(client); |
| 190 break; |
| 191 case "oauth2_auth_token": |
| 192 await RunOAuth2AuthTokenAsync(client, options.OAuthScope); |
| 193 break; |
| 194 case "per_rpc_creds": |
| 195 await RunPerRpcCredsAsync(client, options.OAuthScope); |
| 196 break; |
| 197 case "cancel_after_begin": |
| 198 await RunCancelAfterBeginAsync(client); |
| 199 break; |
| 200 case "cancel_after_first_response": |
| 201 await RunCancelAfterFirstResponseAsync(client); |
| 202 break; |
| 203 case "timeout_on_sleeping_server": |
| 204 await RunTimeoutOnSleepingServerAsync(client); |
| 205 break; |
| 206 case "custom_metadata": |
| 207 await RunCustomMetadataAsync(client); |
| 208 break; |
| 209 case "status_code_and_message": |
| 210 await RunStatusCodeAndMessageAsync(client); |
| 211 break; |
| 212 case "unimplemented_method": |
| 213 RunUnimplementedMethod(new UnimplementedService.Unimplemente
dServiceClient(channel)); |
| 214 break; |
| 215 default: |
| 216 throw new ArgumentException("Unknown test case " + options.T
estCase); |
| 217 } |
| 218 } |
| 219 |
| 220 public static void RunEmptyUnary(TestService.ITestServiceClient client) |
| 221 { |
| 222 Console.WriteLine("running empty_unary"); |
| 223 var response = client.EmptyCall(new Empty()); |
| 224 Assert.IsNotNull(response); |
| 225 Console.WriteLine("Passed!"); |
| 226 } |
| 227 |
| 228 public static void RunLargeUnary(TestService.ITestServiceClient client) |
| 229 { |
| 230 Console.WriteLine("running large_unary"); |
| 231 var request = new SimpleRequest |
| 232 { |
| 233 ResponseType = PayloadType.COMPRESSABLE, |
| 234 ResponseSize = 314159, |
| 235 Payload = CreateZerosPayload(271828) |
| 236 }; |
| 237 var response = client.UnaryCall(request); |
| 238 |
| 239 Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
| 240 Assert.AreEqual(314159, response.Payload.Body.Length); |
| 241 Console.WriteLine("Passed!"); |
| 242 } |
| 243 |
| 244 public static async Task RunClientStreamingAsync(TestService.ITestServic
eClient client) |
| 245 { |
| 246 Console.WriteLine("running client_streaming"); |
| 247 |
| 248 var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((
size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) }); |
| 249 |
| 250 using (var call = client.StreamingInputCall()) |
| 251 { |
| 252 await call.RequestStream.WriteAllAsync(bodySizes); |
| 253 |
| 254 var response = await call.ResponseAsync; |
| 255 Assert.AreEqual(74922, response.AggregatedPayloadSize); |
| 256 } |
| 257 Console.WriteLine("Passed!"); |
| 258 } |
| 259 |
| 260 public static async Task RunServerStreamingAsync(TestService.ITestServic
eClient client) |
| 261 { |
| 262 Console.WriteLine("running server_streaming"); |
| 263 |
| 264 var bodySizes = new List<int> { 31415, 9, 2653, 58979 }; |
| 265 |
| 266 var request = new StreamingOutputCallRequest |
| 267 { |
| 268 ResponseType = PayloadType.COMPRESSABLE, |
| 269 ResponseParameters = { bodySizes.ConvertAll((size) => new Respon
seParameters { Size = size }) } |
| 270 }; |
| 271 |
| 272 using (var call = client.StreamingOutputCall(request)) |
| 273 { |
| 274 var responseList = await call.ResponseStream.ToListAsync(); |
| 275 foreach (var res in responseList) |
| 276 { |
| 277 Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type); |
| 278 } |
| 279 CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((it
em) => item.Payload.Body.Length)); |
| 280 } |
| 281 Console.WriteLine("Passed!"); |
| 282 } |
| 283 |
| 284 public static async Task RunPingPongAsync(TestService.ITestServiceClient
client) |
| 285 { |
| 286 Console.WriteLine("running ping_pong"); |
| 287 |
| 288 using (var call = client.FullDuplexCall()) |
| 289 { |
| 290 await call.RequestStream.WriteAsync(new StreamingOutputCallReque
st |
| 291 { |
| 292 ResponseType = PayloadType.COMPRESSABLE, |
| 293 ResponseParameters = { new ResponseParameters { Size = 31415
} }, |
| 294 Payload = CreateZerosPayload(27182) |
| 295 }); |
| 296 |
| 297 Assert.IsTrue(await call.ResponseStream.MoveNext()); |
| 298 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Cu
rrent.Payload.Type); |
| 299 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.
Length); |
| 300 |
| 301 await call.RequestStream.WriteAsync(new StreamingOutputCallReque
st |
| 302 { |
| 303 ResponseType = PayloadType.COMPRESSABLE, |
| 304 ResponseParameters = { new ResponseParameters { Size = 9 } }
, |
| 305 Payload = CreateZerosPayload(8) |
| 306 }); |
| 307 |
| 308 Assert.IsTrue(await call.ResponseStream.MoveNext()); |
| 309 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Cu
rrent.Payload.Type); |
| 310 Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Leng
th); |
| 311 |
| 312 await call.RequestStream.WriteAsync(new StreamingOutputCallReque
st |
| 313 { |
| 314 ResponseType = PayloadType.COMPRESSABLE, |
| 315 ResponseParameters = { new ResponseParameters { Size = 2653
} }, |
| 316 Payload = CreateZerosPayload(1828) |
| 317 }); |
| 318 |
| 319 Assert.IsTrue(await call.ResponseStream.MoveNext()); |
| 320 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Cu
rrent.Payload.Type); |
| 321 Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.L
ength); |
| 322 |
| 323 await call.RequestStream.WriteAsync(new StreamingOutputCallReque
st |
| 324 { |
| 325 ResponseType = PayloadType.COMPRESSABLE, |
| 326 ResponseParameters = { new ResponseParameters { Size = 58979
} }, |
| 327 Payload = CreateZerosPayload(45904) |
| 328 }); |
| 329 |
| 330 Assert.IsTrue(await call.ResponseStream.MoveNext()); |
| 331 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Cu
rrent.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!"); |
| 339 } |
| 340 |
| 341 public static async Task RunEmptyStreamAsync(TestService.ITestServiceCli
ent client) |
| 342 { |
| 343 Console.WriteLine("running empty_stream"); |
| 344 using (var call = client.FullDuplexCall()) |
| 345 { |
| 346 await call.RequestStream.CompleteAsync(); |
| 347 |
| 348 var responseList = await call.ResponseStream.ToListAsync(); |
| 349 Assert.AreEqual(0, responseList.Count); |
| 350 } |
| 351 Console.WriteLine("Passed!"); |
| 352 } |
| 353 |
| 354 public static void RunComputeEngineCreds(TestService.TestServiceClient c
lient, string defaultServiceAccount, string oauthScope) |
| 355 { |
| 356 Console.WriteLine("running compute_engine_creds"); |
| 357 |
| 358 var request = new SimpleRequest |
| 359 { |
| 360 ResponseType = PayloadType.COMPRESSABLE, |
| 361 ResponseSize = 314159, |
| 362 Payload = CreateZerosPayload(271828), |
| 363 FillUsername = true, |
| 364 FillOauthScope = true |
| 365 }; |
| 366 |
| 367 // not setting credentials here because they were set on channel alr
eady |
| 368 var response = client.UnaryCall(request); |
| 369 |
| 370 Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
| 371 Assert.AreEqual(314159, response.Payload.Body.Length); |
| 372 Assert.False(string.IsNullOrEmpty(response.OauthScope)); |
| 373 Assert.True(oauthScope.Contains(response.OauthScope)); |
| 374 Assert.AreEqual(defaultServiceAccount, response.Username); |
| 375 Console.WriteLine("Passed!"); |
| 376 } |
| 377 |
| 378 public static void RunJwtTokenCreds(TestService.TestServiceClient client
) |
| 379 { |
| 380 Console.WriteLine("running jwt_token_creds"); |
| 381 |
| 382 var request = new SimpleRequest |
| 383 { |
| 384 ResponseType = PayloadType.COMPRESSABLE, |
| 385 ResponseSize = 314159, |
| 386 Payload = CreateZerosPayload(271828), |
| 387 FillUsername = true, |
| 388 }; |
| 389 |
| 390 // not setting credentials here because they were set on channel alr
eady |
| 391 var response = client.UnaryCall(request); |
| 392 |
| 393 Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); |
| 394 Assert.AreEqual(314159, response.Payload.Body.Length); |
| 395 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username)
; |
| 396 Console.WriteLine("Passed!"); |
| 397 } |
| 398 |
| 399 public static async Task RunOAuth2AuthTokenAsync(TestService.TestService
Client client, string oauthScope) |
| 400 { |
| 401 Console.WriteLine("running oauth2_auth_token"); |
| 402 ITokenAccess credential = (await GoogleCredential.GetApplicationDefa
ultAsync()).CreateScoped(new[] { oauthScope }); |
| 403 string oauth2Token = await credential.GetAccessTokenForRequestAsync(
); |
| 404 |
| 405 var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token)
; |
| 406 var request = new SimpleRequest |
| 407 { |
| 408 FillUsername = true, |
| 409 FillOauthScope = true |
| 410 }; |
| 411 |
| 412 var response = client.UnaryCall(request, new CallOptions(credentials
: credentials)); |
| 413 |
| 414 Assert.False(string.IsNullOrEmpty(response.OauthScope)); |
| 415 Assert.True(oauthScope.Contains(response.OauthScope)); |
| 416 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username)
; |
| 417 Console.WriteLine("Passed!"); |
| 418 } |
| 419 |
| 420 public static async Task RunPerRpcCredsAsync(TestService.TestServiceClie
nt client, string oauthScope) |
| 421 { |
| 422 Console.WriteLine("running per_rpc_creds"); |
| 423 ITokenAccess googleCredential = await GoogleCredential.GetApplicatio
nDefaultAsync(); |
| 424 |
| 425 var credentials = googleCredential.ToCallCredentials(); |
| 426 var request = new SimpleRequest |
| 427 { |
| 428 FillUsername = true, |
| 429 }; |
| 430 |
| 431 var response = client.UnaryCall(request, new CallOptions(credentials
: credentials)); |
| 432 |
| 433 Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username)
; |
| 434 Console.WriteLine("Passed!"); |
| 435 } |
| 436 |
| 437 public static async Task RunCancelAfterBeginAsync(TestService.ITestServi
ceClient client) |
| 438 { |
| 439 Console.WriteLine("running cancel_after_begin"); |
| 440 |
| 441 var cts = new CancellationTokenSource(); |
| 442 using (var call = client.StreamingInputCall(cancellationToken: cts.T
oken)) |
| 443 { |
| 444 // TODO(jtattermusch): we need this to ensure call has been init
iated once we cancel it. |
| 445 await Task.Delay(1000); |
| 446 cts.Cancel(); |
| 447 |
| 448 var ex = Assert.Throws<RpcException>(async () => await call.Resp
onseAsync); |
| 449 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); |
| 450 } |
| 451 Console.WriteLine("Passed!"); |
| 452 } |
| 453 |
| 454 public static async Task RunCancelAfterFirstResponseAsync(TestService.IT
estServiceClient client) |
| 455 { |
| 456 Console.WriteLine("running cancel_after_first_response"); |
| 457 |
| 458 var cts = new CancellationTokenSource(); |
| 459 using (var call = client.FullDuplexCall(cancellationToken: cts.Token
)) |
| 460 { |
| 461 await call.RequestStream.WriteAsync(new StreamingOutputCallReque
st |
| 462 { |
| 463 ResponseType = PayloadType.COMPRESSABLE, |
| 464 ResponseParameters = { new ResponseParameters { Size = 31415
} }, |
| 465 Payload = CreateZerosPayload(27182) |
| 466 }); |
| 467 |
| 468 Assert.IsTrue(await call.ResponseStream.MoveNext()); |
| 469 Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Cu
rrent.Payload.Type); |
| 470 Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.
Length); |
| 471 |
| 472 cts.Cancel(); |
| 473 |
| 474 var ex = Assert.Throws<RpcException>(async () => await call.Resp
onseStream.MoveNext()); |
| 475 Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode); |
| 476 } |
| 477 Console.WriteLine("Passed!"); |
| 478 } |
| 479 |
| 480 public static async Task RunTimeoutOnSleepingServerAsync(TestService.ITe
stServiceClient client) |
| 481 { |
| 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 { |
| 489 await call.RequestStream.WriteAsync(new StreamingOutputCallR
equest { Payload = CreateZerosPayload(27182) }); |
| 490 } |
| 491 catch (InvalidOperationException) |
| 492 { |
| 493 // Deadline was reached before write has started. Eat the ex
ception and continue. |
| 494 } |
| 495 |
| 496 var ex = Assert.Throws<RpcException>(async () => await call.Resp
onseStream.MoveNext()); |
| 497 Assert.AreEqual(StatusCode.DeadlineExceeded, ex.Status.StatusCod
e); |
| 498 } |
| 499 Console.WriteLine("Passed!"); |
| 500 } |
| 501 |
| 502 public static async Task RunCustomMetadataAsync(TestService.ITestService
Client client) |
| 503 { |
| 504 Console.WriteLine("running custom_metadata"); |
| 505 { |
| 506 // step 1: test unary call |
| 507 var request = new SimpleRequest |
| 508 { |
| 509 ResponseType = PayloadType.COMPRESSABLE, |
| 510 ResponseSize = 314159, |
| 511 Payload = CreateZerosPayload(271828) |
| 512 }; |
| 513 |
| 514 var call = client.UnaryCallAsync(request, headers: CreateTestMet
adata()); |
| 515 await call.ResponseAsync; |
| 516 |
| 517 var responseHeaders = await call.ResponseHeadersAsync; |
| 518 var responseTrailers = call.GetTrailers(); |
| 519 |
| 520 Assert.AreEqual("test_initial_metadata_value", responseHeaders.F
irst((entry) => entry.Key == "x-grpc-test-echo-initial").Value); |
| 521 CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, respo
nseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").Value
Bytes); |
| 522 } |
| 523 |
| 524 { |
| 525 // step 2: test full duplex call |
| 526 var request = new StreamingOutputCallRequest |
| 527 { |
| 528 ResponseType = PayloadType.COMPRESSABLE, |
| 529 ResponseParameters = { new ResponseParameters { Size = 31415
} }, |
| 530 Payload = CreateZerosPayload(27182) |
| 531 }; |
| 532 |
| 533 var call = client.FullDuplexCall(headers: CreateTestMetadata()); |
| 534 var responseHeaders = await call.ResponseHeadersAsync; |
| 535 |
| 536 await call.RequestStream.WriteAsync(request); |
| 537 await call.RequestStream.CompleteAsync(); |
| 538 await call.ResponseStream.ToListAsync(); |
| 539 |
| 540 var responseTrailers = call.GetTrailers(); |
| 541 |
| 542 Assert.AreEqual("test_initial_metadata_value", responseHeaders.F
irst((entry) => entry.Key == "x-grpc-test-echo-initial").Value); |
| 543 CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, respo
nseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").Value
Bytes); |
| 544 } |
| 545 |
| 546 Console.WriteLine("Passed!"); |
| 547 } |
| 548 |
| 549 public static async Task RunStatusCodeAndMessageAsync(TestService.ITestS
erviceClient client) |
| 550 { |
| 551 Console.WriteLine("running status_code_and_message"); |
| 552 var echoStatus = new EchoStatus |
| 553 { |
| 554 Code = 2, |
| 555 Message = "test status message" |
| 556 }; |
| 557 |
| 558 { |
| 559 // step 1: test unary call |
| 560 var request = new SimpleRequest { ResponseStatus = echoStatus }; |
| 561 |
| 562 var e = Assert.Throws<RpcException>(() => client.UnaryCall(reque
st)); |
| 563 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); |
| 564 Assert.AreEqual(echoStatus.Message, e.Status.Detail); |
| 565 } |
| 566 |
| 567 { |
| 568 // step 2: test full duplex call |
| 569 var request = new StreamingOutputCallRequest { ResponseStatus =
echoStatus }; |
| 570 |
| 571 var call = client.FullDuplexCall(); |
| 572 await call.RequestStream.WriteAsync(request); |
| 573 await call.RequestStream.CompleteAsync(); |
| 574 |
| 575 var e = Assert.Throws<RpcException>(async () => await call.Respo
nseStream.ToListAsync()); |
| 576 Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); |
| 577 Assert.AreEqual(echoStatus.Message, e.Status.Detail); |
| 578 } |
| 579 |
| 580 Console.WriteLine("Passed!"); |
| 581 } |
| 582 |
| 583 public static void RunUnimplementedMethod(UnimplementedService.IUnimplem
entedServiceClient client) |
| 584 { |
| 585 Console.WriteLine("running unimplemented_method"); |
| 586 var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(n
ew Empty())); |
| 587 |
| 588 Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode); |
| 589 Assert.AreEqual("", e.Status.Detail); |
| 590 Console.WriteLine("Passed!"); |
| 591 } |
| 592 |
| 593 private static Payload CreateZerosPayload(int size) |
| 594 { |
| 595 return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; |
| 596 } |
| 597 |
| 598 // extracts the client_email field from service account file used for au
th test cases |
| 599 private static string GetEmailFromServiceAccountFile() |
| 600 { |
| 601 string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICAT
ION_CREDENTIALS"); |
| 602 Assert.IsNotNull(keyFile); |
| 603 |
| 604 var jobject = JObject.Parse(File.ReadAllText(keyFile)); |
| 605 string email = jobject.GetValue("client_email").Value<string>(); |
| 606 Assert.IsTrue(email.Length > 0); // spec requires nonempty client e
mail. |
| 607 return email; |
| 608 } |
| 609 |
| 610 private static Metadata CreateTestMetadata() |
| 611 { |
| 612 return new Metadata |
| 613 { |
| 614 {"x-grpc-test-echo-initial", "test_initial_metadata_value"}, |
| 615 {"x-grpc-test-echo-trailing-bin", new byte[] {0xab, 0xab, 0xab}} |
| 616 }; |
| 617 } |
| 618 } |
| 619 } |
OLD | NEW |