Update tests

pull/16190/head
Muxi Yan 7 years ago
parent af1b4d6b48
commit 9fbc9105a6
  1. 164
      src/objective-c/tests/ChannelTests/ChannelPoolTest.m
  2. 93
      src/objective-c/tests/ChannelTests/ChannelTests.m
  3. 22
      src/objective-c/tests/ChannelTests/Info.plist
  4. 291
      src/objective-c/tests/GRPCClientTests.m
  5. 21
      src/objective-c/tests/InteropTests.h
  6. 201
      src/objective-c/tests/InteropTests.m
  7. 22
      src/objective-c/tests/InteropTestsCallOptions/Info.plist
  8. 116
      src/objective-c/tests/InteropTestsCallOptions/InteropTestsCallOptions.m
  9. 12
      src/objective-c/tests/InteropTestsLocalCleartext.m
  10. 16
      src/objective-c/tests/InteropTestsLocalSSL.m
  11. 22
      src/objective-c/tests/InteropTestsMultipleChannels/Info.plist
  12. 259
      src/objective-c/tests/InteropTestsMultipleChannels/InteropTestsMultipleChannels.m
  13. 18
      src/objective-c/tests/InteropTestsRemote.m
  14. 10
      src/objective-c/tests/Podfile
  15. 832
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  16. 92
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/ChannelTests.xcscheme
  17. 56
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsCallOptions.xcscheme
  18. 8
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme
  19. 56
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsMultipleChannels.xcscheme
  20. 2
      src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme
  21. 10
      src/objective-c/tests/run_tests.sh

@ -0,0 +1,164 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <XCTest/XCTest.h>
#import "../../GRPCClient/private/GRPCChannel.h"
#import "../../GRPCClient/private/GRPCChannelPool.h"
#define TEST_TIMEOUT 32
NSString *kDummyHost = @"dummy.host";
@interface ChannelPoolTest : XCTestCase
@end
@implementation ChannelPoolTest
+ (void)setUp {
grpc_init();
}
- (void)testCreateChannel {
NSString *kDummyHost = @"dummy.host";
GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init];
options1.transportType = GRPCTransportTypeInsecure;
GRPCCallOptions *options2 = [options1 copy];
GRPCChannelConfiguration *config1 =
[[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1];
GRPCChannelConfiguration *config2 =
[[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2];
GRPCChannelPool *pool = [[GRPCChannelPool alloc] initWithChannelDestroyDelay:1];
__weak XCTestExpectation *expectCreateChannel =
[self expectationWithDescription:@"Create first channel"];
GRPCChannel *channel1 =
[pool channelWithConfiguration:config1
createChannel:^{
[expectCreateChannel fulfill];
return [GRPCChannel createChannelWithConfiguration:config1];
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
GRPCChannel *channel2 = [pool channelWithConfiguration:config2
createChannel:^{
XCTFail(@"Should not create a second channel.");
return (GRPCChannel *)nil;
}];
XCTAssertEqual(channel1, channel2);
}
- (void)testChannelTimeout {
NSTimeInterval kChannelDestroyDelay = 1.0;
GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init];
options1.transportType = GRPCTransportTypeInsecure;
GRPCChannelConfiguration *config1 =
[[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1];
GRPCChannelPool *pool =
[[GRPCChannelPool alloc] initWithChannelDestroyDelay:kChannelDestroyDelay];
GRPCChannel *channel1 =
[pool channelWithConfiguration:config1
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config1];
}];
[pool unrefChannelWithConfiguration:config1];
__weak XCTestExpectation *expectTimerDone = [self expectationWithDescription:@"Timer elapse."];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:kChannelDestroyDelay + 1
repeats:NO
block:^(NSTimer *_Nonnull timer) {
[expectTimerDone fulfill];
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
timer = nil;
GRPCChannel *channel2 =
[pool channelWithConfiguration:config1
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config1];
}];
XCTAssertNotEqual(channel1, channel2);
}
- (void)testChannelTimeoutCancel {
NSTimeInterval kChannelDestroyDelay = 3.0;
GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init];
options1.transportType = GRPCTransportTypeInsecure;
GRPCChannelConfiguration *config1 =
[[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1];
GRPCChannelPool *pool =
[[GRPCChannelPool alloc] initWithChannelDestroyDelay:kChannelDestroyDelay];
GRPCChannel *channel1 =
[pool channelWithConfiguration:config1
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config1];
}];
[channel1 unmanagedCallUnref];
sleep(1);
GRPCChannel *channel2 =
[pool channelWithConfiguration:config1
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config1];
}];
XCTAssertEqual(channel1, channel2);
sleep((int)kChannelDestroyDelay + 2);
GRPCChannel *channel3 =
[pool channelWithConfiguration:config1
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config1];
}];
XCTAssertEqual(channel1, channel3);
}
- (void)testClearChannels {
GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init];
options1.transportType = GRPCTransportTypeInsecure;
GRPCMutableCallOptions *options2 = [[GRPCMutableCallOptions alloc] init];
options2.transportType = GRPCTransportTypeDefault;
GRPCChannelConfiguration *config1 =
[[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options1];
GRPCChannelConfiguration *config2 =
[[GRPCChannelConfiguration alloc] initWithHost:kDummyHost callOptions:options2];
GRPCChannelPool *pool = [[GRPCChannelPool alloc] initWithChannelDestroyDelay:1];
GRPCChannel *channel1 =
[pool channelWithConfiguration:config1
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config1];
}];
GRPCChannel *channel2 =
[pool channelWithConfiguration:config2
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config2];
}];
XCTAssertNotEqual(channel1, channel2);
[pool clear];
GRPCChannel *channel3 =
[pool channelWithConfiguration:config1
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config1];
}];
GRPCChannel *channel4 =
[pool channelWithConfiguration:config2
createChannel:^{
return [GRPCChannel createChannelWithConfiguration:config2];
}];
XCTAssertNotEqual(channel1, channel3);
XCTAssertNotEqual(channel2, channel4);
}
@end

