| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 | 
							- /*
 
-  *
 
-  * Copyright 2018 gRPC authors.
 
-  *
 
-  * Licensed under the Apache License, Version 2.0 (the "License");
 
-  * you may not use this file except in compliance with the License.
 
-  * You may obtain a copy of the License at
 
-  *
 
-  *     http://www.apache.org/licenses/LICENSE-2.0
 
-  *
 
-  * Unless required by applicable law or agreed to in writing, software
 
-  * distributed under the License is distributed on an "AS IS" BASIS,
 
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
-  * See the License for the specific language governing permissions and
 
-  * limitations under the License.
 
-  *
 
-  */
 
- #import <GRPCClient/GRPCCall.h>
 
- #import <ProtoRPC/ProtoMethod.h>
 
- #import <RemoteTest/Messages.pbobjc.h>
 
- #import <XCTest/XCTest.h>
 
- #include <grpc/grpc.h>
 
- #import "../version.h"
 
- // The server address is derived from preprocessor macro, which is
 
- // in turn derived from environment variable of the same name.
 
- #define NSStringize_helper(x) #x
 
- #define NSStringize(x) @NSStringize_helper(x)
 
- static NSString *const kHostAddress = NSStringize(HOST_PORT_LOCAL);
 
- static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
 
- // Package and service name of test server
 
- static NSString *const kPackage = @"grpc.testing";
 
- static NSString *const kService = @"TestService";
 
- static GRPCProtoMethod *kInexistentMethod;
 
- static GRPCProtoMethod *kEmptyCallMethod;
 
- static GRPCProtoMethod *kUnaryCallMethod;
 
- static GRPCProtoMethod *kOutputStreamingCallMethod;
 
- static GRPCProtoMethod *kFullDuplexCallMethod;
 
- static const int kSimpleDataLength = 100;
 
- static const NSTimeInterval kTestTimeout = 8;
 
- static const NSTimeInterval kInvertedTimeout = 2;
 
- // Reveal the _class ivar for testing access
 
- @interface GRPCCall2 () {
 
-  @public
 
-   GRPCCall *_call;
 
- }
 
- @end
 
- // Convenience class to use blocks as callbacks
 
- @interface ClientTestsBlockCallbacks : NSObject<GRPCResponseHandler>
 
- - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
 
-                                 messageCallback:(void (^)(id))messageCallback
 
-                                   closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
 
-                               writeDataCallback:(void (^)(void))writeDataCallback;
 
- - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
 
-                                 messageCallback:(void (^)(id))messageCallback
 
-                                   closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
 
- @end
 
- @implementation ClientTestsBlockCallbacks {
 
-   void (^_initialMetadataCallback)(NSDictionary *);
 
-   void (^_messageCallback)(id);
 
-   void (^_closeCallback)(NSDictionary *, NSError *);
 
-   void (^_writeDataCallback)(void);
 
-   dispatch_queue_t _dispatchQueue;
 
- }
 
- - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
 
-                                 messageCallback:(void (^)(id))messageCallback
 
-                                   closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
 
-                               writeDataCallback:(void (^)(void))writeDataCallback {
 
-   if ((self = [super init])) {
 
-     _initialMetadataCallback = initialMetadataCallback;
 
-     _messageCallback = messageCallback;
 
-     _closeCallback = closeCallback;
 
-     _writeDataCallback = writeDataCallback;
 
-     _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
 
-   }
 
-   return self;
 
- }
 
- - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
 
-                                 messageCallback:(void (^)(id))messageCallback
 
-                                   closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
 
-   return [self initWithInitialMetadataCallback:initialMetadataCallback
 
-                                messageCallback:messageCallback
 
-                                  closeCallback:closeCallback
 
-                              writeDataCallback:nil];
 
- }
 
- - (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
 
-   if (self->_initialMetadataCallback) {
 
-     self->_initialMetadataCallback(initialMetadata);
 
-   }
 
- }
 
- - (void)didReceiveRawMessage:(GPBMessage *)message {
 
-   if (self->_messageCallback) {
 
-     self->_messageCallback(message);
 
-   }
 
- }
 
- - (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
 
-   if (self->_closeCallback) {
 
-     self->_closeCallback(trailingMetadata, error);
 
-   }
 
- }
 
