1/* 2 * 3 * Copyright 2018 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 */ 18 19#import <GRPCClient/GRPCCall.h> 20#import <ProtoRPC/ProtoMethod.h> 21#import <XCTest/XCTest.h> 22#import "src/objective-c/tests/RemoteTestClient/Messages.pbobjc.h" 23 24#include <grpc/grpc.h> 25#include <grpc/support/port_platform.h> 26 27#import "../Common/GRPCBlockCallbackResponseHandler.h" 28#import "../Common/TestUtils.h" 29#import "../version.h" 30 31// Package and service name of test server 32static NSString *const kPackage = @"grpc.testing"; 33static NSString *const kService = @"TestService"; 34 35static GRPCProtoMethod *kInexistentMethod; 36static GRPCProtoMethod *kEmptyCallMethod; 37static GRPCProtoMethod *kUnaryCallMethod; 38static GRPCProtoMethod *kOutputStreamingCallMethod; 39static GRPCProtoMethod *kFullDuplexCallMethod; 40 41static const int kSimpleDataLength = 100; 42 43static const NSTimeInterval kTestTimeout = 8; 44static const NSTimeInterval kInvertedTimeout = 2; 45 46// Reveal the _class ivar for testing access 47@interface GRPCCall2 () { 48 @public 49 GRPCCall *_call; 50} 51 52@end 53 54@interface CallAPIv2Tests : XCTestCase <GRPCAuthorizationProtocol> 55 56@end 57 58@implementation CallAPIv2Tests 59 60+ (void)setUp { 61 GRPCPrintInteropTestServerDebugInfo(); 62} 63 64- (void)setUp { 65 // This method isn't implemented by the remote server. 66 kInexistentMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage 67 service:kService 68 method:@"Inexistent"]; 69 kEmptyCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage 70 service:kService 71 method:@"EmptyCall"]; 72 kUnaryCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage 73 service:kService 74 method:@"UnaryCall"]; 75 kOutputStreamingCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage 76 service:kService 77 method:@"StreamingOutputCall"]; 78 kFullDuplexCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage 79 service:kService 80 method:@"FullDuplexCall"]; 81} 82 83- (void)testUserAgentPrefix { 84 __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; 85 __weak XCTestExpectation *recvInitialMd = 86 [self expectationWithDescription:@"Did not receive initial md."]; 87 88 GRPCRequestOptions *request = 89 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 90 path:kEmptyCallMethod.HTTPPath 91 safety:GRPCCallSafetyDefault]; 92 NSDictionary *headers = 93 [NSDictionary dictionaryWithObjectsAndKeys:@"", @"x-grpc-test-echo-useragent", nil]; 94 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 95 options.transportType = GRPCTransportTypeInsecure; 96 options.userAgentPrefix = @"Foo"; 97 options.initialMetadata = headers; 98 GRPCCall2 *call = [[GRPCCall2 alloc] 99 initWithRequestOptions:request 100 responseHandler: 101 [[GRPCBlockCallbackResponseHandler alloc] 102 initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) { 103 NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"]; 104 // Test the regex is correct 105 NSString *expectedUserAgent = @"Foo grpc-objc-cfstream/"; 106 expectedUserAgent = 107 [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING]; 108 expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"]; 109 expectedUserAgent = 110 [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING]; 111 expectedUserAgent = [expectedUserAgent stringByAppendingString:@" ("]; 112 expectedUserAgent = 113 [expectedUserAgent stringByAppendingString:@GPR_PLATFORM_STRING]; 114 expectedUserAgent = [expectedUserAgent stringByAppendingString:@"; chttp2)"]; 115 XCTAssertEqualObjects(userAgent, expectedUserAgent); 116 117 NSError *error = nil; 118 // Change in format of user-agent field in a direction that does not match 119 // the regex will likely cause problem for certain gRPC users. For details, 120 // refer to internal doc https://goo.gl/c2diBc 121 NSRegularExpression *regex = [NSRegularExpression 122 regularExpressionWithPattern: 123 @" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?" 124 options:0 125 error:&error]; 126 127 NSString *customUserAgent = [regex 128 stringByReplacingMatchesInString:userAgent 129 options:0 130 range:NSMakeRange(0, [userAgent length]) 131 withTemplate:@""]; 132 XCTAssertEqualObjects(customUserAgent, @"Foo"); 133 [recvInitialMd fulfill]; 134 } 135 messageCallback:^(id message) { 136 XCTAssertNotNil(message); 137 XCTAssertEqual([message length], 0, @"Non-empty response received: %@", 138 message); 139 } 140 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { 141 if (error) { 142 XCTFail(@"Finished with unexpected error: %@", error); 143 } else { 144 [completion fulfill]; 145 } 146 }] 147 callOptions:options]; 148 [call writeData:[NSData data]]; 149 [call start]; 150 151 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 152} 153 154- (void)getTokenWithHandler:(void (^)(NSString *token))handler { 155 dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); 156 dispatch_sync(queue, ^{ 157 handler(@"test-access-token"); 158 }); 159} 160 161- (void)testOAuthToken { 162 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; 163 164 GRPCRequestOptions *requestOptions = 165 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 166 path:kEmptyCallMethod.HTTPPath 167 safety:GRPCCallSafetyDefault]; 168 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 169 options.transportType = GRPCTransportTypeInsecure; 170 options.authTokenProvider = self; 171 __block GRPCCall2 *call = [[GRPCCall2 alloc] 172 initWithRequestOptions:requestOptions 173 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 174 initWithInitialMetadataCallback:nil 175 messageCallback:nil 176 closeCallback:^(NSDictionary *trailingMetadata, 177 NSError *error) { 178 [completion fulfill]; 179 }] 180 callOptions:options]; 181 [call writeData:[NSData data]]; 182 [call start]; 183 [call finish]; 184 185 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 186} 187 188- (void)testResponseSizeLimitExceeded { 189 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; 190 191 GRPCRequestOptions *requestOptions = 192 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 193 path:kUnaryCallMethod.HTTPPath 194 safety:GRPCCallSafetyDefault]; 195 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 196 options.responseSizeLimit = kSimpleDataLength; 197 options.transportType = GRPCTransportTypeInsecure; 198 199 RMTSimpleRequest *request = [RMTSimpleRequest message]; 200 request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit]; 201 request.responseSize = (int32_t)(options.responseSizeLimit * 2); 202 203 GRPCCall2 *call = [[GRPCCall2 alloc] 204 initWithRequestOptions:requestOptions 205 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 206 initWithInitialMetadataCallback:nil 207 messageCallback:nil 208 closeCallback:^(NSDictionary *trailingMetadata, 209 NSError *error) { 210 XCTAssertNotNil(error, 211 @"Expecting non-nil error"); 212 XCTAssertEqual(error.code, 213 GRPCErrorCodeResourceExhausted); 214 [completion fulfill]; 215 }] 216 callOptions:options]; 217 [call writeData:[request data]]; 218 [call start]; 219 [call finish]; 220 221 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 222} 223 224- (void)testTimeout { 225 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; 226 227 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 228 options.timeout = 0.001; 229 options.transportType = GRPCTransportTypeInsecure; 230 GRPCRequestOptions *requestOptions = 231 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 232 path:kFullDuplexCallMethod.HTTPPath 233 safety:GRPCCallSafetyDefault]; 234 235 GRPCCall2 *call = [[GRPCCall2 alloc] 236 initWithRequestOptions:requestOptions 237 responseHandler: 238 [[GRPCBlockCallbackResponseHandler alloc] initWithInitialMetadataCallback:nil 239 messageCallback:^(NSData *data) { 240 XCTFail(@"Failure: response received; Expect: no response received."); 241 } 242 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { 243 XCTAssertNotNil(error, @"Failure: no error received; Expect: receive " 244 @"deadline exceeded."); 245 if (error.code != GRPCErrorCodeDeadlineExceeded) { 246 NSLog(@"Unexpected error: %@", error); 247 } 248 XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded); 249 [completion fulfill]; 250 }] 251 callOptions:options]; 252 253 [call start]; 254 255 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 256} 257 258- (void)testTimeoutBackoffWithTimeout:(double)timeout Backoff:(double)backoff { 259 const double maxConnectTime = timeout > backoff ? timeout : backoff; 260 const double kMargin = 0.1; 261 262 __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."]; 263 NSString *const kPhonyAddress = [NSString stringWithFormat:@"127.0.0.1:10000"]; 264 GRPCRequestOptions *requestOptions = 265 [[GRPCRequestOptions alloc] initWithHost:kPhonyAddress 266 path:@"/phony/path" 267 safety:GRPCCallSafetyDefault]; 268 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 269 options.connectMinTimeout = timeout; 270 options.connectInitialBackoff = backoff; 271 options.connectMaxBackoff = 0; 272 273 NSDate *startTime = [NSDate date]; 274 GRPCCall2 *call = [[GRPCCall2 alloc] 275 initWithRequestOptions:requestOptions 276 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 277 initWithInitialMetadataCallback:nil 278 messageCallback:^(NSData *data) { 279 XCTFail(@"Received message. Should not reach here."); 280 } 281 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { 282 XCTAssertNotNil(error, 283 @"Finished with no error; expecting error"); 284 XCTAssertLessThan( 285 [[NSDate date] timeIntervalSinceDate:startTime], 286 maxConnectTime + kMargin); 287 [completion fulfill]; 288 }] 289 callOptions:options]; 290 291 [call start]; 292 293 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 294} 295 296- (void)testTimeoutBackoff1 { 297 [self testTimeoutBackoffWithTimeout:0.7 Backoff:0.4]; 298} 299 300- (void)testTimeoutBackoff2 { 301 [self testTimeoutBackoffWithTimeout:0.3 Backoff:0.8]; 302} 303 304- (void)testCompression { 305 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; 306 307 RMTSimpleRequest *request = [RMTSimpleRequest message]; 308 request.expectCompressed = [RMTBoolValue message]; 309 request.expectCompressed.value = YES; 310 request.responseCompressed = [RMTBoolValue message]; 311 request.expectCompressed.value = YES; 312 request.responseSize = kSimpleDataLength; 313 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength]; 314 GRPCRequestOptions *requestOptions = 315 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 316 path:kUnaryCallMethod.HTTPPath 317 safety:GRPCCallSafetyDefault]; 318 319 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 320 options.transportType = GRPCTransportTypeInsecure; 321 options.compressionAlgorithm = GRPCCompressGzip; 322 GRPCCall2 *call = [[GRPCCall2 alloc] 323 initWithRequestOptions:requestOptions 324 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 325 initWithInitialMetadataCallback:nil 326 messageCallback:^(NSData *data) { 327 NSError *error; 328 RMTSimpleResponse *response = 329 [RMTSimpleResponse parseFromData:data error:&error]; 330 XCTAssertNil(error, @"Error when parsing response: %@", error); 331 XCTAssertEqual(response.payload.body.length, kSimpleDataLength); 332 } 333 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { 334 XCTAssertNil(error, @"Received failure: %@", error); 335 [completion fulfill]; 336 }] 337 338 callOptions:options]; 339 340 [call start]; 341 [call writeData:[request data]]; 342 [call finish]; 343 344 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 345} 346 347- (void)testFlowControlWrite { 348 __weak XCTestExpectation *expectWriteData = 349 [self expectationWithDescription:@"Reported write data"]; 350 351 RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message]; 352 RMTResponseParameters *parameters = [RMTResponseParameters message]; 353 parameters.size = kSimpleDataLength; 354 [request.responseParametersArray addObject:parameters]; 355 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength]; 356 357 GRPCRequestOptions *callRequest = 358 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 359 path:kUnaryCallMethod.HTTPPath 360 safety:GRPCCallSafetyDefault]; 361 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 362 options.transportType = GRPCTransportTypeInsecure; 363 options.flowControlEnabled = YES; 364 GRPCCall2 *call = 365 [[GRPCCall2 alloc] initWithRequestOptions:callRequest 366 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 367 initWithInitialMetadataCallback:nil 368 messageCallback:nil 369 closeCallback:nil 370 writeDataCallback:^{ 371 [expectWriteData fulfill]; 372 }] 373 callOptions:options]; 374 375 [call start]; 376 [call receiveNextMessages:1]; 377 [call writeData:[request data]]; 378 379 // Wait for 3 seconds and make sure we do not receive the response 380 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 381 382 [call finish]; 383} 384 385- (void)testFlowControlRead { 386 __weak __block XCTestExpectation *expectBlockedMessage = 387 [self expectationWithDescription:@"Message not delivered without recvNextMessage"]; 388 __weak __block XCTestExpectation *expectPassedMessage = nil; 389 __weak __block XCTestExpectation *expectBlockedClose = 390 [self expectationWithDescription:@"Call not closed with pending message"]; 391 __weak __block XCTestExpectation *expectPassedClose = nil; 392 expectBlockedMessage.inverted = YES; 393 expectBlockedClose.inverted = YES; 394 395 RMTSimpleRequest *request = [RMTSimpleRequest message]; 396 request.responseSize = kSimpleDataLength; 397 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength]; 398 399 GRPCRequestOptions *callRequest = 400 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 401 path:kUnaryCallMethod.HTTPPath 402 safety:GRPCCallSafetyDefault]; 403 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 404 options.transportType = GRPCTransportTypeInsecure; 405 options.flowControlEnabled = YES; 406 __block int unblocked = NO; 407 GRPCCall2 *call = [[GRPCCall2 alloc] 408 initWithRequestOptions:callRequest 409 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 410 initWithInitialMetadataCallback:nil 411 messageCallback:^(NSData *message) { 412 if (!unblocked) { 413 [expectBlockedMessage fulfill]; 414 } else { 415 [expectPassedMessage fulfill]; 416 } 417 } 418 closeCallback:^(NSDictionary *trailers, NSError *error) { 419 if (!unblocked) { 420 [expectBlockedClose fulfill]; 421 } else { 422 [expectPassedClose fulfill]; 423 } 424 }] 425 callOptions:options]; 426 427 [call start]; 428 [call writeData:[request data]]; 429 [call finish]; 430 431 // Wait to make sure we do not receive the response 432 [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil]; 433 434 expectPassedMessage = 435 [self expectationWithDescription:@"Message delivered with receiveNextMessage"]; 436 expectPassedClose = [self expectationWithDescription:@"Close delivered after receiveNextMessage"]; 437 438 unblocked = YES; 439 [call receiveNextMessages:1]; 440 441 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 442} 443 444- (void)testFlowControlMultipleMessages { 445 __weak XCTestExpectation *expectPassedMessage = 446 [self expectationWithDescription:@"two messages delivered with receiveNextMessage"]; 447 expectPassedMessage.expectedFulfillmentCount = 2; 448 __weak XCTestExpectation *expectBlockedMessage = 449 [self expectationWithDescription:@"Message 3 not delivered"]; 450 expectBlockedMessage.inverted = YES; 451 __weak XCTestExpectation *expectWriteTwice = 452 [self expectationWithDescription:@"Write 2 messages done"]; 453 expectWriteTwice.expectedFulfillmentCount = 2; 454 455 RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message]; 456 RMTResponseParameters *parameters = [RMTResponseParameters message]; 457 parameters.size = kSimpleDataLength; 458 [request.responseParametersArray addObject:parameters]; 459 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength]; 460 461 GRPCRequestOptions *callRequest = 462 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 463 path:kFullDuplexCallMethod.HTTPPath 464 safety:GRPCCallSafetyDefault]; 465 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 466 options.transportType = GRPCTransportTypeInsecure; 467 options.flowControlEnabled = YES; 468 __block NSUInteger messageId = 0; 469 __block GRPCCall2 *call = 470 [[GRPCCall2 alloc] initWithRequestOptions:callRequest 471 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 472 initWithInitialMetadataCallback:nil 473 messageCallback:^(NSData *message) { 474 if (messageId <= 1) { 475 [expectPassedMessage fulfill]; 476 } else { 477 [expectBlockedMessage fulfill]; 478 } 479 messageId++; 480 } 481 closeCallback:nil 482 writeDataCallback:^{ 483 [expectWriteTwice fulfill]; 484 }] 485 callOptions:options]; 486 487 [call receiveNextMessages:2]; 488 [call start]; 489 [call writeData:[request data]]; 490 [call writeData:[request data]]; 491 492 [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil]; 493} 494 495- (void)testFlowControlReadReadyBeforeStart { 496 __weak XCTestExpectation *expectPassedMessage = 497 [self expectationWithDescription:@"Message delivered with receiveNextMessage"]; 498 __weak XCTestExpectation *expectPassedClose = 499 [self expectationWithDescription:@"Close delivered with receiveNextMessage"]; 500 501 RMTSimpleRequest *request = [RMTSimpleRequest message]; 502 request.responseSize = kSimpleDataLength; 503 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength]; 504 505 GRPCRequestOptions *callRequest = 506 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 507 path:kUnaryCallMethod.HTTPPath 508 safety:GRPCCallSafetyDefault]; 509 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 510 options.transportType = GRPCTransportTypeInsecure; 511 options.flowControlEnabled = YES; 512 __block BOOL closed = NO; 513 GRPCCall2 *call = [[GRPCCall2 alloc] 514 initWithRequestOptions:callRequest 515 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 516 initWithInitialMetadataCallback:nil 517 messageCallback:^(NSData *message) { 518 [expectPassedMessage fulfill]; 519 XCTAssertFalse(closed); 520 } 521 closeCallback:^(NSDictionary *ttrailers, NSError *error) { 522 closed = YES; 523 [expectPassedClose fulfill]; 524 }] 525 callOptions:options]; 526 527 [call receiveNextMessages:1]; 528 [call start]; 529 [call writeData:[request data]]; 530 [call finish]; 531 532 [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil]; 533} 534 535- (void)testFlowControlReadReadyAfterStart { 536 __weak XCTestExpectation *expectPassedMessage = 537 [self expectationWithDescription:@"Message delivered with receiveNextMessage"]; 538 __weak XCTestExpectation *expectPassedClose = 539 [self expectationWithDescription:@"Close delivered with receiveNextMessage"]; 540 541 RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message]; 542 RMTResponseParameters *parameters = [RMTResponseParameters message]; 543 parameters.size = kSimpleDataLength; 544 [request.responseParametersArray addObject:parameters]; 545 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength]; 546 547 GRPCRequestOptions *callRequest = 548 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 549 path:kUnaryCallMethod.HTTPPath 550 safety:GRPCCallSafetyDefault]; 551 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 552 options.transportType = GRPCTransportTypeInsecure; 553 options.flowControlEnabled = YES; 554 __block BOOL closed = NO; 555 GRPCCall2 *call = [[GRPCCall2 alloc] 556 initWithRequestOptions:callRequest 557 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 558 initWithInitialMetadataCallback:nil 559 messageCallback:^(NSData *message) { 560 [expectPassedMessage fulfill]; 561 XCTAssertFalse(closed); 562 } 563 closeCallback:^(NSDictionary *trailers, NSError *error) { 564 closed = YES; 565 [expectPassedClose fulfill]; 566 }] 567 callOptions:options]; 568 569 [call start]; 570 [call receiveNextMessages:1]; 571 [call writeData:[request data]]; 572 [call finish]; 573 574 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 575} 576 577- (void)testFlowControlReadNonBlockingFailure { 578 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."]; 579 580 GRPCRequestOptions *requestOptions = 581 [[GRPCRequestOptions alloc] initWithHost:GRPCGetLocalInteropTestServerAddressPlainText() 582 path:kUnaryCallMethod.HTTPPath 583 safety:GRPCCallSafetyDefault]; 584 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 585 options.flowControlEnabled = YES; 586 options.transportType = GRPCTransportTypeInsecure; 587 588 RMTSimpleRequest *request = [RMTSimpleRequest message]; 589 request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit]; 590 591 RMTEchoStatus *status = [RMTEchoStatus message]; 592 status.code = 2; 593 status.message = @"test"; 594 request.responseStatus = status; 595 596 GRPCCall2 *call = [[GRPCCall2 alloc] 597 initWithRequestOptions:requestOptions 598 responseHandler:[[GRPCBlockCallbackResponseHandler alloc] 599 initWithInitialMetadataCallback:nil 600 messageCallback:^(NSData *data) { 601 XCTFail(@"Received unexpected message"); 602 } 603 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { 604 XCTAssertNotNil(error, @"Expecting non-nil error"); 605 XCTAssertEqual(error.code, 2); 606 [completion fulfill]; 607 }] 608 callOptions:options]; 609 [call writeData:[request data]]; 610 [call start]; 611 [call finish]; 612 613 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 614} 615 616@end 617