xref: /aosp_15_r20/external/grpc-grpc/src/objective-c/tests/InteropTests/InteropTests.m (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker/*
2*cc02d7e2SAndroid Build Coastguard Worker *
3*cc02d7e2SAndroid Build Coastguard Worker * Copyright 2015 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 "InteropTests.h"
20*cc02d7e2SAndroid Build Coastguard Worker
21*cc02d7e2SAndroid Build Coastguard Worker#include <grpc/status.h>
22*cc02d7e2SAndroid Build Coastguard Worker
23*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/GRPCCall+ChannelArg.h>
24*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/GRPCCall+Cronet.h>
25*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/GRPCCall+Interceptor.h>
26*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/GRPCCall+Tests.h>
27*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/GRPCInterceptor.h>
28*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/internal_testing/GRPCCall+InternalTests.h>
29*cc02d7e2SAndroid Build Coastguard Worker#import <ProtoRPC/ProtoRPC.h>
30*cc02d7e2SAndroid Build Coastguard Worker#import <RxLibrary/GRXBufferedPipe.h>
31*cc02d7e2SAndroid Build Coastguard Worker#import <RxLibrary/GRXWriter+Immediate.h>
32*cc02d7e2SAndroid Build Coastguard Worker#import <grpc/grpc.h>
33*cc02d7e2SAndroid Build Coastguard Worker#import <grpc/support/log.h>
34*cc02d7e2SAndroid Build Coastguard Worker#import "src/objective-c/tests/RemoteTestClient/Messages.pbobjc.h"
35*cc02d7e2SAndroid Build Coastguard Worker#import "src/objective-c/tests/RemoteTestClient/Test.pbobjc.h"
36*cc02d7e2SAndroid Build Coastguard Worker#import "src/objective-c/tests/RemoteTestClient/Test.pbrpc.h"
37*cc02d7e2SAndroid Build Coastguard Worker
38*cc02d7e2SAndroid Build Coastguard Worker#import "../Common/TestUtils.h"
39*cc02d7e2SAndroid Build Coastguard Worker#import "InteropTestsBlockCallbacks.h"
40*cc02d7e2SAndroid Build Coastguard Worker
41*cc02d7e2SAndroid Build Coastguard Worker#define SMALL_PAYLOAD_SIZE 10
42*cc02d7e2SAndroid Build Coastguard Worker#define LARGE_REQUEST_PAYLOAD_SIZE 271828
43*cc02d7e2SAndroid Build Coastguard Worker#define LARGE_RESPONSE_PAYLOAD_SIZE 314159
44*cc02d7e2SAndroid Build Coastguard Worker
45*cc02d7e2SAndroid Build Coastguard Workerstatic const int kTestRetries = 3;
46*cc02d7e2SAndroid Build Coastguard Workerextern const char *kCFStreamVarName;
47*cc02d7e2SAndroid Build Coastguard Worker
48*cc02d7e2SAndroid Build Coastguard Worker@interface RMTStreamingOutputCallRequest (Constructors)
49*cc02d7e2SAndroid Build Coastguard Worker+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
50*cc02d7e2SAndroid Build Coastguard Worker                 requestedResponseSize:(NSNumber *)responseSize;
51*cc02d7e2SAndroid Build Coastguard Worker@end
52*cc02d7e2SAndroid Build Coastguard Worker
53*cc02d7e2SAndroid Build Coastguard Worker@implementation RMTStreamingOutputCallRequest (Constructors)
54*cc02d7e2SAndroid Build Coastguard Worker+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
55*cc02d7e2SAndroid Build Coastguard Worker                 requestedResponseSize:(NSNumber *)responseSize {
56*cc02d7e2SAndroid Build Coastguard Worker  RMTStreamingOutputCallRequest *request = [self message];
57*cc02d7e2SAndroid Build Coastguard Worker  RMTResponseParameters *parameters = [RMTResponseParameters message];
58*cc02d7e2SAndroid Build Coastguard Worker  parameters.size = responseSize.intValue;
59*cc02d7e2SAndroid Build Coastguard Worker  [request.responseParametersArray addObject:parameters];
60*cc02d7e2SAndroid Build Coastguard Worker  request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
61*cc02d7e2SAndroid Build Coastguard Worker  return request;
62*cc02d7e2SAndroid Build Coastguard Worker}
63*cc02d7e2SAndroid Build Coastguard Worker@end
64*cc02d7e2SAndroid Build Coastguard Worker
65*cc02d7e2SAndroid Build Coastguard Worker@interface RMTStreamingOutputCallResponse (Constructors)
66*cc02d7e2SAndroid Build Coastguard Worker+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize;
67*cc02d7e2SAndroid Build Coastguard Worker@end
68*cc02d7e2SAndroid Build Coastguard Worker
69*cc02d7e2SAndroid Build Coastguard Worker@implementation RMTStreamingOutputCallResponse (Constructors)
70*cc02d7e2SAndroid Build Coastguard Worker+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize {
71*cc02d7e2SAndroid Build Coastguard Worker  RMTStreamingOutputCallResponse *response = [self message];
72*cc02d7e2SAndroid Build Coastguard Worker  response.payload.type = RMTPayloadType_Compressable;
73*cc02d7e2SAndroid Build Coastguard Worker  response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
74*cc02d7e2SAndroid Build Coastguard Worker  return response;
75*cc02d7e2SAndroid Build Coastguard Worker}
76*cc02d7e2SAndroid Build Coastguard Worker@end
77*cc02d7e2SAndroid Build Coastguard Worker
78*cc02d7e2SAndroid Build Coastguard WorkerBOOL isRemoteInteropTest(NSString *host) {
79*cc02d7e2SAndroid Build Coastguard Worker  return [host isEqualToString:@"grpc-test.sandbox.googleapis.com"];
80*cc02d7e2SAndroid Build Coastguard Worker}
81*cc02d7e2SAndroid Build Coastguard Worker
82*cc02d7e2SAndroid Build Coastguard Worker@interface DefaultInterceptorFactory : NSObject <GRPCInterceptorFactory>
83*cc02d7e2SAndroid Build Coastguard Worker
84*cc02d7e2SAndroid Build Coastguard Worker- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager;
85*cc02d7e2SAndroid Build Coastguard Worker
86*cc02d7e2SAndroid Build Coastguard Worker@end
87*cc02d7e2SAndroid Build Coastguard Worker
88*cc02d7e2SAndroid Build Coastguard Worker@implementation DefaultInterceptorFactory
89*cc02d7e2SAndroid Build Coastguard Worker
90*cc02d7e2SAndroid Build Coastguard Worker- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager {
91*cc02d7e2SAndroid Build Coastguard Worker  dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
92*cc02d7e2SAndroid Build Coastguard Worker  return [[GRPCInterceptor alloc] initWithInterceptorManager:interceptorManager
93*cc02d7e2SAndroid Build Coastguard Worker                                               dispatchQueue:queue];
94*cc02d7e2SAndroid Build Coastguard Worker}
95*cc02d7e2SAndroid Build Coastguard Worker
96*cc02d7e2SAndroid Build Coastguard Worker@end
97*cc02d7e2SAndroid Build Coastguard Worker
98*cc02d7e2SAndroid Build Coastguard Worker@interface HookInterceptorFactory : NSObject <GRPCInterceptorFactory>
99*cc02d7e2SAndroid Build Coastguard Worker
100*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)
101*cc02d7e2SAndroid Build Coastguard Worker      initWithDispatchQueue:(dispatch_queue_t)dispatchQueue
102*cc02d7e2SAndroid Build Coastguard Worker                  startHook:(void (^)(GRPCRequestOptions *requestOptions,
103*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCCallOptions *callOptions,
104*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))startHook
105*cc02d7e2SAndroid Build Coastguard Worker              writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
106*cc02d7e2SAndroid Build Coastguard Worker                 finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
107*cc02d7e2SAndroid Build Coastguard Worker    receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
108*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))receiveNextMessagesHook
109*cc02d7e2SAndroid Build Coastguard Worker         responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
110*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))responseHeaderHook
111*cc02d7e2SAndroid Build Coastguard Worker           responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
112*cc02d7e2SAndroid Build Coastguard Worker          responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
113*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))responseCloseHook
114*cc02d7e2SAndroid Build Coastguard Worker           didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook;
115*cc02d7e2SAndroid Build Coastguard Worker
116*cc02d7e2SAndroid Build Coastguard Worker- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager;
117*cc02d7e2SAndroid Build Coastguard Worker
118*cc02d7e2SAndroid Build Coastguard Worker@end
119*cc02d7e2SAndroid Build Coastguard Worker
120*cc02d7e2SAndroid Build Coastguard Worker@interface HookInterceptor : GRPCInterceptor
121*cc02d7e2SAndroid Build Coastguard Worker
122*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)
123*cc02d7e2SAndroid Build Coastguard Worker    initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
124*cc02d7e2SAndroid Build Coastguard Worker                 dispatchQueue:(dispatch_queue_t)dispatchQueue
125*cc02d7e2SAndroid Build Coastguard Worker                     startHook:(void (^)(GRPCRequestOptions *requestOptions,
126*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCCallOptions *callOptions,
127*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCInterceptorManager *manager))startHook
128*cc02d7e2SAndroid Build Coastguard Worker                 writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
129*cc02d7e2SAndroid Build Coastguard Worker                    finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
130*cc02d7e2SAndroid Build Coastguard Worker       receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
131*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCInterceptorManager *manager))receiveNextMessagesHook
132*cc02d7e2SAndroid Build Coastguard Worker            responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
133*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCInterceptorManager *manager))responseHeaderHook
134*cc02d7e2SAndroid Build Coastguard Worker              responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
135*cc02d7e2SAndroid Build Coastguard Worker             responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
136*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCInterceptorManager *manager))responseCloseHook
137*cc02d7e2SAndroid Build Coastguard Worker              didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook;
138*cc02d7e2SAndroid Build Coastguard Worker
139*cc02d7e2SAndroid Build Coastguard Worker@end
140*cc02d7e2SAndroid Build Coastguard Worker
141*cc02d7e2SAndroid Build Coastguard Worker@implementation HookInterceptorFactory {
142*cc02d7e2SAndroid Build Coastguard Worker @protected
143*cc02d7e2SAndroid Build Coastguard Worker  void (^_startHook)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
144*cc02d7e2SAndroid Build Coastguard Worker                     GRPCInterceptorManager *manager);
145*cc02d7e2SAndroid Build Coastguard Worker  void (^_writeDataHook)(id data, GRPCInterceptorManager *manager);
146*cc02d7e2SAndroid Build Coastguard Worker  void (^_finishHook)(GRPCInterceptorManager *manager);
147*cc02d7e2SAndroid Build Coastguard Worker  void (^_receiveNextMessagesHook)(NSUInteger numberOfMessages, GRPCInterceptorManager *manager);
148*cc02d7e2SAndroid Build Coastguard Worker  void (^_responseHeaderHook)(NSDictionary *initialMetadata, GRPCInterceptorManager *manager);
149*cc02d7e2SAndroid Build Coastguard Worker  void (^_responseDataHook)(id data, GRPCInterceptorManager *manager);
150*cc02d7e2SAndroid Build Coastguard Worker  void (^_responseCloseHook)(NSDictionary *trailingMetadata, NSError *error,
151*cc02d7e2SAndroid Build Coastguard Worker                             GRPCInterceptorManager *manager);
152*cc02d7e2SAndroid Build Coastguard Worker  void (^_didWriteDataHook)(GRPCInterceptorManager *manager);
153*cc02d7e2SAndroid Build Coastguard Worker  dispatch_queue_t _dispatchQueue;
154*cc02d7e2SAndroid Build Coastguard Worker}
155*cc02d7e2SAndroid Build Coastguard Worker
156*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)
157*cc02d7e2SAndroid Build Coastguard Worker      initWithDispatchQueue:(dispatch_queue_t)dispatchQueue
158*cc02d7e2SAndroid Build Coastguard Worker                  startHook:(void (^)(GRPCRequestOptions *requestOptions,
159*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCCallOptions *callOptions,
160*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))startHook
161*cc02d7e2SAndroid Build Coastguard Worker              writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
162*cc02d7e2SAndroid Build Coastguard Worker                 finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
163*cc02d7e2SAndroid Build Coastguard Worker    receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
164*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))receiveNextMessagesHook
165*cc02d7e2SAndroid Build Coastguard Worker         responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
166*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))responseHeaderHook
167*cc02d7e2SAndroid Build Coastguard Worker           responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
168*cc02d7e2SAndroid Build Coastguard Worker          responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
169*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))responseCloseHook
170*cc02d7e2SAndroid Build Coastguard Worker           didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook {
171*cc02d7e2SAndroid Build Coastguard Worker  if ((self = [super init])) {
172*cc02d7e2SAndroid Build Coastguard Worker    _dispatchQueue = dispatchQueue;
173*cc02d7e2SAndroid Build Coastguard Worker    _startHook = startHook;
174*cc02d7e2SAndroid Build Coastguard Worker    _writeDataHook = writeDataHook;
175*cc02d7e2SAndroid Build Coastguard Worker    _finishHook = finishHook;
176*cc02d7e2SAndroid Build Coastguard Worker    _receiveNextMessagesHook = receiveNextMessagesHook;
177*cc02d7e2SAndroid Build Coastguard Worker    _responseHeaderHook = responseHeaderHook;
178*cc02d7e2SAndroid Build Coastguard Worker    _responseDataHook = responseDataHook;
179*cc02d7e2SAndroid Build Coastguard Worker    _responseCloseHook = responseCloseHook;
180*cc02d7e2SAndroid Build Coastguard Worker    _didWriteDataHook = didWriteDataHook;
181*cc02d7e2SAndroid Build Coastguard Worker  }
182*cc02d7e2SAndroid Build Coastguard Worker  return self;
183*cc02d7e2SAndroid Build Coastguard Worker}
184*cc02d7e2SAndroid Build Coastguard Worker
185*cc02d7e2SAndroid Build Coastguard Worker- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager {
186*cc02d7e2SAndroid Build Coastguard Worker  return [[HookInterceptor alloc] initWithInterceptorManager:interceptorManager
187*cc02d7e2SAndroid Build Coastguard Worker                                               dispatchQueue:_dispatchQueue
188*cc02d7e2SAndroid Build Coastguard Worker                                                   startHook:_startHook
189*cc02d7e2SAndroid Build Coastguard Worker                                               writeDataHook:_writeDataHook
190*cc02d7e2SAndroid Build Coastguard Worker                                                  finishHook:_finishHook
191*cc02d7e2SAndroid Build Coastguard Worker                                     receiveNextMessagesHook:_receiveNextMessagesHook
192*cc02d7e2SAndroid Build Coastguard Worker                                          responseHeaderHook:_responseHeaderHook
193*cc02d7e2SAndroid Build Coastguard Worker                                            responseDataHook:_responseDataHook
194*cc02d7e2SAndroid Build Coastguard Worker                                           responseCloseHook:_responseCloseHook
195*cc02d7e2SAndroid Build Coastguard Worker                                            didWriteDataHook:_didWriteDataHook];
196*cc02d7e2SAndroid Build Coastguard Worker}
197*cc02d7e2SAndroid Build Coastguard Worker
198*cc02d7e2SAndroid Build Coastguard Worker@end
199*cc02d7e2SAndroid Build Coastguard Worker
200*cc02d7e2SAndroid Build Coastguard Worker@implementation HookInterceptor {
201*cc02d7e2SAndroid Build Coastguard Worker  void (^_startHook)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
202*cc02d7e2SAndroid Build Coastguard Worker                     GRPCInterceptorManager *manager);
203*cc02d7e2SAndroid Build Coastguard Worker  void (^_writeDataHook)(id data, GRPCInterceptorManager *manager);
204*cc02d7e2SAndroid Build Coastguard Worker  void (^_finishHook)(GRPCInterceptorManager *manager);
205*cc02d7e2SAndroid Build Coastguard Worker  void (^_receiveNextMessagesHook)(NSUInteger numberOfMessages, GRPCInterceptorManager *manager);
206*cc02d7e2SAndroid Build Coastguard Worker  void (^_responseHeaderHook)(NSDictionary *initialMetadata, GRPCInterceptorManager *manager);
207*cc02d7e2SAndroid Build Coastguard Worker  void (^_responseDataHook)(id data, GRPCInterceptorManager *manager);
208*cc02d7e2SAndroid Build Coastguard Worker  void (^_responseCloseHook)(NSDictionary *trailingMetadata, NSError *error,
209*cc02d7e2SAndroid Build Coastguard Worker                             GRPCInterceptorManager *manager);
210*cc02d7e2SAndroid Build Coastguard Worker  void (^_didWriteDataHook)(GRPCInterceptorManager *manager);
211*cc02d7e2SAndroid Build Coastguard Worker  GRPCInterceptorManager *_manager;
212*cc02d7e2SAndroid Build Coastguard Worker  dispatch_queue_t _dispatchQueue;
213*cc02d7e2SAndroid Build Coastguard Worker}
214*cc02d7e2SAndroid Build Coastguard Worker
215*cc02d7e2SAndroid Build Coastguard Worker- (dispatch_queue_t)dispatchQueue {
216*cc02d7e2SAndroid Build Coastguard Worker  return _dispatchQueue;
217*cc02d7e2SAndroid Build Coastguard Worker}
218*cc02d7e2SAndroid Build Coastguard Worker
219*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)
220*cc02d7e2SAndroid Build Coastguard Worker    initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
221*cc02d7e2SAndroid Build Coastguard Worker                 dispatchQueue:(dispatch_queue_t)dispatchQueue
222*cc02d7e2SAndroid Build Coastguard Worker                     startHook:(void (^)(GRPCRequestOptions *requestOptions,
223*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCCallOptions *callOptions,
224*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCInterceptorManager *manager))startHook
225*cc02d7e2SAndroid Build Coastguard Worker                 writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
226*cc02d7e2SAndroid Build Coastguard Worker                    finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
227*cc02d7e2SAndroid Build Coastguard Worker       receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
228*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCInterceptorManager *manager))receiveNextMessagesHook
229*cc02d7e2SAndroid Build Coastguard Worker            responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
230*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCInterceptorManager *manager))responseHeaderHook
231*cc02d7e2SAndroid Build Coastguard Worker              responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
232*cc02d7e2SAndroid Build Coastguard Worker             responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
233*cc02d7e2SAndroid Build Coastguard Worker                                         GRPCInterceptorManager *manager))responseCloseHook
234*cc02d7e2SAndroid Build Coastguard Worker              didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook {
235*cc02d7e2SAndroid Build Coastguard Worker  if ((self = [super initWithInterceptorManager:interceptorManager dispatchQueue:dispatchQueue])) {
236*cc02d7e2SAndroid Build Coastguard Worker    _startHook = startHook;
237*cc02d7e2SAndroid Build Coastguard Worker    _writeDataHook = writeDataHook;
238*cc02d7e2SAndroid Build Coastguard Worker    _finishHook = finishHook;
239*cc02d7e2SAndroid Build Coastguard Worker    _receiveNextMessagesHook = receiveNextMessagesHook;
240*cc02d7e2SAndroid Build Coastguard Worker    _responseHeaderHook = responseHeaderHook;
241*cc02d7e2SAndroid Build Coastguard Worker    _responseDataHook = responseDataHook;
242*cc02d7e2SAndroid Build Coastguard Worker    _responseCloseHook = responseCloseHook;
243*cc02d7e2SAndroid Build Coastguard Worker    _didWriteDataHook = didWriteDataHook;
244*cc02d7e2SAndroid Build Coastguard Worker    _dispatchQueue = dispatchQueue;
245*cc02d7e2SAndroid Build Coastguard Worker    _manager = interceptorManager;
246*cc02d7e2SAndroid Build Coastguard Worker  }
247*cc02d7e2SAndroid Build Coastguard Worker  return self;
248*cc02d7e2SAndroid Build Coastguard Worker}
249*cc02d7e2SAndroid Build Coastguard Worker
250*cc02d7e2SAndroid Build Coastguard Worker- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
251*cc02d7e2SAndroid Build Coastguard Worker                    callOptions:(GRPCCallOptions *)callOptions {
252*cc02d7e2SAndroid Build Coastguard Worker  if (_startHook) {
253*cc02d7e2SAndroid Build Coastguard Worker    _startHook(requestOptions, callOptions, _manager);
254*cc02d7e2SAndroid Build Coastguard Worker  }
255*cc02d7e2SAndroid Build Coastguard Worker}
256*cc02d7e2SAndroid Build Coastguard Worker
257*cc02d7e2SAndroid Build Coastguard Worker- (void)writeData:(id)data {
258*cc02d7e2SAndroid Build Coastguard Worker  if (_writeDataHook) {
259*cc02d7e2SAndroid Build Coastguard Worker    _writeDataHook(data, _manager);
260*cc02d7e2SAndroid Build Coastguard Worker  }
261*cc02d7e2SAndroid Build Coastguard Worker}
262*cc02d7e2SAndroid Build Coastguard Worker
263*cc02d7e2SAndroid Build Coastguard Worker- (void)finish {
264*cc02d7e2SAndroid Build Coastguard Worker  if (_finishHook) {
265*cc02d7e2SAndroid Build Coastguard Worker    _finishHook(_manager);
266*cc02d7e2SAndroid Build Coastguard Worker  }
267*cc02d7e2SAndroid Build Coastguard Worker}
268*cc02d7e2SAndroid Build Coastguard Worker
269*cc02d7e2SAndroid Build Coastguard Worker- (void)receiveNextMessages:(NSUInteger)numberOfMessages {
270*cc02d7e2SAndroid Build Coastguard Worker  if (_receiveNextMessagesHook) {
271*cc02d7e2SAndroid Build Coastguard Worker    _receiveNextMessagesHook(numberOfMessages, _manager);
272*cc02d7e2SAndroid Build Coastguard Worker  }
273*cc02d7e2SAndroid Build Coastguard Worker}
274*cc02d7e2SAndroid Build Coastguard Worker
275*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
276*cc02d7e2SAndroid Build Coastguard Worker  if (_responseHeaderHook) {
277*cc02d7e2SAndroid Build Coastguard Worker    _responseHeaderHook(initialMetadata, _manager);
278*cc02d7e2SAndroid Build Coastguard Worker  }
279*cc02d7e2SAndroid Build Coastguard Worker}
280*cc02d7e2SAndroid Build Coastguard Worker
281*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveData:(id)data {
282*cc02d7e2SAndroid Build Coastguard Worker  if (_responseDataHook) {
283*cc02d7e2SAndroid Build Coastguard Worker    _responseDataHook(data, _manager);
284*cc02d7e2SAndroid Build Coastguard Worker  }
285*cc02d7e2SAndroid Build Coastguard Worker}
286*cc02d7e2SAndroid Build Coastguard Worker
287*cc02d7e2SAndroid Build Coastguard Worker- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
288*cc02d7e2SAndroid Build Coastguard Worker  if (_responseCloseHook) {
289*cc02d7e2SAndroid Build Coastguard Worker    _responseCloseHook(trailingMetadata, error, _manager);
290*cc02d7e2SAndroid Build Coastguard Worker  }
291*cc02d7e2SAndroid Build Coastguard Worker}
292*cc02d7e2SAndroid Build Coastguard Worker
293*cc02d7e2SAndroid Build Coastguard Worker- (void)didWriteData {
294*cc02d7e2SAndroid Build Coastguard Worker  if (_didWriteDataHook) {
295*cc02d7e2SAndroid Build Coastguard Worker    _didWriteDataHook(_manager);
296*cc02d7e2SAndroid Build Coastguard Worker  }
297*cc02d7e2SAndroid Build Coastguard Worker}
298*cc02d7e2SAndroid Build Coastguard Worker
299*cc02d7e2SAndroid Build Coastguard Worker@end
300*cc02d7e2SAndroid Build Coastguard Worker
301*cc02d7e2SAndroid Build Coastguard Worker@interface GlobalInterceptorFactory : HookInterceptorFactory
302*cc02d7e2SAndroid Build Coastguard Worker
303*cc02d7e2SAndroid Build Coastguard Worker@property BOOL enabled;
304*cc02d7e2SAndroid Build Coastguard Worker
305*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue;
306*cc02d7e2SAndroid Build Coastguard Worker
307*cc02d7e2SAndroid Build Coastguard Worker- (void)setStartHook:(void (^)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
308*cc02d7e2SAndroid Build Coastguard Worker                               GRPCInterceptorManager *manager))startHook
309*cc02d7e2SAndroid Build Coastguard Worker              writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
310*cc02d7e2SAndroid Build Coastguard Worker                 finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
311*cc02d7e2SAndroid Build Coastguard Worker    receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
312*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))receiveNextMessagesHook
313*cc02d7e2SAndroid Build Coastguard Worker         responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
314*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))responseHeaderHook
315*cc02d7e2SAndroid Build Coastguard Worker           responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
316*cc02d7e2SAndroid Build Coastguard Worker          responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
317*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))responseCloseHook
318*cc02d7e2SAndroid Build Coastguard Worker           didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook;
319*cc02d7e2SAndroid Build Coastguard Worker
320*cc02d7e2SAndroid Build Coastguard Worker@end
321*cc02d7e2SAndroid Build Coastguard Worker
322*cc02d7e2SAndroid Build Coastguard Worker@implementation GlobalInterceptorFactory
323*cc02d7e2SAndroid Build Coastguard Worker
324*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)initWithDispatchQueue:(dispatch_queue_t)dispatchQueue {
325*cc02d7e2SAndroid Build Coastguard Worker  _enabled = NO;
326*cc02d7e2SAndroid Build Coastguard Worker  return [super initWithDispatchQueue:dispatchQueue
327*cc02d7e2SAndroid Build Coastguard Worker                            startHook:nil
328*cc02d7e2SAndroid Build Coastguard Worker                        writeDataHook:nil
329*cc02d7e2SAndroid Build Coastguard Worker                           finishHook:nil
330*cc02d7e2SAndroid Build Coastguard Worker              receiveNextMessagesHook:nil
331*cc02d7e2SAndroid Build Coastguard Worker                   responseHeaderHook:nil
332*cc02d7e2SAndroid Build Coastguard Worker                     responseDataHook:nil
333*cc02d7e2SAndroid Build Coastguard Worker                    responseCloseHook:nil
334*cc02d7e2SAndroid Build Coastguard Worker                     didWriteDataHook:nil];
335*cc02d7e2SAndroid Build Coastguard Worker}
336*cc02d7e2SAndroid Build Coastguard Worker
337*cc02d7e2SAndroid Build Coastguard Worker- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager {
338*cc02d7e2SAndroid Build Coastguard Worker  if (_enabled) {
339*cc02d7e2SAndroid Build Coastguard Worker    return [[HookInterceptor alloc] initWithInterceptorManager:interceptorManager
340*cc02d7e2SAndroid Build Coastguard Worker                                                 dispatchQueue:_dispatchQueue
341*cc02d7e2SAndroid Build Coastguard Worker                                                     startHook:_startHook
342*cc02d7e2SAndroid Build Coastguard Worker                                                 writeDataHook:_writeDataHook
343*cc02d7e2SAndroid Build Coastguard Worker                                                    finishHook:_finishHook
344*cc02d7e2SAndroid Build Coastguard Worker                                       receiveNextMessagesHook:_receiveNextMessagesHook
345*cc02d7e2SAndroid Build Coastguard Worker                                            responseHeaderHook:_responseHeaderHook
346*cc02d7e2SAndroid Build Coastguard Worker                                              responseDataHook:_responseDataHook
347*cc02d7e2SAndroid Build Coastguard Worker                                             responseCloseHook:_responseCloseHook
348*cc02d7e2SAndroid Build Coastguard Worker                                              didWriteDataHook:_didWriteDataHook];
349*cc02d7e2SAndroid Build Coastguard Worker  } else {
350*cc02d7e2SAndroid Build Coastguard Worker    return nil;
351*cc02d7e2SAndroid Build Coastguard Worker  }
352*cc02d7e2SAndroid Build Coastguard Worker}
353*cc02d7e2SAndroid Build Coastguard Worker
354*cc02d7e2SAndroid Build Coastguard Worker- (void)setStartHook:(void (^)(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
355*cc02d7e2SAndroid Build Coastguard Worker                               GRPCInterceptorManager *manager))startHook
356*cc02d7e2SAndroid Build Coastguard Worker              writeDataHook:(void (^)(id data, GRPCInterceptorManager *manager))writeDataHook
357*cc02d7e2SAndroid Build Coastguard Worker                 finishHook:(void (^)(GRPCInterceptorManager *manager))finishHook
358*cc02d7e2SAndroid Build Coastguard Worker    receiveNextMessagesHook:(void (^)(NSUInteger numberOfMessages,
359*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))receiveNextMessagesHook
360*cc02d7e2SAndroid Build Coastguard Worker         responseHeaderHook:(void (^)(NSDictionary *initialMetadata,
361*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))responseHeaderHook
362*cc02d7e2SAndroid Build Coastguard Worker           responseDataHook:(void (^)(id data, GRPCInterceptorManager *manager))responseDataHook
363*cc02d7e2SAndroid Build Coastguard Worker          responseCloseHook:(void (^)(NSDictionary *trailingMetadata, NSError *error,
364*cc02d7e2SAndroid Build Coastguard Worker                                      GRPCInterceptorManager *manager))responseCloseHook
365*cc02d7e2SAndroid Build Coastguard Worker           didWriteDataHook:(void (^)(GRPCInterceptorManager *manager))didWriteDataHook {
366*cc02d7e2SAndroid Build Coastguard Worker  _startHook = startHook;
367*cc02d7e2SAndroid Build Coastguard Worker  _writeDataHook = writeDataHook;
368*cc02d7e2SAndroid Build Coastguard Worker  _finishHook = finishHook;
369*cc02d7e2SAndroid Build Coastguard Worker  _receiveNextMessagesHook = receiveNextMessagesHook;
370*cc02d7e2SAndroid Build Coastguard Worker  _responseHeaderHook = responseHeaderHook;
371*cc02d7e2SAndroid Build Coastguard Worker  _responseDataHook = responseDataHook;
372*cc02d7e2SAndroid Build Coastguard Worker  _responseCloseHook = responseCloseHook;
373*cc02d7e2SAndroid Build Coastguard Worker  _didWriteDataHook = didWriteDataHook;
374*cc02d7e2SAndroid Build Coastguard Worker}
375*cc02d7e2SAndroid Build Coastguard Worker
376*cc02d7e2SAndroid Build Coastguard Worker@end
377*cc02d7e2SAndroid Build Coastguard Worker
378*cc02d7e2SAndroid Build Coastguard Workerstatic GlobalInterceptorFactory *globalInterceptorFactory = nil;
379*cc02d7e2SAndroid Build Coastguard Workerstatic dispatch_once_t initGlobalInterceptorFactory;
380*cc02d7e2SAndroid Build Coastguard Worker
381*cc02d7e2SAndroid Build Coastguard Worker#pragma mark Tests
382*cc02d7e2SAndroid Build Coastguard Worker
383*cc02d7e2SAndroid Build Coastguard Worker@implementation InteropTests
384*cc02d7e2SAndroid Build Coastguard Worker
385*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic push
386*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
387*cc02d7e2SAndroid Build Coastguard Worker- (void)retriableTest:(SEL)selector retries:(int)retries timeout:(NSTimeInterval)timeout {
388*cc02d7e2SAndroid Build Coastguard Worker  for (int i = 0; i < retries; i++) {
389*cc02d7e2SAndroid Build Coastguard Worker    NSDate *waitUntil = [[NSDate date] dateByAddingTimeInterval:timeout];
390*cc02d7e2SAndroid Build Coastguard Worker    NSCondition *cv = [[NSCondition alloc] init];
391*cc02d7e2SAndroid Build Coastguard Worker    __block BOOL done = NO;
392*cc02d7e2SAndroid Build Coastguard Worker    [cv lock];
393*cc02d7e2SAndroid Build Coastguard Worker    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
394*cc02d7e2SAndroid Build Coastguard Worker      [self performSelector:selector];
395*cc02d7e2SAndroid Build Coastguard Worker      [cv lock];
396*cc02d7e2SAndroid Build Coastguard Worker      done = YES;
397*cc02d7e2SAndroid Build Coastguard Worker      [cv signal];
398*cc02d7e2SAndroid Build Coastguard Worker      [cv unlock];
399*cc02d7e2SAndroid Build Coastguard Worker    });
400*cc02d7e2SAndroid Build Coastguard Worker    while (!done && [waitUntil timeIntervalSinceNow] > 0) {
401*cc02d7e2SAndroid Build Coastguard Worker      [cv waitUntilDate:waitUntil];
402*cc02d7e2SAndroid Build Coastguard Worker    }
403*cc02d7e2SAndroid Build Coastguard Worker    if (done) {
404*cc02d7e2SAndroid Build Coastguard Worker      [cv unlock];
405*cc02d7e2SAndroid Build Coastguard Worker      break;
406*cc02d7e2SAndroid Build Coastguard Worker    } else {
407*cc02d7e2SAndroid Build Coastguard Worker      [cv unlock];
408*cc02d7e2SAndroid Build Coastguard Worker      [self tearDown];
409*cc02d7e2SAndroid Build Coastguard Worker      [self setUp];
410*cc02d7e2SAndroid Build Coastguard Worker    }
411*cc02d7e2SAndroid Build Coastguard Worker  }
412*cc02d7e2SAndroid Build Coastguard Worker}
413*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic pop
414*cc02d7e2SAndroid Build Coastguard Worker
415*cc02d7e2SAndroid Build Coastguard Worker+ (XCTestSuite *)defaultTestSuite {
416*cc02d7e2SAndroid Build Coastguard Worker  if (self == [InteropTests class]) {
417*cc02d7e2SAndroid Build Coastguard Worker    return [XCTestSuite testSuiteWithName:@"InteropTestsEmptySuite"];
418*cc02d7e2SAndroid Build Coastguard Worker  }
419*cc02d7e2SAndroid Build Coastguard Worker  return super.defaultTestSuite;
420*cc02d7e2SAndroid Build Coastguard Worker}
421*cc02d7e2SAndroid Build Coastguard Worker
422*cc02d7e2SAndroid Build Coastguard Worker+ (NSString *)host {
423*cc02d7e2SAndroid Build Coastguard Worker  return nil;
424*cc02d7e2SAndroid Build Coastguard Worker}
425*cc02d7e2SAndroid Build Coastguard Worker
426*cc02d7e2SAndroid Build Coastguard Worker// This number indicates how many bytes of overhead does Protocol Buffers encoding add onto the
427*cc02d7e2SAndroid Build Coastguard Worker// message. The number varies as different message.proto is used on different servers. The actual
428*cc02d7e2SAndroid Build Coastguard Worker// number for each interop server is overridden in corresponding derived test classes.
429*cc02d7e2SAndroid Build Coastguard Worker- (int32_t)encodingOverhead {
430*cc02d7e2SAndroid Build Coastguard Worker  return 0;
431*cc02d7e2SAndroid Build Coastguard Worker}
432*cc02d7e2SAndroid Build Coastguard Worker
433*cc02d7e2SAndroid Build Coastguard Worker// For backwards compatibility
434*cc02d7e2SAndroid Build Coastguard Worker+ (GRPCTransportType)transportType {
435*cc02d7e2SAndroid Build Coastguard Worker  return GRPCTransportTypeChttp2BoringSSL;
436*cc02d7e2SAndroid Build Coastguard Worker}
437*cc02d7e2SAndroid Build Coastguard Worker
438*cc02d7e2SAndroid Build Coastguard Worker+ (GRPCTransportID)transport {
439*cc02d7e2SAndroid Build Coastguard Worker  return NULL;
440*cc02d7e2SAndroid Build Coastguard Worker}
441*cc02d7e2SAndroid Build Coastguard Worker
442*cc02d7e2SAndroid Build Coastguard Worker+ (NSString *)PEMRootCertificates {
443*cc02d7e2SAndroid Build Coastguard Worker  return nil;
444*cc02d7e2SAndroid Build Coastguard Worker}
445*cc02d7e2SAndroid Build Coastguard Worker
446*cc02d7e2SAndroid Build Coastguard Worker+ (NSString *)hostNameOverride {
447*cc02d7e2SAndroid Build Coastguard Worker  return nil;
448*cc02d7e2SAndroid Build Coastguard Worker}
449*cc02d7e2SAndroid Build Coastguard Worker
450*cc02d7e2SAndroid Build Coastguard Worker+ (void)setUp {
451*cc02d7e2SAndroid Build Coastguard Worker  dispatch_once(&initGlobalInterceptorFactory, ^{
452*cc02d7e2SAndroid Build Coastguard Worker    dispatch_queue_t globalInterceptorQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
453*cc02d7e2SAndroid Build Coastguard Worker    globalInterceptorFactory =
454*cc02d7e2SAndroid Build Coastguard Worker        [[GlobalInterceptorFactory alloc] initWithDispatchQueue:globalInterceptorQueue];
455*cc02d7e2SAndroid Build Coastguard Worker    [GRPCCall2 registerGlobalInterceptor:globalInterceptorFactory];
456*cc02d7e2SAndroid Build Coastguard Worker  });
457*cc02d7e2SAndroid Build Coastguard Worker}
458*cc02d7e2SAndroid Build Coastguard Worker
459*cc02d7e2SAndroid Build Coastguard Worker- (void)setUp {
460*cc02d7e2SAndroid Build Coastguard Worker  self.continueAfterFailure = YES;
461*cc02d7e2SAndroid Build Coastguard Worker  [GRPCCall resetHostSettings];
462*cc02d7e2SAndroid Build Coastguard Worker  GRPCResetCallConnections();
463*cc02d7e2SAndroid Build Coastguard Worker  XCTAssertNotNil([[self class] host]);
464*cc02d7e2SAndroid Build Coastguard Worker}
465*cc02d7e2SAndroid Build Coastguard Worker
466*cc02d7e2SAndroid Build Coastguard Worker- (void)testEmptyUnaryRPC {
467*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiter, GRPCTestAssert assertBlock) {
468*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
469*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"];
470*cc02d7e2SAndroid Build Coastguard Worker
471*cc02d7e2SAndroid Build Coastguard Worker    GPBEmpty *request = [GPBEmpty message];
472*cc02d7e2SAndroid Build Coastguard Worker
473*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
474*cc02d7e2SAndroid Build Coastguard Worker    [service emptyCallWithRequest:request
475*cc02d7e2SAndroid Build Coastguard Worker                          handler:^(GPBEmpty *response, NSError *error) {
476*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
477*cc02d7e2SAndroid Build Coastguard Worker                              return;
478*cc02d7e2SAndroid Build Coastguard Worker                            }
479*cc02d7e2SAndroid Build Coastguard Worker
480*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertNil(error, @"Finished with unexpected error: %@", error);
481*cc02d7e2SAndroid Build Coastguard Worker
482*cc02d7e2SAndroid Build Coastguard Worker                            id expectedResponse = [GPBEmpty message];
483*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertEqualObjects(response, expectedResponse);
484*cc02d7e2SAndroid Build Coastguard Worker
485*cc02d7e2SAndroid Build Coastguard Worker                            [expectation fulfill];
486*cc02d7e2SAndroid Build Coastguard Worker                          }];
487*cc02d7e2SAndroid Build Coastguard Worker    waiter(@[ expectation ], GRPCInteropTestTimeoutDefault);
488*cc02d7e2SAndroid Build Coastguard Worker  });
489*cc02d7e2SAndroid Build Coastguard Worker}
490*cc02d7e2SAndroid Build Coastguard Worker
491*cc02d7e2SAndroid Build Coastguard Worker- (void)testEmptyUnaryRPCWithV2API {
492*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
493*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
494*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectReceive =
495*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"EmptyUnaryWithV2API received message"];
496*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectComplete =
497*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"EmptyUnaryWithV2API completed"];
498*cc02d7e2SAndroid Build Coastguard Worker
499*cc02d7e2SAndroid Build Coastguard Worker    GPBEmpty *request = [GPBEmpty message];
500*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
501*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
502*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
503*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
504*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
505*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
506*cc02d7e2SAndroid Build Coastguard Worker
507*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
508*cc02d7e2SAndroid Build Coastguard Worker    GRPCUnaryProtoCall *call = [service
509*cc02d7e2SAndroid Build Coastguard Worker        emptyCallWithMessage:request
510*cc02d7e2SAndroid Build Coastguard Worker             responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
511*cc02d7e2SAndroid Build Coastguard Worker                                 messageCallback:^(id message) {
512*cc02d7e2SAndroid Build Coastguard Worker                                   if (weakService == nil) {
513*cc02d7e2SAndroid Build Coastguard Worker                                     return;
514*cc02d7e2SAndroid Build Coastguard Worker                                   }
515*cc02d7e2SAndroid Build Coastguard Worker                                   if (message) {
516*cc02d7e2SAndroid Build Coastguard Worker                                     id expectedResponse = [GPBEmpty message];
517*cc02d7e2SAndroid Build Coastguard Worker                                     XCTAssertEqualObjects(message, expectedResponse);
518*cc02d7e2SAndroid Build Coastguard Worker                                     [expectReceive fulfill];
519*cc02d7e2SAndroid Build Coastguard Worker                                   }
520*cc02d7e2SAndroid Build Coastguard Worker                                 }
521*cc02d7e2SAndroid Build Coastguard Worker                                 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
522*cc02d7e2SAndroid Build Coastguard Worker                                   if (weakService == nil) {
523*cc02d7e2SAndroid Build Coastguard Worker                                     return;
524*cc02d7e2SAndroid Build Coastguard Worker                                   }
525*cc02d7e2SAndroid Build Coastguard Worker                                   XCTAssertNil(error, @"Unexpected error: %@", error);
526*cc02d7e2SAndroid Build Coastguard Worker                                   [expectComplete fulfill];
527*cc02d7e2SAndroid Build Coastguard Worker                                 }]
528*cc02d7e2SAndroid Build Coastguard Worker                 callOptions:options];
529*cc02d7e2SAndroid Build Coastguard Worker    [call start];
530*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectReceive, expectComplete ], GRPCInteropTestTimeoutDefault);
531*cc02d7e2SAndroid Build Coastguard Worker  });
532*cc02d7e2SAndroid Build Coastguard Worker}
533*cc02d7e2SAndroid Build Coastguard Worker
534*cc02d7e2SAndroid Build Coastguard Worker// Test that responses can be dispatched even if we do not run main run-loop
535*cc02d7e2SAndroid Build Coastguard Worker- (void)testAsyncDispatchWithV2API {
536*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
537*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
538*cc02d7e2SAndroid Build Coastguard Worker
539*cc02d7e2SAndroid Build Coastguard Worker    XCTestExpectation *receiveExpect = [self expectationWithDescription:@"receiveExpect"];
540*cc02d7e2SAndroid Build Coastguard Worker    XCTestExpectation *closeExpect = [self expectationWithDescription:@"closeExpect"];
541*cc02d7e2SAndroid Build Coastguard Worker
542*cc02d7e2SAndroid Build Coastguard Worker    GPBEmpty *request = [GPBEmpty message];
543*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
544*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
545*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
546*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
547*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
548*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
549*cc02d7e2SAndroid Build Coastguard Worker
550*cc02d7e2SAndroid Build Coastguard Worker    __block BOOL messageReceived = NO;
551*cc02d7e2SAndroid Build Coastguard Worker    __block BOOL done = NO;
552*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
553*cc02d7e2SAndroid Build Coastguard Worker    GRPCUnaryProtoCall *call = [service
554*cc02d7e2SAndroid Build Coastguard Worker        emptyCallWithMessage:request
555*cc02d7e2SAndroid Build Coastguard Worker             responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
556*cc02d7e2SAndroid Build Coastguard Worker                                 messageCallback:^(id message) {
557*cc02d7e2SAndroid Build Coastguard Worker                                   if (weakService == nil) {
558*cc02d7e2SAndroid Build Coastguard Worker                                     return;
559*cc02d7e2SAndroid Build Coastguard Worker                                   }
560*cc02d7e2SAndroid Build Coastguard Worker                                   if (message) {
561*cc02d7e2SAndroid Build Coastguard Worker                                     id expectedResponse = [GPBEmpty message];
562*cc02d7e2SAndroid Build Coastguard Worker                                     XCTAssertEqualObjects(message, expectedResponse);
563*cc02d7e2SAndroid Build Coastguard Worker                                     messageReceived = YES;
564*cc02d7e2SAndroid Build Coastguard Worker                                   }
565*cc02d7e2SAndroid Build Coastguard Worker                                   [receiveExpect fulfill];
566*cc02d7e2SAndroid Build Coastguard Worker                                 }
567*cc02d7e2SAndroid Build Coastguard Worker                                 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
568*cc02d7e2SAndroid Build Coastguard Worker                                   if (weakService == nil) {
569*cc02d7e2SAndroid Build Coastguard Worker                                     return;
570*cc02d7e2SAndroid Build Coastguard Worker                                   }
571*cc02d7e2SAndroid Build Coastguard Worker                                   XCTAssertNil(error, @"Unexpected error: %@", error);
572*cc02d7e2SAndroid Build Coastguard Worker                                   done = YES;
573*cc02d7e2SAndroid Build Coastguard Worker                                   [closeExpect fulfill];
574*cc02d7e2SAndroid Build Coastguard Worker                                 }]
575*cc02d7e2SAndroid Build Coastguard Worker                 callOptions:options];
576*cc02d7e2SAndroid Build Coastguard Worker
577*cc02d7e2SAndroid Build Coastguard Worker    [call start];
578*cc02d7e2SAndroid Build Coastguard Worker
579*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ receiveExpect, closeExpect ], GRPCInteropTestTimeoutDefault);
580*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertTrue(messageReceived);
581*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertTrue(done);
582*cc02d7e2SAndroid Build Coastguard Worker  });
583*cc02d7e2SAndroid Build Coastguard Worker}
584*cc02d7e2SAndroid Build Coastguard Worker
585*cc02d7e2SAndroid Build Coastguard Worker- (void)testLargeUnaryRPC {
586*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
587*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
588*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"];
589*cc02d7e2SAndroid Build Coastguard Worker
590*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
591*cc02d7e2SAndroid Build Coastguard Worker    request.responseType = RMTPayloadType_Compressable;
592*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = LARGE_RESPONSE_PAYLOAD_SIZE;
593*cc02d7e2SAndroid Build Coastguard Worker    request.payload.body = [NSMutableData dataWithLength:LARGE_REQUEST_PAYLOAD_SIZE];
594*cc02d7e2SAndroid Build Coastguard Worker
595*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
596*cc02d7e2SAndroid Build Coastguard Worker    [service unaryCallWithRequest:request
597*cc02d7e2SAndroid Build Coastguard Worker                          handler:^(RMTSimpleResponse *response, NSError *error) {
598*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
599*cc02d7e2SAndroid Build Coastguard Worker                              return;
600*cc02d7e2SAndroid Build Coastguard Worker                            }
601*cc02d7e2SAndroid Build Coastguard Worker
602*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertNil(error, @"Finished with unexpected error: %@", error);
603*cc02d7e2SAndroid Build Coastguard Worker
604*cc02d7e2SAndroid Build Coastguard Worker                            RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message];
605*cc02d7e2SAndroid Build Coastguard Worker                            expectedResponse.payload.type = RMTPayloadType_Compressable;
606*cc02d7e2SAndroid Build Coastguard Worker                            expectedResponse.payload.body =
607*cc02d7e2SAndroid Build Coastguard Worker                                [NSMutableData dataWithLength:LARGE_RESPONSE_PAYLOAD_SIZE];
608*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertEqualObjects(response, expectedResponse);
609*cc02d7e2SAndroid Build Coastguard Worker
610*cc02d7e2SAndroid Build Coastguard Worker                            [expectation fulfill];
611*cc02d7e2SAndroid Build Coastguard Worker                          }];
612*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
613*cc02d7e2SAndroid Build Coastguard Worker  });
614*cc02d7e2SAndroid Build Coastguard Worker}
615*cc02d7e2SAndroid Build Coastguard Worker
616*cc02d7e2SAndroid Build Coastguard Worker- (void)testUnaryResponseHandler {
617*cc02d7e2SAndroid Build Coastguard Worker  // The test does not work on a remote server since it does not echo a trailer
618*cc02d7e2SAndroid Build Coastguard Worker  if ([[self class] isRemoteTest]) {
619*cc02d7e2SAndroid Build Coastguard Worker    return;
620*cc02d7e2SAndroid Build Coastguard Worker  }
621*cc02d7e2SAndroid Build Coastguard Worker
622*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
623*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
624*cc02d7e2SAndroid Build Coastguard Worker
625*cc02d7e2SAndroid Build Coastguard Worker    XCTestExpectation *expectComplete = [self expectationWithDescription:@"call complete"];
626*cc02d7e2SAndroid Build Coastguard Worker    XCTestExpectation *expectCompleteMainQueue =
627*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"main queue call complete"];
628*cc02d7e2SAndroid Build Coastguard Worker
629*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
630*cc02d7e2SAndroid Build Coastguard Worker    request.responseType = RMTPayloadType_Compressable;
631*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = LARGE_RESPONSE_PAYLOAD_SIZE;
632*cc02d7e2SAndroid Build Coastguard Worker    request.payload.body = [NSMutableData dataWithLength:LARGE_REQUEST_PAYLOAD_SIZE];
633*cc02d7e2SAndroid Build Coastguard Worker
634*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
635*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
636*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
637*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
638*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
639*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
640*cc02d7e2SAndroid Build Coastguard Worker    const unsigned char raw_bytes[] = {1, 2, 3, 4};
641*cc02d7e2SAndroid Build Coastguard Worker    NSData *trailer_data = [NSData dataWithBytes:raw_bytes length:sizeof(raw_bytes)];
642*cc02d7e2SAndroid Build Coastguard Worker    options.initialMetadata = @{
643*cc02d7e2SAndroid Build Coastguard Worker      @"x-grpc-test-echo-trailing-bin" : trailer_data,
644*cc02d7e2SAndroid Build Coastguard Worker      @"x-grpc-test-echo-initial" : @"test-header"
645*cc02d7e2SAndroid Build Coastguard Worker    };
646*cc02d7e2SAndroid Build Coastguard Worker
647*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
648*cc02d7e2SAndroid Build Coastguard Worker
649*cc02d7e2SAndroid Build Coastguard Worker    __block GRPCUnaryResponseHandler *handler = [[GRPCUnaryResponseHandler alloc]
650*cc02d7e2SAndroid Build Coastguard Worker        initWithResponseHandler:^(GPBMessage *response, NSError *error) {
651*cc02d7e2SAndroid Build Coastguard Worker          if (weakService == nil) {
652*cc02d7e2SAndroid Build Coastguard Worker            return;
653*cc02d7e2SAndroid Build Coastguard Worker          }
654*cc02d7e2SAndroid Build Coastguard Worker
655*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertNil(error, @"Unexpected error: %@", error);
656*cc02d7e2SAndroid Build Coastguard Worker          RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message];
657*cc02d7e2SAndroid Build Coastguard Worker          expectedResponse.payload.type = RMTPayloadType_Compressable;
658*cc02d7e2SAndroid Build Coastguard Worker          expectedResponse.payload.body =
659*cc02d7e2SAndroid Build Coastguard Worker              [NSMutableData dataWithLength:LARGE_RESPONSE_PAYLOAD_SIZE];
660*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(response, expectedResponse);
661*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(handler.responseHeaders[@"x-grpc-test-echo-initial"],
662*cc02d7e2SAndroid Build Coastguard Worker                                @"test-header");
663*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(handler.responseTrailers[@"x-grpc-test-echo-trailing-bin"],
664*cc02d7e2SAndroid Build Coastguard Worker                                trailer_data);
665*cc02d7e2SAndroid Build Coastguard Worker          [expectComplete fulfill];
666*cc02d7e2SAndroid Build Coastguard Worker        }
667*cc02d7e2SAndroid Build Coastguard Worker          responseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)];
668*cc02d7e2SAndroid Build Coastguard Worker    __block GRPCUnaryResponseHandler *handlerMainQueue = [[GRPCUnaryResponseHandler alloc]
669*cc02d7e2SAndroid Build Coastguard Worker        initWithResponseHandler:^(GPBMessage *response, NSError *error) {
670*cc02d7e2SAndroid Build Coastguard Worker          if (weakService == nil) {
671*cc02d7e2SAndroid Build Coastguard Worker            return;
672*cc02d7e2SAndroid Build Coastguard Worker          }
673*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertNil(error, @"Unexpected error: %@", error);
674*cc02d7e2SAndroid Build Coastguard Worker          RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message];
675*cc02d7e2SAndroid Build Coastguard Worker          expectedResponse.payload.type = RMTPayloadType_Compressable;
676*cc02d7e2SAndroid Build Coastguard Worker          expectedResponse.payload.body =
677*cc02d7e2SAndroid Build Coastguard Worker              [NSMutableData dataWithLength:LARGE_RESPONSE_PAYLOAD_SIZE];
678*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(response, expectedResponse);
679*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(handlerMainQueue.responseHeaders[@"x-grpc-test-echo-initial"],
680*cc02d7e2SAndroid Build Coastguard Worker                                @"test-header");
681*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(handlerMainQueue.responseTrailers[@"x-grpc-test-echo-trailing-bin"],
682*cc02d7e2SAndroid Build Coastguard Worker                                trailer_data);
683*cc02d7e2SAndroid Build Coastguard Worker          [expectCompleteMainQueue fulfill];
684*cc02d7e2SAndroid Build Coastguard Worker        }
685*cc02d7e2SAndroid Build Coastguard Worker          responseDispatchQueue:nil];
686*cc02d7e2SAndroid Build Coastguard Worker
687*cc02d7e2SAndroid Build Coastguard Worker    [[service unaryCallWithMessage:request responseHandler:handler callOptions:options] start];
688*cc02d7e2SAndroid Build Coastguard Worker    [[service unaryCallWithMessage:request responseHandler:handlerMainQueue
689*cc02d7e2SAndroid Build Coastguard Worker                       callOptions:options] start];
690*cc02d7e2SAndroid Build Coastguard Worker
691*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectComplete, expectCompleteMainQueue ], GRPCInteropTestTimeoutDefault);
692*cc02d7e2SAndroid Build Coastguard Worker  });
693*cc02d7e2SAndroid Build Coastguard Worker}
694*cc02d7e2SAndroid Build Coastguard Worker
695*cc02d7e2SAndroid Build Coastguard Worker- (void)testLargeUnaryRPCWithV2API {
696*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
697*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
698*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectReceive =
699*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"LargeUnaryWithV2API received message"];
700*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectComplete =
701*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"LargeUnaryWithV2API received complete"];
702*cc02d7e2SAndroid Build Coastguard Worker
703*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
704*cc02d7e2SAndroid Build Coastguard Worker    request.responseType = RMTPayloadType_Compressable;
705*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = LARGE_RESPONSE_PAYLOAD_SIZE;
706*cc02d7e2SAndroid Build Coastguard Worker    request.payload.body = [NSMutableData dataWithLength:LARGE_REQUEST_PAYLOAD_SIZE];
707*cc02d7e2SAndroid Build Coastguard Worker
708*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
709*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
710*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
711*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
712*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
713*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
714*cc02d7e2SAndroid Build Coastguard Worker
715*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
716*cc02d7e2SAndroid Build Coastguard Worker    GRPCUnaryProtoCall *call = [service
717*cc02d7e2SAndroid Build Coastguard Worker        unaryCallWithMessage:request
718*cc02d7e2SAndroid Build Coastguard Worker             responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
719*cc02d7e2SAndroid Build Coastguard Worker                                 messageCallback:^(id message) {
720*cc02d7e2SAndroid Build Coastguard Worker                                   if (weakService == nil) {
721*cc02d7e2SAndroid Build Coastguard Worker                                     return;
722*cc02d7e2SAndroid Build Coastguard Worker                                   }
723*cc02d7e2SAndroid Build Coastguard Worker                                   XCTAssertNotNil(message);
724*cc02d7e2SAndroid Build Coastguard Worker                                   if (message) {
725*cc02d7e2SAndroid Build Coastguard Worker                                     RMTSimpleResponse *expectedResponse =
726*cc02d7e2SAndroid Build Coastguard Worker                                         [RMTSimpleResponse message];
727*cc02d7e2SAndroid Build Coastguard Worker                                     expectedResponse.payload.type = RMTPayloadType_Compressable;
728*cc02d7e2SAndroid Build Coastguard Worker                                     expectedResponse.payload.body =
729*cc02d7e2SAndroid Build Coastguard Worker                                         [NSMutableData dataWithLength:LARGE_RESPONSE_PAYLOAD_SIZE];
730*cc02d7e2SAndroid Build Coastguard Worker                                     XCTAssertEqualObjects(message, expectedResponse);
731*cc02d7e2SAndroid Build Coastguard Worker
732*cc02d7e2SAndroid Build Coastguard Worker                                     [expectReceive fulfill];
733*cc02d7e2SAndroid Build Coastguard Worker                                   }
734*cc02d7e2SAndroid Build Coastguard Worker                                 }
735*cc02d7e2SAndroid Build Coastguard Worker                                 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
736*cc02d7e2SAndroid Build Coastguard Worker                                   if (weakService == nil) {
737*cc02d7e2SAndroid Build Coastguard Worker                                     return;
738*cc02d7e2SAndroid Build Coastguard Worker                                   }
739*cc02d7e2SAndroid Build Coastguard Worker                                   XCTAssertNil(error, @"Unexpected error: %@", error);
740*cc02d7e2SAndroid Build Coastguard Worker                                   [expectComplete fulfill];
741*cc02d7e2SAndroid Build Coastguard Worker                                 }]
742*cc02d7e2SAndroid Build Coastguard Worker                 callOptions:options];
743*cc02d7e2SAndroid Build Coastguard Worker    [call start];
744*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectReceive, expectComplete ], GRPCInteropTestTimeoutDefault);
745*cc02d7e2SAndroid Build Coastguard Worker  });
746*cc02d7e2SAndroid Build Coastguard Worker}
747*cc02d7e2SAndroid Build Coastguard Worker
748*cc02d7e2SAndroid Build Coastguard Worker- (void)testConcurrentRPCsWithErrorsWithV2API {
749*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
750*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
751*cc02d7e2SAndroid Build Coastguard Worker    NSMutableArray *completeExpectations = [NSMutableArray array];
752*cc02d7e2SAndroid Build Coastguard Worker    NSMutableArray *calls = [NSMutableArray array];
753*cc02d7e2SAndroid Build Coastguard Worker    int num_rpcs = 10;
754*cc02d7e2SAndroid Build Coastguard Worker    for (int i = 0; i < num_rpcs; ++i) {
755*cc02d7e2SAndroid Build Coastguard Worker      [completeExpectations
756*cc02d7e2SAndroid Build Coastguard Worker          addObject:[self expectationWithDescription:
757*cc02d7e2SAndroid Build Coastguard Worker                              [NSString stringWithFormat:@"Received trailer for RPC %d", i]]];
758*cc02d7e2SAndroid Build Coastguard Worker
759*cc02d7e2SAndroid Build Coastguard Worker      RMTSimpleRequest *request = [RMTSimpleRequest message];
760*cc02d7e2SAndroid Build Coastguard Worker      request.responseType = RMTPayloadType_Compressable;
761*cc02d7e2SAndroid Build Coastguard Worker      request.responseSize = SMALL_PAYLOAD_SIZE;
762*cc02d7e2SAndroid Build Coastguard Worker      request.payload.body = [NSMutableData dataWithLength:SMALL_PAYLOAD_SIZE];
763*cc02d7e2SAndroid Build Coastguard Worker      if (i % 3 == 0) {
764*cc02d7e2SAndroid Build Coastguard Worker        request.responseStatus.code = GRPC_STATUS_UNAVAILABLE;
765*cc02d7e2SAndroid Build Coastguard Worker      } else if (i % 7 == 0) {
766*cc02d7e2SAndroid Build Coastguard Worker        request.responseStatus.code = GRPC_STATUS_CANCELLED;
767*cc02d7e2SAndroid Build Coastguard Worker      }
768*cc02d7e2SAndroid Build Coastguard Worker      GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
769*cc02d7e2SAndroid Build Coastguard Worker      // For backwards compatibility
770*cc02d7e2SAndroid Build Coastguard Worker      options.transportType = [[self class] transportType];
771*cc02d7e2SAndroid Build Coastguard Worker      options.transport = [[self class] transport];
772*cc02d7e2SAndroid Build Coastguard Worker      options.PEMRootCertificates = [[self class] PEMRootCertificates];
773*cc02d7e2SAndroid Build Coastguard Worker      options.hostNameOverride = [[self class] hostNameOverride];
774*cc02d7e2SAndroid Build Coastguard Worker
775*cc02d7e2SAndroid Build Coastguard Worker      __weak RMTTestService *weakService = service;
776*cc02d7e2SAndroid Build Coastguard Worker      GRPCUnaryProtoCall *call = [service
777*cc02d7e2SAndroid Build Coastguard Worker          unaryCallWithMessage:request
778*cc02d7e2SAndroid Build Coastguard Worker               responseHandler:[[InteropTestsBlockCallbacks alloc]
779*cc02d7e2SAndroid Build Coastguard Worker                                   initWithInitialMetadataCallback:nil
780*cc02d7e2SAndroid Build Coastguard Worker                                   messageCallback:^(id message) {
781*cc02d7e2SAndroid Build Coastguard Worker                                     if (weakService == nil) {
782*cc02d7e2SAndroid Build Coastguard Worker                                       return;
783*cc02d7e2SAndroid Build Coastguard Worker                                     }
784*cc02d7e2SAndroid Build Coastguard Worker                                     if (message) {
785*cc02d7e2SAndroid Build Coastguard Worker                                       RMTSimpleResponse *expectedResponse =
786*cc02d7e2SAndroid Build Coastguard Worker                                           [RMTSimpleResponse message];
787*cc02d7e2SAndroid Build Coastguard Worker                                       expectedResponse.payload.type = RMTPayloadType_Compressable;
788*cc02d7e2SAndroid Build Coastguard Worker                                       expectedResponse.payload.body =
789*cc02d7e2SAndroid Build Coastguard Worker                                           [NSMutableData dataWithLength:SMALL_PAYLOAD_SIZE];
790*cc02d7e2SAndroid Build Coastguard Worker                                       XCTAssertEqualObjects(message, expectedResponse);
791*cc02d7e2SAndroid Build Coastguard Worker                                     }
792*cc02d7e2SAndroid Build Coastguard Worker                                   }
793*cc02d7e2SAndroid Build Coastguard Worker                                   closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
794*cc02d7e2SAndroid Build Coastguard Worker                                     if (weakService == nil) {
795*cc02d7e2SAndroid Build Coastguard Worker                                       return;
796*cc02d7e2SAndroid Build Coastguard Worker                                     }
797*cc02d7e2SAndroid Build Coastguard Worker                                     [completeExpectations[i] fulfill];
798*cc02d7e2SAndroid Build Coastguard Worker                                   }]
799*cc02d7e2SAndroid Build Coastguard Worker                   callOptions:options];
800*cc02d7e2SAndroid Build Coastguard Worker      [calls addObject:call];
801*cc02d7e2SAndroid Build Coastguard Worker    }
802*cc02d7e2SAndroid Build Coastguard Worker
803*cc02d7e2SAndroid Build Coastguard Worker    for (int i = 0; i < num_rpcs; ++i) {
804*cc02d7e2SAndroid Build Coastguard Worker      GRPCUnaryProtoCall *call = calls[i];
805*cc02d7e2SAndroid Build Coastguard Worker      [call start];
806*cc02d7e2SAndroid Build Coastguard Worker    }
807*cc02d7e2SAndroid Build Coastguard Worker
808*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(completeExpectations, GRPCInteropTestTimeoutDefault);
809*cc02d7e2SAndroid Build Coastguard Worker  });
810*cc02d7e2SAndroid Build Coastguard Worker}
811*cc02d7e2SAndroid Build Coastguard Worker
812*cc02d7e2SAndroid Build Coastguard Worker- (void)concurrentRPCsWithErrors {
813*cc02d7e2SAndroid Build Coastguard Worker  const int kNumRpcs = 10;
814*cc02d7e2SAndroid Build Coastguard Worker  __block int completedCallCount = 0;
815*cc02d7e2SAndroid Build Coastguard Worker  NSCondition *cv = [[NSCondition alloc] init];
816*cc02d7e2SAndroid Build Coastguard Worker  NSDate *waitUntil = [[NSDate date] dateByAddingTimeInterval:GRPCInteropTestTimeoutDefault];
817*cc02d7e2SAndroid Build Coastguard Worker  [cv lock];
818*cc02d7e2SAndroid Build Coastguard Worker  for (int i = 0; i < kNumRpcs; ++i) {
819*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
820*cc02d7e2SAndroid Build Coastguard Worker    request.responseType = RMTPayloadType_Compressable;
821*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = SMALL_PAYLOAD_SIZE;
822*cc02d7e2SAndroid Build Coastguard Worker    request.payload.body = [NSMutableData dataWithLength:SMALL_PAYLOAD_SIZE];
823*cc02d7e2SAndroid Build Coastguard Worker    if (i % 3 == 0) {
824*cc02d7e2SAndroid Build Coastguard Worker      request.responseStatus.code = GRPC_STATUS_UNAVAILABLE;
825*cc02d7e2SAndroid Build Coastguard Worker    } else if (i % 7 == 0) {
826*cc02d7e2SAndroid Build Coastguard Worker      request.responseStatus.code = GRPC_STATUS_CANCELLED;
827*cc02d7e2SAndroid Build Coastguard Worker    }
828*cc02d7e2SAndroid Build Coastguard Worker
829*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
830*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
831*cc02d7e2SAndroid Build Coastguard Worker    GRPCProtoCall *call = [service
832*cc02d7e2SAndroid Build Coastguard Worker        RPCToUnaryCallWithRequest:request
833*cc02d7e2SAndroid Build Coastguard Worker                          handler:^(RMTSimpleResponse *response, NSError *error) {
834*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
835*cc02d7e2SAndroid Build Coastguard Worker                              return;
836*cc02d7e2SAndroid Build Coastguard Worker                            }
837*cc02d7e2SAndroid Build Coastguard Worker                            if (error == nil) {
838*cc02d7e2SAndroid Build Coastguard Worker                              RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message];
839*cc02d7e2SAndroid Build Coastguard Worker                              expectedResponse.payload.type = RMTPayloadType_Compressable;
840*cc02d7e2SAndroid Build Coastguard Worker                              expectedResponse.payload.body =
841*cc02d7e2SAndroid Build Coastguard Worker                                  [NSMutableData dataWithLength:SMALL_PAYLOAD_SIZE];
842*cc02d7e2SAndroid Build Coastguard Worker                              XCTAssertEqualObjects(response, expectedResponse);
843*cc02d7e2SAndroid Build Coastguard Worker                            }
844*cc02d7e2SAndroid Build Coastguard Worker                            // DEBUG
845*cc02d7e2SAndroid Build Coastguard Worker                            [cv lock];
846*cc02d7e2SAndroid Build Coastguard Worker                            if (++completedCallCount == kNumRpcs) {
847*cc02d7e2SAndroid Build Coastguard Worker                              [cv signal];
848*cc02d7e2SAndroid Build Coastguard Worker                            }
849*cc02d7e2SAndroid Build Coastguard Worker                            [cv unlock];
850*cc02d7e2SAndroid Build Coastguard Worker                          }];
851*cc02d7e2SAndroid Build Coastguard Worker    [call setResponseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)];
852*cc02d7e2SAndroid Build Coastguard Worker    [call start];
853*cc02d7e2SAndroid Build Coastguard Worker  }
854*cc02d7e2SAndroid Build Coastguard Worker  while (completedCallCount < kNumRpcs && [waitUntil timeIntervalSinceNow] > 0) {
855*cc02d7e2SAndroid Build Coastguard Worker    [cv waitUntilDate:waitUntil];
856*cc02d7e2SAndroid Build Coastguard Worker  }
857*cc02d7e2SAndroid Build Coastguard Worker  [cv unlock];
858*cc02d7e2SAndroid Build Coastguard Worker}
859*cc02d7e2SAndroid Build Coastguard Worker
860*cc02d7e2SAndroid Build Coastguard Worker- (void)testConcurrentRPCsWithErrors {
861*cc02d7e2SAndroid Build Coastguard Worker  [self retriableTest:@selector(concurrentRPCsWithErrors) retries:kTestRetries timeout:10];
862*cc02d7e2SAndroid Build Coastguard Worker}
863*cc02d7e2SAndroid Build Coastguard Worker
864*cc02d7e2SAndroid Build Coastguard Worker- (void)testPacketCoalescing {
865*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
866*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
867*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"];
868*cc02d7e2SAndroid Build Coastguard Worker
869*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
870*cc02d7e2SAndroid Build Coastguard Worker    request.responseType = RMTPayloadType_Compressable;
871*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = SMALL_PAYLOAD_SIZE;
872*cc02d7e2SAndroid Build Coastguard Worker    request.payload.body = [NSMutableData dataWithLength:SMALL_PAYLOAD_SIZE];
873*cc02d7e2SAndroid Build Coastguard Worker
874*cc02d7e2SAndroid Build Coastguard Worker    [GRPCCall enableOpBatchLog:YES];
875*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
876*cc02d7e2SAndroid Build Coastguard Worker    [service unaryCallWithRequest:request
877*cc02d7e2SAndroid Build Coastguard Worker                          handler:^(RMTSimpleResponse *response, NSError *error) {
878*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
879*cc02d7e2SAndroid Build Coastguard Worker                              return;
880*cc02d7e2SAndroid Build Coastguard Worker                            }
881*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertNil(error, @"Finished with unexpected error: %@", error);
882*cc02d7e2SAndroid Build Coastguard Worker
883*cc02d7e2SAndroid Build Coastguard Worker                            RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message];
884*cc02d7e2SAndroid Build Coastguard Worker                            expectedResponse.payload.type = RMTPayloadType_Compressable;
885*cc02d7e2SAndroid Build Coastguard Worker                            expectedResponse.payload.body = [NSMutableData dataWithLength:10];
886*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertEqualObjects(response, expectedResponse);
887*cc02d7e2SAndroid Build Coastguard Worker
888*cc02d7e2SAndroid Build Coastguard Worker                            // The test is a success if there is a batch of exactly 3 ops
889*cc02d7e2SAndroid Build Coastguard Worker                            // (SEND_INITIAL_METADATA, SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT).
890*cc02d7e2SAndroid Build Coastguard Worker                            // Without packet coalescing each batch of ops contains only one op.
891*cc02d7e2SAndroid Build Coastguard Worker                            NSArray *opBatches = [GRPCCall obtainAndCleanOpBatchLog];
892*cc02d7e2SAndroid Build Coastguard Worker                            const NSInteger kExpectedOpBatchSize = 3;
893*cc02d7e2SAndroid Build Coastguard Worker                            for (NSObject *o in opBatches) {
894*cc02d7e2SAndroid Build Coastguard Worker                              if ([o isKindOfClass:[NSArray class]]) {
895*cc02d7e2SAndroid Build Coastguard Worker                                NSArray *batch = (NSArray *)o;
896*cc02d7e2SAndroid Build Coastguard Worker                                if ([batch count] == kExpectedOpBatchSize) {
897*cc02d7e2SAndroid Build Coastguard Worker                                  [expectation fulfill];
898*cc02d7e2SAndroid Build Coastguard Worker                                  break;
899*cc02d7e2SAndroid Build Coastguard Worker                                }
900*cc02d7e2SAndroid Build Coastguard Worker                              }
901*cc02d7e2SAndroid Build Coastguard Worker                            }
902*cc02d7e2SAndroid Build Coastguard Worker                          }];
903*cc02d7e2SAndroid Build Coastguard Worker
904*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
905*cc02d7e2SAndroid Build Coastguard Worker    [GRPCCall enableOpBatchLog:NO];
906*cc02d7e2SAndroid Build Coastguard Worker  });
907*cc02d7e2SAndroid Build Coastguard Worker}
908*cc02d7e2SAndroid Build Coastguard Worker
909*cc02d7e2SAndroid Build Coastguard Worker- (void)test4MBResponsesAreAccepted {
910*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
911*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
912*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"];
913*cc02d7e2SAndroid Build Coastguard Worker
914*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
915*cc02d7e2SAndroid Build Coastguard Worker    const int32_t kPayloadSize =
916*cc02d7e2SAndroid Build Coastguard Worker        4 * 1024 * 1024 - self.encodingOverhead;  // 4MB - encoding overhead
917*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = kPayloadSize;
918*cc02d7e2SAndroid Build Coastguard Worker
919*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
920*cc02d7e2SAndroid Build Coastguard Worker    [service unaryCallWithRequest:request
921*cc02d7e2SAndroid Build Coastguard Worker                          handler:^(RMTSimpleResponse *response, NSError *error) {
922*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
923*cc02d7e2SAndroid Build Coastguard Worker                              return;
924*cc02d7e2SAndroid Build Coastguard Worker                            }
925*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertNil(error, @"Finished with unexpected error: %@", error);
926*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertEqual(response.payload.body.length, kPayloadSize);
927*cc02d7e2SAndroid Build Coastguard Worker                            [expectation fulfill];
928*cc02d7e2SAndroid Build Coastguard Worker                          }];
929*cc02d7e2SAndroid Build Coastguard Worker
930*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
931*cc02d7e2SAndroid Build Coastguard Worker  });
932*cc02d7e2SAndroid Build Coastguard Worker}
933*cc02d7e2SAndroid Build Coastguard Worker
934*cc02d7e2SAndroid Build Coastguard Worker- (void)testResponsesOverMaxSizeFailWithActionableMessage {
935*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
936*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
937*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
938*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"ResponseOverMaxSize"];
939*cc02d7e2SAndroid Build Coastguard Worker
940*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
941*cc02d7e2SAndroid Build Coastguard Worker    const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead + 1;  // 1B over max size
942*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = kPayloadSize;
943*cc02d7e2SAndroid Build Coastguard Worker
944*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
945*cc02d7e2SAndroid Build Coastguard Worker    [service unaryCallWithRequest:request
946*cc02d7e2SAndroid Build Coastguard Worker                          handler:^(RMTSimpleResponse *response, NSError *error) {
947*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
948*cc02d7e2SAndroid Build Coastguard Worker                              return;
949*cc02d7e2SAndroid Build Coastguard Worker                            }
950*cc02d7e2SAndroid Build Coastguard Worker                            // TODO(jcanizales): Catch the error and rethrow it with an
951*cc02d7e2SAndroid Build Coastguard Worker                            // actionable message:
952*cc02d7e2SAndroid Build Coastguard Worker                            // - Use +[GRPCCall setResponseSizeLimit:forHost:] to set a
953*cc02d7e2SAndroid Build Coastguard Worker                            // higher limit.
954*cc02d7e2SAndroid Build Coastguard Worker                            // - If you're developing the server, consider using response
955*cc02d7e2SAndroid Build Coastguard Worker                            // streaming, or let clients filter
956*cc02d7e2SAndroid Build Coastguard Worker                            //   responses by setting a google.protobuf.FieldMask in the
957*cc02d7e2SAndroid Build Coastguard Worker                            //   request:
958*cc02d7e2SAndroid Build Coastguard Worker                            //   https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/field_mask.proto
959*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertEqualObjects(
960*cc02d7e2SAndroid Build Coastguard Worker                                error.localizedDescription,
961*cc02d7e2SAndroid Build Coastguard Worker                                @"CLIENT: Received message larger than max (4194305 vs. 4194304)");
962*cc02d7e2SAndroid Build Coastguard Worker                            [expectation fulfill];
963*cc02d7e2SAndroid Build Coastguard Worker                          }];
964*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
965*cc02d7e2SAndroid Build Coastguard Worker  });
966*cc02d7e2SAndroid Build Coastguard Worker}
967*cc02d7e2SAndroid Build Coastguard Worker
968*cc02d7e2SAndroid Build Coastguard Worker- (void)testResponsesOver4MBAreAcceptedIfOptedIn {
969*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
970*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
971*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
972*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"HigherResponseSizeLimit"];
973*cc02d7e2SAndroid Build Coastguard Worker    __block NSError *callError = nil;
974*cc02d7e2SAndroid Build Coastguard Worker
975*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
976*cc02d7e2SAndroid Build Coastguard Worker    const size_t kPayloadSize = 5 * 1024 * 1024;  // 5MB
977*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = kPayloadSize;
978*cc02d7e2SAndroid Build Coastguard Worker
979*cc02d7e2SAndroid Build Coastguard Worker    [GRPCCall setResponseSizeLimit:6 * 1024 * 1024 forHost:[[self class] host]];
980*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
981*cc02d7e2SAndroid Build Coastguard Worker    [service unaryCallWithRequest:request
982*cc02d7e2SAndroid Build Coastguard Worker                          handler:^(RMTSimpleResponse *response, NSError *error) {
983*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
984*cc02d7e2SAndroid Build Coastguard Worker                              return;
985*cc02d7e2SAndroid Build Coastguard Worker                            }
986*cc02d7e2SAndroid Build Coastguard Worker                            callError = error;
987*cc02d7e2SAndroid Build Coastguard Worker                            [expectation fulfill];
988*cc02d7e2SAndroid Build Coastguard Worker                          }];
989*cc02d7e2SAndroid Build Coastguard Worker
990*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
991*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertNil(callError, @"Finished with unexpected error: %@", callError);
992*cc02d7e2SAndroid Build Coastguard Worker  });
993*cc02d7e2SAndroid Build Coastguard Worker}
994*cc02d7e2SAndroid Build Coastguard Worker
995*cc02d7e2SAndroid Build Coastguard Worker- (void)testClientStreamingRPC {
996*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
997*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
998*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ClientStreaming"];
999*cc02d7e2SAndroid Build Coastguard Worker
1000*cc02d7e2SAndroid Build Coastguard Worker    RMTStreamingInputCallRequest *request1 = [RMTStreamingInputCallRequest message];
1001*cc02d7e2SAndroid Build Coastguard Worker    request1.payload.body = [NSMutableData dataWithLength:27182];
1002*cc02d7e2SAndroid Build Coastguard Worker
1003*cc02d7e2SAndroid Build Coastguard Worker    RMTStreamingInputCallRequest *request2 = [RMTStreamingInputCallRequest message];
1004*cc02d7e2SAndroid Build Coastguard Worker    request2.payload.body = [NSMutableData dataWithLength:8];
1005*cc02d7e2SAndroid Build Coastguard Worker
1006*cc02d7e2SAndroid Build Coastguard Worker    RMTStreamingInputCallRequest *request3 = [RMTStreamingInputCallRequest message];
1007*cc02d7e2SAndroid Build Coastguard Worker    request3.payload.body = [NSMutableData dataWithLength:1828];
1008*cc02d7e2SAndroid Build Coastguard Worker
1009*cc02d7e2SAndroid Build Coastguard Worker    RMTStreamingInputCallRequest *request4 = [RMTStreamingInputCallRequest message];
1010*cc02d7e2SAndroid Build Coastguard Worker    request4.payload.body = [NSMutableData dataWithLength:45904];
1011*cc02d7e2SAndroid Build Coastguard Worker
1012*cc02d7e2SAndroid Build Coastguard Worker    GRXWriter *writer = [GRXWriter writerWithContainer:@[ request1, request2, request3, request4 ]];
1013*cc02d7e2SAndroid Build Coastguard Worker
1014*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1015*cc02d7e2SAndroid Build Coastguard Worker    [service
1016*cc02d7e2SAndroid Build Coastguard Worker        streamingInputCallWithRequestsWriter:writer
1017*cc02d7e2SAndroid Build Coastguard Worker                                     handler:^(RMTStreamingInputCallResponse *response,
1018*cc02d7e2SAndroid Build Coastguard Worker                                               NSError *error) {
1019*cc02d7e2SAndroid Build Coastguard Worker                                       if (weakService == nil) {
1020*cc02d7e2SAndroid Build Coastguard Worker                                         return;
1021*cc02d7e2SAndroid Build Coastguard Worker                                       }
1022*cc02d7e2SAndroid Build Coastguard Worker                                       XCTAssertNil(error, @"Finished with unexpected error: %@",
1023*cc02d7e2SAndroid Build Coastguard Worker                                                    error);
1024*cc02d7e2SAndroid Build Coastguard Worker
1025*cc02d7e2SAndroid Build Coastguard Worker                                       RMTStreamingInputCallResponse *expectedResponse =
1026*cc02d7e2SAndroid Build Coastguard Worker                                           [RMTStreamingInputCallResponse message];
1027*cc02d7e2SAndroid Build Coastguard Worker                                       expectedResponse.aggregatedPayloadSize = 74922;
1028*cc02d7e2SAndroid Build Coastguard Worker                                       XCTAssertEqualObjects(response, expectedResponse);
1029*cc02d7e2SAndroid Build Coastguard Worker
1030*cc02d7e2SAndroid Build Coastguard Worker                                       [expectation fulfill];
1031*cc02d7e2SAndroid Build Coastguard Worker                                     }];
1032*cc02d7e2SAndroid Build Coastguard Worker
1033*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1034*cc02d7e2SAndroid Build Coastguard Worker  });
1035*cc02d7e2SAndroid Build Coastguard Worker}
1036*cc02d7e2SAndroid Build Coastguard Worker
1037*cc02d7e2SAndroid Build Coastguard Worker- (void)testServerStreamingRPC {
1038*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1039*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1040*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ServerStreaming"];
1041*cc02d7e2SAndroid Build Coastguard Worker
1042*cc02d7e2SAndroid Build Coastguard Worker    NSArray *expectedSizes = @[ @31415, @9, @2653, @58979 ];
1043*cc02d7e2SAndroid Build Coastguard Worker
1044*cc02d7e2SAndroid Build Coastguard Worker    RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
1045*cc02d7e2SAndroid Build Coastguard Worker    for (NSNumber *size in expectedSizes) {
1046*cc02d7e2SAndroid Build Coastguard Worker      RMTResponseParameters *parameters = [RMTResponseParameters message];
1047*cc02d7e2SAndroid Build Coastguard Worker      parameters.size = [size intValue];
1048*cc02d7e2SAndroid Build Coastguard Worker      [request.responseParametersArray addObject:parameters];
1049*cc02d7e2SAndroid Build Coastguard Worker    }
1050*cc02d7e2SAndroid Build Coastguard Worker
1051*cc02d7e2SAndroid Build Coastguard Worker    __block int index = 0;
1052*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1053*cc02d7e2SAndroid Build Coastguard Worker    [service
1054*cc02d7e2SAndroid Build Coastguard Worker        streamingOutputCallWithRequest:request
1055*cc02d7e2SAndroid Build Coastguard Worker                          eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response,
1056*cc02d7e2SAndroid Build Coastguard Worker                                         NSError *error) {
1057*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
1058*cc02d7e2SAndroid Build Coastguard Worker                              return;
1059*cc02d7e2SAndroid Build Coastguard Worker                            }
1060*cc02d7e2SAndroid Build Coastguard Worker
1061*cc02d7e2SAndroid Build Coastguard Worker                            assertBlock(
1062*cc02d7e2SAndroid Build Coastguard Worker                                error == nil,
1063*cc02d7e2SAndroid Build Coastguard Worker                                [NSString
1064*cc02d7e2SAndroid Build Coastguard Worker                                    stringWithFormat:@"Finished with unexpected error: %@", error]);
1065*cc02d7e2SAndroid Build Coastguard Worker                            assertBlock(done || response,
1066*cc02d7e2SAndroid Build Coastguard Worker                                        @"Event handler called without an event.");
1067*cc02d7e2SAndroid Build Coastguard Worker
1068*cc02d7e2SAndroid Build Coastguard Worker                            if (response) {
1069*cc02d7e2SAndroid Build Coastguard Worker                              assertBlock(index < 4, @"More than 4 responses received.");
1070*cc02d7e2SAndroid Build Coastguard Worker
1071*cc02d7e2SAndroid Build Coastguard Worker                              id expected = [RMTStreamingOutputCallResponse
1072*cc02d7e2SAndroid Build Coastguard Worker                                  messageWithPayloadSize:expectedSizes[index]];
1073*cc02d7e2SAndroid Build Coastguard Worker                              assertBlock(
1074*cc02d7e2SAndroid Build Coastguard Worker                                  [response isEqual:expected],
1075*cc02d7e2SAndroid Build Coastguard Worker                                  [NSString
1076*cc02d7e2SAndroid Build Coastguard Worker                                      stringWithFormat:@"response %@ not equal to expected %@",
1077*cc02d7e2SAndroid Build Coastguard Worker                                                       response, expected]);
1078*cc02d7e2SAndroid Build Coastguard Worker
1079*cc02d7e2SAndroid Build Coastguard Worker                              index += 1;
1080*cc02d7e2SAndroid Build Coastguard Worker                            }
1081*cc02d7e2SAndroid Build Coastguard Worker
1082*cc02d7e2SAndroid Build Coastguard Worker                            if (done) {
1083*cc02d7e2SAndroid Build Coastguard Worker                              assertBlock(
1084*cc02d7e2SAndroid Build Coastguard Worker                                  index == 4,
1085*cc02d7e2SAndroid Build Coastguard Worker                                  [NSString stringWithFormat:@"Received %@ responses instead of 4.",
1086*cc02d7e2SAndroid Build Coastguard Worker                                                             @(index)]);
1087*cc02d7e2SAndroid Build Coastguard Worker                              [expectation fulfill];
1088*cc02d7e2SAndroid Build Coastguard Worker                            }
1089*cc02d7e2SAndroid Build Coastguard Worker                          }];
1090*cc02d7e2SAndroid Build Coastguard Worker
1091*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1092*cc02d7e2SAndroid Build Coastguard Worker  });
1093*cc02d7e2SAndroid Build Coastguard Worker}
1094*cc02d7e2SAndroid Build Coastguard Worker
1095*cc02d7e2SAndroid Build Coastguard Worker- (void)testPingPongRPC {
1096*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1097*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1098*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPong"];
1099*cc02d7e2SAndroid Build Coastguard Worker
1100*cc02d7e2SAndroid Build Coastguard Worker    NSArray *requests = @[ @27182, @8, @1828, @45904 ];
1101*cc02d7e2SAndroid Build Coastguard Worker    NSArray *responses = @[ @31415, @9, @2653, @58979 ];
1102*cc02d7e2SAndroid Build Coastguard Worker
1103*cc02d7e2SAndroid Build Coastguard Worker    GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init];
1104*cc02d7e2SAndroid Build Coastguard Worker
1105*cc02d7e2SAndroid Build Coastguard Worker    __block int index = 0;
1106*cc02d7e2SAndroid Build Coastguard Worker
1107*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1108*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:responses[index]];
1109*cc02d7e2SAndroid Build Coastguard Worker    [requestsBuffer writeValue:request];
1110*cc02d7e2SAndroid Build Coastguard Worker
1111*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1112*cc02d7e2SAndroid Build Coastguard Worker    [service
1113*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithRequestsWriter:requestsBuffer
1114*cc02d7e2SAndroid Build Coastguard Worker                            eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response,
1115*cc02d7e2SAndroid Build Coastguard Worker                                           NSError *error) {
1116*cc02d7e2SAndroid Build Coastguard Worker                              if (weakService == nil) {
1117*cc02d7e2SAndroid Build Coastguard Worker                                return;
1118*cc02d7e2SAndroid Build Coastguard Worker                              }
1119*cc02d7e2SAndroid Build Coastguard Worker
1120*cc02d7e2SAndroid Build Coastguard Worker                              assertBlock(
1121*cc02d7e2SAndroid Build Coastguard Worker                                  error == nil,
1122*cc02d7e2SAndroid Build Coastguard Worker                                  [NSString stringWithFormat:@"Finished with unexpected error: %@",
1123*cc02d7e2SAndroid Build Coastguard Worker                                                             error]);
1124*cc02d7e2SAndroid Build Coastguard Worker                              assertBlock(done || response,
1125*cc02d7e2SAndroid Build Coastguard Worker                                          @"Event handler called without an event.");
1126*cc02d7e2SAndroid Build Coastguard Worker
1127*cc02d7e2SAndroid Build Coastguard Worker                              if (response) {
1128*cc02d7e2SAndroid Build Coastguard Worker                                assertBlock(index < 4, @"More than 4 responses received.");
1129*cc02d7e2SAndroid Build Coastguard Worker
1130*cc02d7e2SAndroid Build Coastguard Worker                                id expected = [RMTStreamingOutputCallResponse
1131*cc02d7e2SAndroid Build Coastguard Worker                                    messageWithPayloadSize:responses[index]];
1132*cc02d7e2SAndroid Build Coastguard Worker                                assertBlock(
1133*cc02d7e2SAndroid Build Coastguard Worker                                    [response isEqual:expected],
1134*cc02d7e2SAndroid Build Coastguard Worker                                    [NSString
1135*cc02d7e2SAndroid Build Coastguard Worker                                        stringWithFormat:@"response %@ not equal to expected %@",
1136*cc02d7e2SAndroid Build Coastguard Worker                                                         response, expected]);
1137*cc02d7e2SAndroid Build Coastguard Worker
1138*cc02d7e2SAndroid Build Coastguard Worker                                index += 1;
1139*cc02d7e2SAndroid Build Coastguard Worker                                if (index < 4) {
1140*cc02d7e2SAndroid Build Coastguard Worker                                  id request = [RMTStreamingOutputCallRequest
1141*cc02d7e2SAndroid Build Coastguard Worker                                      messageWithPayloadSize:requests[index]
1142*cc02d7e2SAndroid Build Coastguard Worker                                       requestedResponseSize:responses[index]];
1143*cc02d7e2SAndroid Build Coastguard Worker                                  [requestsBuffer writeValue:request];
1144*cc02d7e2SAndroid Build Coastguard Worker                                } else {
1145*cc02d7e2SAndroid Build Coastguard Worker                                  [requestsBuffer writesFinishedWithError:nil];
1146*cc02d7e2SAndroid Build Coastguard Worker                                }
1147*cc02d7e2SAndroid Build Coastguard Worker                              }
1148*cc02d7e2SAndroid Build Coastguard Worker
1149*cc02d7e2SAndroid Build Coastguard Worker                              if (done) {
1150*cc02d7e2SAndroid Build Coastguard Worker                                assertBlock(
1151*cc02d7e2SAndroid Build Coastguard Worker                                    index == 4,
1152*cc02d7e2SAndroid Build Coastguard Worker                                    [NSString
1153*cc02d7e2SAndroid Build Coastguard Worker                                        stringWithFormat:@"Received %@ responses instead of 4.",
1154*cc02d7e2SAndroid Build Coastguard Worker                                                         @(index)]);
1155*cc02d7e2SAndroid Build Coastguard Worker                                [expectation fulfill];
1156*cc02d7e2SAndroid Build Coastguard Worker                              }
1157*cc02d7e2SAndroid Build Coastguard Worker                            }];
1158*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1159*cc02d7e2SAndroid Build Coastguard Worker  });
1160*cc02d7e2SAndroid Build Coastguard Worker}
1161*cc02d7e2SAndroid Build Coastguard Worker
1162*cc02d7e2SAndroid Build Coastguard Worker- (void)testPingPongRPCWithV2API {
1163*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1164*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1165*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPongWithV2API"];
1166*cc02d7e2SAndroid Build Coastguard Worker
1167*cc02d7e2SAndroid Build Coastguard Worker    NSArray *requests = @[ @27182, @8, @1828, @45904 ];
1168*cc02d7e2SAndroid Build Coastguard Worker    NSArray *responses = @[ @31415, @9, @2653, @58979 ];
1169*cc02d7e2SAndroid Build Coastguard Worker
1170*cc02d7e2SAndroid Build Coastguard Worker    __block int index = 0;
1171*cc02d7e2SAndroid Build Coastguard Worker
1172*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1173*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:responses[index]];
1174*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
1175*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
1176*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
1177*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
1178*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
1179*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
1180*cc02d7e2SAndroid Build Coastguard Worker
1181*cc02d7e2SAndroid Build Coastguard Worker    __weak __block GRPCStreamingProtoCall *weakCall;
1182*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1183*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:
1184*cc02d7e2SAndroid Build Coastguard Worker            [[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
1185*cc02d7e2SAndroid Build Coastguard Worker                messageCallback:^(id message) {
1186*cc02d7e2SAndroid Build Coastguard Worker                  GRPCStreamingProtoCall *localCall = weakCall;
1187*cc02d7e2SAndroid Build Coastguard Worker                  if (localCall == nil) {
1188*cc02d7e2SAndroid Build Coastguard Worker                    return;
1189*cc02d7e2SAndroid Build Coastguard Worker                  }
1190*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(index < 4, @"More than 4 responses received.");
1191*cc02d7e2SAndroid Build Coastguard Worker
1192*cc02d7e2SAndroid Build Coastguard Worker                  id expected =
1193*cc02d7e2SAndroid Build Coastguard Worker                      [RMTStreamingOutputCallResponse messageWithPayloadSize:responses[index]];
1194*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock([message isEqual:expected],
1195*cc02d7e2SAndroid Build Coastguard Worker                              [NSString stringWithFormat:@"message %@ not equal to expected %@",
1196*cc02d7e2SAndroid Build Coastguard Worker                                                         message, expected]);
1197*cc02d7e2SAndroid Build Coastguard Worker                  index += 1;
1198*cc02d7e2SAndroid Build Coastguard Worker                  if (index < 4) {
1199*cc02d7e2SAndroid Build Coastguard Worker                    id request =
1200*cc02d7e2SAndroid Build Coastguard Worker                        [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1201*cc02d7e2SAndroid Build Coastguard Worker                                                        requestedResponseSize:responses[index]];
1202*cc02d7e2SAndroid Build Coastguard Worker                    [localCall writeMessage:request];
1203*cc02d7e2SAndroid Build Coastguard Worker                  } else {
1204*cc02d7e2SAndroid Build Coastguard Worker                    [localCall finish];
1205*cc02d7e2SAndroid Build Coastguard Worker                  }
1206*cc02d7e2SAndroid Build Coastguard Worker                }
1207*cc02d7e2SAndroid Build Coastguard Worker                closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
1208*cc02d7e2SAndroid Build Coastguard Worker                  if (weakCall == nil) {
1209*cc02d7e2SAndroid Build Coastguard Worker                    return;
1210*cc02d7e2SAndroid Build Coastguard Worker                  }
1211*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1212*cc02d7e2SAndroid Build Coastguard Worker                      error == nil,
1213*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Finished with unexpected error: %@", error]);
1214*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1215*cc02d7e2SAndroid Build Coastguard Worker                      index == 4,
1216*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Received %@ responses instead of 4.", @(index)]);
1217*cc02d7e2SAndroid Build Coastguard Worker                  [expectation fulfill];
1218*cc02d7e2SAndroid Build Coastguard Worker                }]
1219*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
1220*cc02d7e2SAndroid Build Coastguard Worker    weakCall = call;
1221*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1222*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
1223*cc02d7e2SAndroid Build Coastguard Worker
1224*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1225*cc02d7e2SAndroid Build Coastguard Worker  });
1226*cc02d7e2SAndroid Build Coastguard Worker}
1227*cc02d7e2SAndroid Build Coastguard Worker
1228*cc02d7e2SAndroid Build Coastguard Worker- (void)testPingPongRPCWithFlowControl {
1229*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1230*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1231*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPongWithV2API"];
1232*cc02d7e2SAndroid Build Coastguard Worker
1233*cc02d7e2SAndroid Build Coastguard Worker    NSArray *requests = @[ @27182, @8, @1828, @45904 ];
1234*cc02d7e2SAndroid Build Coastguard Worker    NSArray *responses = @[ @31415, @9, @2653, @58979 ];
1235*cc02d7e2SAndroid Build Coastguard Worker
1236*cc02d7e2SAndroid Build Coastguard Worker    __block int index = 0;
1237*cc02d7e2SAndroid Build Coastguard Worker
1238*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1239*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:responses[index]];
1240*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
1241*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
1242*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
1243*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
1244*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
1245*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
1246*cc02d7e2SAndroid Build Coastguard Worker    options.flowControlEnabled = YES;
1247*cc02d7e2SAndroid Build Coastguard Worker    __block int writeMessageCount = 0;
1248*cc02d7e2SAndroid Build Coastguard Worker
1249*cc02d7e2SAndroid Build Coastguard Worker    __weak __block GRPCStreamingProtoCall *weakCall;
1250*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1251*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:
1252*cc02d7e2SAndroid Build Coastguard Worker            [[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
1253*cc02d7e2SAndroid Build Coastguard Worker                messageCallback:^(id message) {
1254*cc02d7e2SAndroid Build Coastguard Worker                  GRPCStreamingProtoCall *localCall = weakCall;
1255*cc02d7e2SAndroid Build Coastguard Worker                  if (localCall == nil) {
1256*cc02d7e2SAndroid Build Coastguard Worker                    return;
1257*cc02d7e2SAndroid Build Coastguard Worker                  }
1258*cc02d7e2SAndroid Build Coastguard Worker
1259*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock((index < 4), @"More than 4 responses received.");
1260*cc02d7e2SAndroid Build Coastguard Worker                  id expected =
1261*cc02d7e2SAndroid Build Coastguard Worker                      [RMTStreamingOutputCallResponse messageWithPayloadSize:responses[index]];
1262*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1263*cc02d7e2SAndroid Build Coastguard Worker                      [message isEqual:expected],
1264*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"message %@ not equal to %@", message, expected]);
1265*cc02d7e2SAndroid Build Coastguard Worker
1266*cc02d7e2SAndroid Build Coastguard Worker                  index += 1;
1267*cc02d7e2SAndroid Build Coastguard Worker                  if (index < 4) {
1268*cc02d7e2SAndroid Build Coastguard Worker                    id request =
1269*cc02d7e2SAndroid Build Coastguard Worker                        [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1270*cc02d7e2SAndroid Build Coastguard Worker                                                        requestedResponseSize:responses[index]];
1271*cc02d7e2SAndroid Build Coastguard Worker                    [localCall writeMessage:request];
1272*cc02d7e2SAndroid Build Coastguard Worker                    [localCall receiveNextMessage];
1273*cc02d7e2SAndroid Build Coastguard Worker                  } else {
1274*cc02d7e2SAndroid Build Coastguard Worker                    [localCall finish];
1275*cc02d7e2SAndroid Build Coastguard Worker                  }
1276*cc02d7e2SAndroid Build Coastguard Worker                }
1277*cc02d7e2SAndroid Build Coastguard Worker                closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
1278*cc02d7e2SAndroid Build Coastguard Worker                  if (weakCall == nil) {
1279*cc02d7e2SAndroid Build Coastguard Worker                    return;
1280*cc02d7e2SAndroid Build Coastguard Worker                  }
1281*cc02d7e2SAndroid Build Coastguard Worker
1282*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1283*cc02d7e2SAndroid Build Coastguard Worker                      error == nil,
1284*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Finished with unexpected error: %@", error]);
1285*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1286*cc02d7e2SAndroid Build Coastguard Worker                      index == 4,
1287*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Received %i responses instead of 4.", index]);
1288*cc02d7e2SAndroid Build Coastguard Worker                  [expectation fulfill];
1289*cc02d7e2SAndroid Build Coastguard Worker                }
1290*cc02d7e2SAndroid Build Coastguard Worker                writeMessageCallback:^{
1291*cc02d7e2SAndroid Build Coastguard Worker                  writeMessageCount++;
1292*cc02d7e2SAndroid Build Coastguard Worker                }]
1293*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
1294*cc02d7e2SAndroid Build Coastguard Worker    weakCall = call;
1295*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1296*cc02d7e2SAndroid Build Coastguard Worker    [call receiveNextMessage];
1297*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
1298*cc02d7e2SAndroid Build Coastguard Worker
1299*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1300*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(
1301*cc02d7e2SAndroid Build Coastguard Worker        writeMessageCount == 4,
1302*cc02d7e2SAndroid Build Coastguard Worker        [NSString stringWithFormat:@"writeMessageCount %@ not equal to 4", @(writeMessageCount)]);
1303*cc02d7e2SAndroid Build Coastguard Worker  });
1304*cc02d7e2SAndroid Build Coastguard Worker}
1305*cc02d7e2SAndroid Build Coastguard Worker
1306*cc02d7e2SAndroid Build Coastguard Worker- (void)testEmptyStreamRPC {
1307*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1308*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1309*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyStream"];
1310*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1311*cc02d7e2SAndroid Build Coastguard Worker    [service
1312*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithRequestsWriter:[GRXWriter emptyWriter]
1313*cc02d7e2SAndroid Build Coastguard Worker                            eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response,
1314*cc02d7e2SAndroid Build Coastguard Worker                                           NSError *error) {
1315*cc02d7e2SAndroid Build Coastguard Worker                              if (weakService == nil) {
1316*cc02d7e2SAndroid Build Coastguard Worker                                return;
1317*cc02d7e2SAndroid Build Coastguard Worker                              }
1318*cc02d7e2SAndroid Build Coastguard Worker                              XCTAssertNil(error, @"Finished with unexpected error: %@", error);
1319*cc02d7e2SAndroid Build Coastguard Worker                              XCTAssert(done, @"Unexpected response: %@", response);
1320*cc02d7e2SAndroid Build Coastguard Worker                              [expectation fulfill];
1321*cc02d7e2SAndroid Build Coastguard Worker                            }];
1322*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1323*cc02d7e2SAndroid Build Coastguard Worker  });
1324*cc02d7e2SAndroid Build Coastguard Worker}
1325*cc02d7e2SAndroid Build Coastguard Worker
1326*cc02d7e2SAndroid Build Coastguard Worker- (void)testCancelAfterBeginRPC {
1327*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1328*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1329*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBegin"];
1330*cc02d7e2SAndroid Build Coastguard Worker
1331*cc02d7e2SAndroid Build Coastguard Worker    // A buffered pipe to which we never write any value acts as a writer that just hangs.
1332*cc02d7e2SAndroid Build Coastguard Worker    GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init];
1333*cc02d7e2SAndroid Build Coastguard Worker
1334*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1335*cc02d7e2SAndroid Build Coastguard Worker    GRPCProtoCall *call = [service
1336*cc02d7e2SAndroid Build Coastguard Worker        RPCToStreamingInputCallWithRequestsWriter:requestsBuffer
1337*cc02d7e2SAndroid Build Coastguard Worker                                          handler:^(RMTStreamingInputCallResponse *response,
1338*cc02d7e2SAndroid Build Coastguard Worker                                                    NSError *error) {
1339*cc02d7e2SAndroid Build Coastguard Worker                                            if (weakService == nil) {
1340*cc02d7e2SAndroid Build Coastguard Worker                                              return;
1341*cc02d7e2SAndroid Build Coastguard Worker                                            }
1342*cc02d7e2SAndroid Build Coastguard Worker                                            XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
1343*cc02d7e2SAndroid Build Coastguard Worker                                            [expectation fulfill];
1344*cc02d7e2SAndroid Build Coastguard Worker                                          }];
1345*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertEqual(call.state, GRXWriterStateNotStarted);
1346*cc02d7e2SAndroid Build Coastguard Worker
1347*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1348*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertEqual(call.state, GRXWriterStateStarted);
1349*cc02d7e2SAndroid Build Coastguard Worker
1350*cc02d7e2SAndroid Build Coastguard Worker    [call cancel];
1351*cc02d7e2SAndroid Build Coastguard Worker    XCTAssertEqual(call.state, GRXWriterStateFinished);
1352*cc02d7e2SAndroid Build Coastguard Worker
1353*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1354*cc02d7e2SAndroid Build Coastguard Worker  });
1355*cc02d7e2SAndroid Build Coastguard Worker}
1356*cc02d7e2SAndroid Build Coastguard Worker
1357*cc02d7e2SAndroid Build Coastguard Worker- (void)testCancelAfterBeginRPCWithV2API {
1358*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1359*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1360*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
1361*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"CancelAfterBeginWithV2API"];
1362*cc02d7e2SAndroid Build Coastguard Worker
1363*cc02d7e2SAndroid Build Coastguard Worker    // A buffered pipe to which we never write any value acts as a writer that just hangs.
1364*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1365*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1366*cc02d7e2SAndroid Build Coastguard Worker        streamingInputCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
1367*cc02d7e2SAndroid Build Coastguard Worker                                                  initWithInitialMetadataCallback:nil
1368*cc02d7e2SAndroid Build Coastguard Worker                                                  messageCallback:^(id message) {
1369*cc02d7e2SAndroid Build Coastguard Worker                                                    if (weakService == nil) {
1370*cc02d7e2SAndroid Build Coastguard Worker                                                      return;
1371*cc02d7e2SAndroid Build Coastguard Worker                                                    }
1372*cc02d7e2SAndroid Build Coastguard Worker                                                    XCTFail(@"Not expected to receive message");
1373*cc02d7e2SAndroid Build Coastguard Worker                                                  }
1374*cc02d7e2SAndroid Build Coastguard Worker                                                  closeCallback:^(NSDictionary *trailingMetadata,
1375*cc02d7e2SAndroid Build Coastguard Worker                                                                  NSError *error) {
1376*cc02d7e2SAndroid Build Coastguard Worker                                                    if (weakService == nil) {
1377*cc02d7e2SAndroid Build Coastguard Worker                                                      return;
1378*cc02d7e2SAndroid Build Coastguard Worker                                                    }
1379*cc02d7e2SAndroid Build Coastguard Worker                                                    XCTAssertEqual(error.code,
1380*cc02d7e2SAndroid Build Coastguard Worker                                                                   GRPC_STATUS_CANCELLED);
1381*cc02d7e2SAndroid Build Coastguard Worker                                                    [expectation fulfill];
1382*cc02d7e2SAndroid Build Coastguard Worker                                                  }]
1383*cc02d7e2SAndroid Build Coastguard Worker                                  callOptions:nil];
1384*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1385*cc02d7e2SAndroid Build Coastguard Worker    [call cancel];
1386*cc02d7e2SAndroid Build Coastguard Worker
1387*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1388*cc02d7e2SAndroid Build Coastguard Worker  });
1389*cc02d7e2SAndroid Build Coastguard Worker}
1390*cc02d7e2SAndroid Build Coastguard Worker
1391*cc02d7e2SAndroid Build Coastguard Worker- (void)testCancelAfterFirstResponseRPC {
1392*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1393*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1394*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
1395*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"CancelAfterFirstResponse"];
1396*cc02d7e2SAndroid Build Coastguard Worker
1397*cc02d7e2SAndroid Build Coastguard Worker    // A buffered pipe to which we write a single value but never close
1398*cc02d7e2SAndroid Build Coastguard Worker    GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init];
1399*cc02d7e2SAndroid Build Coastguard Worker
1400*cc02d7e2SAndroid Build Coastguard Worker    __block BOOL receivedResponse = NO;
1401*cc02d7e2SAndroid Build Coastguard Worker
1402*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782
1403*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:@31415];
1404*cc02d7e2SAndroid Build Coastguard Worker
1405*cc02d7e2SAndroid Build Coastguard Worker    [requestsBuffer writeValue:request];
1406*cc02d7e2SAndroid Build Coastguard Worker
1407*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1408*cc02d7e2SAndroid Build Coastguard Worker    __block GRPCProtoCall *call = [service
1409*cc02d7e2SAndroid Build Coastguard Worker        RPCToFullDuplexCallWithRequestsWriter:requestsBuffer
1410*cc02d7e2SAndroid Build Coastguard Worker                                 eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response,
1411*cc02d7e2SAndroid Build Coastguard Worker                                                NSError *error) {
1412*cc02d7e2SAndroid Build Coastguard Worker                                   if (weakService == nil) {
1413*cc02d7e2SAndroid Build Coastguard Worker                                     return;
1414*cc02d7e2SAndroid Build Coastguard Worker                                   }
1415*cc02d7e2SAndroid Build Coastguard Worker                                   if (receivedResponse) {
1416*cc02d7e2SAndroid Build Coastguard Worker                                     XCTAssert(done, @"Unexpected extra response %@", response);
1417*cc02d7e2SAndroid Build Coastguard Worker                                     XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
1418*cc02d7e2SAndroid Build Coastguard Worker                                     [expectation fulfill];
1419*cc02d7e2SAndroid Build Coastguard Worker                                   } else {
1420*cc02d7e2SAndroid Build Coastguard Worker                                     XCTAssertNil(error, @"Finished with unexpected error: %@",
1421*cc02d7e2SAndroid Build Coastguard Worker                                                  error);
1422*cc02d7e2SAndroid Build Coastguard Worker                                     XCTAssertFalse(done, @"Finished without response");
1423*cc02d7e2SAndroid Build Coastguard Worker                                     XCTAssertNotNil(response);
1424*cc02d7e2SAndroid Build Coastguard Worker                                     receivedResponse = YES;
1425*cc02d7e2SAndroid Build Coastguard Worker                                     [call cancel];
1426*cc02d7e2SAndroid Build Coastguard Worker                                   }
1427*cc02d7e2SAndroid Build Coastguard Worker                                 }];
1428*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1429*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1430*cc02d7e2SAndroid Build Coastguard Worker  });
1431*cc02d7e2SAndroid Build Coastguard Worker}
1432*cc02d7e2SAndroid Build Coastguard Worker
1433*cc02d7e2SAndroid Build Coastguard Worker- (void)testCancelAfterFirstResponseRPCWithV2API {
1434*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1435*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1436*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *completionExpectation =
1437*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"Call completed."];
1438*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *responseExpectation =
1439*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"Received response."];
1440*cc02d7e2SAndroid Build Coastguard Worker
1441*cc02d7e2SAndroid Build Coastguard Worker    __block BOOL receivedResponse = NO;
1442*cc02d7e2SAndroid Build Coastguard Worker
1443*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
1444*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
1445*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = self.class.transportType;
1446*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
1447*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = self.class.PEMRootCertificates;
1448*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
1449*cc02d7e2SAndroid Build Coastguard Worker
1450*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782
1451*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:@31415];
1452*cc02d7e2SAndroid Build Coastguard Worker
1453*cc02d7e2SAndroid Build Coastguard Worker    __weak __block GRPCStreamingProtoCall *weakCall;
1454*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1455*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
1456*cc02d7e2SAndroid Build Coastguard Worker                                              initWithInitialMetadataCallback:nil
1457*cc02d7e2SAndroid Build Coastguard Worker                                              messageCallback:^(id message) {
1458*cc02d7e2SAndroid Build Coastguard Worker                                                GRPCStreamingProtoCall *localCall = weakCall;
1459*cc02d7e2SAndroid Build Coastguard Worker                                                if (localCall == nil) {
1460*cc02d7e2SAndroid Build Coastguard Worker                                                  return;
1461*cc02d7e2SAndroid Build Coastguard Worker                                                }
1462*cc02d7e2SAndroid Build Coastguard Worker                                                XCTAssertFalse(receivedResponse);
1463*cc02d7e2SAndroid Build Coastguard Worker                                                receivedResponse = YES;
1464*cc02d7e2SAndroid Build Coastguard Worker                                                [localCall cancel];
1465*cc02d7e2SAndroid Build Coastguard Worker                                                [responseExpectation fulfill];
1466*cc02d7e2SAndroid Build Coastguard Worker                                              }
1467*cc02d7e2SAndroid Build Coastguard Worker                                              closeCallback:^(NSDictionary *trailingMetadata,
1468*cc02d7e2SAndroid Build Coastguard Worker                                                              NSError *error) {
1469*cc02d7e2SAndroid Build Coastguard Worker                                                if (weakCall == nil) {
1470*cc02d7e2SAndroid Build Coastguard Worker                                                  return;
1471*cc02d7e2SAndroid Build Coastguard Worker                                                }
1472*cc02d7e2SAndroid Build Coastguard Worker                                                XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
1473*cc02d7e2SAndroid Build Coastguard Worker                                                [completionExpectation fulfill];
1474*cc02d7e2SAndroid Build Coastguard Worker                                              }]
1475*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
1476*cc02d7e2SAndroid Build Coastguard Worker    weakCall = call;
1477*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1478*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
1479*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ completionExpectation, responseExpectation ], GRPCInteropTestTimeoutDefault);
1480*cc02d7e2SAndroid Build Coastguard Worker  });
1481*cc02d7e2SAndroid Build Coastguard Worker}
1482*cc02d7e2SAndroid Build Coastguard Worker
1483*cc02d7e2SAndroid Build Coastguard Worker- (void)testCancelAfterFirstRequestWithV2API {
1484*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1485*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1486*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *completionExpectation =
1487*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"Call completed."];
1488*cc02d7e2SAndroid Build Coastguard Worker
1489*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
1490*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
1491*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = self.class.transportType;
1492*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
1493*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = self.class.PEMRootCertificates;
1494*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
1495*cc02d7e2SAndroid Build Coastguard Worker
1496*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782
1497*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:@31415];
1498*cc02d7e2SAndroid Build Coastguard Worker
1499*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1500*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1501*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
1502*cc02d7e2SAndroid Build Coastguard Worker                                              initWithInitialMetadataCallback:nil
1503*cc02d7e2SAndroid Build Coastguard Worker                                              messageCallback:^(id message) {
1504*cc02d7e2SAndroid Build Coastguard Worker                                                if (weakService == nil) {
1505*cc02d7e2SAndroid Build Coastguard Worker                                                  return;
1506*cc02d7e2SAndroid Build Coastguard Worker                                                }
1507*cc02d7e2SAndroid Build Coastguard Worker                                                XCTFail(@"Received unexpected response.");
1508*cc02d7e2SAndroid Build Coastguard Worker                                              }
1509*cc02d7e2SAndroid Build Coastguard Worker                                              closeCallback:^(NSDictionary *trailingMetadata,
1510*cc02d7e2SAndroid Build Coastguard Worker                                                              NSError *error) {
1511*cc02d7e2SAndroid Build Coastguard Worker                                                if (weakService == nil) {
1512*cc02d7e2SAndroid Build Coastguard Worker                                                  return;
1513*cc02d7e2SAndroid Build Coastguard Worker                                                }
1514*cc02d7e2SAndroid Build Coastguard Worker                                                XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
1515*cc02d7e2SAndroid Build Coastguard Worker                                                [completionExpectation fulfill];
1516*cc02d7e2SAndroid Build Coastguard Worker                                              }]
1517*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
1518*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1519*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
1520*cc02d7e2SAndroid Build Coastguard Worker    [call cancel];
1521*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ completionExpectation ], GRPCInteropTestTimeoutDefault);
1522*cc02d7e2SAndroid Build Coastguard Worker  });
1523*cc02d7e2SAndroid Build Coastguard Worker}
1524*cc02d7e2SAndroid Build Coastguard Worker
1525*cc02d7e2SAndroid Build Coastguard Worker- (void)testRPCAfterClosingOpenConnections {
1526*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1527*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1528*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
1529*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"RPC after closing connection"];
1530*cc02d7e2SAndroid Build Coastguard Worker
1531*cc02d7e2SAndroid Build Coastguard Worker    GPBEmpty *request = [GPBEmpty message];
1532*cc02d7e2SAndroid Build Coastguard Worker
1533*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1534*cc02d7e2SAndroid Build Coastguard Worker    [service
1535*cc02d7e2SAndroid Build Coastguard Worker        emptyCallWithRequest:request
1536*cc02d7e2SAndroid Build Coastguard Worker                     handler:^(GPBEmpty *response, NSError *error) {
1537*cc02d7e2SAndroid Build Coastguard Worker                       if (weakService == nil) {
1538*cc02d7e2SAndroid Build Coastguard Worker                         return;
1539*cc02d7e2SAndroid Build Coastguard Worker                       }
1540*cc02d7e2SAndroid Build Coastguard Worker                       XCTAssertNil(error, @"First RPC finished with unexpected error: %@", error);
1541*cc02d7e2SAndroid Build Coastguard Worker
1542*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic push
1543*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Wdeprecated-declarations"
1544*cc02d7e2SAndroid Build Coastguard Worker                       [GRPCCall closeOpenConnections];
1545*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic pop
1546*cc02d7e2SAndroid Build Coastguard Worker
1547*cc02d7e2SAndroid Build Coastguard Worker                       [weakService
1548*cc02d7e2SAndroid Build Coastguard Worker                           emptyCallWithRequest:request
1549*cc02d7e2SAndroid Build Coastguard Worker                                        handler:^(GPBEmpty *response, NSError *error) {
1550*cc02d7e2SAndroid Build Coastguard Worker                                          XCTAssertNil(
1551*cc02d7e2SAndroid Build Coastguard Worker                                              error,
1552*cc02d7e2SAndroid Build Coastguard Worker                                              @"Second RPC finished with unexpected error: %@",
1553*cc02d7e2SAndroid Build Coastguard Worker                                              error);
1554*cc02d7e2SAndroid Build Coastguard Worker                                          [expectation fulfill];
1555*cc02d7e2SAndroid Build Coastguard Worker                                        }];
1556*cc02d7e2SAndroid Build Coastguard Worker                     }];
1557*cc02d7e2SAndroid Build Coastguard Worker
1558*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1559*cc02d7e2SAndroid Build Coastguard Worker  });
1560*cc02d7e2SAndroid Build Coastguard Worker}
1561*cc02d7e2SAndroid Build Coastguard Worker
1562*cc02d7e2SAndroid Build Coastguard Worker- (void)testCompressedUnaryRPC {
1563*cc02d7e2SAndroid Build Coastguard Worker  // This test needs to be disabled for remote test because interop server grpc-test
1564*cc02d7e2SAndroid Build Coastguard Worker  // does not support compression.
1565*cc02d7e2SAndroid Build Coastguard Worker  if (isRemoteInteropTest([[self class] host])) {
1566*cc02d7e2SAndroid Build Coastguard Worker    return;
1567*cc02d7e2SAndroid Build Coastguard Worker  }
1568*cc02d7e2SAndroid Build Coastguard Worker
1569*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1570*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1571*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"];
1572*cc02d7e2SAndroid Build Coastguard Worker
1573*cc02d7e2SAndroid Build Coastguard Worker    RMTSimpleRequest *request = [RMTSimpleRequest message];
1574*cc02d7e2SAndroid Build Coastguard Worker    request.responseType = RMTPayloadType_Compressable;
1575*cc02d7e2SAndroid Build Coastguard Worker    request.responseSize = LARGE_RESPONSE_PAYLOAD_SIZE;
1576*cc02d7e2SAndroid Build Coastguard Worker    request.payload.body = [NSMutableData dataWithLength:LARGE_REQUEST_PAYLOAD_SIZE];
1577*cc02d7e2SAndroid Build Coastguard Worker    request.expectCompressed.value = YES;
1578*cc02d7e2SAndroid Build Coastguard Worker    [GRPCCall setDefaultCompressMethod:GRPCCompressGzip forhost:[[self class] host]];
1579*cc02d7e2SAndroid Build Coastguard Worker
1580*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1581*cc02d7e2SAndroid Build Coastguard Worker    [service unaryCallWithRequest:request
1582*cc02d7e2SAndroid Build Coastguard Worker                          handler:^(RMTSimpleResponse *response, NSError *error) {
1583*cc02d7e2SAndroid Build Coastguard Worker                            if (weakService == nil) {
1584*cc02d7e2SAndroid Build Coastguard Worker                              return;
1585*cc02d7e2SAndroid Build Coastguard Worker                            }
1586*cc02d7e2SAndroid Build Coastguard Worker
1587*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertNil(error, @"Finished with unexpected error: %@", error);
1588*cc02d7e2SAndroid Build Coastguard Worker
1589*cc02d7e2SAndroid Build Coastguard Worker                            RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message];
1590*cc02d7e2SAndroid Build Coastguard Worker                            expectedResponse.payload.type = RMTPayloadType_Compressable;
1591*cc02d7e2SAndroid Build Coastguard Worker                            expectedResponse.payload.body =
1592*cc02d7e2SAndroid Build Coastguard Worker                                [NSMutableData dataWithLength:LARGE_RESPONSE_PAYLOAD_SIZE];
1593*cc02d7e2SAndroid Build Coastguard Worker                            XCTAssertEqualObjects(response, expectedResponse);
1594*cc02d7e2SAndroid Build Coastguard Worker
1595*cc02d7e2SAndroid Build Coastguard Worker                            [expectation fulfill];
1596*cc02d7e2SAndroid Build Coastguard Worker                          }];
1597*cc02d7e2SAndroid Build Coastguard Worker
1598*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1599*cc02d7e2SAndroid Build Coastguard Worker  });
1600*cc02d7e2SAndroid Build Coastguard Worker}
1601*cc02d7e2SAndroid Build Coastguard Worker
1602*cc02d7e2SAndroid Build Coastguard Worker// TODO(b/268379869): This test has a race and is flaky in any configurations. One possible way to
1603*cc02d7e2SAndroid Build Coastguard Worker// deflake this test is to find a way to disable ping ack on the interop server for this test case.
1604*cc02d7e2SAndroid Build Coastguard Worker- (void)testKeepaliveWithV2API {
1605*cc02d7e2SAndroid Build Coastguard Worker  return;
1606*cc02d7e2SAndroid Build Coastguard Worker
1607*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1608*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1609*cc02d7e2SAndroid Build Coastguard Worker    if ([[self class] transport] == gGRPCCoreCronetID) {
1610*cc02d7e2SAndroid Build Coastguard Worker      // Cronet does not support keepalive
1611*cc02d7e2SAndroid Build Coastguard Worker      return;
1612*cc02d7e2SAndroid Build Coastguard Worker    }
1613*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Keepalive"];
1614*cc02d7e2SAndroid Build Coastguard Worker
1615*cc02d7e2SAndroid Build Coastguard Worker    const NSTimeInterval kTestTimeout = 5;
1616*cc02d7e2SAndroid Build Coastguard Worker    NSNumber *kRequestSize = @27182;
1617*cc02d7e2SAndroid Build Coastguard Worker    NSNumber *kResponseSize = @31415;
1618*cc02d7e2SAndroid Build Coastguard Worker
1619*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:kRequestSize
1620*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:kResponseSize];
1621*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
1622*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
1623*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
1624*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
1625*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
1626*cc02d7e2SAndroid Build Coastguard Worker    options.keepaliveInterval = 1.5;
1627*cc02d7e2SAndroid Build Coastguard Worker    options.keepaliveTimeout = 0;
1628*cc02d7e2SAndroid Build Coastguard Worker
1629*cc02d7e2SAndroid Build Coastguard Worker    __weak RMTTestService *weakService = service;
1630*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1631*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:
1632*cc02d7e2SAndroid Build Coastguard Worker            [[InteropTestsBlockCallbacks alloc]
1633*cc02d7e2SAndroid Build Coastguard Worker                initWithInitialMetadataCallback:nil
1634*cc02d7e2SAndroid Build Coastguard Worker                                messageCallback:nil
1635*cc02d7e2SAndroid Build Coastguard Worker                                  closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
1636*cc02d7e2SAndroid Build Coastguard Worker                                    if (weakService == nil) {
1637*cc02d7e2SAndroid Build Coastguard Worker                                      return;
1638*cc02d7e2SAndroid Build Coastguard Worker                                    }
1639*cc02d7e2SAndroid Build Coastguard Worker                                    XCTAssertNotNil(error);
1640*cc02d7e2SAndroid Build Coastguard Worker                                    XCTAssertEqual(
1641*cc02d7e2SAndroid Build Coastguard Worker                                        error.code, GRPC_STATUS_UNAVAILABLE,
1642*cc02d7e2SAndroid Build Coastguard Worker                                        @"Received status %@ instead of UNAVAILABLE (14).",
1643*cc02d7e2SAndroid Build Coastguard Worker                                        @(error.code));
1644*cc02d7e2SAndroid Build Coastguard Worker                                    [expectation fulfill];
1645*cc02d7e2SAndroid Build Coastguard Worker                                  }]
1646*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
1647*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
1648*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1649*cc02d7e2SAndroid Build Coastguard Worker
1650*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], kTestTimeout);
1651*cc02d7e2SAndroid Build Coastguard Worker    [call finish];
1652*cc02d7e2SAndroid Build Coastguard Worker  });
1653*cc02d7e2SAndroid Build Coastguard Worker}
1654*cc02d7e2SAndroid Build Coastguard Worker
1655*cc02d7e2SAndroid Build Coastguard Worker- (void)testDefaultInterceptor {
1656*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1657*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1658*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
1659*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"testDefaultInterceptor"];
1660*cc02d7e2SAndroid Build Coastguard Worker
1661*cc02d7e2SAndroid Build Coastguard Worker    NSArray *requests = @[ @27182, @8, @1828, @45904 ];
1662*cc02d7e2SAndroid Build Coastguard Worker    NSArray *responses = @[ @31415, @9, @2653, @58979 ];
1663*cc02d7e2SAndroid Build Coastguard Worker
1664*cc02d7e2SAndroid Build Coastguard Worker    __block int index = 0;
1665*cc02d7e2SAndroid Build Coastguard Worker
1666*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1667*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:responses[index]];
1668*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
1669*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
1670*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
1671*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
1672*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
1673*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
1674*cc02d7e2SAndroid Build Coastguard Worker    options.interceptorFactories = @[ [[DefaultInterceptorFactory alloc] init] ];
1675*cc02d7e2SAndroid Build Coastguard Worker
1676*cc02d7e2SAndroid Build Coastguard Worker    __weak __block GRPCStreamingProtoCall *weakCall;
1677*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1678*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:
1679*cc02d7e2SAndroid Build Coastguard Worker            [[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
1680*cc02d7e2SAndroid Build Coastguard Worker                messageCallback:^(id message) {
1681*cc02d7e2SAndroid Build Coastguard Worker                  GRPCStreamingProtoCall *localCall = weakCall;
1682*cc02d7e2SAndroid Build Coastguard Worker                  if (localCall == nil) {
1683*cc02d7e2SAndroid Build Coastguard Worker                    return;
1684*cc02d7e2SAndroid Build Coastguard Worker                  }
1685*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(index < 4, @"More than 4 responses received.");
1686*cc02d7e2SAndroid Build Coastguard Worker
1687*cc02d7e2SAndroid Build Coastguard Worker                  id expected =
1688*cc02d7e2SAndroid Build Coastguard Worker                      [RMTStreamingOutputCallResponse messageWithPayloadSize:responses[index]];
1689*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock([message isEqual:expected],
1690*cc02d7e2SAndroid Build Coastguard Worker                              [NSString stringWithFormat:@"message %@ not equal to expected %@",
1691*cc02d7e2SAndroid Build Coastguard Worker                                                         message, expected]);
1692*cc02d7e2SAndroid Build Coastguard Worker
1693*cc02d7e2SAndroid Build Coastguard Worker                  index += 1;
1694*cc02d7e2SAndroid Build Coastguard Worker                  if (index < 4) {
1695*cc02d7e2SAndroid Build Coastguard Worker                    id request =
1696*cc02d7e2SAndroid Build Coastguard Worker                        [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1697*cc02d7e2SAndroid Build Coastguard Worker                                                        requestedResponseSize:responses[index]];
1698*cc02d7e2SAndroid Build Coastguard Worker                    [localCall writeMessage:request];
1699*cc02d7e2SAndroid Build Coastguard Worker                  } else {
1700*cc02d7e2SAndroid Build Coastguard Worker                    [localCall finish];
1701*cc02d7e2SAndroid Build Coastguard Worker                  }
1702*cc02d7e2SAndroid Build Coastguard Worker                }
1703*cc02d7e2SAndroid Build Coastguard Worker                closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
1704*cc02d7e2SAndroid Build Coastguard Worker                  if (weakCall == nil) {
1705*cc02d7e2SAndroid Build Coastguard Worker                    return;
1706*cc02d7e2SAndroid Build Coastguard Worker                  }
1707*cc02d7e2SAndroid Build Coastguard Worker
1708*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1709*cc02d7e2SAndroid Build Coastguard Worker                      index == 4,
1710*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Received %@ responses instead of 4.", @(index)]);
1711*cc02d7e2SAndroid Build Coastguard Worker
1712*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1713*cc02d7e2SAndroid Build Coastguard Worker                      error == nil,
1714*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Finished with unexpected error: %@", error]);
1715*cc02d7e2SAndroid Build Coastguard Worker
1716*cc02d7e2SAndroid Build Coastguard Worker                  [expectation fulfill];
1717*cc02d7e2SAndroid Build Coastguard Worker                }]
1718*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
1719*cc02d7e2SAndroid Build Coastguard Worker    weakCall = call;
1720*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1721*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
1722*cc02d7e2SAndroid Build Coastguard Worker
1723*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1724*cc02d7e2SAndroid Build Coastguard Worker  });
1725*cc02d7e2SAndroid Build Coastguard Worker}
1726*cc02d7e2SAndroid Build Coastguard Worker
1727*cc02d7e2SAndroid Build Coastguard Worker- (void)testLoggingInterceptor {
1728*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1729*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1730*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
1731*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"testLoggingInterceptor"];
1732*cc02d7e2SAndroid Build Coastguard Worker
1733*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger startCount = 0;
1734*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger writeDataCount = 0;
1735*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger finishCount = 0;
1736*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger receiveNextMessageCount = 0;
1737*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseHeaderCount = 0;
1738*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseDataCount = 0;
1739*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseCloseCount = 0;
1740*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger didWriteDataCount = 0;
1741*cc02d7e2SAndroid Build Coastguard Worker    id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc]
1742*cc02d7e2SAndroid Build Coastguard Worker        initWithDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)
1743*cc02d7e2SAndroid Build Coastguard Worker        startHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
1744*cc02d7e2SAndroid Build Coastguard Worker                    GRPCInterceptorManager *manager) {
1745*cc02d7e2SAndroid Build Coastguard Worker          startCount++;
1746*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(requestOptions.host, [[self class] host]);
1747*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(requestOptions.path, @"/grpc.testing.TestService/FullDuplexCall");
1748*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqual(requestOptions.safety, GRPCCallSafetyDefault);
1749*cc02d7e2SAndroid Build Coastguard Worker          [manager startNextInterceptorWithRequest:[requestOptions copy]
1750*cc02d7e2SAndroid Build Coastguard Worker                                       callOptions:[callOptions copy]];
1751*cc02d7e2SAndroid Build Coastguard Worker        }
1752*cc02d7e2SAndroid Build Coastguard Worker        writeDataHook:^(id data, GRPCInterceptorManager *manager) {
1753*cc02d7e2SAndroid Build Coastguard Worker          writeDataCount++;
1754*cc02d7e2SAndroid Build Coastguard Worker          [manager writeNextInterceptorWithData:data];
1755*cc02d7e2SAndroid Build Coastguard Worker        }
1756*cc02d7e2SAndroid Build Coastguard Worker        finishHook:^(GRPCInterceptorManager *manager) {
1757*cc02d7e2SAndroid Build Coastguard Worker          finishCount++;
1758*cc02d7e2SAndroid Build Coastguard Worker          [manager finishNextInterceptor];
1759*cc02d7e2SAndroid Build Coastguard Worker        }
1760*cc02d7e2SAndroid Build Coastguard Worker        receiveNextMessagesHook:^(NSUInteger numberOfMessages, GRPCInterceptorManager *manager) {
1761*cc02d7e2SAndroid Build Coastguard Worker          receiveNextMessageCount++;
1762*cc02d7e2SAndroid Build Coastguard Worker          [manager receiveNextInterceptorMessages:numberOfMessages];
1763*cc02d7e2SAndroid Build Coastguard Worker        }
1764*cc02d7e2SAndroid Build Coastguard Worker        responseHeaderHook:^(NSDictionary *initialMetadata, GRPCInterceptorManager *manager) {
1765*cc02d7e2SAndroid Build Coastguard Worker          responseHeaderCount++;
1766*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
1767*cc02d7e2SAndroid Build Coastguard Worker        }
1768*cc02d7e2SAndroid Build Coastguard Worker        responseDataHook:^(id data, GRPCInterceptorManager *manager) {
1769*cc02d7e2SAndroid Build Coastguard Worker          responseDataCount++;
1770*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithData:data];
1771*cc02d7e2SAndroid Build Coastguard Worker        }
1772*cc02d7e2SAndroid Build Coastguard Worker        responseCloseHook:^(NSDictionary *trailingMetadata, NSError *error,
1773*cc02d7e2SAndroid Build Coastguard Worker                            GRPCInterceptorManager *manager) {
1774*cc02d7e2SAndroid Build Coastguard Worker          responseCloseCount++;
1775*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata
1776*cc02d7e2SAndroid Build Coastguard Worker                                                                 error:error];
1777*cc02d7e2SAndroid Build Coastguard Worker        }
1778*cc02d7e2SAndroid Build Coastguard Worker        didWriteDataHook:^(GRPCInterceptorManager *manager) {
1779*cc02d7e2SAndroid Build Coastguard Worker          didWriteDataCount++;
1780*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorDidWriteData];
1781*cc02d7e2SAndroid Build Coastguard Worker        }];
1782*cc02d7e2SAndroid Build Coastguard Worker
1783*cc02d7e2SAndroid Build Coastguard Worker    NSArray *requests = @[ @1, @2, @3, @4 ];
1784*cc02d7e2SAndroid Build Coastguard Worker    NSArray *responses = @[ @1, @2, @3, @4 ];
1785*cc02d7e2SAndroid Build Coastguard Worker
1786*cc02d7e2SAndroid Build Coastguard Worker    __block int messageIndex = 0;
1787*cc02d7e2SAndroid Build Coastguard Worker
1788*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[messageIndex]
1789*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:responses[messageIndex]];
1790*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
1791*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
1792*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
1793*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
1794*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
1795*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
1796*cc02d7e2SAndroid Build Coastguard Worker    options.flowControlEnabled = YES;
1797*cc02d7e2SAndroid Build Coastguard Worker    options.interceptorFactories = @[ factory ];
1798*cc02d7e2SAndroid Build Coastguard Worker
1799*cc02d7e2SAndroid Build Coastguard Worker    __block int writeMessageCount = 0;
1800*cc02d7e2SAndroid Build Coastguard Worker    __block __weak GRPCStreamingProtoCall *weakCall;
1801*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1802*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:
1803*cc02d7e2SAndroid Build Coastguard Worker            [[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
1804*cc02d7e2SAndroid Build Coastguard Worker                messageCallback:^(id message) {
1805*cc02d7e2SAndroid Build Coastguard Worker                  GRPCStreamingProtoCall *localCall = weakCall;
1806*cc02d7e2SAndroid Build Coastguard Worker                  if (localCall == nil) {
1807*cc02d7e2SAndroid Build Coastguard Worker                    return;
1808*cc02d7e2SAndroid Build Coastguard Worker                  }
1809*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock((messageIndex < 4), @"More than 4 responses received.");
1810*cc02d7e2SAndroid Build Coastguard Worker
1811*cc02d7e2SAndroid Build Coastguard Worker                  id expected = [RMTStreamingOutputCallResponse
1812*cc02d7e2SAndroid Build Coastguard Worker                      messageWithPayloadSize:responses[messageIndex]];
1813*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock([message isEqual:expected],
1814*cc02d7e2SAndroid Build Coastguard Worker                              [NSString stringWithFormat:@"message %@ not equal to expected %@",
1815*cc02d7e2SAndroid Build Coastguard Worker                                                         message, expected]);
1816*cc02d7e2SAndroid Build Coastguard Worker                  messageIndex += 1;
1817*cc02d7e2SAndroid Build Coastguard Worker                  if (messageIndex < 4) {
1818*cc02d7e2SAndroid Build Coastguard Worker                    id request = [RMTStreamingOutputCallRequest
1819*cc02d7e2SAndroid Build Coastguard Worker                        messageWithPayloadSize:requests[messageIndex]
1820*cc02d7e2SAndroid Build Coastguard Worker                         requestedResponseSize:responses[messageIndex]];
1821*cc02d7e2SAndroid Build Coastguard Worker                    [localCall writeMessage:request];
1822*cc02d7e2SAndroid Build Coastguard Worker                    [localCall receiveNextMessage];
1823*cc02d7e2SAndroid Build Coastguard Worker                  } else {
1824*cc02d7e2SAndroid Build Coastguard Worker                    [localCall finish];
1825*cc02d7e2SAndroid Build Coastguard Worker                  }
1826*cc02d7e2SAndroid Build Coastguard Worker                }
1827*cc02d7e2SAndroid Build Coastguard Worker                closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
1828*cc02d7e2SAndroid Build Coastguard Worker                  if (weakCall == nil) {
1829*cc02d7e2SAndroid Build Coastguard Worker                    return;
1830*cc02d7e2SAndroid Build Coastguard Worker                  }
1831*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1832*cc02d7e2SAndroid Build Coastguard Worker                      error == nil,
1833*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Finished with unexpected error: %@", error]);
1834*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(messageIndex == 4,
1835*cc02d7e2SAndroid Build Coastguard Worker                              [NSString stringWithFormat:@"Received %@ responses instead of 4.",
1836*cc02d7e2SAndroid Build Coastguard Worker                                                         @(messageIndex)]);
1837*cc02d7e2SAndroid Build Coastguard Worker                  [expectation fulfill];
1838*cc02d7e2SAndroid Build Coastguard Worker                }
1839*cc02d7e2SAndroid Build Coastguard Worker                writeMessageCallback:^{
1840*cc02d7e2SAndroid Build Coastguard Worker                  writeMessageCount++;
1841*cc02d7e2SAndroid Build Coastguard Worker                }]
1842*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
1843*cc02d7e2SAndroid Build Coastguard Worker
1844*cc02d7e2SAndroid Build Coastguard Worker    weakCall = call;
1845*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1846*cc02d7e2SAndroid Build Coastguard Worker    [call receiveNextMessage];
1847*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
1848*cc02d7e2SAndroid Build Coastguard Worker
1849*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
1850*cc02d7e2SAndroid Build Coastguard Worker
1851*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(startCount == 1, [NSString stringWithFormat:@"%@", @(startCount)]);
1852*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(writeDataCount == 4, [NSString stringWithFormat:@"%@", @(writeDataCount)]);
1853*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(finishCount == 1, [NSString stringWithFormat:@"%@", @(finishCount)]);
1854*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(receiveNextMessageCount == 4,
1855*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(receiveNextMessageCount)]);
1856*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseHeaderCount == 1,
1857*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(responseHeaderCount)]);
1858*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseDataCount == 4, [NSString stringWithFormat:@"%@", @(responseDataCount)]);
1859*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseCloseCount == 1, [NSString stringWithFormat:@"%@", @(responseCloseCount)]);
1860*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(didWriteDataCount == 4, [NSString stringWithFormat:@"%@", @(didWriteDataCount)]);
1861*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(writeMessageCount == 4, [NSString stringWithFormat:@"%@", @(writeMessageCount)]);
1862*cc02d7e2SAndroid Build Coastguard Worker  });
1863*cc02d7e2SAndroid Build Coastguard Worker}
1864*cc02d7e2SAndroid Build Coastguard Worker
1865*cc02d7e2SAndroid Build Coastguard Worker// Chain a default interceptor and a hook interceptor which, after one write, cancels the call
1866*cc02d7e2SAndroid Build Coastguard Worker// under the hood but forward further data to the user.
1867*cc02d7e2SAndroid Build Coastguard Worker- (void)testHijackingInterceptor {
1868*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
1869*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
1870*cc02d7e2SAndroid Build Coastguard Worker    NSUInteger kCancelAfterWrites = 1;
1871*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectUserCallComplete =
1872*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"User call completed."];
1873*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectResponseCallbackComplete =
1874*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"Hook interceptor response callback completed"];
1875*cc02d7e2SAndroid Build Coastguard Worker
1876*cc02d7e2SAndroid Build Coastguard Worker    NSArray *responses = @[ @1, @2, @3, @4 ];
1877*cc02d7e2SAndroid Build Coastguard Worker    __block int index = 0;
1878*cc02d7e2SAndroid Build Coastguard Worker
1879*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger startCount = 0;
1880*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger writeDataCount = 0;
1881*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger finishCount = 0;
1882*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseHeaderCount = 0;
1883*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseDataCount = 0;
1884*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseCloseCount = 0;
1885*cc02d7e2SAndroid Build Coastguard Worker    id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc]
1886*cc02d7e2SAndroid Build Coastguard Worker        initWithDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)
1887*cc02d7e2SAndroid Build Coastguard Worker        startHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
1888*cc02d7e2SAndroid Build Coastguard Worker                    GRPCInterceptorManager *manager) {
1889*cc02d7e2SAndroid Build Coastguard Worker          startCount++;
1890*cc02d7e2SAndroid Build Coastguard Worker          [manager startNextInterceptorWithRequest:[requestOptions copy]
1891*cc02d7e2SAndroid Build Coastguard Worker                                       callOptions:[callOptions copy]];
1892*cc02d7e2SAndroid Build Coastguard Worker        }
1893*cc02d7e2SAndroid Build Coastguard Worker        writeDataHook:^(id data, GRPCInterceptorManager *manager) {
1894*cc02d7e2SAndroid Build Coastguard Worker          writeDataCount++;
1895*cc02d7e2SAndroid Build Coastguard Worker          if (index < kCancelAfterWrites) {
1896*cc02d7e2SAndroid Build Coastguard Worker            [manager writeNextInterceptorWithData:data];
1897*cc02d7e2SAndroid Build Coastguard Worker          } else if (index == kCancelAfterWrites) {
1898*cc02d7e2SAndroid Build Coastguard Worker            [manager cancelNextInterceptor];
1899*cc02d7e2SAndroid Build Coastguard Worker            [manager forwardPreviousInterceptorWithData:[[RMTStreamingOutputCallResponse
1900*cc02d7e2SAndroid Build Coastguard Worker                                                            messageWithPayloadSize:responses[index]]
1901*cc02d7e2SAndroid Build Coastguard Worker                                                            data]];
1902*cc02d7e2SAndroid Build Coastguard Worker          } else {  // (index > kCancelAfterWrites)
1903*cc02d7e2SAndroid Build Coastguard Worker            [manager forwardPreviousInterceptorWithData:[[RMTStreamingOutputCallResponse
1904*cc02d7e2SAndroid Build Coastguard Worker                                                            messageWithPayloadSize:responses[index]]
1905*cc02d7e2SAndroid Build Coastguard Worker                                                            data]];
1906*cc02d7e2SAndroid Build Coastguard Worker          }
1907*cc02d7e2SAndroid Build Coastguard Worker        }
1908*cc02d7e2SAndroid Build Coastguard Worker        finishHook:^(GRPCInterceptorManager *manager) {
1909*cc02d7e2SAndroid Build Coastguard Worker          finishCount++;
1910*cc02d7e2SAndroid Build Coastguard Worker          // finish must happen after the hijacking, so directly reply with a close
1911*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorCloseWithTrailingMetadata:@{@"grpc-status" : @"0"}
1912*cc02d7e2SAndroid Build Coastguard Worker                                                                 error:nil];
1913*cc02d7e2SAndroid Build Coastguard Worker          [manager shutDown];
1914*cc02d7e2SAndroid Build Coastguard Worker        }
1915*cc02d7e2SAndroid Build Coastguard Worker        receiveNextMessagesHook:nil
1916*cc02d7e2SAndroid Build Coastguard Worker        responseHeaderHook:^(NSDictionary *initialMetadata, GRPCInterceptorManager *manager) {
1917*cc02d7e2SAndroid Build Coastguard Worker          responseHeaderCount++;
1918*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
1919*cc02d7e2SAndroid Build Coastguard Worker        }
1920*cc02d7e2SAndroid Build Coastguard Worker        responseDataHook:^(id data, GRPCInterceptorManager *manager) {
1921*cc02d7e2SAndroid Build Coastguard Worker          responseDataCount++;
1922*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithData:data];
1923*cc02d7e2SAndroid Build Coastguard Worker        }
1924*cc02d7e2SAndroid Build Coastguard Worker        responseCloseHook:^(NSDictionary *trailingMetadata, NSError *error,
1925*cc02d7e2SAndroid Build Coastguard Worker                            GRPCInterceptorManager *manager) {
1926*cc02d7e2SAndroid Build Coastguard Worker          responseCloseCount++;
1927*cc02d7e2SAndroid Build Coastguard Worker          // since we canceled the call, it should return cancel error
1928*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertNil(trailingMetadata);
1929*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertNotNil(error);
1930*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
1931*cc02d7e2SAndroid Build Coastguard Worker          [expectResponseCallbackComplete fulfill];
1932*cc02d7e2SAndroid Build Coastguard Worker        }
1933*cc02d7e2SAndroid Build Coastguard Worker        didWriteDataHook:nil];
1934*cc02d7e2SAndroid Build Coastguard Worker
1935*cc02d7e2SAndroid Build Coastguard Worker    NSArray *requests = @[ @1, @2, @3, @4 ];
1936*cc02d7e2SAndroid Build Coastguard Worker
1937*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1938*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:responses[index]];
1939*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
1940*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
1941*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
1942*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
1943*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
1944*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
1945*cc02d7e2SAndroid Build Coastguard Worker    options.interceptorFactories = @[ [[DefaultInterceptorFactory alloc] init], factory ];
1946*cc02d7e2SAndroid Build Coastguard Worker
1947*cc02d7e2SAndroid Build Coastguard Worker    __weak __block GRPCStreamingProtoCall *weakCall;
1948*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
1949*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:
1950*cc02d7e2SAndroid Build Coastguard Worker            [[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
1951*cc02d7e2SAndroid Build Coastguard Worker                messageCallback:^(id message) {
1952*cc02d7e2SAndroid Build Coastguard Worker                  GRPCStreamingProtoCall *localCall = weakCall;
1953*cc02d7e2SAndroid Build Coastguard Worker                  if (localCall == nil) {
1954*cc02d7e2SAndroid Build Coastguard Worker                    return;
1955*cc02d7e2SAndroid Build Coastguard Worker                  }
1956*cc02d7e2SAndroid Build Coastguard Worker
1957*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(index < 4, @"More than 4 responses received.");
1958*cc02d7e2SAndroid Build Coastguard Worker
1959*cc02d7e2SAndroid Build Coastguard Worker                  id expected =
1960*cc02d7e2SAndroid Build Coastguard Worker                      [RMTStreamingOutputCallResponse messageWithPayloadSize:responses[index]];
1961*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock([message isEqual:expected],
1962*cc02d7e2SAndroid Build Coastguard Worker                              [NSString stringWithFormat:@"message %@ not equal to expected %@",
1963*cc02d7e2SAndroid Build Coastguard Worker                                                         message, expected]);
1964*cc02d7e2SAndroid Build Coastguard Worker                  index += 1;
1965*cc02d7e2SAndroid Build Coastguard Worker                  if (index < 4) {
1966*cc02d7e2SAndroid Build Coastguard Worker                    id request =
1967*cc02d7e2SAndroid Build Coastguard Worker                        [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
1968*cc02d7e2SAndroid Build Coastguard Worker                                                        requestedResponseSize:responses[index]];
1969*cc02d7e2SAndroid Build Coastguard Worker                    [localCall writeMessage:request];
1970*cc02d7e2SAndroid Build Coastguard Worker                    [localCall receiveNextMessage];
1971*cc02d7e2SAndroid Build Coastguard Worker                  } else {
1972*cc02d7e2SAndroid Build Coastguard Worker                    [self waitForExpectations:@[ expectResponseCallbackComplete ]
1973*cc02d7e2SAndroid Build Coastguard Worker                                      timeout:GRPCInteropTestTimeoutDefault];
1974*cc02d7e2SAndroid Build Coastguard Worker                    [localCall finish];
1975*cc02d7e2SAndroid Build Coastguard Worker                  }
1976*cc02d7e2SAndroid Build Coastguard Worker                }
1977*cc02d7e2SAndroid Build Coastguard Worker                closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
1978*cc02d7e2SAndroid Build Coastguard Worker                  if (weakCall == nil) {
1979*cc02d7e2SAndroid Build Coastguard Worker                    return;
1980*cc02d7e2SAndroid Build Coastguard Worker                  }
1981*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1982*cc02d7e2SAndroid Build Coastguard Worker                      error == nil,
1983*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Finished with unexpected error: %@", error]);
1984*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
1985*cc02d7e2SAndroid Build Coastguard Worker                      index == 4,
1986*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Received %@ responses instead of 4.", @(index)]);
1987*cc02d7e2SAndroid Build Coastguard Worker
1988*cc02d7e2SAndroid Build Coastguard Worker                  [expectUserCallComplete fulfill];
1989*cc02d7e2SAndroid Build Coastguard Worker                }]
1990*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
1991*cc02d7e2SAndroid Build Coastguard Worker    weakCall = call;
1992*cc02d7e2SAndroid Build Coastguard Worker    [call start];
1993*cc02d7e2SAndroid Build Coastguard Worker    [call receiveNextMessage];
1994*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
1995*cc02d7e2SAndroid Build Coastguard Worker
1996*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectUserCallComplete ], GRPCInteropTestTimeoutDefault);
1997*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(startCount == 1, [NSString stringWithFormat:@"%@", @(startCount)]);
1998*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(writeDataCount == 4, [NSString stringWithFormat:@"%@", @(writeDataCount)]);
1999*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(finishCount == 1, [NSString stringWithFormat:@"%@", @(finishCount)]);
2000*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseHeaderCount == 1,
2001*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(responseHeaderCount)]);
2002*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseDataCount == 1, [NSString stringWithFormat:@"%@", @(responseDataCount)]);
2003*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseCloseCount == 1, [NSString stringWithFormat:@"%@", @(responseCloseCount)]);
2004*cc02d7e2SAndroid Build Coastguard Worker  });
2005*cc02d7e2SAndroid Build Coastguard Worker}
2006*cc02d7e2SAndroid Build Coastguard Worker
2007*cc02d7e2SAndroid Build Coastguard Worker- (void)testGlobalInterceptor {
2008*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
2009*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
2010*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
2011*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"testGlobalInterceptor"];
2012*cc02d7e2SAndroid Build Coastguard Worker
2013*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger startCount = 0;
2014*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger writeDataCount = 0;
2015*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger finishCount = 0;
2016*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger receiveNextMessageCount = 0;
2017*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseHeaderCount = 0;
2018*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseDataCount = 0;
2019*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseCloseCount = 0;
2020*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger didWriteDataCount = 0;
2021*cc02d7e2SAndroid Build Coastguard Worker    [globalInterceptorFactory
2022*cc02d7e2SAndroid Build Coastguard Worker        setStartHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
2023*cc02d7e2SAndroid Build Coastguard Worker                       GRPCInterceptorManager *manager) {
2024*cc02d7e2SAndroid Build Coastguard Worker          startCount++;
2025*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(requestOptions.host, [[self class] host]);
2026*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(requestOptions.path, @"/grpc.testing.TestService/FullDuplexCall");
2027*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqual(requestOptions.safety, GRPCCallSafetyDefault);
2028*cc02d7e2SAndroid Build Coastguard Worker          [manager startNextInterceptorWithRequest:[requestOptions copy]
2029*cc02d7e2SAndroid Build Coastguard Worker                                       callOptions:[callOptions copy]];
2030*cc02d7e2SAndroid Build Coastguard Worker        }
2031*cc02d7e2SAndroid Build Coastguard Worker        writeDataHook:^(id data, GRPCInterceptorManager *manager) {
2032*cc02d7e2SAndroid Build Coastguard Worker          writeDataCount++;
2033*cc02d7e2SAndroid Build Coastguard Worker          [manager writeNextInterceptorWithData:data];
2034*cc02d7e2SAndroid Build Coastguard Worker        }
2035*cc02d7e2SAndroid Build Coastguard Worker        finishHook:^(GRPCInterceptorManager *manager) {
2036*cc02d7e2SAndroid Build Coastguard Worker          finishCount++;
2037*cc02d7e2SAndroid Build Coastguard Worker          [manager finishNextInterceptor];
2038*cc02d7e2SAndroid Build Coastguard Worker        }
2039*cc02d7e2SAndroid Build Coastguard Worker        receiveNextMessagesHook:^(NSUInteger numberOfMessages, GRPCInterceptorManager *manager) {
2040*cc02d7e2SAndroid Build Coastguard Worker          receiveNextMessageCount++;
2041*cc02d7e2SAndroid Build Coastguard Worker          [manager receiveNextInterceptorMessages:numberOfMessages];
2042*cc02d7e2SAndroid Build Coastguard Worker        }
2043*cc02d7e2SAndroid Build Coastguard Worker        responseHeaderHook:^(NSDictionary *initialMetadata, GRPCInterceptorManager *manager) {
2044*cc02d7e2SAndroid Build Coastguard Worker          responseHeaderCount++;
2045*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
2046*cc02d7e2SAndroid Build Coastguard Worker        }
2047*cc02d7e2SAndroid Build Coastguard Worker        responseDataHook:^(id data, GRPCInterceptorManager *manager) {
2048*cc02d7e2SAndroid Build Coastguard Worker          responseDataCount++;
2049*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithData:data];
2050*cc02d7e2SAndroid Build Coastguard Worker        }
2051*cc02d7e2SAndroid Build Coastguard Worker        responseCloseHook:^(NSDictionary *trailingMetadata, NSError *error,
2052*cc02d7e2SAndroid Build Coastguard Worker                            GRPCInterceptorManager *manager) {
2053*cc02d7e2SAndroid Build Coastguard Worker          responseCloseCount++;
2054*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata
2055*cc02d7e2SAndroid Build Coastguard Worker                                                                 error:error];
2056*cc02d7e2SAndroid Build Coastguard Worker        }
2057*cc02d7e2SAndroid Build Coastguard Worker        didWriteDataHook:^(GRPCInterceptorManager *manager) {
2058*cc02d7e2SAndroid Build Coastguard Worker          didWriteDataCount++;
2059*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorDidWriteData];
2060*cc02d7e2SAndroid Build Coastguard Worker        }];
2061*cc02d7e2SAndroid Build Coastguard Worker
2062*cc02d7e2SAndroid Build Coastguard Worker    NSArray *requests = @[ @1, @2, @3, @4 ];
2063*cc02d7e2SAndroid Build Coastguard Worker    NSArray *responses = @[ @1, @2, @3, @4 ];
2064*cc02d7e2SAndroid Build Coastguard Worker
2065*cc02d7e2SAndroid Build Coastguard Worker    __block int index = 0;
2066*cc02d7e2SAndroid Build Coastguard Worker
2067*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
2068*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:responses[index]];
2069*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
2070*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
2071*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
2072*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
2073*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
2074*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
2075*cc02d7e2SAndroid Build Coastguard Worker    options.flowControlEnabled = YES;
2076*cc02d7e2SAndroid Build Coastguard Worker    globalInterceptorFactory.enabled = YES;
2077*cc02d7e2SAndroid Build Coastguard Worker
2078*cc02d7e2SAndroid Build Coastguard Worker    __block int writeMessageCount = 0;
2079*cc02d7e2SAndroid Build Coastguard Worker    __weak __block GRPCStreamingProtoCall *weakCall;
2080*cc02d7e2SAndroid Build Coastguard Worker    __block GRPCStreamingProtoCall *call = [service
2081*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:
2082*cc02d7e2SAndroid Build Coastguard Worker            [[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
2083*cc02d7e2SAndroid Build Coastguard Worker                messageCallback:^(id message) {
2084*cc02d7e2SAndroid Build Coastguard Worker                  GRPCStreamingProtoCall *localCall = weakCall;
2085*cc02d7e2SAndroid Build Coastguard Worker                  if (localCall == nil) {
2086*cc02d7e2SAndroid Build Coastguard Worker                    return;
2087*cc02d7e2SAndroid Build Coastguard Worker                  }
2088*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(index < 4, @"More than 4 responses received.");
2089*cc02d7e2SAndroid Build Coastguard Worker
2090*cc02d7e2SAndroid Build Coastguard Worker                  index += 1;
2091*cc02d7e2SAndroid Build Coastguard Worker                  if (index < 4) {
2092*cc02d7e2SAndroid Build Coastguard Worker                    id request =
2093*cc02d7e2SAndroid Build Coastguard Worker                        [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
2094*cc02d7e2SAndroid Build Coastguard Worker                                                        requestedResponseSize:responses[index]];
2095*cc02d7e2SAndroid Build Coastguard Worker                    [localCall writeMessage:request];
2096*cc02d7e2SAndroid Build Coastguard Worker                    [localCall receiveNextMessage];
2097*cc02d7e2SAndroid Build Coastguard Worker                  } else {
2098*cc02d7e2SAndroid Build Coastguard Worker                    [localCall finish];
2099*cc02d7e2SAndroid Build Coastguard Worker                  }
2100*cc02d7e2SAndroid Build Coastguard Worker                }
2101*cc02d7e2SAndroid Build Coastguard Worker                closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
2102*cc02d7e2SAndroid Build Coastguard Worker                  if (weakCall == nil) {
2103*cc02d7e2SAndroid Build Coastguard Worker                    return;
2104*cc02d7e2SAndroid Build Coastguard Worker                  }
2105*cc02d7e2SAndroid Build Coastguard Worker                  assertBlock(
2106*cc02d7e2SAndroid Build Coastguard Worker                      error == nil,
2107*cc02d7e2SAndroid Build Coastguard Worker                      [NSString stringWithFormat:@"Finished with unexpected error: %@", error]);
2108*cc02d7e2SAndroid Build Coastguard Worker                  [expectation fulfill];
2109*cc02d7e2SAndroid Build Coastguard Worker                }
2110*cc02d7e2SAndroid Build Coastguard Worker                writeMessageCallback:^{
2111*cc02d7e2SAndroid Build Coastguard Worker                  writeMessageCount++;
2112*cc02d7e2SAndroid Build Coastguard Worker                }]
2113*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
2114*cc02d7e2SAndroid Build Coastguard Worker    weakCall = call;
2115*cc02d7e2SAndroid Build Coastguard Worker    [call start];
2116*cc02d7e2SAndroid Build Coastguard Worker    [call receiveNextMessage];
2117*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
2118*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
2119*cc02d7e2SAndroid Build Coastguard Worker
2120*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(startCount == 1, [NSString stringWithFormat:@"%@", @(startCount)]);
2121*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(writeDataCount == 4, [NSString stringWithFormat:@"%@", @(writeDataCount)]);
2122*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(finishCount == 1, [NSString stringWithFormat:@"%@", @(finishCount)]);
2123*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(receiveNextMessageCount == 4,
2124*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(receiveNextMessageCount)]);
2125*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseHeaderCount == 1,
2126*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(responseHeaderCount)]);
2127*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseDataCount == 4, [NSString stringWithFormat:@"%@", @(responseDataCount)]);
2128*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseCloseCount == 1, [NSString stringWithFormat:@"%@", @(responseCloseCount)]);
2129*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(didWriteDataCount == 4, [NSString stringWithFormat:@"%@", @(didWriteDataCount)]);
2130*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(writeMessageCount == 4, [NSString stringWithFormat:@"%@", @(writeMessageCount)]);
2131*cc02d7e2SAndroid Build Coastguard Worker    globalInterceptorFactory.enabled = NO;
2132*cc02d7e2SAndroid Build Coastguard Worker  });
2133*cc02d7e2SAndroid Build Coastguard Worker}
2134*cc02d7e2SAndroid Build Coastguard Worker
2135*cc02d7e2SAndroid Build Coastguard Worker- (void)testConflictingGlobalInterceptors {
2136*cc02d7e2SAndroid Build Coastguard Worker  id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc]
2137*cc02d7e2SAndroid Build Coastguard Worker        initWithDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)
2138*cc02d7e2SAndroid Build Coastguard Worker                    startHook:nil
2139*cc02d7e2SAndroid Build Coastguard Worker                writeDataHook:nil
2140*cc02d7e2SAndroid Build Coastguard Worker                   finishHook:nil
2141*cc02d7e2SAndroid Build Coastguard Worker      receiveNextMessagesHook:nil
2142*cc02d7e2SAndroid Build Coastguard Worker           responseHeaderHook:nil
2143*cc02d7e2SAndroid Build Coastguard Worker             responseDataHook:nil
2144*cc02d7e2SAndroid Build Coastguard Worker            responseCloseHook:nil
2145*cc02d7e2SAndroid Build Coastguard Worker             didWriteDataHook:nil];
2146*cc02d7e2SAndroid Build Coastguard Worker  @try {
2147*cc02d7e2SAndroid Build Coastguard Worker    [GRPCCall2 registerGlobalInterceptor:factory];
2148*cc02d7e2SAndroid Build Coastguard Worker    XCTFail(@"Did not receive an exception when registering global interceptor the second time");
2149*cc02d7e2SAndroid Build Coastguard Worker  } @catch (NSException *exception) {
2150*cc02d7e2SAndroid Build Coastguard Worker    // Do nothing; test passes
2151*cc02d7e2SAndroid Build Coastguard Worker  }
2152*cc02d7e2SAndroid Build Coastguard Worker}
2153*cc02d7e2SAndroid Build Coastguard Worker
2154*cc02d7e2SAndroid Build Coastguard Worker- (void)testInterceptorAndGlobalInterceptor {
2155*cc02d7e2SAndroid Build Coastguard Worker  GRPCTestRunWithFlakeRepeats(self, ^(GRPCTestWaiter waiterBlock, GRPCTestAssert assertBlock) {
2156*cc02d7e2SAndroid Build Coastguard Worker    RMTTestService *service = [RMTTestService serviceWithHost:[[self class] host]];
2157*cc02d7e2SAndroid Build Coastguard Worker    __weak XCTestExpectation *expectation =
2158*cc02d7e2SAndroid Build Coastguard Worker        [self expectationWithDescription:@"testInterceptorAndGlobalInterceptor"];
2159*cc02d7e2SAndroid Build Coastguard Worker
2160*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger startCount = 0;
2161*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger writeDataCount = 0;
2162*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger finishCount = 0;
2163*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger receiveNextMessageCount = 0;
2164*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseHeaderCount = 0;
2165*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseDataCount = 0;
2166*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger responseCloseCount = 0;
2167*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger didWriteDataCount = 0;
2168*cc02d7e2SAndroid Build Coastguard Worker
2169*cc02d7e2SAndroid Build Coastguard Worker    id<GRPCInterceptorFactory> factory = [[HookInterceptorFactory alloc]
2170*cc02d7e2SAndroid Build Coastguard Worker        initWithDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)
2171*cc02d7e2SAndroid Build Coastguard Worker        startHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
2172*cc02d7e2SAndroid Build Coastguard Worker                    GRPCInterceptorManager *manager) {
2173*cc02d7e2SAndroid Build Coastguard Worker          startCount++;
2174*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(requestOptions.host, [[self class] host]);
2175*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(requestOptions.path, @"/grpc.testing.TestService/FullDuplexCall");
2176*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqual(requestOptions.safety, GRPCCallSafetyDefault);
2177*cc02d7e2SAndroid Build Coastguard Worker          [manager startNextInterceptorWithRequest:[requestOptions copy]
2178*cc02d7e2SAndroid Build Coastguard Worker                                       callOptions:[callOptions copy]];
2179*cc02d7e2SAndroid Build Coastguard Worker        }
2180*cc02d7e2SAndroid Build Coastguard Worker        writeDataHook:^(id data, GRPCInterceptorManager *manager) {
2181*cc02d7e2SAndroid Build Coastguard Worker          writeDataCount++;
2182*cc02d7e2SAndroid Build Coastguard Worker          [manager writeNextInterceptorWithData:data];
2183*cc02d7e2SAndroid Build Coastguard Worker        }
2184*cc02d7e2SAndroid Build Coastguard Worker        finishHook:^(GRPCInterceptorManager *manager) {
2185*cc02d7e2SAndroid Build Coastguard Worker          finishCount++;
2186*cc02d7e2SAndroid Build Coastguard Worker          [manager finishNextInterceptor];
2187*cc02d7e2SAndroid Build Coastguard Worker        }
2188*cc02d7e2SAndroid Build Coastguard Worker        receiveNextMessagesHook:^(NSUInteger numberOfMessages, GRPCInterceptorManager *manager) {
2189*cc02d7e2SAndroid Build Coastguard Worker          receiveNextMessageCount++;
2190*cc02d7e2SAndroid Build Coastguard Worker          [manager receiveNextInterceptorMessages:numberOfMessages];
2191*cc02d7e2SAndroid Build Coastguard Worker        }
2192*cc02d7e2SAndroid Build Coastguard Worker        responseHeaderHook:^(NSDictionary *initialMetadata, GRPCInterceptorManager *manager) {
2193*cc02d7e2SAndroid Build Coastguard Worker          responseHeaderCount++;
2194*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
2195*cc02d7e2SAndroid Build Coastguard Worker        }
2196*cc02d7e2SAndroid Build Coastguard Worker        responseDataHook:^(id data, GRPCInterceptorManager *manager) {
2197*cc02d7e2SAndroid Build Coastguard Worker          responseDataCount++;
2198*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithData:data];
2199*cc02d7e2SAndroid Build Coastguard Worker        }
2200*cc02d7e2SAndroid Build Coastguard Worker        responseCloseHook:^(NSDictionary *trailingMetadata, NSError *error,
2201*cc02d7e2SAndroid Build Coastguard Worker                            GRPCInterceptorManager *manager) {
2202*cc02d7e2SAndroid Build Coastguard Worker          responseCloseCount++;
2203*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata
2204*cc02d7e2SAndroid Build Coastguard Worker                                                                 error:error];
2205*cc02d7e2SAndroid Build Coastguard Worker        }
2206*cc02d7e2SAndroid Build Coastguard Worker        didWriteDataHook:^(GRPCInterceptorManager *manager) {
2207*cc02d7e2SAndroid Build Coastguard Worker          didWriteDataCount++;
2208*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorDidWriteData];
2209*cc02d7e2SAndroid Build Coastguard Worker        }];
2210*cc02d7e2SAndroid Build Coastguard Worker
2211*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger globalStartCount = 0;
2212*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger globalWriteDataCount = 0;
2213*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger globalFinishCount = 0;
2214*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger globalReceiveNextMessageCount = 0;
2215*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger globalResponseHeaderCount = 0;
2216*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger globalResponseDataCount = 0;
2217*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger globalResponseCloseCount = 0;
2218*cc02d7e2SAndroid Build Coastguard Worker    __block NSUInteger globalDidWriteDataCount = 0;
2219*cc02d7e2SAndroid Build Coastguard Worker
2220*cc02d7e2SAndroid Build Coastguard Worker    [globalInterceptorFactory
2221*cc02d7e2SAndroid Build Coastguard Worker        setStartHook:^(GRPCRequestOptions *requestOptions, GRPCCallOptions *callOptions,
2222*cc02d7e2SAndroid Build Coastguard Worker                       GRPCInterceptorManager *manager) {
2223*cc02d7e2SAndroid Build Coastguard Worker          globalStartCount++;
2224*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(requestOptions.host, [[self class] host]);
2225*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqualObjects(requestOptions.path, @"/grpc.testing.TestService/FullDuplexCall");
2226*cc02d7e2SAndroid Build Coastguard Worker          XCTAssertEqual(requestOptions.safety, GRPCCallSafetyDefault);
2227*cc02d7e2SAndroid Build Coastguard Worker          [manager startNextInterceptorWithRequest:[requestOptions copy]
2228*cc02d7e2SAndroid Build Coastguard Worker                                       callOptions:[callOptions copy]];
2229*cc02d7e2SAndroid Build Coastguard Worker        }
2230*cc02d7e2SAndroid Build Coastguard Worker        writeDataHook:^(id data, GRPCInterceptorManager *manager) {
2231*cc02d7e2SAndroid Build Coastguard Worker          globalWriteDataCount++;
2232*cc02d7e2SAndroid Build Coastguard Worker          [manager writeNextInterceptorWithData:data];
2233*cc02d7e2SAndroid Build Coastguard Worker        }
2234*cc02d7e2SAndroid Build Coastguard Worker        finishHook:^(GRPCInterceptorManager *manager) {
2235*cc02d7e2SAndroid Build Coastguard Worker          globalFinishCount++;
2236*cc02d7e2SAndroid Build Coastguard Worker          [manager finishNextInterceptor];
2237*cc02d7e2SAndroid Build Coastguard Worker        }
2238*cc02d7e2SAndroid Build Coastguard Worker        receiveNextMessagesHook:^(NSUInteger numberOfMessages, GRPCInterceptorManager *manager) {
2239*cc02d7e2SAndroid Build Coastguard Worker          globalReceiveNextMessageCount++;
2240*cc02d7e2SAndroid Build Coastguard Worker          [manager receiveNextInterceptorMessages:numberOfMessages];
2241*cc02d7e2SAndroid Build Coastguard Worker        }
2242*cc02d7e2SAndroid Build Coastguard Worker        responseHeaderHook:^(NSDictionary *initialMetadata, GRPCInterceptorManager *manager) {
2243*cc02d7e2SAndroid Build Coastguard Worker          globalResponseHeaderCount++;
2244*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithInitialMetadata:initialMetadata];
2245*cc02d7e2SAndroid Build Coastguard Worker        }
2246*cc02d7e2SAndroid Build Coastguard Worker        responseDataHook:^(id data, GRPCInterceptorManager *manager) {
2247*cc02d7e2SAndroid Build Coastguard Worker          globalResponseDataCount++;
2248*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorWithData:data];
2249*cc02d7e2SAndroid Build Coastguard Worker        }
2250*cc02d7e2SAndroid Build Coastguard Worker        responseCloseHook:^(NSDictionary *trailingMetadata, NSError *error,
2251*cc02d7e2SAndroid Build Coastguard Worker                            GRPCInterceptorManager *manager) {
2252*cc02d7e2SAndroid Build Coastguard Worker          globalResponseCloseCount++;
2253*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorCloseWithTrailingMetadata:trailingMetadata
2254*cc02d7e2SAndroid Build Coastguard Worker                                                                 error:error];
2255*cc02d7e2SAndroid Build Coastguard Worker        }
2256*cc02d7e2SAndroid Build Coastguard Worker        didWriteDataHook:^(GRPCInterceptorManager *manager) {
2257*cc02d7e2SAndroid Build Coastguard Worker          globalDidWriteDataCount++;
2258*cc02d7e2SAndroid Build Coastguard Worker          [manager forwardPreviousInterceptorDidWriteData];
2259*cc02d7e2SAndroid Build Coastguard Worker        }];
2260*cc02d7e2SAndroid Build Coastguard Worker
2261*cc02d7e2SAndroid Build Coastguard Worker    NSArray *requests = @[ @1, @2, @3, @4 ];
2262*cc02d7e2SAndroid Build Coastguard Worker    NSArray *responses = @[ @1, @2, @3, @4 ];
2263*cc02d7e2SAndroid Build Coastguard Worker
2264*cc02d7e2SAndroid Build Coastguard Worker    __block int index = 0;
2265*cc02d7e2SAndroid Build Coastguard Worker
2266*cc02d7e2SAndroid Build Coastguard Worker    id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
2267*cc02d7e2SAndroid Build Coastguard Worker                                                 requestedResponseSize:responses[index]];
2268*cc02d7e2SAndroid Build Coastguard Worker    GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
2269*cc02d7e2SAndroid Build Coastguard Worker    // For backwards compatibility
2270*cc02d7e2SAndroid Build Coastguard Worker    options.transportType = [[self class] transportType];
2271*cc02d7e2SAndroid Build Coastguard Worker    options.transport = [[self class] transport];
2272*cc02d7e2SAndroid Build Coastguard Worker    options.PEMRootCertificates = [[self class] PEMRootCertificates];
2273*cc02d7e2SAndroid Build Coastguard Worker    options.hostNameOverride = [[self class] hostNameOverride];
2274*cc02d7e2SAndroid Build Coastguard Worker    options.flowControlEnabled = YES;
2275*cc02d7e2SAndroid Build Coastguard Worker    options.interceptorFactories = @[ factory ];
2276*cc02d7e2SAndroid Build Coastguard Worker    globalInterceptorFactory.enabled = YES;
2277*cc02d7e2SAndroid Build Coastguard Worker
2278*cc02d7e2SAndroid Build Coastguard Worker    __block int writeMessageCount = 0;
2279*cc02d7e2SAndroid Build Coastguard Worker    __weak __block GRPCStreamingProtoCall *weakCall;
2280*cc02d7e2SAndroid Build Coastguard Worker    GRPCStreamingProtoCall *call = [service
2281*cc02d7e2SAndroid Build Coastguard Worker        fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
2282*cc02d7e2SAndroid Build Coastguard Worker                                              initWithInitialMetadataCallback:nil
2283*cc02d7e2SAndroid Build Coastguard Worker                                              messageCallback:^(id message) {
2284*cc02d7e2SAndroid Build Coastguard Worker                                                GRPCStreamingProtoCall *localCall = weakCall;
2285*cc02d7e2SAndroid Build Coastguard Worker                                                if (localCall == nil) {
2286*cc02d7e2SAndroid Build Coastguard Worker                                                  return;
2287*cc02d7e2SAndroid Build Coastguard Worker                                                }
2288*cc02d7e2SAndroid Build Coastguard Worker                                                index += 1;
2289*cc02d7e2SAndroid Build Coastguard Worker                                                if (index < 4) {
2290*cc02d7e2SAndroid Build Coastguard Worker                                                  id request = [RMTStreamingOutputCallRequest
2291*cc02d7e2SAndroid Build Coastguard Worker                                                      messageWithPayloadSize:requests[index]
2292*cc02d7e2SAndroid Build Coastguard Worker                                                       requestedResponseSize:responses[index]];
2293*cc02d7e2SAndroid Build Coastguard Worker                                                  [localCall writeMessage:request];
2294*cc02d7e2SAndroid Build Coastguard Worker                                                  [localCall receiveNextMessage];
2295*cc02d7e2SAndroid Build Coastguard Worker                                                } else {
2296*cc02d7e2SAndroid Build Coastguard Worker                                                  [localCall finish];
2297*cc02d7e2SAndroid Build Coastguard Worker                                                }
2298*cc02d7e2SAndroid Build Coastguard Worker                                              }
2299*cc02d7e2SAndroid Build Coastguard Worker                                              closeCallback:^(NSDictionary *trailingMetadata,
2300*cc02d7e2SAndroid Build Coastguard Worker                                                              NSError *error) {
2301*cc02d7e2SAndroid Build Coastguard Worker                                                if (weakCall == nil) {
2302*cc02d7e2SAndroid Build Coastguard Worker                                                  return;
2303*cc02d7e2SAndroid Build Coastguard Worker                                                }
2304*cc02d7e2SAndroid Build Coastguard Worker                                                [expectation fulfill];
2305*cc02d7e2SAndroid Build Coastguard Worker                                              }
2306*cc02d7e2SAndroid Build Coastguard Worker                                              writeMessageCallback:^{
2307*cc02d7e2SAndroid Build Coastguard Worker                                                writeMessageCount++;
2308*cc02d7e2SAndroid Build Coastguard Worker                                              }]
2309*cc02d7e2SAndroid Build Coastguard Worker                              callOptions:options];
2310*cc02d7e2SAndroid Build Coastguard Worker    weakCall = call;
2311*cc02d7e2SAndroid Build Coastguard Worker    [call start];
2312*cc02d7e2SAndroid Build Coastguard Worker    [call receiveNextMessage];
2313*cc02d7e2SAndroid Build Coastguard Worker    [call writeMessage:request];
2314*cc02d7e2SAndroid Build Coastguard Worker
2315*cc02d7e2SAndroid Build Coastguard Worker    waiterBlock(@[ expectation ], GRPCInteropTestTimeoutDefault);
2316*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(startCount == 1, [NSString stringWithFormat:@"%@", @(startCount)]);
2317*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(writeDataCount == 4, [NSString stringWithFormat:@"%@", @(writeDataCount)]);
2318*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(finishCount == 1, [NSString stringWithFormat:@"%@", @(finishCount)]);
2319*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(receiveNextMessageCount == 4,
2320*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(receiveNextMessageCount)]);
2321*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseHeaderCount == 1,
2322*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(responseHeaderCount)]);
2323*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseDataCount == 4, [NSString stringWithFormat:@"%@", @(responseDataCount)]);
2324*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(responseCloseCount == 1, [NSString stringWithFormat:@"%@", @(responseCloseCount)]);
2325*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(didWriteDataCount == 4, [NSString stringWithFormat:@"%@", @(didWriteDataCount)]);
2326*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(globalStartCount == 1, [NSString stringWithFormat:@"%@", @(globalStartCount)]);
2327*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(globalWriteDataCount == 4,
2328*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(globalWriteDataCount)]);
2329*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(globalFinishCount == 1, [NSString stringWithFormat:@"%@", @(globalFinishCount)]);
2330*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(globalReceiveNextMessageCount == 4,
2331*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(globalReceiveNextMessageCount)]);
2332*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(globalResponseHeaderCount == 1,
2333*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(globalResponseHeaderCount)]);
2334*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(globalResponseDataCount == 4,
2335*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(globalResponseDataCount)]);
2336*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(globalResponseCloseCount == 1,
2337*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(globalResponseCloseCount)]);
2338*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(globalDidWriteDataCount == 4,
2339*cc02d7e2SAndroid Build Coastguard Worker                [NSString stringWithFormat:@"%@", @(globalDidWriteDataCount)]);
2340*cc02d7e2SAndroid Build Coastguard Worker    assertBlock(writeMessageCount == 4, [NSString stringWithFormat:@"%@", @(writeMessageCount)]);
2341*cc02d7e2SAndroid Build Coastguard Worker    globalInterceptorFactory.enabled = NO;
2342*cc02d7e2SAndroid Build Coastguard Worker  });
2343*cc02d7e2SAndroid Build Coastguard Worker}
2344*cc02d7e2SAndroid Build Coastguard Worker
2345*cc02d7e2SAndroid Build Coastguard Worker@end
2346