- - (void)didWriteData {
 
-   if (self->_writeDataCallback) {
 
-     self->_writeDataCallback();
 
-   }
 
- }
 
- - (dispatch_queue_t)dispatchQueue {
 
-   return _dispatchQueue;
 
- }
 
- @end
 
- @interface CallAPIv2Tests : XCTestCase<GRPCAuthorizationProtocol>
 
- @end
 
- @implementation CallAPIv2Tests
 
- - (void)setUp {
 
-   // This method isn't implemented by the remote server.
 
-   kInexistentMethod =
 
-       [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"Inexistent"];
 
-   kEmptyCallMethod =
 
-       [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"EmptyCall"];
 
-   kUnaryCallMethod =
 
-       [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"UnaryCall"];
 
-   kOutputStreamingCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
 
-                                                                 service:kService
 
-                                                                  method:@"StreamingOutputCall"];
 
-   kFullDuplexCallMethod =
 
-       [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"FullDuplexCall"];
 
- }
 
- - (void)testMetadata {
 
-   __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."];
 
-   RMTSimpleRequest *request = [RMTSimpleRequest message];
 
-   request.fillUsername = YES;
 
-   request.fillOauthScope = YES;
 
-   GRPCRequestOptions *callRequest =
 
-       [[GRPCRequestOptions alloc] initWithHost:(NSString *)kRemoteSSLHost
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   __block NSDictionary *init_md;
 
-   __block NSDictionary *trailing_md;
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.oauth2AccessToken = @"bogusToken";
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:callRequest
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc]
 
-                                  initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) {
 
-                                    init_md = initialMetadata;
 
-                                  }
 
-                                  messageCallback:^(id message) {
 
-                                    XCTFail(@"Received unexpected response.");
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
 
-                                    trailing_md = trailingMetadata;
 
-                                    if (error) {
 
-                                      XCTAssertEqual(error.code, 16,
 
-                                                     @"Finished with unexpected error: %@", error);
 
-                                      XCTAssertEqualObjects(init_md,
 
-                                                            error.userInfo[kGRPCHeadersKey]);
 
-                                      XCTAssertEqualObjects(trailing_md,
 
-                                                            error.userInfo[kGRPCTrailersKey]);
 
-                                      NSString *challengeHeader = init_md[@"www-authenticate"];
 
-                                      XCTAssertGreaterThan(challengeHeader.length, 0,
 
-                                                           @"No challenge in response headers %@",
 
-                                                           init_md);
 
-                                      [expectation fulfill];
 
-                                    }
 
-                                  }]
 
-                  callOptions:options];
 
-   [call start];
 
-   [call writeData:[request data]];
 
-   [call finish];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testUserAgentPrefix {
 
-   __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
 
-   __weak XCTestExpectation *recvInitialMd =
 
-       [self expectationWithDescription:@"Did not receive initial md."];
 
-   GRPCRequestOptions *request = [[GRPCRequestOptions alloc] initWithHost:kHostAddress
 
-                                                                     path:kEmptyCallMethod.HTTPPath
 
-                                                                   safety:GRPCCallSafetyDefault];
 
-   NSDictionary *headers =
 
-       [NSDictionary dictionaryWithObjectsAndKeys:@"", @"x-grpc-test-echo-useragent", nil];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   options.userAgentPrefix = @"Foo";
 
-   options.initialMetadata = headers;
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:request
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^(
 
-                                                                     NSDictionary *initialMetadata) {
 
-                NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"];
 
-                // Test the regex is correct
 
-                NSString *expectedUserAgent = @"Foo grpc-objc/";
 
-                expectedUserAgent =
 
-                    [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING];
 
-                expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"];
 
-                expectedUserAgent =
 
-                    [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING];
 
-                expectedUserAgent = [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "];
 
-                expectedUserAgent = [expectedUserAgent
 
-                    stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]];
 
-                expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"];
 
-                XCTAssertEqualObjects(userAgent, expectedUserAgent);
 
-                NSError *error = nil;
 
-                // Change in format of user-agent field in a direction that does not match
 
-                // the regex will likely cause problem for certain gRPC users. For details,
 
-                // refer to internal doc https://goo.gl/c2diBc
 
-                NSRegularExpression *regex = [NSRegularExpression
 
-                    regularExpressionWithPattern:
 
-                        @" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?"
 
-                                         options:0
 
-                                           error:&error];
 
-                NSString *customUserAgent =
 
-                    [regex stringByReplacingMatchesInString:userAgent
 
-                                                    options:0
 
-                                                      range:NSMakeRange(0, [userAgent length])
 
-                                               withTemplate:@""];
 
-                XCTAssertEqualObjects(customUserAgent, @"Foo");
 
-                [recvInitialMd fulfill];
 
-              }
 
-                                  messageCallback:^(id message) {
 
-                                    XCTAssertNotNil(message);
 
-                                    XCTAssertEqual([message length], 0,
 
-                                                   @"Non-empty response received: %@", message);
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
 
-                                    if (error) {
 
-                                      XCTFail(@"Finished with unexpected error: %@", error);
 
-                                    } else {
 
-                                      [completion fulfill];
 
-                                    }
 
-                                  }]
 
