blob: deaaf17b07ee899a4c3dc1891e783671dc59073e [file] [log] [blame]
Jorge Canizalesb3be2292015-05-31 19:11:20 -07001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Jorge Canizalesb3be2292015-05-31 19:11:20 -07004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#import <UIKit/UIKit.h>
35#import <XCTest/XCTest.h>
36
Jorge Canizalesc42a38e2015-06-21 14:44:25 -070037#import <GRPCClient/GRPCCall.h>
Makarand Dharmapurikar1c2890d2016-02-24 14:35:46 -080038#import <GRPCClient/GRPCCall+ChannelArg.h>
Jorge Canizales631dc002015-08-06 23:08:41 -070039#import <GRPCClient/GRPCCall+OAuth2.h>
Muxi Yan8e6aec52017-02-10 09:40:18 -080040#import <GRPCClient/GRPCCall+Tests.h>
41#import <GRPCClient/internal_testing/GRPCCall+InternalTests.h>
Jorge Canizalesbe808e32015-07-04 14:37:58 -070042#import <ProtoRPC/ProtoMethod.h>
Jorge Canizalesb3be2292015-05-31 19:11:20 -070043#import <RemoteTest/Messages.pbobjc.h>
Jorge Canizalesc42a38e2015-06-21 14:44:25 -070044#import <RxLibrary/GRXWriteable.h>
45#import <RxLibrary/GRXWriter+Immediate.h>
Makarand Dharmapurikara0414ee2016-02-23 16:58:46 -080046
Muxi Yanb1341a32016-12-05 16:38:02 -080047#define TEST_TIMEOUT 16
48
Jorge Canizalesb2bd0672015-08-01 23:19:11 -070049static NSString * const kHostAddress = @"localhost:5050";
Jorge Canizalesd666fd02015-06-12 18:59:11 -070050static NSString * const kPackage = @"grpc.testing";
51static NSString * const kService = @"TestService";
Test User9656eca2016-02-18 14:47:22 -080052static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
Makarand Dharmapurikara0414ee2016-02-23 16:58:46 -080053
Yuchen Zengdbe2b9e2016-06-15 20:23:04 -070054static GRPCProtoMethod *kInexistentMethod;
55static GRPCProtoMethod *kEmptyCallMethod;
56static GRPCProtoMethod *kUnaryCallMethod;
Jorge Canizalesd666fd02015-06-12 18:59:11 -070057
Jorge Canizales2beb88c2015-10-28 15:13:40 -070058/** Observer class for testing that responseMetadata is KVO-compliant */
murgatroid9981b4fcb2015-08-24 10:56:44 -070059@interface PassthroughObserver : NSObject
Jorge Canizales2beb88c2015-10-28 15:13:40 -070060- (instancetype) initWithCallback:(void (^)(NSString*, id, NSDictionary*))callback
61 NS_DESIGNATED_INITIALIZER;
murgatroid9981b4fcb2015-08-24 10:56:44 -070062
63- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change
64 context:(void *)context;
65@end
66
67@implementation PassthroughObserver {
68 void (^_callback)(NSString*, id, NSDictionary*);
69}
70
Jorge Canizales2beb88c2015-10-28 15:13:40 -070071- (instancetype)init {
72 return [self initWithCallback:nil];
73}
74
murgatroid9981b4fcb2015-08-24 10:56:44 -070075- (instancetype)initWithCallback:(void (^)(NSString *, id, NSDictionary *))callback {
Jorge Canizales2beb88c2015-10-28 15:13:40 -070076 if (!callback) {
77 return nil;
78 }
79 if ((self = [super init])) {
murgatroid9981b4fcb2015-08-24 10:56:44 -070080 _callback = callback;
81 }
82 return self;
murgatroid9981b4fcb2015-08-24 10:56:44 -070083}
84
Jorge Canizales2beb88c2015-10-28 15:13:40 -070085- (void)observeValueForKeyPath:(NSString *)keyPath
86 ofObject:(id)object
87 change:(NSDictionary *)change
88 context:(void *)context {
murgatroid9981b4fcb2015-08-24 10:56:44 -070089 _callback(keyPath, object, change);
murgatroid992e49a352015-08-24 14:40:45 -070090 [object removeObserver:self forKeyPath:keyPath];
murgatroid9981b4fcb2015-08-24 10:56:44 -070091}
92
93@end
94
Jorge Canizales2beb88c2015-10-28 15:13:40 -070095# pragma mark Tests
96
97/**
98 * A few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall) rather than
99 * a generated proto library on top of it. Its RPCs are sent to a local cleartext server.
100 *
101 * TODO(jcanizales): Run them also against a local SSL server and against a remote server.
102 */
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700103@interface GRPCClientTests : XCTestCase
104@end
105
106@implementation GRPCClientTests
107
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700108- (void)setUp {
Makarand Dharmapurikarc2b34902016-02-26 16:38:17 -0800109 // Add a custom user agent prefix that will be used in test
110 [GRPCCall setUserAgentPrefix:@"Foo" forHost:kHostAddress];
Jorge Canizalesb2bd0672015-08-01 23:19:11 -0700111 // Register test server as non-SSL.
112 [GRPCCall useInsecureConnectionsForHost:kHostAddress];
113
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700114 // This method isn't implemented by the remote server.
Yuchen Zengdbe2b9e2016-06-15 20:23:04 -0700115 kInexistentMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
Yuchen Zengd5fd7dd2016-06-21 11:13:23 -0700116 service:kService
117 method:@"Inexistent"];
Yuchen Zengdbe2b9e2016-06-15 20:23:04 -0700118 kEmptyCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
Yuchen Zengd5fd7dd2016-06-21 11:13:23 -0700119 service:kService
120 method:@"EmptyCall"];
Yuchen Zengdbe2b9e2016-06-15 20:23:04 -0700121 kUnaryCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
Yuchen Zengd5fd7dd2016-06-21 11:13:23 -0700122 service:kService
123 method:@"UnaryCall"];
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700124}
125
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700126- (void)testConnectionToRemoteServer {
127 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Server reachable."];
128
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700129 GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
Jorge Canizales5260f532015-07-04 14:47:41 -0700130 path:kInexistentMethod.HTTPPath
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700131 requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700132
133 id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
134 XCTFail(@"Received unexpected response: %@", value);
135 } completionHandler:^(NSError *errorOrNil) {
136 XCTAssertNotNil(errorOrNil, @"Finished without error!");
Test User9656eca2016-02-18 14:47:22 -0800137 XCTAssertEqual(errorOrNil.code, 12, @"Finished with unexpected error: %@", errorOrNil);
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700138 [expectation fulfill];
139 }];
140
141 [call startWithWriteable:responsesWriteable];
142
Muxi Yanb1341a32016-12-05 16:38:02 -0800143 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700144}
145
146- (void)testEmptyRPC {
147 __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
148 __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
149
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700150 GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
Jorge Canizales5260f532015-07-04 14:47:41 -0700151 path:kEmptyCallMethod.HTTPPath
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700152 requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700153
154 id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
155 XCTAssertNotNil(value, @"nil value received as response.");
156 XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
157 [response fulfill];
158 } completionHandler:^(NSError *errorOrNil) {
159 XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
160 [completion fulfill];
161 }];
162
163 [call startWithWriteable:responsesWriteable];
164
Muxi Yanb1341a32016-12-05 16:38:02 -0800165 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700166}
167
168- (void)testSimpleProtoRPC {
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700169 __weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700170 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
171
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700172 RMTSimpleRequest *request = [RMTSimpleRequest message];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700173 request.responseSize = 100;
174 request.fillUsername = YES;
175 request.fillOauthScope = YES;
Jorge Canizalesa8c5d962015-07-16 18:55:31 -0700176 GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700177
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700178 GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
Jorge Canizales5260f532015-07-04 14:47:41 -0700179 path:kUnaryCallMethod.HTTPPath
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700180 requestsWriter:requestsWriter];
181
182 id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
183 XCTAssertNotNil(value, @"nil value received as response.");
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700184 XCTAssertGreaterThan(value.length, 0, @"Empty response received.");
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700185 RMTSimpleResponse *responseProto = [RMTSimpleResponse parseFromData:value error:NULL];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700186 // We expect empty strings, not nil:
Jorge Canizalesd666fd02015-06-12 18:59:11 -0700187 XCTAssertNotNil(responseProto.username, @"Response's username is nil.");
188 XCTAssertNotNil(responseProto.oauthScope, @"Response's OAuth scope is nil.");
189 [response fulfill];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700190 } completionHandler:^(NSError *errorOrNil) {
191 XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
192 [completion fulfill];
193 }];
194
195 [call startWithWriteable:responsesWriteable];
196
Muxi Yanb1341a32016-12-05 16:38:02 -0800197 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700198}
199
Jorge Canizalesd7981252015-06-12 19:15:18 -0700200- (void)testMetadata {
201 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."];
202
203 RMTSimpleRequest *request = [RMTSimpleRequest message];
204 request.fillUsername = YES;
205 request.fillOauthScope = YES;
Jorge Canizalesa8c5d962015-07-16 18:55:31 -0700206 GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];
Jorge Canizalesd7981252015-06-12 19:15:18 -0700207
Test User9656eca2016-02-18 14:47:22 -0800208 GRPCCall *call = [[GRPCCall alloc] initWithHost:kRemoteSSLHost
Jorge Canizales5260f532015-07-04 14:47:41 -0700209 path:kUnaryCallMethod.HTTPPath
Jorge Canizalesd7981252015-06-12 19:15:18 -0700210 requestsWriter:requestsWriter];
211
Jorge Canizales721b7a32015-08-07 10:11:16 -0700212 call.oauth2AccessToken = @"bogusToken";
Jorge Canizalesd7981252015-06-12 19:15:18 -0700213
214 id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
215 XCTFail(@"Received unexpected response: %@", value);
216 } completionHandler:^(NSError *errorOrNil) {
217 XCTAssertNotNil(errorOrNil, @"Finished without error!");
218 XCTAssertEqual(errorOrNil.code, 16, @"Finished with unexpected error: %@", errorOrNil);
Jorge Canizales1ab2a712015-08-12 20:32:11 -0700219 XCTAssertEqualObjects(call.responseHeaders, errorOrNil.userInfo[kGRPCHeadersKey],
220 @"Headers in the NSError object and call object differ.");
221 XCTAssertEqualObjects(call.responseTrailers, errorOrNil.userInfo[kGRPCTrailersKey],
222 @"Trailers in the NSError object and call object differ.");
Jorge Canizales721b7a32015-08-07 10:11:16 -0700223 NSString *challengeHeader = call.oauth2ChallengeHeader;
Jorge Canizalesd7981252015-06-12 19:15:18 -0700224 XCTAssertGreaterThan(challengeHeader.length, 0,
Jorge Canizales1ab2a712015-08-12 20:32:11 -0700225 @"No challenge in response headers %@", call.responseHeaders);
Jorge Canizalesd7981252015-06-12 19:15:18 -0700226 [expectation fulfill];
227 }];
228
229 [call startWithWriteable:responsesWriteable];
230
Muxi Yanb1341a32016-12-05 16:38:02 -0800231 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
Jorge Canizalesd7981252015-06-12 19:15:18 -0700232}
233
murgatroid9981b4fcb2015-08-24 10:56:44 -0700234- (void)testResponseMetadataKVO {
235 __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
236 __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
237 __weak XCTestExpectation *metadata = [self expectationWithDescription:@"Metadata changed."];
238
murgatroid9981b4fcb2015-08-24 10:56:44 -0700239 GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
240 path:kEmptyCallMethod.HTTPPath
241 requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
242
murgatroid992e49a352015-08-24 14:40:45 -0700243 PassthroughObserver *observer = [[PassthroughObserver alloc] initWithCallback:^(NSString *keypath, id object, NSDictionary * change) {
244 if ([keypath isEqual: @"responseHeaders"]) {
245 [metadata fulfill];
246 }
247 }];
248
murgatroid9981b4fcb2015-08-24 10:56:44 -0700249 [call addObserver:observer forKeyPath:@"responseHeaders" options:0 context:NULL];
250
251 id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
252 XCTAssertNotNil(value, @"nil value received as response.");
253 XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
254 [response fulfill];
255 } completionHandler:^(NSError *errorOrNil) {
256 XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
257 [completion fulfill];
258 }];
259
260 [call startWithWriteable:responsesWriteable];
261
Muxi Yanb1341a32016-12-05 16:38:02 -0800262 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
murgatroid9981b4fcb2015-08-24 10:56:44 -0700263}
264
Makarand Dharmapurikarc2b34902016-02-26 16:38:17 -0800265- (void)testUserAgentPrefix {
266 __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
267 __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
268
269 GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
270 path:kEmptyCallMethod.HTTPPath
271 requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
272 // Setting this special key in the header will cause the interop server to echo back the
273 // user-agent value, which we confirm.
274 call.requestHeaders[@"x-grpc-test-echo-useragent"] = @"";
275
276 id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
277 XCTAssertNotNil(value, @"nil value received as response.");
278 XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
Nicolas "Pixel" Nobleaad41562016-03-11 22:21:11 +0100279 /* This test needs to be more clever in regards to changing the version of the core.
Makarand Dharmapurikarc2b34902016-02-26 16:38:17 -0800280 XCTAssertEqualObjects(call.responseHeaders[@"x-grpc-test-echo-useragent"],
Makarand Dharmapurikarf1588b52016-02-26 17:05:47 -0800281 @"Foo grpc-objc/0.13.0 grpc-c/0.14.0-dev (ios)",
282 @"Did not receive expected user agent %@",
283 call.responseHeaders[@"x-grpc-test-echo-useragent"]);
Nicolas "Pixel" Nobleaad41562016-03-11 22:21:11 +0100284 */
Makarand Dharmapurikarc9dbf642016-02-26 16:59:08 -0800285 [response fulfill];
Makarand Dharmapurikarc2b34902016-02-26 16:38:17 -0800286 } completionHandler:^(NSError *errorOrNil) {
287 XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
288 [completion fulfill];
289 }];
290
291 [call startWithWriteable:responsesWriteable];
292
Muxi Yanb1341a32016-12-05 16:38:02 -0800293 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
Makarand Dharmapurikarc2b34902016-02-26 16:38:17 -0800294}
295
Makarand Dharmapurikar716c7c52017-05-09 13:04:41 -0700296- (void)testTrailers {
297 __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
298 __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
299
300 GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
301 path:kEmptyCallMethod.HTTPPath
302 requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
303 // Setting this special key in the header will cause the interop server to echo back the
304 // trailer data.
305 const unsigned char raw_bytes[] = {1,2,3,4};
306 NSData *trailer_data = [NSData dataWithBytes:raw_bytes length:sizeof(raw_bytes)];
307 call.requestHeaders[@"x-grpc-test-echo-trailing-bin"] = trailer_data;
308
309 id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
310 XCTAssertNotNil(value, @"nil value received as response.");
311 XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
312 [response fulfill];
313 } completionHandler:^(NSError *errorOrNil) {
314 XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
315 XCTAssertEqualObjects((NSData *)call.responseTrailers[@"x-grpc-test-echo-trailing-bin"],
316 trailer_data,
317 @"Did not receive expected trailer");
318 [completion fulfill];
319 }];
320
321 [call startWithWriteable:responsesWriteable];
322 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
323}
324
Makarand Dharmapurikar63f2b5b2016-02-24 13:54:48 -0800325// TODO(makarandd): Move to a different file that contains only unit tests
Test User9656eca2016-02-18 14:47:22 -0800326- (void)testExceptions {
Test User9656eca2016-02-18 14:47:22 -0800327 // Try to set parameters to nil for GRPCCall. This should cause an exception
328 @try {
Yuchen Zengd5fd7dd2016-06-21 11:13:23 -0700329 (void)[[GRPCCall alloc] initWithHost:nil
330 path:nil
331 requestsWriter:nil];
Test User9656eca2016-02-18 14:47:22 -0800332 XCTFail(@"Did not receive an exception when parameters are nil");
333 } @catch(NSException *theException) {
334 NSLog(@"Received exception as expected: %@", theException.name);
335 }
336
337
338 // Set state to Finished by force
339 GRXWriter *requestsWriter = [GRXWriter emptyWriter];
340 [requestsWriter finishWithError:nil];
341 @try {
Yuchen Zengd5fd7dd2016-06-21 11:13:23 -0700342 (void)[[GRPCCall alloc] initWithHost:kHostAddress
343 path:kUnaryCallMethod.HTTPPath
344 requestsWriter:requestsWriter];
Test User9656eca2016-02-18 14:47:22 -0800345 XCTFail(@"Did not receive an exception when GRXWriter has incorrect state.");
346 } @catch(NSException *theException) {
347 NSLog(@"Received exception as expected: %@", theException.name);
348 }
349
350}
351
Muxi Yan1bd5c772016-09-30 15:13:58 -0700352- (void)testIdempotentProtoRPC {
353 __weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."];
354 __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
355
356 RMTSimpleRequest *request = [RMTSimpleRequest message];
357 request.responseSize = 100;
358 request.fillUsername = YES;
359 request.fillOauthScope = YES;
360 GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];
361
362 GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
363 path:kUnaryCallMethod.HTTPPath
364 requestsWriter:requestsWriter];
Muxi Yan8739e802016-10-03 09:41:31 -0700365 [GRPCCall setCallSafety:GRPCCallSafetyIdempotentRequest host:kHostAddress path:kUnaryCallMethod.HTTPPath];
Muxi Yan1bd5c772016-09-30 15:13:58 -0700366
367 id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
368 XCTAssertNotNil(value, @"nil value received as response.");
369 XCTAssertGreaterThan(value.length, 0, @"Empty response received.");
370 RMTSimpleResponse *responseProto = [RMTSimpleResponse parseFromData:value error:NULL];
371 // We expect empty strings, not nil:
372 XCTAssertNotNil(responseProto.username, @"Response's username is nil.");
373 XCTAssertNotNil(responseProto.oauthScope, @"Response's OAuth scope is nil.");
374 [response fulfill];
375 } completionHandler:^(NSError *errorOrNil) {
376 XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
377 [completion fulfill];
378 }];
379
380 [call startWithWriteable:responsesWriteable];
381
Muxi Yanb1341a32016-12-05 16:38:02 -0800382 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
Muxi Yan1bd5c772016-09-30 15:13:58 -0700383}
384
Muxi Yanb965ff62017-04-19 14:27:47 -0700385- (void)testAlternateDispatchQueue {
386 const int32_t kPayloadSize = 100;
387 RMTSimpleRequest *request = [RMTSimpleRequest message];
388 request.responseSize = kPayloadSize;
389
390 __weak XCTestExpectation *expectation1 = [self expectationWithDescription:@"AlternateDispatchQueue1"];
391
392 // Use default (main) dispatch queue
393 NSString *main_queue_label = [NSString stringWithUTF8String:dispatch_queue_get_label(dispatch_get_main_queue())];
394
395 GRXWriter *requestsWriter1 = [GRXWriter writerWithValue:[request data]];
396
397 GRPCCall *call1 = [[GRPCCall alloc] initWithHost:kHostAddress
Muxi Yanfd002632017-04-20 16:16:49 -0700398 path:kUnaryCallMethod.HTTPPath
399 requestsWriter:requestsWriter1];
Muxi Yanb965ff62017-04-19 14:27:47 -0700400
401 id<GRXWriteable> responsesWriteable1 = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
402 NSString *label = [NSString stringWithUTF8String:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)];
403 XCTAssert([label isEqualToString:main_queue_label]);
404
405 [expectation1 fulfill];
406 } completionHandler:^(NSError *errorOrNil) {
407 }];
408
409 [call1 startWithWriteable:responsesWriteable1];
410
411 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
412
413 // Use a custom queue
414 __weak XCTestExpectation *expectation2 = [self expectationWithDescription:@"AlternateDispatchQueue2"];
415
416 NSString *queue_label = @"test.queue1";
417 dispatch_queue_t queue = dispatch_queue_create([queue_label UTF8String], DISPATCH_QUEUE_SERIAL);
418
419 GRXWriter *requestsWriter2 = [GRXWriter writerWithValue:[request data]];
420
421 GRPCCall *call2 = [[GRPCCall alloc] initWithHost:kHostAddress
422 path:kUnaryCallMethod.HTTPPath
423 requestsWriter:requestsWriter2];
424
425 [call2 setResponseDispatchQueue:queue];
426
427 id<GRXWriteable> responsesWriteable2 = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
428 NSString *label = [NSString stringWithUTF8String:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)];
429 XCTAssert([label isEqualToString:queue_label]);
430
431 [expectation2 fulfill];
432 } completionHandler:^(NSError *errorOrNil) {
433 }];
434
435 [call2 startWithWriteable:responsesWriteable2];
436
437 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
438}
439
Jorge Canizalesb3be2292015-05-31 19:11:20 -0700440@end