xref: /aosp_15_r20/external/grpc-grpc/src/objective-c/tests/UnitTests/APIv2Tests.m (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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