-                  callOptions:options];
 
-   [call writeData:[NSData data]];
 
-   [call start];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)getTokenWithHandler:(void (^)(NSString *token))handler {
 
-   dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
 
-   dispatch_sync(queue, ^{
 
-     handler(@"test-access-token");
 
-   });
 
- }
 
- - (void)testOAuthToken {
 
-   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
 
-   GRPCRequestOptions *requestOptions =
 
-       [[GRPCRequestOptions alloc] initWithHost:kHostAddress
 
-                                           path:kEmptyCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   options.authTokenProvider = self;
 
-   __block GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:requestOptions
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc]
 
-                                  initWithInitialMetadataCallback:nil
 
-                                                  messageCallback:nil
 
-                                                    closeCallback:^(NSDictionary *trailingMetadata,
 
-                                                                    NSError *error) {
 
-                                                      [completion fulfill];
 
-                                                    }]
 
-                  callOptions:options];
 
-   [call writeData:[NSData data]];
 
-   [call start];
 
-   [call finish];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testResponseSizeLimitExceeded {
 
-   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
 
-   GRPCRequestOptions *requestOptions =
 
-       [[GRPCRequestOptions alloc] initWithHost:kHostAddress
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.responseSizeLimit = kSimpleDataLength;
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   RMTSimpleRequest *request = [RMTSimpleRequest message];
 
-   request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit];
 
-   request.responseSize = (int32_t)(options.responseSizeLimit * 2);
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:requestOptions
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc]
 
-                                  initWithInitialMetadataCallback:nil
 
-                                                  messageCallback:nil
 
-                                                    closeCallback:^(NSDictionary *trailingMetadata,
 
-                                                                    NSError *error) {
 
-                                                      XCTAssertNotNil(error,
 
-                                                                      @"Expecting non-nil error");
 
-                                                      XCTAssertEqual(error.code,
 
-                                                                     GRPCErrorCodeResourceExhausted);
 
-                                                      [completion fulfill];
 
-                                                    }]
 
-                  callOptions:options];
 
-   [call writeData:[request data]];
 
-   [call start];
 
-   [call finish];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testIdempotentProtoRPC {
 
-   __weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."];
 
-   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
 
-   RMTSimpleRequest *request = [RMTSimpleRequest message];
 
-   request.responseSize = kSimpleDataLength;
 
-   request.fillUsername = YES;
 
-   request.fillOauthScope = YES;
 
-   GRPCRequestOptions *requestOptions =
 
-       [[GRPCRequestOptions alloc] initWithHost:kHostAddress
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyIdempotentRequest];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:requestOptions
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                                  messageCallback:^(id message) {
 
-                                    NSData *data = (NSData *)message;
 
-                                    XCTAssertNotNil(data, @"nil value received as response.");
 
-                                    XCTAssertGreaterThan(data.length, 0,
 
-                                                         @"Empty response received.");
 
-                                    RMTSimpleResponse *responseProto =
 
-                                        [RMTSimpleResponse parseFromData:data error:NULL];
 
-                                    // We expect empty strings, not nil:
 
-                                    XCTAssertNotNil(responseProto.username,
 
-                                                    @"Response's username is nil.");
 
-                                    XCTAssertNotNil(responseProto.oauthScope,
 
-                                                    @"Response's OAuth scope is nil.");
 
-                                    [response fulfill];
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
 
-                                    XCTAssertNil(error, @"Finished with unexpected error: %@",
 
-                                                 error);
 
-                                    [completion fulfill];
 
-                                  }]
 
