Imported Upstream version 1.21.3
[platform/upstream/grpc.git] / src / objective-c / tests / APIv2Tests / APIv2Tests.m
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 <RemoteTest/Messages.pbobjc.h>
22 #import <XCTest/XCTest.h>
23
24 #include <grpc/grpc.h>
25 #include <grpc/support/port_platform.h>
26
27 #import "../version.h"
28
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);
35
36 // Package and service name of test server
37 static NSString *const kPackage = @"grpc.testing";
38 static NSString *const kService = @"TestService";
39
40 static GRPCProtoMethod *kInexistentMethod;
41 static GRPCProtoMethod *kEmptyCallMethod;
42 static GRPCProtoMethod *kUnaryCallMethod;
43 static GRPCProtoMethod *kOutputStreamingCallMethod;
44 static GRPCProtoMethod *kFullDuplexCallMethod;
45
46 static const int kSimpleDataLength = 100;
47
48 static const NSTimeInterval kTestTimeout = 8;
49 static const NSTimeInterval kInvertedTimeout = 2;
50
51 // Reveal the _class ivar for testing access
52 @interface GRPCCall2 () {
53  @public
54   GRPCCall *_call;
55 }
56
57 @end
58
59 // Convenience class to use blocks as callbacks
60 @interface ClientTestsBlockCallbacks : NSObject<GRPCResponseHandler>
61
62 - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
63                                 messageCallback:(void (^)(id))messageCallback
64                                   closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
65                               writeDataCallback:(void (^)(void))writeDataCallback;
66
67 - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
68                                 messageCallback:(void (^)(id))messageCallback
69                                   closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
70
71 @end
72
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;
79 }
80
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);
91   }
92   return self;
93 }
94
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];
102 }
103
104 - (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
105   if (self->_initialMetadataCallback) {
106     self->_initialMetadataCallback(initialMetadata);
107   }
108 }
109
110 - (void)didReceiveRawMessage:(GPBMessage *)message {
111   if (self->_messageCallback) {
112     self->_messageCallback(message);
113   }
114 }
115
116 - (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
117   if (self->_closeCallback) {
118     self->_closeCallback(trailingMetadata, error);
119   }
120 }
121
122 - (void)didWriteData {
123   if (self->_writeDataCallback) {
124     self->_writeDataCallback();
125   }
126 }
127
128 - (dispatch_queue_t)dispatchQueue {
129   return _dispatchQueue;
130 }
131
132 @end
133
134 @interface CallAPIv2Tests : XCTestCase<GRPCAuthorizationProtocol>
135
136 @end
137
138 @implementation CallAPIv2Tests
139
140 - (void)setUp {
141   // This method isn't implemented by the remote server.
142   kInexistentMethod =
143       [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"Inexistent"];
144   kEmptyCallMethod =
145       [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"EmptyCall"];
146   kUnaryCallMethod =
147       [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"UnaryCall"];
148   kOutputStreamingCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
149                                                                 service:kService
150                                                                  method:@"StreamingOutputCall"];
151   kFullDuplexCallMethod =
152       [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"FullDuplexCall"];
153 }
154
155 - (void)testMetadata {
156   __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."];
157
158   RMTSimpleRequest *request = [RMTSimpleRequest message];
159   request.fillUsername = YES;
160   request.fillOauthScope = YES;
161
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;
175                                  }
176                                  messageCallback:^(id message) {
177                                    XCTFail(@"Received unexpected response.");
178                                  }
179                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
180                                    trailing_md = trailingMetadata;
181                                    if (error) {
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 %@",
191                                                           init_md);
192                                      [expectation fulfill];
193                                    }
194                                  }]
195                  callOptions:options];
196
197   [call start];
198   [call writeData:[request data]];
199   [call finish];
200
201   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
202 }
203
204 - (void)testUserAgentPrefix {
205   __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
206   __weak XCTestExpectation *recvInitialMd =
207       [self expectationWithDescription:@"Did not receive initial md."];
208
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/";
225                expectedUserAgent =
226                    [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING];
227                expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"];
228                expectedUserAgent =
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);
237
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]+)?/[^ ,]+( \\([^)]*\\))?"
245                                         options:0
246                                           error:&error];
247
248                NSString *customUserAgent =
249                    [regex stringByReplacingMatchesInString:userAgent
250                                                    options:0
251                                                      range:NSMakeRange(0, [userAgent length])
252                                               withTemplate:@""];
253                XCTAssertEqualObjects(customUserAgent, @"Foo");
254                [recvInitialMd fulfill];
255              }
256                                  messageCallback:^(id message) {
257                                    XCTAssertNotNil(message);
258                                    XCTAssertEqual([message length], 0,
259                                                   @"Non-empty response received: %@", message);
260                                  }
261                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
262                                    if (error) {
263                                      XCTFail(@"Finished with unexpected error: %@", error);
264                                    } else {
265                                      [completion fulfill];
266                                    }
267                                  }]
268                  callOptions:options];
269   [call writeData:[NSData data]];
270   [call start];
271
272   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
273 }
274
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");
279   });
280 }
281
282 - (void)testOAuthToken {
283   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
284
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
296                                                  messageCallback:nil
297                                                    closeCallback:^(NSDictionary *trailingMetadata,
298                                                                    NSError *error) {
299                                                      [completion fulfill];
300                                                    }]
301                  callOptions:options];
302   [call writeData:[NSData data]];
303   [call start];
304   [call finish];
305
306   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
307 }
308
309 - (void)testResponseSizeLimitExceeded {
310   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
311
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;
319
320   RMTSimpleRequest *request = [RMTSimpleRequest message];
321   request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit];
322   request.responseSize = (int32_t)(options.responseSizeLimit * 2);
323
324   GRPCCall2 *call = [[GRPCCall2 alloc]
325       initWithRequestOptions:requestOptions
326              responseHandler:[[ClientTestsBlockCallbacks alloc]
327                                  initWithInitialMetadataCallback:nil
328                                                  messageCallback:nil
329                                                    closeCallback:^(NSDictionary *trailingMetadata,
330                                                                    NSError *error) {
331                                                      XCTAssertNotNil(error,
332                                                                      @"Expecting non-nil error");
333                                                      XCTAssertEqual(error.code,
334                                                                     GRPCErrorCodeResourceExhausted);
335                                                      [completion fulfill];
336                                                    }]
337                  callOptions:options];
338   [call writeData:[request data]];
339   [call start];
340   [call finish];
341
342   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
343 }
344
345 - (void)testIdempotentProtoRPC {
346   __weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."];
347   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
348
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];
357
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.");
375                                    [response fulfill];
376                                  }
377                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
378                                    XCTAssertNil(error, @"Finished with unexpected error: %@",
379                                                 error);
380                                    [completion fulfill];
381                                  }]
382                  callOptions:options];
383
384   [call start];
385   [call writeData:[request data]];
386   [call finish];
387
388   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
389 }
390
391 - (void)testTimeout {
392   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
393
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];
400
401   GRPCCall2 *call = [[GRPCCall2 alloc]
402       initWithRequestOptions:requestOptions
403              responseHandler:
404                  [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
405                      messageCallback:^(NSData *data) {
406                        XCTFail(@"Failure: response received; Expect: no response received.");
407                      }
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];
414                      }]
415                  callOptions:options];
416
417   [call start];
418
419   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
420 }
421
422 - (void)testTimeoutBackoffWithTimeout:(double)timeout Backoff:(double)backoff {
423   const double maxConnectTime = timeout > backoff ? timeout : backoff;
424   const double kMargin = 0.1;
425
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
430                                           path:@"/dummy/path"
431                                         safety:GRPCCallSafetyDefault];
432   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
433   options.connectMinTimeout = timeout;
434   options.connectInitialBackoff = backoff;
435   options.connectMaxBackoff = 0;
436
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.");
443                                  }
444                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
445                                    XCTAssertNotNil(error,
446                                                    @"Finished with no error; expecting error");
447                                    XCTAssertLessThan(
448                                        [[NSDate date] timeIntervalSinceDate:startTime],
449                                        maxConnectTime + kMargin);
450                                    [completion fulfill];
451                                  }]
452                  callOptions:options];
453
454   [call start];
455
456   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
457 }
458
459 - (void)testTimeoutBackoff1 {
460   [self testTimeoutBackoffWithTimeout:0.7 Backoff:0.4];
461 }
462
463 - (void)testTimeoutBackoff2 {
464   [self testTimeoutBackoffWithTimeout:0.3 Backoff:0.8];
465 }
466
467 - (void)testCompression {
468   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
469
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];
481
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) {
489                                    NSError *error;
490                                    RMTSimpleResponse *response =
491                                        [RMTSimpleResponse parseFromData:data error:&error];
492                                    XCTAssertNil(error, @"Error when parsing response: %@", error);
493                                    XCTAssertEqual(response.payload.body.length, kSimpleDataLength);
494                                  }
495                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
496                                    XCTAssertNil(error, @"Received failure: %@", error);
497                                    [completion fulfill];
498                                  }]
499
500                  callOptions:options];
501
502   [call start];
503   [call writeData:[request data]];
504   [call finish];
505
506   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
507 }
508
509 - (void)testFlowControlWrite {
510   __weak XCTestExpectation *expectWriteData =
511       [self expectationWithDescription:@"Reported write data"];
512
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];
518
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;
526   GRPCCall2 *call =
527       [[GRPCCall2 alloc] initWithRequestOptions:callRequest
528                                 responseHandler:[[ClientTestsBlockCallbacks alloc]
529                                                     initWithInitialMetadataCallback:nil
530                                                                     messageCallback:nil
531                                                                       closeCallback:nil
532                                                                   writeDataCallback:^{
533                                                                     [expectWriteData fulfill];
534                                                                   }]
535                                     callOptions:options];
536
537   [call start];
538   [call receiveNextMessages:1];
539   [call writeData:[request data]];
540
541   // Wait for 3 seconds and make sure we do not receive the response
542   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
543
544   [call finish];
545 }
546
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;
556
557   RMTSimpleRequest *request = [RMTSimpleRequest message];
558   request.responseSize = kSimpleDataLength;
559   request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
560
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) {
573                                    if (!unblocked) {
574                                      [expectBlockedMessage fulfill];
575                                    } else {
576                                      [expectPassedMessage fulfill];
577                                    }
578                                  }
579                                  closeCallback:^(NSDictionary *trailers, NSError *error) {
580                                    if (!unblocked) {
581                                      [expectBlockedClose fulfill];
582                                    } else {
583                                      [expectPassedClose fulfill];
584                                    }
585                                  }]
586                  callOptions:options];
587
588   [call start];
589   [call writeData:[request data]];
590   [call finish];
591
592   // Wait to make sure we do not receive the response
593   [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
594
595   expectPassedMessage =
596       [self expectationWithDescription:@"Message delivered with receiveNextMessage"];
597   expectPassedClose = [self expectationWithDescription:@"Close delivered after receiveNextMessage"];
598
599   unblocked = YES;
600   [call receiveNextMessages:1];
601
602   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
603 }
604
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;
615
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];
621
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];
636                                    } else {
637                                      [expectBlockedMessage fulfill];
638                                    }
639                                    messageId++;
640                                  }
641                                  closeCallback:nil
642                                  writeDataCallback:^{
643                                    [expectWriteTwice fulfill];
644                                  }]
645                  callOptions:options];
646
647   [call receiveNextMessages:2];
648   [call start];
649   [call writeData:[request data]];
650   [call writeData:[request data]];
651
652   [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
653 }
654
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"];
660
661   RMTSimpleRequest *request = [RMTSimpleRequest message];
662   request.responseSize = kSimpleDataLength;
663   request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
664
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);
679                                  }
680                                  closeCallback:^(NSDictionary *ttrailers, NSError *error) {
681                                    closed = YES;
682                                    [expectPassedClose fulfill];
683                                  }]
684                  callOptions:options];
685
686   [call receiveNextMessages:1];
687   [call start];
688   [call writeData:[request data]];
689   [call finish];
690
691   [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
692 }
693
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"];
699
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];
705
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);
720                                  }
721                                  closeCallback:^(NSDictionary *trailers, NSError *error) {
722                                    closed = YES;
723                                    [expectPassedClose fulfill];
724                                  }]
725                  callOptions:options];
726
727   [call start];
728   [call receiveNextMessages:1];
729   [call writeData:[request data]];
730   [call finish];
731
732   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
733 }
734
735 - (void)testFlowControlReadNonBlockingFailure {
736   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
737
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;
745
746   RMTSimpleRequest *request = [RMTSimpleRequest message];
747   request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit];
748
749   RMTEchoStatus *status = [RMTEchoStatus message];
750   status.code = 2;
751   status.message = @"test";
752   request.responseStatus = status;
753
754   GRPCCall2 *call = [[GRPCCall2 alloc]
755       initWithRequestOptions:requestOptions
756              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
757                                  messageCallback:^(NSData *data) {
758                                    XCTFail(@"Received unexpected message");
759                                  }
760                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
761                                    XCTAssertNotNil(error, @"Expecting non-nil error");
762                                    XCTAssertEqual(error.code, 2);
763                                    [completion fulfill];
764                                  }]
765                  callOptions:options];
766   [call writeData:[request data]];
767   [call start];
768   [call finish];
769
770   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
771 }
772
773 @end