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