-                  callOptions:options];
 
-   [call start];
 
-   [call writeData:[request data]];
 
-   [call finish];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testTimeout {
 
-   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.timeout = 0.001;
 
-   GRPCRequestOptions *requestOptions =
 
-       [[GRPCRequestOptions alloc] initWithHost:kHostAddress
 
-                                           path:kFullDuplexCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:requestOptions
 
-              responseHandler:
 
-                  [[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                      messageCallback:^(NSData *data) {
 
-                        XCTFail(@"Failure: response received; Expect: no response received.");
 
-                      }
 
-                      closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
 
-                        XCTAssertNotNil(error,
 
-                                        @"Failure: no error received; Expect: receive "
 
-                                        @"deadline exceeded.");
 
-                        XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded);
 
-                        [completion fulfill];
 
-                      }]
 
-                  callOptions:options];
 
-   [call start];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testTimeoutBackoffWithTimeout:(double)timeout Backoff:(double)backoff {
 
-   const double maxConnectTime = timeout > backoff ? timeout : backoff;
 
-   const double kMargin = 0.1;
 
-   __weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."];
 
-   NSString *const kDummyAddress = [NSString stringWithFormat:@"127.0.0.1:10000"];
 
-   GRPCRequestOptions *requestOptions =
 
-       [[GRPCRequestOptions alloc] initWithHost:kDummyAddress
 
-                                           path:@"/dummy/path"
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.connectMinTimeout = timeout;
 
-   options.connectInitialBackoff = backoff;
 
-   options.connectMaxBackoff = 0;
 
-   NSDate *startTime = [NSDate date];
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:requestOptions
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                                  messageCallback:^(NSData *data) {
 
-                                    XCTFail(@"Received message. Should not reach here.");
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
 
-                                    XCTAssertNotNil(error,
 
-                                                    @"Finished with no error; expecting error");
 
-                                    XCTAssertLessThan(
 
-                                        [[NSDate date] timeIntervalSinceDate:startTime],
 
-                                        maxConnectTime + kMargin);
 
-                                    [completion fulfill];
 
-                                  }]
 
-                  callOptions:options];
 
-   [call start];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testTimeoutBackoff1 {
 
-   [self testTimeoutBackoffWithTimeout:0.7 Backoff:0.4];
 
- }
 
- - (void)testTimeoutBackoff2 {
 
-   [self testTimeoutBackoffWithTimeout:0.3 Backoff:0.8];
 
- }
 
- - (void)testCompression {
 
-   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
 
-   RMTSimpleRequest *request = [RMTSimpleRequest message];
 
-   request.expectCompressed = [RMTBoolValue message];
 
-   request.expectCompressed.value = YES;
 
-   request.responseCompressed = [RMTBoolValue message];
 
-   request.expectCompressed.value = YES;
 
-   request.responseSize = kSimpleDataLength;
 
-   request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
 
-   GRPCRequestOptions *requestOptions =
 
-       [[GRPCRequestOptions alloc] initWithHost:kHostAddress
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   options.compressionAlgorithm = GRPCCompressGzip;
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:requestOptions
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                                  messageCallback:^(NSData *data) {
 
-                                    NSError *error;
 
-                                    RMTSimpleResponse *response =
 
-                                        [RMTSimpleResponse parseFromData:data error:&error];
 
-                                    XCTAssertNil(error, @"Error when parsing response: %@", error);
 
-                                    XCTAssertEqual(response.payload.body.length, kSimpleDataLength);
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
 
-                                    XCTAssertNil(error, @"Received failure: %@", error);
 
-                                    [completion fulfill];
 
-                                  }]
 
-                  callOptions:options];
 
-   [call start];
 
-   [call writeData:[request data]];
 
-   [call finish];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testFlowControlWrite {
 
-   __weak XCTestExpectation *expectWriteData =
 
-       [self expectationWithDescription:@"Reported write data"];
 
-   RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
 
-   RMTResponseParameters *parameters = [RMTResponseParameters message];
 
-   parameters.size = kSimpleDataLength;
 
-   [request.responseParametersArray addObject:parameters];
 
-   request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
 
-   GRPCRequestOptions *callRequest =
 
-       [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   options.enableFlowControl = YES;
 
-   GRPCCall2 *call =
 
-       [[GRPCCall2 alloc] initWithRequestOptions:callRequest
 
-                                 responseHandler:[[ClientTestsBlockCallbacks alloc]
 
-                                                     initWithInitialMetadataCallback:nil
 
-                                                                     messageCallback:nil
 
-                                                                       closeCallback:nil
 
-                                                                   writeDataCallback:^{
 
-                                                                     [expectWriteData fulfill];
 
-                                                                   }]
 
-                                     callOptions:options];
 
-   [call start];
 
-   [call receiveNextMessages:1];
 
-   [call writeData:[request data]];
 
-   // Wait for 3 seconds and make sure we do not receive the response
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
-   [call finish];
 
- }
 
- - (void)testFlowControlRead {
 
-   __weak __block XCTestExpectation *expectBlockedMessage =
 
-       [self expectationWithDescription:@"Message not delivered without recvNextMessage"];
 
-   __weak __block XCTestExpectation *expectPassedMessage = nil;
 
-   __weak __block XCTestExpectation *expectBlockedClose =
 
-       [self expectationWithDescription:@"Call not closed with pending message"];
 
-   __weak __block XCTestExpectation *expectPassedClose = nil;
 
-   expectBlockedMessage.inverted = YES;
 
-   expectBlockedClose.inverted = YES;
 
-   RMTSimpleRequest *request = [RMTSimpleRequest message];
 
-   request.responseSize = kSimpleDataLength;
 
-   request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
 
-   GRPCRequestOptions *callRequest =
 
-       [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   options.enableFlowControl = YES;
 
-   __block int unblocked = NO;
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:callRequest
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                                  messageCallback:^(NSData *message) {
 
-                                    if (!unblocked) {
 
-                                      [expectBlockedMessage fulfill];
 
-                                    } else {
 
-                                      [expectPassedMessage fulfill];
 
-                                    }
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *trailers, NSError *error) {
 
-                                    if (!unblocked) {
 
-                                      [expectBlockedClose fulfill];
 
-                                    } else {
 
-                                      [expectPassedClose fulfill];
 
-                                    }
 
-                                  }]
 
-                  callOptions:options];
 
-   [call start];
 
-   [call writeData:[request data]];
 
-   [call finish];
 
-   // Wait to make sure we do not receive the response
 
-   [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
 
-   expectPassedMessage =
 
-       [self expectationWithDescription:@"Message delivered with receiveNextMessage"];
 
-   expectPassedClose = [self expectationWithDescription:@"Close delivered after receiveNextMessage"];
 
-   unblocked = YES;
 
-   [call receiveNextMessages:1];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testFlowControlMultipleMessages {
 
-   __weak XCTestExpectation *expectPassedMessage =
 
-       [self expectationWithDescription:@"two messages delivered with receiveNextMessage"];
 
-   expectPassedMessage.expectedFulfillmentCount = 2;
 
-   __weak XCTestExpectation *expectBlockedMessage =
 
-       [self expectationWithDescription:@"Message 3 not delivered"];
 
-   expectBlockedMessage.inverted = YES;
 
-   __weak XCTestExpectation *expectWriteTwice =
 
-       [self expectationWithDescription:@"Write 2 messages done"];
 
-   expectWriteTwice.expectedFulfillmentCount = 2;
 
-   RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
 
-   RMTResponseParameters *parameters = [RMTResponseParameters message];
 
-   parameters.size = kSimpleDataLength;
 
-   [request.responseParametersArray addObject:parameters];
 
-   request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
 
-   GRPCRequestOptions *callRequest =
 
-       [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
 
-                                           path:kFullDuplexCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   options.enableFlowControl = YES;
 
-   __block NSUInteger messageId = 0;
 
-   __block GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:callRequest
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                                  messageCallback:^(NSData *message) {
 
-                                    if (messageId <= 1) {
 
-                                      [expectPassedMessage fulfill];
 
-                                    } else {
 
-                                      [expectBlockedMessage fulfill];
 
-                                    }
 
-                                    messageId++;
 
-                                  }
 
-                                  closeCallback:nil
 
-                                  writeDataCallback:^{
 
-                                    [expectWriteTwice fulfill];
 
-                                  }]
 
-                  callOptions:options];
 
-   [call receiveNextMessages:2];
 
-   [call start];
 
-   [call writeData:[request data]];
 
-   [call writeData:[request data]];
 
-   [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
 
- }
 
- - (void)testFlowControlReadReadyBeforeStart {
 
-   __weak XCTestExpectation *expectPassedMessage =
 
-       [self expectationWithDescription:@"Message delivered with receiveNextMessage"];
 
-   __weak XCTestExpectation *expectPassedClose =
 
-       [self expectationWithDescription:@"Close delivered with receiveNextMessage"];
 
-   RMTSimpleRequest *request = [RMTSimpleRequest message];
 
-   request.responseSize = kSimpleDataLength;
 
-   request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
 
-   GRPCRequestOptions *callRequest =
 
-       [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   options.enableFlowControl = YES;
 
-   __block BOOL closed = NO;
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:callRequest
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                                  messageCallback:^(NSData *message) {
 
-                                    [expectPassedMessage fulfill];
 
-                                    XCTAssertFalse(closed);
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *ttrailers, NSError *error) {
 
-                                    closed = YES;
 
-                                    [expectPassedClose fulfill];
 
-                                  }]
 
-                  callOptions:options];
 
-   [call receiveNextMessages:1];
 
-   [call start];
 
-   [call writeData:[request data]];
 
-   [call finish];
 
-   [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil];
 
- }
 
- - (void)testFlowControlReadReadyAfterStart {
 
-   __weak XCTestExpectation *expectPassedMessage =
 
-       [self expectationWithDescription:@"Message delivered with receiveNextMessage"];
 
-   __weak XCTestExpectation *expectPassedClose =
 
-       [self expectationWithDescription:@"Close delivered with receiveNextMessage"];
 
-   RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
 
-   RMTResponseParameters *parameters = [RMTResponseParameters message];
 
-   parameters.size = kSimpleDataLength;
 
-   [request.responseParametersArray addObject:parameters];
 
-   request.payload.body = [NSMutableData dataWithLength:kSimpleDataLength];
 
-   GRPCRequestOptions *callRequest =
 
-       [[GRPCRequestOptions alloc] initWithHost:(NSString *)kHostAddress
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   options.enableFlowControl = YES;
 
-   __block BOOL closed = NO;
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:callRequest
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                                  messageCallback:^(NSData *message) {
 
-                                    [expectPassedMessage fulfill];
 
-                                    XCTAssertFalse(closed);
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *trailers, NSError *error) {
 
-                                    closed = YES;
 
-                                    [expectPassedClose fulfill];
 
-                                  }]
 
-                  callOptions:options];
 
-   [call start];
 
-   [call receiveNextMessages:1];
 
-   [call writeData:[request data]];
 
-   [call finish];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- - (void)testFlowControlReadNonBlockingFailure {
 
-   __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
 
-   GRPCRequestOptions *requestOptions =
 
-       [[GRPCRequestOptions alloc] initWithHost:kHostAddress
 
-                                           path:kUnaryCallMethod.HTTPPath
 
-                                         safety:GRPCCallSafetyDefault];
 
-   GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
 
-   options.enableFlowControl = YES;
 
-   options.transportType = GRPCTransportTypeInsecure;
 
-   RMTSimpleRequest *request = [RMTSimpleRequest message];
 
-   request.payload.body = [NSMutableData dataWithLength:options.responseSizeLimit];
 
-   RMTEchoStatus *status = [RMTEchoStatus message];
 
-   status.code = 2;
 
-   status.message = @"test";
 
-   request.responseStatus = status;
 
-   GRPCCall2 *call = [[GRPCCall2 alloc]
 
-       initWithRequestOptions:requestOptions
 
-              responseHandler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
 
-                                  messageCallback:^(NSData *data) {
 
-                                    XCTFail(@"Received unexpected message");
 
-                                  }
 
-                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
 
-                                    XCTAssertNotNil(error, @"Expecting non-nil error");
 
-                                    XCTAssertEqual(error.code, 2);
 
-                                    [completion fulfill];
 
-                                  }]
 
-                  callOptions:options];
 
-   [call writeData:[request data]];
 
-   [call start];
 
-   [call finish];
 
-   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil];
 
- }
 
- @end
 
 
  |