1/*
2 *
3 * Copyright 2018 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19#import <XCTest/XCTest.h>
20
21#ifdef GRPC_COMPILE_WITH_CRONET
22#import <Cronet/Cronet.h>
23#endif
24#import <RemoteTest/Messages.pbobjc.h>
25#import <RemoteTest/Test.pbobjc.h>
26#import <RemoteTest/Test.pbrpc.h>
27#import <RxLibrary/GRXBufferedPipe.h>
28
29#import "../ConfigureCronet.h"
30#import "InteropTestsBlockCallbacks.h"
31
32#define NSStringize_helper(x) #x
33#define NSStringize(x) @NSStringize_helper(x)
34static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
35static NSString *const kLocalSSLHost = NSStringize(HOST_PORT_LOCALSSL);
36static NSString *const kLocalCleartextHost = NSStringize(HOST_PORT_LOCAL);
37
38static const NSTimeInterval TEST_TIMEOUT = 8000;
39
40@interface RMTStreamingOutputCallRequest (Constructors)
41+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
42                 requestedResponseSize:(NSNumber *)responseSize;
43@end
44
45@implementation RMTStreamingOutputCallRequest (Constructors)
46+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
47                 requestedResponseSize:(NSNumber *)responseSize {
48  RMTStreamingOutputCallRequest *request = [self message];
49  RMTResponseParameters *parameters = [RMTResponseParameters message];
50  parameters.size = responseSize.intValue;
51  [request.responseParametersArray addObject:parameters];
52  request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
53  return request;
54}
55@end
56
57@interface RMTStreamingOutputCallResponse (Constructors)
58+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize;
59@end
60
61@implementation RMTStreamingOutputCallResponse (Constructors)
62+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize {
63  RMTStreamingOutputCallResponse *response = [self message];
64  response.payload.type = RMTPayloadType_Compressable;
65  response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
66  return response;
67}
68@end
69
70@interface InteropTestsMultipleChannels : XCTestCase
71
72@end
73
74dispatch_once_t initCronet;
75
76@implementation InteropTestsMultipleChannels {
77  RMTTestService *_remoteService;
78  RMTTestService *_remoteCronetService;
79  RMTTestService *_localCleartextService;
80  RMTTestService *_localSSLService;
81}
82
83- (void)setUp {
84  [super setUp];
85
86  self.continueAfterFailure = NO;
87
88  _remoteService = [RMTTestService serviceWithHost:kRemoteSSLHost callOptions:nil];
89
90  configureCronet();
91
92  // Default stack with remote host
93  GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
94  options.transportType = GRPCTransportTypeCronet;
95  // Cronet stack with remote host
96  _remoteCronetService = [RMTTestService serviceWithHost:kRemoteSSLHost callOptions:options];
97
98  // Local stack with no SSL
99  options = [[GRPCMutableCallOptions alloc] init];
100  options.transportType = GRPCTransportTypeInsecure;
101  _localCleartextService = [RMTTestService serviceWithHost:kLocalCleartextHost callOptions:options];
102
103  // Local stack with SSL
104  NSBundle *bundle = [NSBundle bundleForClass:[self class]];
105  NSString *certsPath =
106      [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"];
107  NSError *error = nil;
108  NSString *certs =
109      [NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error];
110  XCTAssertNil(error);
111
112  options = [[GRPCMutableCallOptions alloc] init];
113  options.transportType = GRPCTransportTypeChttp2BoringSSL;
114  options.PEMRootCertificates = certs;
115  options.hostNameOverride = @"foo.test.google.fr";
116  _localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost callOptions:options];
117}
118
119- (void)testEmptyUnaryRPC {
120  __weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
121  __weak XCTestExpectation *expectCronetRemote =
122      [self expectationWithDescription:@"Remote RPC finish"];
123  __weak XCTestExpectation *expectCleartext =
124      [self expectationWithDescription:@"Remote RPC finish"];
125  __weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
126
127  GPBEmpty *request = [GPBEmpty message];
128
129  void (^messageHandler)(id message) = ^(id message) {
130    id expectedResponse = [GPBEmpty message];
131    XCTAssertEqualObjects(message, expectedResponse);
132  };
133
134  GRPCUnaryProtoCall *callRemote = [_remoteService
135      emptyCallWithMessage:request
136           responseHandler:[[InteropTestsBlockCallbacks alloc]
137                               initWithInitialMetadataCallback:nil
138                                               messageCallback:messageHandler
139                                                 closeCallback:^(NSDictionary *trailingMetadata,
140                                                                 NSError *error) {
141                                                   XCTAssertNil(error);
142                                                   [expectRemote fulfill];
143                                                 }
144                                          writeMessageCallback:nil]
145               callOptions:nil];
146  GRPCUnaryProtoCall *callCronet = [_remoteCronetService
147      emptyCallWithMessage:request
148           responseHandler:[[InteropTestsBlockCallbacks alloc]
149                               initWithInitialMetadataCallback:nil
150                                               messageCallback:messageHandler
151                                                 closeCallback:^(NSDictionary *trailingMetadata,
152                                                                 NSError *error) {
153                                                   XCTAssertNil(error);
154                                                   [expectCronetRemote fulfill];
155                                                 }
156                                          writeMessageCallback:nil]
157               callOptions:nil];
158  GRPCUnaryProtoCall *callCleartext = [_localCleartextService
159      emptyCallWithMessage:request
160           responseHandler:[[InteropTestsBlockCallbacks alloc]
161                               initWithInitialMetadataCallback:nil
162                                               messageCallback:messageHandler
163                                                 closeCallback:^(NSDictionary *trailingMetadata,
164                                                                 NSError *error) {
165                                                   XCTAssertNil(error);
166                                                   [expectCleartext fulfill];
167                                                 }
168                                          writeMessageCallback:nil]
169               callOptions:nil];
170  GRPCUnaryProtoCall *callSSL = [_localSSLService
171      emptyCallWithMessage:request
172           responseHandler:[[InteropTestsBlockCallbacks alloc]
173                               initWithInitialMetadataCallback:nil
174                                               messageCallback:messageHandler
175                                                 closeCallback:^(NSDictionary *trailingMetadata,
176                                                                 NSError *error) {
177                                                   XCTAssertNil(error);
178                                                   [expectSSL fulfill];
179                                                 }
180                                          writeMessageCallback:nil]
181               callOptions:nil];
182  [callRemote start];
183  [callCronet start];
184  [callCleartext start];
185  [callSSL start];
186
187  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
188}
189
190- (void)testFullDuplexRPC {
191  __weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
192  __weak XCTestExpectation *expectCronetRemote =
193      [self expectationWithDescription:@"Remote RPC finish"];
194  __weak XCTestExpectation *expectCleartext =
195      [self expectationWithDescription:@"Remote RPC finish"];
196  __weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
197
198  NSArray *requestSizes = @[ @100, @101, @102, @103 ];
199  NSArray *responseSizes = @[ @104, @105, @106, @107 ];
200  XCTAssertEqual([requestSizes count], [responseSizes count]);
201  NSUInteger kRounds = [requestSizes count];
202  NSMutableArray<GRPCStreamingProtoCall *> *calls = [NSMutableArray arrayWithCapacity:4];
203
204  NSMutableArray *requests = [NSMutableArray arrayWithCapacity:kRounds];
205  NSMutableArray *responses = [NSMutableArray arrayWithCapacity:kRounds];
206  for (int i = 0; i < kRounds; i++) {
207    requests[i] = [RMTStreamingOutputCallRequest messageWithPayloadSize:requestSizes[i]
208                                                  requestedResponseSize:responseSizes[i]];
209    responses[i] = [RMTStreamingOutputCallResponse messageWithPayloadSize:responseSizes[i]];
210  }
211
212  __block NSMutableArray *steps = [NSMutableArray arrayWithCapacity:4];
213  __block NSMutableArray *requestsBuffers = [NSMutableArray arrayWithCapacity:4];
214  for (int i = 0; i < 4; i++) {
215    steps[i] = [NSNumber numberWithUnsignedInteger:0];
216    requestsBuffers[i] = [[GRXBufferedPipe alloc] init];
217    [requestsBuffers[i] writeValue:requests[0]];
218  }
219
220  void (^handler)(NSUInteger index, id message) = ^(NSUInteger index, id message) {
221    NSUInteger step = [steps[index] unsignedIntegerValue];
222    step++;
223    steps[index] = [NSNumber numberWithUnsignedInteger:step];
224    if (step < kRounds) {
225      [calls[index] writeMessage:requests[step]];
226    } else {
227      [calls[index] finish];
228    }
229  };
230
231  calls[0] = [_remoteService
232      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
233                                            initWithInitialMetadataCallback:nil
234                                            messageCallback:^(id message) {
235                                              handler(0, message);
236                                            }
237                                            closeCallback:^(NSDictionary *trailingMetadata,
238                                                            NSError *error) {
239                                              XCTAssertNil(error);
240                                              [expectRemote fulfill];
241                                            }
242                                            writeMessageCallback:nil]
243                            callOptions:nil];
244  calls[1] = [_remoteCronetService
245      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
246                                            initWithInitialMetadataCallback:nil
247                                            messageCallback:^(id message) {
248                                              handler(1, message);
249                                            }
250                                            closeCallback:^(NSDictionary *trailingMetadata,
251                                                            NSError *error) {
252                                              XCTAssertNil(error);
253                                              [expectCronetRemote fulfill];
254                                            }
255                                            writeMessageCallback:nil]
256                            callOptions:nil];
257  calls[2] = [_localCleartextService
258      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
259                                            initWithInitialMetadataCallback:nil
260                                            messageCallback:^(id message) {
261                                              handler(2, message);
262                                            }
263                                            closeCallback:^(NSDictionary *trailingMetadata,
264                                                            NSError *error) {
265                                              XCTAssertNil(error);
266                                              [expectCleartext fulfill];
267                                            }
268                                            writeMessageCallback:nil]
269                            callOptions:nil];
270  calls[3] = [_localSSLService
271      fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
272                                            initWithInitialMetadataCallback:nil
273                                            messageCallback:^(id message) {
274                                              handler(3, message);
275                                            }
276                                            closeCallback:^(NSDictionary *trailingMetadata,
277                                                            NSError *error) {
278                                              XCTAssertNil(error);
279                                              [expectSSL fulfill];
280                                            }
281                                            writeMessageCallback:nil]
282                            callOptions:nil];
283  for (int i = 0; i < 4; i++) {
284    [calls[i] start];
285    [calls[i] writeMessage:requests[0]];
286  }
287
288  [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
289}
290
291@end
292