/* * * 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 #import #import #import #import "src/objective-c/tests/RemoteTestClient/Messages.pbobjc.h" #import "src/objective-c/tests/RemoteTestClient/Test.pbobjc.h" #import "src/objective-c/tests/RemoteTestClient/Test.pbrpc.h" #import "../ConfigureCronet.h" #import "InteropTestsBlockCallbacks.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; _remoteService = [RMTTestService serviceWithHost:kRemoteSSLHost callOptions:nil]; configureCronet(/*enable_netlog=*/false); // Default stack with remote host GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; options.transportType = GRPCTransportTypeCronet; // Cronet stack with remote host _remoteCronetService = [RMTTestService serviceWithHost:kRemoteSSLHost callOptions:options]; // Local stack with no SSL options = [[GRPCMutableCallOptions alloc] init]; options.transportType = GRPCTransportTypeInsecure; _localCleartextService = [RMTTestService serviceWithHost:kLocalCleartextHost callOptions:options]; // Local stack with SSL 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 = [[GRPCMutableCallOptions alloc] init]; options.transportType = GRPCTransportTypeChttp2BoringSSL; options.PEMRootCertificates = certs; options.hostNameOverride = @"foo.test.google.fr"; _localSSLService = [RMTTestService serviceWithHost:kLocalSSLHost callOptions: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 (^messageHandler)(id message) = ^(id message) { id expectedResponse = [GPBEmpty message]; XCTAssertEqualObjects(message, expectedResponse); }; GRPCUnaryProtoCall *callRemote = [_remoteService emptyCallWithMessage:request responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:messageHandler closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error); [expectRemote fulfill]; } writeMessageCallback:nil] callOptions:nil]; GRPCUnaryProtoCall *callCronet = [_remoteCronetService emptyCallWithMessage:request responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:messageHandler closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error); [expectCronetRemote fulfill]; } writeMessageCallback:nil] callOptions:nil]; GRPCUnaryProtoCall *callCleartext = [_localCleartextService emptyCallWithMessage:request responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:messageHandler closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error); [expectCleartext fulfill]; } writeMessageCallback:nil] callOptions:nil]; GRPCUnaryProtoCall *callSSL = [_localSSLService emptyCallWithMessage:request responseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:messageHandler closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error); [expectSSL fulfill]; } writeMessageCallback:nil] callOptions:nil]; [callRemote start]; [callCronet start]; [callCleartext start]; [callSSL start]; [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 *calls = [NSMutableArray arrayWithCapacity:4]; 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]]; } void (^handler)(NSUInteger index, id message) = ^(NSUInteger index, id message) { NSUInteger step = [steps[index] unsignedIntegerValue]; step++; steps[index] = [NSNumber numberWithUnsignedInteger:step]; if (step < kRounds) { [calls[index] writeMessage:requests[step]]; } else { [calls[index] finish]; } }; calls[0] = [_remoteService fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id message) { handler(0, message); } closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error); [expectRemote fulfill]; } writeMessageCallback:nil] callOptions:nil]; calls[1] = [_remoteCronetService fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id message) { handler(1, message); } closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error); [expectCronetRemote fulfill]; } writeMessageCallback:nil] callOptions:nil]; calls[2] = [_localCleartextService fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id message) { handler(2, message); } closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error); [expectCleartext fulfill]; } writeMessageCallback:nil] callOptions:nil]; calls[3] = [_localSSLService fullDuplexCallWithResponseHandler:[[InteropTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil messageCallback:^(id message) { handler(3, message); } closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { XCTAssertNil(error); [expectSSL fulfill]; } writeMessageCallback:nil] callOptions:nil]; for (int i = 0; i < 4; i++) { [calls[i] start]; [calls[i] writeMessage:requests[0]]; } [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @end