| 
					
				 | 
			
			
				@@ -44,6 +44,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static const int kSimpleDataLength = 100; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static const NSTimeInterval kTestTimeout = 16; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const NSTimeInterval kInvertedTimeout = 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Reveal the _class ivar for testing access 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 @interface GRPCCall2 () { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -56,6 +57,11 @@ static const NSTimeInterval kTestTimeout = 16; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 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; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -66,21 +72,33 @@ static const NSTimeInterval kTestTimeout = 16; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   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 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  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); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -99,6 +117,12 @@ static const NSTimeInterval kTestTimeout = 16; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+- (void)didWriteData { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (self->_writeDataCallback) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    self->_writeDataCallback(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 - (dispatch_queue_t)dispatchQueue { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return _dispatchQueue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -475,4 +499,219 @@ static const NSTimeInterval kTestTimeout = 16; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+- (void)testWriteFlowControl { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  __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 receiveNextMessage]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [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)testReadFlowControl { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  __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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  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 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 receiveNextMessage]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+- (void)testReadFlowControlReadyBeforeStart { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  __weak XCTestExpectation *expectBlockedMessage = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      [self expectationWithDescription:@"Message delivered with receiveNextMessage"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  expectBlockedMessage.inverted = YES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  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) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                   [expectBlockedMessage fulfill]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                   XCTAssertFalse(closed); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                   closeCallback:nil] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 callOptions:options]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [call receiveNextMessage]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [call start]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [call writeData:[request data]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [call finish]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [self waitForExpectationsWithTimeout:kInvertedTimeout handler:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+- (void)testReadFlowControlReadyAfterStart { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  __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 receiveNextMessage]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [call writeData:[request data]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [call finish]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  [self waitForExpectationsWithTimeout:kTestTimeout handler:nil]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+- (void)testReadFlowControlNonBlockingFailure { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  __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 
			 |