3 * Copyright 2018 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #import <GRPCClient/GRPCCall.h>
20 #import <ProtoRPC/ProtoMethod.h>
21 #import <RemoteTest/Messages.pbobjc.h>
22 #import <XCTest/XCTest.h>
24 #include <grpc/grpc.h>
25 #include <grpc/support/port_platform.h>
27 #import "../version.h"
29 // The server address is derived from preprocessor macro, which is
30 // in turn derived from environment variable of the same name.
31 #define NSStringize_helper(x) #x
32 #define NSStringize(x) @NSStringize_helper(x)
33 static NSString *const kHostAddress = NSStringize(HOST_PORT_LOCAL);
34 static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
36 // Package and service name of test server
37 static NSString *const kPackage = @"grpc.testing";
38 static NSString *const kService = @"TestService";
40 static GRPCProtoMethod *kInexistentMethod;
41 static GRPCProtoMethod *kEmptyCallMethod;
42 static GRPCProtoMethod *kUnaryCallMethod;
43 static GRPCProtoMethod *kOutputStreamingCallMethod;
44 static GRPCProtoMethod *kFullDuplexCallMethod;
46 static const int kSimpleDataLength = 100;
48 static const NSTimeInterval kTestTimeout = 8;
49 static const NSTimeInterval kInvertedTimeout = 2;
51 // Reveal the _class ivar for testing access
52 @interface GRPCCall2 () {
59 // Convenience class to use blocks as callbacks
60 @interface ClientTestsBlockCallbacks : NSObject<GRPCResponseHandler>
62 - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
63 messageCallback:(void (^)(id))messageCallback
64 closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
65 writeDataCallback:(void (^)(void))writeDataCallback;
67 - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
68 messageCallback:(void (^)(id))messageCallback
69 closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
73 @implementation ClientTestsBlockCallbacks {
74 void (^_initialMetadataCallback)(NSDictionary *);
75 void (^_messageCallback)(id);
76 void (^_closeCallback)(NSDictionary *, NSError *);
77 void (^_writeDataCallback)(void);
78 dispatch_queue_t _dispatchQueue;
81 - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
82 messageCallback:(void (^)(id))messageCallback
83 closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
84 writeDataCallback:(void (^)(void))writeDataCallback {
85 if ((self = [super init])) {
86 _initialMetadataCallback = initialMetadataCallback;
87 _messageCallback = messageCallback;
88 _closeCallback = closeCallback;
89 _writeDataCallback = writeDataCallback;
90 _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
95 - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
96 messageCallback:(void (^)(id))messageCallback
97 closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
98 return [self initWithInitialMetadataCallback:initialMetadataCallback
99 messageCallback:messageCallback
100 closeCallback:closeCallback
101 writeDataCallback:nil];
104 - (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
105 if (self->_initialMetadataCallback) {
106 self->_initialMetadataCallback(initialMetadata);
110 - (void)didReceiveRawMessage:(GPBMessage *)message {
111 if (self->_messageCallback) {
112 self->_messageCallback(message);
116 - (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
117 if (self->_closeCallback) {
118 self->_closeCallback(trailingMetadata, error);
122 - (void)didWriteData {
123 if (self->_writeDataCallback) {
124 self->_writeDataCallback();
128 - (dispatch_queue_t)dispatchQueue {
129 return _dispatchQueue;
134 @interface CallAPIv2Tests : XCTestCase<GRPCAuthorizationProtocol>
138 @implementation CallAPIv2Tests
141 // This method isn't implemented by the remote server.
143 [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"Inexistent"];
145 [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"EmptyCall"];
147 [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"UnaryCall"];
148 kOutputStreamingCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
150 method:@"StreamingOutputCall"];
151 kFullDuplexCallMethod =
152 [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"FullDuplexCall"];
155 - (void)testMetadata {
156 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."];
158 RMTSimpleRequest *request = [RMTSimpleRequest message];
159 request.fillUsername = YES;
160 request.fillOauthScope = YES;
162 GRPCRequestOptions *callRequest =
163 [[GRPCRequestOptions alloc] initWithHost:(NSString *)kRemoteSSLHost
164 path:kUnaryCallMethod.HTTPPath
165 safety:GRPCCallSafetyDefault];
166 __block NSDictionary *init_md;
167 __block NSDictionary *trailing_md;
168 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
169 options.oauth2AccessToken = @"bogusToken";
170 GRPCCall2 *call = [[GRPCCall2 alloc]
171 initWithRequestOptions:callRequest
172 responseHandler:[[ClientTestsBlockCallbacks alloc]
173 initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) {
174 init_md = initialMetadata;
176 messageCallback:^(id message) {
177 XCTFail(@"Received unexpected response.");
179 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
180 trailing_md = trailingMetadata;
182 XCTAssertEqual(error.code, 16,
183 @"Finished with unexpected error: %@", error);
184 XCTAssertEqualObjects(init_md,
185 error.userInfo[kGRPCHeadersKey]);
186 XCTAssertEqualObjects(trailing_md,
187 error.userInfo[kGRPCTrailersKey]);
188 NSString *challengeHeader = init_md[@"www-authenticate"];
189 XCTAssertGreaterThan(challengeHeader.length, 0,
190 @"No challenge in response headers %@",
192 [expectation fulfill];
195 callOptions:options];
198 [call writeData:[request data]];
201 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
204 - (void)testUserAgentPrefix {
205 __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
206 __weak XCTestExpectation *recvInitialMd =
207 [self expectationWithDescription:@"Did not receive initial md."];
209 GRPCRequestOptions *request = [[GRPCRequestOptions alloc] initWithHost:kHostAddress
210 path:kEmptyCallMethod.HTTPPath
211 safety:GRPCCallSafetyDefault];
212 NSDictionary *headers =
213 [NSDictionary dictionaryWithObjectsAndKeys:@"", @"x-grpc-test-echo-useragent", nil];
214 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
215 options.transportType = GRPCTransportTypeInsecure;
216 options.userAgentPrefix = @"Foo";
217 options.initialMetadata = headers;
218 GRPCCall2 *call = [[GRPCCall2 alloc]
219 initWithRequestOptions:request
220 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^(
221 NSDictionary *initialMetadata) {
222 NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"];
223 // Test the regex is correct
224 NSString *expectedUserAgent = @"Foo grpc-objc/";
226 [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING];
227 expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"];
229 [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING];
230 expectedUserAgent = [expectedUserAgent stringByAppendingString:@" ("];
231 expectedUserAgent = [expectedUserAgent stringByAppendingString:@GPR_PLATFORM_STRING];
232 expectedUserAgent = [expectedUserAgent stringByAppendingString:@"; chttp2; "];
233 expectedUserAgent = [expectedUserAgent
234 stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]];
235 expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"];
236 XCTAssertEqualObjects(userAgent, expectedUserAgent);
238 NSError *error = nil;
239 // Change in format of user-agent field in a direction that does not match
240 // the regex will likely cause problem for certain gRPC users. For details,
241 // refer to internal doc https://goo.gl/c2diBc
242 NSRegularExpression *regex = [NSRegularExpression
243 regularExpressionWithPattern:
244 @" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?"
248 NSString *customUserAgent =
249 [regex stringByReplacingMatchesInString:userAgent
251 range:NSMakeRange(0, [userAgent length])
253 XCTAssertEqualObjects(customUserAgent, @"Foo");
254 [recvInitialMd fulfill];
256 messageCallback:^(id message) {
257 XCTAssertNotNil(message);
258 XCTAssertEqual([message length], 0,
259 @"Non-empty response received: %@", message);
261 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
263 XCTFail(@"Finished with unexpected error: %@", error);
265 [completion fulfill];
268 callOptions:options];
269 [call writeData:[NSData data]];
272 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
275 - (void)getTokenWithHandler:(void (^)(NSString *token))handler {
276 dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
277 dispatch_sync(queue, ^{
278 handler(@"test-access-token");
282 - (void)testOAuthToken {
283 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
285 GRPCRequestOptions *requestOptions =
286 [[GRPCRequestOptions alloc] initWithHost:kHostAddress
287 path:kEmptyCallMethod.HTTPPath
288 safety:GRPCCallSafetyDefault];
289 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
290 options.transportType = GRPCTransportTypeInsecure;
291 options.authTokenProvider = self;
292 __block GRPCCall2 *call = [[GRPCCall2 alloc]
293 initWithRequestOptions:requestOptions
294 responseHandler:[[ClientTestsBlockCallbacks alloc]
295 initWithInitialMetadataCallback:nil
297 closeCallback:^(NSDictionary *trailingMetadata,
299 [completion fulfill];
301 callOptions:options];
302 [call writeData:[NSData data]];
306 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
309 - (void)testResponseSizeLimitExceeded {
310 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
312 GRPCRequestOptions *requestOptions =
313 [[GRPCRequestOptions alloc] initWithHost:kHostAddress
314 path:kUnaryCallMethod.HTTPPath
315 safety:GRPCCallSafetyDefault];
316 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
317 options.responseSizeLimit = kSimpleDataLength;
318 options.transportType = GRPCTransportTypeInsecure;
320 RMTSimpleRequest *request = [RMTSimpleRequest message];
321 request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit];
322 request.responseSize = (int32_t)(options.responseSizeLimit * 2);
324 GRPCCall2 *call = [[GRPCCall2 alloc]
325 initWithRequestOptions:requestOptions
326 responseHandler:[[ClientTestsBlockCallbacks alloc]
327 initWithInitialMetadataCallback:nil
329 closeCallback:^(NSDictionary *trailingMetadata,
331 XCTAssertNotNil(error,
332 @"Expecting non-nil error");
333 XCTAssertEqual(error.code,
334 GRPCErrorCodeResourceExhausted);
335 [completion fulfill];
337 callOptions:options];
338 [call writeData:[request data]];
342 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
345 - (void)testIdempotentProtoRPC {
346 __weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."];
347 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
349 RMTSimpleRequest *request = [RMTSimpleRequest message];
350 request.responseSize = kSimpleDataLength;
351 request.fillUsername = YES;
352 request.fillOauthScope = YES;
353 GRPCRequestOptions *requestOptions =
354 [[GRPCRequestOptions alloc] initWithHost:kHostAddress
355 path:kUnaryCallMethod.HTTPPath
356 safety:GRPCCallSafetyIdempotentRequest];
358 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
359 options.transportType = GRPCTransportTypeInsecure;
360 GRPCCall2 *call = [[GRPCCall2 alloc]
361 initWithRequestOptions:requestOptions
362 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
363 messageCallback:^(id message) {
364 NSData *data = (NSData *)message;
365 XCTAssertNotNil(data, @"nil value received as response.");
366 XCTAssertGreaterThan(data.length, 0,
367 @"Empty response received.");
368 RMTSimpleResponse *responseProto =
369 [RMTSimpleResponse parseFromData:data error:NULL];
370 // We expect empty strings, not nil:
371 XCTAssertNotNil(responseProto.username,
372 @"Response's username is nil.");
373 XCTAssertNotNil(responseProto.oauthScope,
374 @"Response's OAuth scope is nil.");
377 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
378 XCTAssertNil(error, @"Finished with unexpected error: %@",
380 [completion fulfill];
382 callOptions:options];
385 [call writeData:[request data]];
388 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
391 - (void)testTimeout {
392 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
394 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
395 options.timeout = 0.001;
396 GRPCRequestOptions *requestOptions =
397 [[GRPCRequestOptions alloc] initWithHost:kHostAddress
398 path:kFullDuplexCallMethod.HTTPPath
399 safety:GRPCCallSafetyDefault];
401 GRPCCall2 *call = [[GRPCCall2 alloc]
402 initWithRequestOptions:requestOptions
404 [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
405 messageCallback:^(NSData *data) {
406 XCTFail(@"Failure: response received; Expect: no response received.");
408 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
409 XCTAssertNotNil(error,
410 @"Failure: no error received; Expect: receive "
411 @"deadline exceeded.");
412 XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded);
413 [completion fulfill];
415 callOptions:options];
419 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
422 - (void)testTimeoutBackoffWithTimeout:(double)timeout Backoff:(double)backoff {
423 const double maxConnectTime = timeout > backoff ? timeout : backoff;
424 const double kMargin = 0.1;
426 __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."];
427 NSString *const kDummyAddress = [NSString stringWithFormat:@"127.0.0.1:10000"];
428 GRPCRequestOptions *requestOptions =
429 [[GRPCRequestOptions alloc] initWithHost:kDummyAddress
431 safety:GRPCCallSafetyDefault];
432 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
433 options.connectMinTimeout = timeout;
434 options.connectInitialBackoff = backoff;
435 options.connectMaxBackoff = 0;
437 NSDate *startTime = [NSDate date];
438 GRPCCall2 *call = [[GRPCCall2 alloc]
439 initWithRequestOptions:requestOptions
440 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
441 messageCallback:^(NSData *data) {
442 XCTFail(@"Received message. Should not reach here.");
444 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
445 XCTAssertNotNil(error,
446 @"Finished with no error; expecting error");
448 [[NSDate date] timeIntervalSinceDate:startTime],
449 maxConnectTime + kMargin);
450 [completion fulfill];
452 callOptions:options];
456 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
459 - (void)testTimeoutBackoff1 {
460 [self testTimeoutBackoffWithTimeout:0.7 Backoff:0.4];
463 - (void)testTimeoutBackoff2 {
464 [self testTimeoutBackoffWithTimeout:0.3 Backoff:0.8];
467 - (void)testCompression {
468 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
470 RMTSimpleRequest *request = [RMTSimpleRequest message];
471 request.expectCompressed = [RMTBoolValue message];
472 request.expectCompressed.value = YES;
473 request.responseCompressed = [RMTBoolValue message];
474 request.expectCompressed.value = YES;
475 request.responseSize = kSimpleDataLength;
476 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
477 GRPCRequestOptions *requestOptions =
478 [[GRPCRequestOptions alloc] initWithHost:kHostAddress
479 path:kUnaryCallMethod.HTTPPath
480 safety:GRPCCallSafetyDefault];
482 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
483 options.transportType = GRPCTransportTypeInsecure;
484 options.compressionAlgorithm = GRPCCompressGzip;
485 GRPCCall2 *call = [[GRPCCall2 alloc]
486 initWithRequestOptions:requestOptions
487 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
488 messageCallback:^(NSData *data) {
490 RMTSimpleResponse *response =
491 [RMTSimpleResponse parseFromData:data error:&error];
492 XCTAssertNil(error, @"Error when parsing response: %@", error);
493 XCTAssertEqual(response.payload.body.length, kSimpleDataLength);
495 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
496 XCTAssertNil(error, @"Received failure: %@", error);
497 [completion fulfill];
500 callOptions:options];
503 [call writeData:[request data]];
506 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
509 - (void)testFlowControlWrite {
510 __weak XCTestExpectation *expectWriteData =
511 [self expectationWithDescription:@"Reported write data"];
513 RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
514 RMTResponseParameters *parameters = [RMTResponseParameters message];
515 parameters.size = kSimpleDataLength;
516 [request.responseParametersArray addObject:parameters];
517 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
519 GRPCRequestOptions *callRequest =
520 [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
521 path:kUnaryCallMethod.HTTPPath
522 safety:GRPCCallSafetyDefault];
523 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
524 options.transportType = GRPCTransportTypeInsecure;
525 options.flowControlEnabled = YES;
527 [[GRPCCall2 alloc] initWithRequestOptions:callRequest
528 responseHandler:[[ClientTestsBlockCallbacks alloc]
529 initWithInitialMetadataCallback:nil
533 [expectWriteData fulfill];
535 callOptions:options];
538 [call receiveNextMessages:1];
539 [call writeData:[request data]];
541 // Wait for 3 seconds and make sure we do not receive the response
542 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
547 - (void)testFlowControlRead {
548 __weak __block XCTestExpectation *expectBlockedMessage =
549 [self expectationWithDescription:@"Message not delivered without recvNextMessage"];
550 __weak __block XCTestExpectation *expectPassedMessage = nil;
551 __weak __block XCTestExpectation *expectBlockedClose =
552 [self expectationWithDescription:@"Call not closed with pending message"];
553 __weak __block XCTestExpectation *expectPassedClose = nil;
554 expectBlockedMessage.inverted = YES;
555 expectBlockedClose.inverted = YES;
557 RMTSimpleRequest *request = [RMTSimpleRequest message];
558 request.responseSize = kSimpleDataLength;
559 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
561 GRPCRequestOptions *callRequest =
562 [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
563 path:kUnaryCallMethod.HTTPPath
564 safety:GRPCCallSafetyDefault];
565 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
566 options.transportType = GRPCTransportTypeInsecure;
567 options.flowControlEnabled = YES;
568 __block int unblocked = NO;
569 GRPCCall2 *call = [[GRPCCall2 alloc]
570 initWithRequestOptions:callRequest
571 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
572 messageCallback:^(NSData *message) {
574 [expectBlockedMessage fulfill];
576 [expectPassedMessage fulfill];
579 closeCallback:^(NSDictionary *trailers, NSError *error) {
581 [expectBlockedClose fulfill];
583 [expectPassedClose fulfill];
586 callOptions:options];
589 [call writeData:[request data]];
592 // Wait to make sure we do not receive the response
593 [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
595 expectPassedMessage =
596 [self expectationWithDescription:@"Message delivered with receiveNextMessage"];
597 expectPassedClose = [self expectationWithDescription:@"Close delivered after receiveNextMessage"];
600 [call receiveNextMessages:1];
602 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
605 - (void)testFlowControlMultipleMessages {
606 __weak XCTestExpectation *expectPassedMessage =
607 [self expectationWithDescription:@"two messages delivered with receiveNextMessage"];
608 expectPassedMessage.expectedFulfillmentCount = 2;
609 __weak XCTestExpectation *expectBlockedMessage =
610 [self expectationWithDescription:@"Message 3 not delivered"];
611 expectBlockedMessage.inverted = YES;
612 __weak XCTestExpectation *expectWriteTwice =
613 [self expectationWithDescription:@"Write 2 messages done"];
614 expectWriteTwice.expectedFulfillmentCount = 2;
616 RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
617 RMTResponseParameters *parameters = [RMTResponseParameters message];
618 parameters.size = kSimpleDataLength;
619 [request.responseParametersArray addObject:parameters];
620 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
622 GRPCRequestOptions *callRequest =
623 [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
624 path:kFullDuplexCallMethod.HTTPPath
625 safety:GRPCCallSafetyDefault];
626 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
627 options.transportType = GRPCTransportTypeInsecure;
628 options.flowControlEnabled = YES;
629 __block NSUInteger messageId = 0;
630 __block GRPCCall2 *call = [[GRPCCall2 alloc]
631 initWithRequestOptions:callRequest
632 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
633 messageCallback:^(NSData *message) {
634 if (messageId <= 1) {
635 [expectPassedMessage fulfill];
637 [expectBlockedMessage fulfill];
643 [expectWriteTwice fulfill];
645 callOptions:options];
647 [call receiveNextMessages:2];
649 [call writeData:[request data]];
650 [call writeData:[request data]];
652 [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
655 - (void)testFlowControlReadReadyBeforeStart {
656 __weak XCTestExpectation *expectPassedMessage =
657 [self expectationWithDescription:@"Message delivered with receiveNextMessage"];
658 __weak XCTestExpectation *expectPassedClose =
659 [self expectationWithDescription:@"Close delivered with receiveNextMessage"];
661 RMTSimpleRequest *request = [RMTSimpleRequest message];
662 request.responseSize = kSimpleDataLength;
663 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
665 GRPCRequestOptions *callRequest =
666 [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
667 path:kUnaryCallMethod.HTTPPath
668 safety:GRPCCallSafetyDefault];
669 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
670 options.transportType = GRPCTransportTypeInsecure;
671 options.flowControlEnabled = YES;
672 __block BOOL closed = NO;
673 GRPCCall2 *call = [[GRPCCall2 alloc]
674 initWithRequestOptions:callRequest
675 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
676 messageCallback:^(NSData *message) {
677 [expectPassedMessage fulfill];
678 XCTAssertFalse(closed);
680 closeCallback:^(NSDictionary *ttrailers, NSError *error) {
682 [expectPassedClose fulfill];
684 callOptions:options];
686 [call receiveNextMessages:1];
688 [call writeData:[request data]];
691 [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
694 - (void)testFlowControlReadReadyAfterStart {
695 __weak XCTestExpectation *expectPassedMessage =
696 [self expectationWithDescription:@"Message delivered with receiveNextMessage"];
697 __weak XCTestExpectation *expectPassedClose =
698 [self expectationWithDescription:@"Close delivered with receiveNextMessage"];
700 RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
701 RMTResponseParameters *parameters = [RMTResponseParameters message];
702 parameters.size = kSimpleDataLength;
703 [request.responseParametersArray addObject:parameters];
704 request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
706 GRPCRequestOptions *callRequest =
707 [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
708 path:kUnaryCallMethod.HTTPPath
709 safety:GRPCCallSafetyDefault];
710 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
711 options.transportType = GRPCTransportTypeInsecure;
712 options.flowControlEnabled = YES;
713 __block BOOL closed = NO;
714 GRPCCall2 *call = [[GRPCCall2 alloc]
715 initWithRequestOptions:callRequest
716 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
717 messageCallback:^(NSData *message) {
718 [expectPassedMessage fulfill];
719 XCTAssertFalse(closed);
721 closeCallback:^(NSDictionary *trailers, NSError *error) {
723 [expectPassedClose fulfill];
725 callOptions:options];
728 [call receiveNextMessages:1];
729 [call writeData:[request data]];
732 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
735 - (void)testFlowControlReadNonBlockingFailure {
736 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
738 GRPCRequestOptions *requestOptions =
739 [[GRPCRequestOptions alloc] initWithHost:kHostAddress
740 path:kUnaryCallMethod.HTTPPath
741 safety:GRPCCallSafetyDefault];
742 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
743 options.flowControlEnabled = YES;
744 options.transportType = GRPCTransportTypeInsecure;
746 RMTSimpleRequest *request = [RMTSimpleRequest message];
747 request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit];
749 RMTEchoStatus *status = [RMTEchoStatus message];
751 status.message = @"test";
752 request.responseStatus = status;
754 GRPCCall2 *call = [[GRPCCall2 alloc]
755 initWithRequestOptions:requestOptions
756 responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
757 messageCallback:^(NSData *data) {
758 XCTFail(@"Received unexpected message");
760 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
761 XCTAssertNotNil(error, @"Expecting non-nil error");
762 XCTAssertEqual(error.code, 2);
763 [completion fulfill];
765 callOptions:options];
766 [call writeData:[request data]];
770 [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];