@ -0,0 +1,93 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <XCTest/XCTest.h>
#import "../../GRPCClient/GRPCCallOptions.h"
#import "../../GRPCClient/private/GRPCChannel.h"
@interface ChannelTests : XCTestCase
@end
@implementation ChannelTests
+ (void)setUp {
grpc_init();
}
- (void)testSameConfiguration {
NSString *host = @"grpc-test.sandbox.googleapis.com";
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.userAgentPrefix = @"TestUAPrefix";
NSMutableDictionary *args = [NSMutableDictionary new];
args[@"abc"] = @"xyz";
options.additionalChannelArgs = [args copy];
GRPCChannel *channel1 = [GRPCChannel channelWithHost:host callOptions:options];
GRPCChannel *channel2 = [GRPCChannel channelWithHost:host callOptions:options];
XCTAssertEqual(channel1, channel2);
GRPCMutableCallOptions *options2 = [options mutableCopy];
options2.additionalChannelArgs = [args copy];
GRPCChannel *channel3 = [GRPCChannel channelWithHost:host callOptions:options2];
XCTAssertEqual(channel1, channel3);
}
- (void)testDifferentHost {
NSString *host1 = @"grpc-test.sandbox.googleapis.com";
NSString *host2 = @"grpc-test2.sandbox.googleapis.com";
NSString *host3 = @"http://grpc-test.sandbox.googleapis.com";
NSString *host4 = @"dns://grpc-test.sandbox.googleapis.com";
NSString *host5 = @"grpc-test.sandbox.googleapis.com:80";
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.userAgentPrefix = @"TestUAPrefix";
NSMutableDictionary *args = [NSMutableDictionary new];
args[@"abc"] = @"xyz";
options.additionalChannelArgs = [args copy];
GRPCChannel *channel1 = [GRPCChannel channelWithHost:host1 callOptions:options];
GRPCChannel *channel2 = [GRPCChannel channelWithHost:host2 callOptions:options];
GRPCChannel *channel3 = [GRPCChannel channelWithHost:host3 callOptions:options];
GRPCChannel *channel4 = [GRPCChannel channelWithHost:host4 callOptions:options];
GRPCChannel *channel5 = [GRPCChannel channelWithHost:host5 callOptions:options];
XCTAssertNotEqual(channel1, channel2);
XCTAssertNotEqual(channel1, channel3);
XCTAssertNotEqual(channel1, channel4);
XCTAssertNotEqual(channel1, channel5);
}
- (void)testDifferentChannelParameters {
NSString *host = @"grpc-test.sandbox.googleapis.com";
GRPCMutableCallOptions *options1 = [[GRPCMutableCallOptions alloc] init];
options1.transportType = GRPCTransportTypeDefault;
NSMutableDictionary *args = [NSMutableDictionary new];
args[@"abc"] = @"xyz";
options1.additionalChannelArgs = [args copy];
GRPCMutableCallOptions *options2 = [[GRPCMutableCallOptions alloc] init];
options2.transportType = GRPCTransportTypeInsecure;
options2.additionalChannelArgs = [args copy];
GRPCMutableCallOptions *options3 = [[GRPCMutableCallOptions alloc] init];
options3.transportType = GRPCTransportTypeDefault;
args[@"def"] = @"uvw";
options3.additionalChannelArgs = [args copy];
GRPCChannel *channel1 = [GRPCChannel channelWithHost:host callOptions:options1];
GRPCChannel *channel2 = [GRPCChannel channelWithHost:host callOptions:options2];
GRPCChannel *channel3 = [GRPCChannel channelWithHost:host callOptions:options3];
XCTAssertNotEqual(channel1, channel2);
XCTAssertNotEqual(channel1, channel3);
}
@end

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -86,6 +86,58 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
@end
// Convenience class to use blocks as callbacks
@interface ClientTestsBlockCallbacks : NSObject<GRPCResponseHandler>
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
@end
@implementation ClientTestsBlockCallbacks {
void (^_initialMetadataCallback)(NSDictionary *);
void (^_messageCallback)(id);
void (^_closeCallback)(NSDictionary *, NSError *);
dispatch_queue_t _dispatchQueue;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
if ((self = [super init])) {
_initialMetadataCallback = initialMetadataCallback;
_messageCallback = messageCallback;
_closeCallback = closeCallback;
_dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata {
if (_initialMetadataCallback) {
_initialMetadataCallback(initialMetadata);
}
}
- (void)receivedMessage:(id)message {
if (_messageCallback) {
_messageCallback(message);
}
}
- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (_closeCallback) {
_closeCallback(trailingMetadata, error);
}
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
@end
#pragma mark Tests
/**
@ -237,6 +289,55 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testMetadataWithV2API {
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."];
RMTSimpleRequest *request = [RMTSimpleRequest message];
request.fillUsername = YES;
request.fillOauthScope = YES;
GRPCRequestOptions *callRequest =
[[GRPCRequestOptions alloc] initWithHost:(NSString *)kRemoteSSLHost
path:kUnaryCallMethod.HTTPPath
safety:GRPCCallSafetyDefault];
__block NSDictionary *init_md;
__block NSDictionary *trailing_md;
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.oauth2AccessToken = @"bogusToken";
GRPCCall2 *call = [[GRPCCall2 alloc]
initWithRequestOptions:callRequest
handler:[[ClientTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:^(NSDictionary *initialMetadata) {
init_md = initialMetadata;
}
messageCallback:^(id message) {
XCTFail(@"Received unexpected response.");
}
closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
trailing_md = trailingMetadata;
if (error) {
XCTAssertEqual(error.code, 16,
@"Finished with unexpected error: %@", error);
XCTAssertEqualObjects(init_md,
error.userInfo[kGRPCHeadersKey]);
XCTAssertEqualObjects(trailing_md,
error.userInfo[kGRPCTrailersKey]);
NSString *challengeHeader = init_md[@"www-authenticate"];
XCTAssertGreaterThan(challengeHeader.length, 0,
@"No challenge in response headers %@",
init_md);
[expectation fulfill];
}
}]
callOptions:options];
[call start];
[call writeWithData:[request data]];
[call finish];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testResponseMetadataKVO {
__weak XCTestExpectation *response =
[self expectationWithDescription:@"Empty response received."];
@ -329,6 +430,77 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testUserAgentPrefixWithV2API {
__weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
__weak XCTestExpectation *recvInitialMd =
[self expectationWithDescription:@"Did not receive initial md."];
GRPCRequestOptions *request = [[GRPCRequestOptions alloc] initWithHost:kHostAddress
path:kEmptyCallMethod.HTTPPath
safety:GRPCCallSafetyDefault];
NSDictionary *headers =
[NSDictionary dictionaryWithObjectsAndKeys:@"", @"x-grpc-test-echo-useragent", nil];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
options.userAgentPrefix = @"Foo";
options.initialMetadata = headers;
GRPCCall2 *call = [[GRPCCall2 alloc]
initWithRequestOptions:request
handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:^(
NSDictionary *initialMetadata) {
NSString *userAgent = initialMetadata[@"x-grpc-test-echo-useragent"];
// Test the regex is correct
NSString *expectedUserAgent = @"Foo grpc-objc/";
expectedUserAgent =
[expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING];
expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"];
expectedUserAgent =
[expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING];
expectedUserAgent =
[expectedUserAgent stringByAppendingString:@" (ios; chttp2; "];
expectedUserAgent = [expectedUserAgent
stringByAppendingString:[NSString
stringWithUTF8String:grpc_g_stands_for()]];
expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"];
XCTAssertEqualObjects(userAgent, expectedUserAgent);
NSError *error = nil;
// Change in format of user-agent field in a direction that does not match
// the regex will likely cause problem for certain gRPC users. For details,
// refer to internal doc https://goo.gl/c2diBc
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:
@" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?"
options:0
error:&error];
NSString *customUserAgent = [regex
stringByReplacingMatchesInString:userAgent
options:0
range:NSMakeRange(0, [userAgent length])
withTemplate:@""];
XCTAssertEqualObjects(customUserAgent, @"Foo");
[recvInitialMd fulfill];
}
messageCallback:^(id message) {
XCTAssertNotNil(message);
XCTAssertEqual([message length], 0,
@"Non-empty response received: %@", message);
}
closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
if (error) {
XCTFail(@"Finished with unexpected error: %@", error);
} else {
[completion fulfill];
}
}]
callOptions:options];
[call writeWithData:[NSData data]];
[call start];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testTrailers {
__weak XCTestExpectation *response =
[self expectationWithDescription:@"Empty response received."];
@ -420,6 +592,52 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testIdempotentProtoRPCWithV2API {
__weak XCTestExpectation *response = [self expectationWithDescription:@"Expected response."];
__weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
RMTSimpleRequest *request = [RMTSimpleRequest message];
request.responseSize = 100;
request.fillUsername = YES;
request.fillOauthScope = YES;
GRPCRequestOptions *requestOptions =
[[GRPCRequestOptions alloc] initWithHost:kHostAddress
path:kUnaryCallMethod.HTTPPath
safety:GRPCCallSafetyIdempotentRequest];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
GRPCCall2 *call = [[GRPCCall2 alloc]
initWithRequestOptions:requestOptions
handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
NSData *data = (NSData *)message;
XCTAssertNotNil(data, @"nil value received as response.");
XCTAssertGreaterThan(data.length, 0,
@"Empty response received.");
RMTSimpleResponse *responseProto =
[RMTSimpleResponse parseFromData:data error:NULL];
// We expect empty strings, not nil:
XCTAssertNotNil(responseProto.username,
@"Response's username is nil.");
XCTAssertNotNil(responseProto.oauthScope,
@"Response's OAuth scope is nil.");
[response fulfill];
}
closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@",
error);
[completion fulfill];
}]
callOptions:options];
[call start];
[call writeWithData:[request data]];
[call finish];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testAlternateDispatchQueue {
const int32_t kPayloadSize = 100;
RMTSimpleRequest *request = [RMTSimpleRequest message];
@ -509,6 +727,38 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testTimeoutWithV2API {
__weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.timeout = 0.001;
GRPCRequestOptions *requestOptions =
[[GRPCRequestOptions alloc] initWithHost:kHostAddress
path:kFullDuplexCallMethod.HTTPPath
safety:GRPCCallSafetyDefault];
GRPCCall2 *call = [[GRPCCall2 alloc]
initWithRequestOptions:requestOptions
handler:
[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
messageCallback:^(id data) {
XCTFail(
@"Failure: response received; Expect: no response received.");
}
closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
XCTAssertNotNil(error,
@"Failure: no error received; Expect: receive "
@"deadline exceeded.");
XCTAssertEqual(error.code, GRPCErrorCodeDeadlineExceeded);
[completion fulfill];
}]
callOptions:options];
[call start];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (int)findFreePort {
struct sockaddr_in addr;
unsigned int addr_len = sizeof(addr);
@ -580,15 +830,52 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testTimeoutBackoffWithOptionsWithTimeout:(double)timeout Backoff:(double)backoff {
const double maxConnectTime = timeout > backoff ? timeout : backoff;
const double kMargin = 0.1;
__weak XCTestExpectation *completion = [self expectationWithDescription:@"Timeout in a second."];
NSString *const kDummyAddress = [NSString stringWithFormat:@"8.8.8.8:1"];
GRPCRequestOptions *requestOptions =
[[GRPCRequestOptions alloc] initWithHost:kDummyAddress path:@"" safety:GRPCCallSafetyDefault];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.connectMinTimeout = timeout;
options.connectInitialBackoff = backoff;
options.connectMaxBackoff = 0;
NSDate *startTime = [NSDate date];
GRPCCall2 *call = [[GRPCCall2 alloc]
initWithRequestOptions:requestOptions
handler:[[ClientTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
messageCallback:^(id data) {
XCTFail(@"Received message. Should not reach here.");
}
closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
XCTAssertNotNil(error,
@"Finished with no error; expecting error");
XCTAssertLessThan(
[[NSDate date] timeIntervalSinceDate:startTime],
maxConnectTime + kMargin);
[completion fulfill];
}]
callOptions:options];
[call start];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
// The numbers of the following three tests are selected to be smaller than the default values of
// initial backoff (1s) and min_connect_timeout (20s), so that if they fail we know the default
// values fail to be overridden by the channel args.
- (void)testTimeoutBackoff2 {
- (void)testTimeoutBackoff1 {
[self testTimeoutBackoffWithTimeout:0.7 Backoff:0.3];
[self testTimeoutBackoffWithOptionsWithTimeout:0.7 Backoff:0.4];
}
- (void)testTimeoutBackoff3 {
- (void)testTimeoutBackoff2 {
[self testTimeoutBackoffWithTimeout:0.3 Backoff:0.7];
[self testTimeoutBackoffWithOptionsWithTimeout:0.3 Backoff:0.8];
}
- (void)testErrorDebugInformation {

@ -18,6 +18,8 @@
#import <XCTest/XCTest.h>
#import <GRPCClient/GRPCCallOptions.h>
/**
* Implements tests as described here:
* https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
@ -38,4 +40,23 @@
* remote servers enconde responses with different overhead (?), so this is defined per-subclass.
*/
- (int32_t)encodingOverhead;
/**
* The type of transport to be used. The base implementation returns default. Subclasses should
* override to appropriate settings.
*/
+ (GRPCTransportType)transportType;
/**
* The root certificates to be used. The base implementation returns nil. Subclasses should override
* to appropriate settings.
*/
+ (NSString *)pemRootCert;
/**
* The root certificates to be used. The base implementation returns nil. Subclasses should override
* to appropriate settings.
*/
+ (NSString *)hostNameOverride;
@end

@ -74,6 +74,58 @@ BOOL isRemoteInteropTest(NSString *host) {
return [host isEqualToString:@"grpc-test.sandbox.googleapis.com"];
}
// Convenience class to use blocks as callbacks
@interface InteropTestsBlockCallbacks : NSObject<GRPCResponseHandler>
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
@end
@implementation InteropTestsBlockCallbacks {
void (^_initialMetadataCallback)(NSDictionary *);
void (^_messageCallback)(id);
void (^_closeCallback)(NSDictionary *, NSError *);
dispatch_queue_t _dispatchQueue;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
messageCallback:(void (^)(id))messageCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback {
if ((self = [super init])) {
_initialMetadataCallback = initialMetadataCallback;
_messageCallback = messageCallback;
_closeCallback = closeCallback;
_dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)receivedInitialMetadata:(NSDictionary *)initialMetadata {
if (_initialMetadataCallback) {
_initialMetadataCallback(initialMetadata);
}
}
- (void)receivedMessage:(id)message {
if (_messageCallback) {
_messageCallback(message);
}
}
- (void)closedWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (_closeCallback) {
_closeCallback(trailingMetadata, error);
}
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
@end
#pragma mark Tests
@implementation InteropTests {
@ -91,6 +143,18 @@ BOOL isRemoteInteropTest(NSString *host) {
return 0;
}
+ (GRPCTransportType)transportType {
return GRPCTransportTypeDefault;
}
+ (NSString *)pemRootCert {
return nil;
}
+ (NSString *)hostNameOverride {
return nil;
}
+ (void)setUp {
NSLog(@"InteropTest Started, class: %@", [[self class] description]);
#ifdef GRPC_COMPILE_WITH_CRONET
@ -131,6 +195,33 @@ BOOL isRemoteInteropTest(NSString *host) {
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testEmptyUnaryRPCWithV2API {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"];
GPBEmpty *request = [GPBEmpty message];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = self.class.transportType;
options.pemRootCert = self.class.pemRootCert;
options.hostNameOverride = self.class.hostNameOverride;
[_service
emptyCallWithMessage:request
responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
if (message) {
id expectedResponse = [GPBEmpty message];
XCTAssertEqualObjects(message, expectedResponse);
[expectation fulfill];
}
}
closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
XCTAssertNil(error, @"Unexpected error: %@", error);
}]
callOptions:options];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testLargeUnaryRPC {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"LargeUnary"];
@ -380,6 +471,57 @@ BOOL isRemoteInteropTest(NSString *host) {
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testPingPongRPCWithV2API {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPong"];
NSArray *requests = @[ @27182, @8, @1828, @45904 ];
NSArray *responses = @[ @31415, @9, @2653, @58979 ];
__block int index = 0;
id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index]
requestedResponseSize:responses[index]];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = self.class.transportType;
options.pemRootCert = self.class.pemRootCert;
options.hostNameOverride = self.class.hostNameOverride;
__block GRPCStreamingProtoCall *call = [_service
fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
XCTAssertLessThan(index, 4,
@"More than 4 responses received.");
id expected = [RMTStreamingOutputCallResponse
messageWithPayloadSize:responses[index]];
XCTAssertEqualObjects(message, expected);
index += 1;
if (index < 4) {
id request = [RMTStreamingOutputCallRequest
messageWithPayloadSize:requests[index]
requestedResponseSize:responses[index]];
[call writeWithMessage:request];
} else {
[call finish];
}
}
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNil(error,
@"Finished with unexpected error: %@",
error);
XCTAssertEqual(index, 4,
@"Received %i responses instead of 4.",
index);
[expectation fulfill];
}]
callOptions:options];
[call writeWithMessage:request];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testEmptyStreamRPC {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyStream"];
@ -418,6 +560,28 @@ BOOL isRemoteInteropTest(NSString *host) {
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testCancelAfterBeginRPCWithV2API {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterBegin"];
// A buffered pipe to which we never write any value acts as a writer that just hangs.
__block GRPCStreamingProtoCall *call = [_service
streamingInputCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
XCTFail(@"Not expected to receive message");
}
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
[expectation fulfill];
}]
callOptions:nil];
[call cancel];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testCancelAfterFirstResponseRPC {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation =
@ -454,6 +618,43 @@ BOOL isRemoteInteropTest(NSString *host) {
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testCancelAfterFirstResponseRPCWithV2API {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *completionExpectation =
[self expectationWithDescription:@"Call completed."];
__weak XCTestExpectation *responseExpectation =
[self expectationWithDescription:@"Received response."];
__block BOOL receivedResponse = NO;
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = self.class.transportType;
options.pemRootCert = self.class.pemRootCert;
options.hostNameOverride = self.class.hostNameOverride;
id request =
[RMTStreamingOutputCallRequest messageWithPayloadSize:@21782 requestedResponseSize:@31415];
__block GRPCStreamingProtoCall *call = [_service
fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
messageCallback:^(id message) {
XCTAssertFalse(receivedResponse);
receivedResponse = YES;
[call cancel];
[responseExpectation fulfill];
}
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
[completionExpectation fulfill];
}]
callOptions:options];
[call writeWithMessage:request];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testRPCAfterClosingOpenConnections {
XCTAssertNotNil(self.class.host);
__weak XCTestExpectation *expectation =

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -0,0 +1,116 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <XCTest/XCTest.h>
#import <RemoteTest/Messages.pbobjc.h>
#import <RemoteTest/Test.pbobjc.h>
#import <RemoteTest/Test.pbrpc.h>
#import <RxLibrary/GRXBufferedPipe.h>
#import <RxLibrary/GRXWriter+Immediate.h>
#import <grpc/grpc.h>
#define NSStringize_helper(x) #x
#define NSStringize(x) @NSStringize_helper(x)
static NSString *kRemoteHost = NSStringize(HOST_PORT_REMOTE);
const int32_t kRemoteInteropServerOverhead = 12;
static const NSTimeInterval TEST_TIMEOUT = 16000;
@interface InteropTestsCallOptions : XCTestCase
@end
@implementation InteropTestsCallOptions {
RMTTestService *_service;
}
- (void)setUp {
self.continueAfterFailure = NO;
_service = [RMTTestService serviceWithHost:kRemoteHost];
_service.options = [[GRPCCallOptions alloc] init];
}
- (void)test4MBResponsesAreAccepted {
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const int32_t kPayloadSize =
4 * 1024 * 1024 - kRemoteInteropServerOverhead; // 4MB - encoding overhead
request.responseSize = kPayloadSize;
[_service unaryCallWithRequest:request
handler:^(RMTSimpleResponse *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
XCTAssertEqual(response.payload.body.length, kPayloadSize);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testResponsesOverMaxSizeFailWithActionableMessage {
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const int32_t kPayloadSize =
4 * 1024 * 1024 - kRemoteInteropServerOverhead + 1; // 1B over max size
request.responseSize = kPayloadSize;
[_service unaryCallWithRequest:request
handler:^(RMTSimpleResponse *response, NSError *error) {
XCTAssertEqualObjects(
error.localizedDescription,
@"Received message larger than max (4194305 vs. 4194304)");
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testResponsesOver4MBAreAcceptedIfOptedIn {
__weak XCTestExpectation *expectation =
[self expectationWithDescription:@"HigherResponseSizeLimit"];
RMTSimpleRequest *request = [RMTSimpleRequest message];
const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB
request.responseSize = kPayloadSize;
GRPCProtoCall *rpc = [_service
RPCToUnaryCallWithRequest:request
handler:^(RMTSimpleResponse *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
XCTAssertEqual(response.payload.body.length, kPayloadSize);
[expectation fulfill];
}];
GRPCCallOptions *options = rpc.options;
options.responseSizeLimit = 6 * 1024 * 1024;
[rpc start];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end

@ -41,6 +41,14 @@ static int32_t kLocalInteropServerOverhead = 10;
return kLocalCleartextHost;
}
+ (NSString *)pemRootCert {
return nil;
}
+ (NSString *)hostNameOverride {
return nil;
}
- (int32_t)encodingOverhead {
return kLocalInteropServerOverhead; // bytes
}
@ -52,4 +60,8 @@ static int32_t kLocalInteropServerOverhead = 10;
[GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost];
}
+ (GRPCTransportType)transportType {
return GRPCTransportTypeInsecure;
}
@end

@ -40,10 +40,26 @@ static int32_t kLocalInteropServerOverhead = 10;
return kLocalSSLHost;
}
+ (NSString *)pemRootCert {
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *certsPath =
[bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"];
NSError *error;
return [NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error];
}
+ (NSString *)hostNameOverride {
return @"foo.test.google.fr";
}
- (int32_t)encodingOverhead {
return kLocalInteropServerOverhead; // bytes
}
+ (GRPCTransportType)transportType {
return GRPCTransportTypeDefault;
}
- (void)setUp {
[super setUp];

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -0,0 +1,259 @@
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <XCTest/XCTest.h>
#import <Cronet/Cronet.h>
#import <RemoteTest/Messages.pbobjc.h>
#import <RemoteTest/Test.pbobjc.h>
#import <RemoteTest/Test.pbrpc.h>
#import <RxLibrary/GRXBufferedPipe.h>
#define NSStringize_helper(x) #x
#define NSStringize(x) @NSStringize_helper(x)
static NSString *const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
static NSString *const kLocalSSLHost = NSStringize(HOST_PORT_LOCALSSL);
static NSString *const kLocalCleartextHost = NSStringize(HOST_PORT_LOCAL);
static const NSTimeInterval TEST_TIMEOUT = 8000;
@interface RMTStreamingOutputCallRequest (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
requestedResponseSize:(NSNumber *)responseSize;
@end
@implementation RMTStreamingOutputCallRequest (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize
requestedResponseSize:(NSNumber *)responseSize {
RMTStreamingOutputCallRequest *request = [self message];
RMTResponseParameters *parameters = [RMTResponseParameters message];
parameters.size = responseSize.intValue;
[request.responseParametersArray addObject:parameters];
request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
return request;
}
@end
@interface RMTStreamingOutputCallResponse (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize;
@end
@implementation RMTStreamingOutputCallResponse (Constructors)
+ (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize {
RMTStreamingOutputCallResponse *response = [self message];
response.payload.type = RMTPayloadType_Compressable;
response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
return response;
}
@end
@interface InteropTestsMultipleChannels : XCTestCase
@end
dispatch_once_t initCronet;
@implementation InteropTestsMultipleChannels {
RMTTestService *_remoteService;
RMTTestService *_remoteCronetService;
RMTTestService *_localCleartextService;
RMTTestService *_localSSLService;
}
- (void)setUp {
[super setUp];
self.continueAfterFailure = NO;
// Default stack with remote host
_remoteService = [RMTTestService serviceWithHost:kRemoteSSLHost];
// Cronet stack with remote host
_remoteCronetService = [RMTTestService serviceWithHost:kRemoteSSLHost];
dispatch_once(&initCronet, ^{
[Cronet setHttp2Enabled:YES];
[Cronet start];
});
GRPCCallOptions *options = [[GRPCCallOptions alloc] init];
options.transportType = GRPCTransportTypeCronet;
options.cronetEngine = [Cronet getGlobalEngine];
_remoteCronetService.options = options;
// Local stack with no SSL
_localCleartextService = [RMTTestService serviceWithHost:kLocalCleartextHost];
options = [[GRPCCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
_localCleartextService.options = options;
// Local stack with SSL
_localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost];
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *certsPath =
[bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"];
NSError *error = nil;
NSString *certs =
[NSString stringWithContentsOfFile:certsPath encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
options = [[GRPCCallOptions alloc] init];
options.transportType = GRPCTransportTypeDefault;
options.pemRootCert = certs;
options.hostNameOverride = @"foo.test.google.fr";
_localSSLService.options = options;
}
- (void)testEmptyUnaryRPC {
__weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCronetRemote =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCleartext =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
GPBEmpty *request = [GPBEmpty message];
void (^handler)(GPBEmpty *response, NSError *error) = ^(GPBEmpty *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
id expectedResponse = [GPBEmpty message];
XCTAssertEqualObjects(response, expectedResponse);
};
[_remoteService emptyCallWithRequest:request
handler:^(GPBEmpty *response, NSError *error) {
handler(response, error);
[expectRemote fulfill];
}];
[_remoteCronetService emptyCallWithRequest:request
handler:^(GPBEmpty *response, NSError *error) {
handler(response, error);
[expectCronetRemote fulfill];
}];
[_localCleartextService emptyCallWithRequest:request
handler:^(GPBEmpty *response, NSError *error) {
handler(response, error);
[expectCleartext fulfill];
}];
[_localSSLService emptyCallWithRequest:request
handler:^(GPBEmpty *response, NSError *error) {
handler(response, error);
[expectSSL fulfill];
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testFullDuplexRPC {
__weak XCTestExpectation *expectRemote = [self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCronetRemote =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectCleartext =
[self expectationWithDescription:@"Remote RPC finish"];
__weak XCTestExpectation *expectSSL = [self expectationWithDescription:@"Remote RPC finish"];
NSArray *requestSizes = @[ @100, @101, @102, @103 ];
NSArray *responseSizes = @[ @104, @105, @106, @107 ];
XCTAssertEqual([requestSizes count], [responseSizes count]);
NSUInteger kRounds = [requestSizes count];
NSMutableArray *requests = [NSMutableArray arrayWithCapacity:kRounds];
NSMutableArray *responses = [NSMutableArray arrayWithCapacity:kRounds];
for (int i = 0; i < kRounds; i++) {
requests[i] = [RMTStreamingOutputCallRequest messageWithPayloadSize:requestSizes[i]
requestedResponseSize:responseSizes[i]];
responses[i] = [RMTStreamingOutputCallResponse messageWithPayloadSize:responseSizes[i]];
}
__block NSMutableArray *steps = [NSMutableArray arrayWithCapacity:4];
__block NSMutableArray *requestsBuffers = [NSMutableArray arrayWithCapacity:4];
for (int i = 0; i < 4; i++) {
steps[i] = [NSNumber numberWithUnsignedInteger:0];
requestsBuffers[i] = [[GRXBufferedPipe alloc] init];
[requestsBuffers[i] writeValue:requests[0]];
}
BOOL (^handler)(int, BOOL, RMTStreamingOutputCallResponse *, NSError *) =
^(int index, BOOL done, RMTStreamingOutputCallResponse *response, NSError *error) {
XCTAssertNil(error, @"Finished with unexpected error: %@", error);
XCTAssertTrue(done || response, @"Event handler called without an event.");
if (response) {
NSUInteger step = [steps[index] unsignedIntegerValue];
XCTAssertLessThan(step, kRounds, @"More than %lu responses received.",
(unsigned long)kRounds);
XCTAssertEqualObjects(response, responses[step]);
step++;
steps[index] = [NSNumber numberWithUnsignedInteger:step];
GRXBufferedPipe *pipe = requestsBuffers[index];
if (step < kRounds) {
[pipe writeValue:requests[step]];
} else {
[pipe writesFinishedWithError:nil];
}
}
if (done) {
NSUInteger step = [steps[index] unsignedIntegerValue];
XCTAssertEqual(step, kRounds, @"Received %lu responses instead of %lu.", step, kRounds);
return YES;
}
return NO;
};
[_remoteService
fullDuplexCallWithRequestsWriter:requestsBuffers[0]
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *_Nullable response,
NSError *_Nullable error) {
if (handler(0, done, response, error)) {
[expectRemote fulfill];
}
}];
[_remoteCronetService
fullDuplexCallWithRequestsWriter:requestsBuffers[1]
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *_Nullable response,
NSError *_Nullable error) {
if (handler(1, done, response, error)) {
[expectCronetRemote fulfill];
}
}];
[_localCleartextService
fullDuplexCallWithRequestsWriter:requestsBuffers[2]
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *_Nullable response,
NSError *_Nullable error) {
if (handler(2, done, response, error)) {
[expectCleartext fulfill];
}
}];
[_localSSLService
fullDuplexCallWithRequestsWriter:requestsBuffers[3]
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *_Nullable response,
NSError *_Nullable error) {
if (handler(3, done, response, error)) {
[expectSSL fulfill];
}
}];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
@end

@ -41,8 +41,26 @@ static int32_t kRemoteInteropServerOverhead = 12;
return kRemoteSSLHost;
}
+ (NSString *)pemRootCert {
return nil;
}
+ (NSString *)hostNameOverride {
return nil;
}
- (int32_t)encodingOverhead {
return kRemoteInteropServerOverhead; // bytes
}
#ifdef GRPC_COMPILE_WITH_CRONET
+ (GRPCTransportType)transportType {
return GRPCTransportTypeCronet;
}
#else
+ (GRPCTransportType)transportType {
return GRPCTransportTypeDefault;
}
#endif
@end

@ -14,6 +14,8 @@ GRPC_LOCAL_SRC = '../../..'
InteropTestsLocalSSL
InteropTestsLocalCleartext
InteropTestsRemoteWithCronet
InteropTestsMultipleChannels
InteropTestsCallOptions
UnitTests
).each do |target_name|
target target_name do
@ -30,7 +32,7 @@ GRPC_LOCAL_SRC = '../../..'
pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true
if target_name == 'InteropTestsRemoteWithCronet'
if target_name == 'InteropTestsRemoteWithCronet' or target_name == 'InteropTestsMultipleChannels'
pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
end
@ -72,6 +74,12 @@ end
end
end
target 'ChannelTests' do
pod 'gRPC', :path => GRPC_LOCAL_SRC
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
end
# gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's
# pre_install hook lets us do that. The block passed to it runs after the podspecs are downloaded
# and before they are installed in the user project.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
BuildableName = "ChannelTests.xctest"
BlueprintName = "ChannelTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
BuildableName = "ChannelTests.xctest"
BlueprintName = "ChannelTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
BuildableName = "ChannelTests.xctest"
BlueprintName = "ChannelTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2E32107DED300EB4B69"
BuildableName = "ChannelTests.xctest"
BlueprintName = "ChannelTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E7D71B1210B9EC8001EA6BA"
BuildableName = "InteropTestsCallOptions.xctest"
BlueprintName = "InteropTestsCallOptions"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -26,7 +26,6 @@
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
@ -39,12 +38,6 @@
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "GRPCClientTests/testConnectionToRemoteServer">
</Test>
<Test
Identifier = "GRPCClientTests/testMetadata">
</Test>
<Test
Identifier = "InteropTests">
</Test>
@ -58,7 +51,6 @@
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Cronet"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5EB2A2F42109284500EB4B69"
BuildableName = "InteropTestsMultipleChannels.xctest"
BlueprintName = "InteropTestsMultipleChannels"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Cronet"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -26,7 +26,6 @@
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
@ -61,7 +60,6 @@
buildConfiguration = "Test"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

@ -173,4 +173,14 @@ xcodebuild \
| egrep -v '^$' \
| egrep -v "(GPBDictionary|GPBArray)" -
echo "TIME: $(date)"
xcodebuild \
-workspace Tests.xcworkspace \
-scheme ChannelTests \
-destination name="iPhone 8" \
test \
| egrep -v "$XCODEBUILD_FILTER" \
| egrep -v '^$' \
| egrep -v "(GPBDictionary|GPBArray)" -
exit 0

Loading…
Cancel
Save