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