1*cc02d7e2SAndroid Build Coastguard Worker/* 2*cc02d7e2SAndroid Build Coastguard Worker * 3*cc02d7e2SAndroid Build Coastguard Worker * Copyright 2019 gRPC authors. 4*cc02d7e2SAndroid Build Coastguard Worker * 5*cc02d7e2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 6*cc02d7e2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 7*cc02d7e2SAndroid Build Coastguard Worker * You may obtain a copy of the License at 8*cc02d7e2SAndroid Build Coastguard Worker * 9*cc02d7e2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 10*cc02d7e2SAndroid Build Coastguard Worker * 11*cc02d7e2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 12*cc02d7e2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 13*cc02d7e2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*cc02d7e2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 15*cc02d7e2SAndroid Build Coastguard Worker * limitations under the License. 16*cc02d7e2SAndroid Build Coastguard Worker * 17*cc02d7e2SAndroid Build Coastguard Worker */ 18*cc02d7e2SAndroid Build Coastguard Worker#include "StressTests.h" 19*cc02d7e2SAndroid Build Coastguard Worker 20*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/GRPCCall+ChannelArg.h> 21*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/GRPCCall+Tests.h> 22*cc02d7e2SAndroid Build Coastguard Worker#import <GRPCClient/internal_testing/GRPCCall+InternalTests.h> 23*cc02d7e2SAndroid Build Coastguard Worker#import <ProtoRPC/ProtoRPC.h> 24*cc02d7e2SAndroid Build Coastguard Worker#import <RxLibrary/GRXBufferedPipe.h> 25*cc02d7e2SAndroid Build Coastguard Worker#import <RxLibrary/GRXWriter+Immediate.h> 26*cc02d7e2SAndroid Build Coastguard Worker#import <grpc/grpc.h> 27*cc02d7e2SAndroid Build Coastguard Worker#import <grpc/support/log.h> 28*cc02d7e2SAndroid Build Coastguard Worker#import "src/objective-c/tests/RemoteTestClient/Messages.pbobjc.h" 29*cc02d7e2SAndroid Build Coastguard Worker#import "src/objective-c/tests/RemoteTestClient/Test.pbobjc.h" 30*cc02d7e2SAndroid Build Coastguard Worker#import "src/objective-c/tests/RemoteTestClient/Test.pbrpc.h" 31*cc02d7e2SAndroid Build Coastguard Worker 32*cc02d7e2SAndroid Build Coastguard Worker#define TEST_TIMEOUT 32 33*cc02d7e2SAndroid Build Coastguard Worker 34*cc02d7e2SAndroid Build Coastguard Workerextern const char *kCFStreamVarName; 35*cc02d7e2SAndroid Build Coastguard Worker 36*cc02d7e2SAndroid Build Coastguard Worker// Convenience class to use blocks as callbacks 37*cc02d7e2SAndroid Build Coastguard Worker@interface MacTestsBlockCallbacks : NSObject <GRPCProtoResponseHandler> 38*cc02d7e2SAndroid Build Coastguard Worker 39*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback 40*cc02d7e2SAndroid Build Coastguard Worker messageCallback:(void (^)(id))messageCallback 41*cc02d7e2SAndroid Build Coastguard Worker closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback; 42*cc02d7e2SAndroid Build Coastguard Worker 43*cc02d7e2SAndroid Build Coastguard Worker@end 44*cc02d7e2SAndroid Build Coastguard Worker 45*cc02d7e2SAndroid Build Coastguard Worker@implementation MacTestsBlockCallbacks { 46*cc02d7e2SAndroid Build Coastguard Worker void (^_initialMetadataCallback)(NSDictionary *); 47*cc02d7e2SAndroid Build Coastguard Worker void (^_messageCallback)(id); 48*cc02d7e2SAndroid Build Coastguard Worker void (^_closeCallback)(NSDictionary *, NSError *); 49*cc02d7e2SAndroid Build Coastguard Worker dispatch_queue_t _dispatchQueue; 50*cc02d7e2SAndroid Build Coastguard Worker} 51*cc02d7e2SAndroid Build Coastguard Worker 52*cc02d7e2SAndroid Build Coastguard Worker- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback 53*cc02d7e2SAndroid Build Coastguard Worker messageCallback:(void (^)(id))messageCallback 54*cc02d7e2SAndroid Build Coastguard Worker closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback { 55*cc02d7e2SAndroid Build Coastguard Worker if ((self = [super init])) { 56*cc02d7e2SAndroid Build Coastguard Worker _initialMetadataCallback = initialMetadataCallback; 57*cc02d7e2SAndroid Build Coastguard Worker _messageCallback = messageCallback; 58*cc02d7e2SAndroid Build Coastguard Worker _closeCallback = closeCallback; 59*cc02d7e2SAndroid Build Coastguard Worker _dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL); 60*cc02d7e2SAndroid Build Coastguard Worker } 61*cc02d7e2SAndroid Build Coastguard Worker return self; 62*cc02d7e2SAndroid Build Coastguard Worker} 63*cc02d7e2SAndroid Build Coastguard Worker 64*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata { 65*cc02d7e2SAndroid Build Coastguard Worker if (_initialMetadataCallback) { 66*cc02d7e2SAndroid Build Coastguard Worker _initialMetadataCallback(initialMetadata); 67*cc02d7e2SAndroid Build Coastguard Worker } 68*cc02d7e2SAndroid Build Coastguard Worker} 69*cc02d7e2SAndroid Build Coastguard Worker 70*cc02d7e2SAndroid Build Coastguard Worker- (void)didReceiveProtoMessage:(GPBMessage *)message { 71*cc02d7e2SAndroid Build Coastguard Worker if (_messageCallback) { 72*cc02d7e2SAndroid Build Coastguard Worker _messageCallback(message); 73*cc02d7e2SAndroid Build Coastguard Worker } 74*cc02d7e2SAndroid Build Coastguard Worker} 75*cc02d7e2SAndroid Build Coastguard Worker 76*cc02d7e2SAndroid Build Coastguard Worker- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error { 77*cc02d7e2SAndroid Build Coastguard Worker if (_closeCallback) { 78*cc02d7e2SAndroid Build Coastguard Worker _closeCallback(trailingMetadata, error); 79*cc02d7e2SAndroid Build Coastguard Worker } 80*cc02d7e2SAndroid Build Coastguard Worker} 81*cc02d7e2SAndroid Build Coastguard Worker 82*cc02d7e2SAndroid Build Coastguard Worker- (dispatch_queue_t)dispatchQueue { 83*cc02d7e2SAndroid Build Coastguard Worker return _dispatchQueue; 84*cc02d7e2SAndroid Build Coastguard Worker} 85*cc02d7e2SAndroid Build Coastguard Worker 86*cc02d7e2SAndroid Build Coastguard Worker@end 87*cc02d7e2SAndroid Build Coastguard Worker 88*cc02d7e2SAndroid Build Coastguard Worker@implementation StressTests { 89*cc02d7e2SAndroid Build Coastguard Worker RMTTestService *_service; 90*cc02d7e2SAndroid Build Coastguard Worker} 91*cc02d7e2SAndroid Build Coastguard Worker 92*cc02d7e2SAndroid Build Coastguard Worker+ (XCTestSuite *)defaultTestSuite { 93*cc02d7e2SAndroid Build Coastguard Worker if (self == [StressTests class]) { 94*cc02d7e2SAndroid Build Coastguard Worker return [XCTestSuite testSuiteWithName:@"StressTestsEmptySuite"]; 95*cc02d7e2SAndroid Build Coastguard Worker } else { 96*cc02d7e2SAndroid Build Coastguard Worker return super.defaultTestSuite; 97*cc02d7e2SAndroid Build Coastguard Worker } 98*cc02d7e2SAndroid Build Coastguard Worker} 99*cc02d7e2SAndroid Build Coastguard Worker 100*cc02d7e2SAndroid Build Coastguard Worker+ (NSString *)host { 101*cc02d7e2SAndroid Build Coastguard Worker return nil; 102*cc02d7e2SAndroid Build Coastguard Worker} 103*cc02d7e2SAndroid Build Coastguard Worker 104*cc02d7e2SAndroid Build Coastguard Worker+ (NSString *)hostAddress { 105*cc02d7e2SAndroid Build Coastguard Worker return nil; 106*cc02d7e2SAndroid Build Coastguard Worker} 107*cc02d7e2SAndroid Build Coastguard Worker 108*cc02d7e2SAndroid Build Coastguard Worker+ (NSString *)PEMRootCertificates { 109*cc02d7e2SAndroid Build Coastguard Worker return nil; 110*cc02d7e2SAndroid Build Coastguard Worker} 111*cc02d7e2SAndroid Build Coastguard Worker 112*cc02d7e2SAndroid Build Coastguard Worker+ (NSString *)hostNameOverride { 113*cc02d7e2SAndroid Build Coastguard Worker return nil; 114*cc02d7e2SAndroid Build Coastguard Worker} 115*cc02d7e2SAndroid Build Coastguard Worker 116*cc02d7e2SAndroid Build Coastguard Worker- (int32_t)encodingOverhead { 117*cc02d7e2SAndroid Build Coastguard Worker return 0; 118*cc02d7e2SAndroid Build Coastguard Worker} 119*cc02d7e2SAndroid Build Coastguard Worker 120*cc02d7e2SAndroid Build Coastguard Worker+ (void)setUp { 121*cc02d7e2SAndroid Build Coastguard Worker setenv(kCFStreamVarName, "1", 1); 122*cc02d7e2SAndroid Build Coastguard Worker} 123*cc02d7e2SAndroid Build Coastguard Worker 124*cc02d7e2SAndroid Build Coastguard Worker- (void)setUp { 125*cc02d7e2SAndroid Build Coastguard Worker self.continueAfterFailure = NO; 126*cc02d7e2SAndroid Build Coastguard Worker 127*cc02d7e2SAndroid Build Coastguard Worker [GRPCCall resetHostSettings]; 128*cc02d7e2SAndroid Build Coastguard Worker 129*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic push 130*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Wdeprecated-declarations" 131*cc02d7e2SAndroid Build Coastguard Worker [GRPCCall closeOpenConnections]; 132*cc02d7e2SAndroid Build Coastguard Worker#pragma clang diagnostic pop 133*cc02d7e2SAndroid Build Coastguard Worker 134*cc02d7e2SAndroid Build Coastguard Worker GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init]; 135*cc02d7e2SAndroid Build Coastguard Worker options.transportType = [[self class] transportType]; 136*cc02d7e2SAndroid Build Coastguard Worker options.PEMRootCertificates = [[self class] PEMRootCertificates]; 137*cc02d7e2SAndroid Build Coastguard Worker options.hostNameOverride = [[self class] hostNameOverride]; 138*cc02d7e2SAndroid Build Coastguard Worker _service = [RMTTestService serviceWithHost:[[self class] host] callOptions:options]; 139*cc02d7e2SAndroid Build Coastguard Worker system([[NSString stringWithFormat:@"sudo ifconfig lo0 alias %@", [[self class] hostAddress]] 140*cc02d7e2SAndroid Build Coastguard Worker UTF8String]); 141*cc02d7e2SAndroid Build Coastguard Worker} 142*cc02d7e2SAndroid Build Coastguard Worker 143*cc02d7e2SAndroid Build Coastguard Worker- (void)tearDown { 144*cc02d7e2SAndroid Build Coastguard Worker system([[NSString stringWithFormat:@"sudo ifconfig lo0 -alias %@", [[self class] hostAddress]] 145*cc02d7e2SAndroid Build Coastguard Worker UTF8String]); 146*cc02d7e2SAndroid Build Coastguard Worker} 147*cc02d7e2SAndroid Build Coastguard Worker 148*cc02d7e2SAndroid Build Coastguard Worker+ (GRPCTransportType)transportType { 149*cc02d7e2SAndroid Build Coastguard Worker return GRPCTransportTypeChttp2BoringSSL; 150*cc02d7e2SAndroid Build Coastguard Worker} 151*cc02d7e2SAndroid Build Coastguard Worker 152*cc02d7e2SAndroid Build Coastguard Worker- (void)testNetworkFlapWithV2API { 153*cc02d7e2SAndroid Build Coastguard Worker NSMutableArray *completeExpectations = [NSMutableArray array]; 154*cc02d7e2SAndroid Build Coastguard Worker NSMutableArray *calls = [NSMutableArray array]; 155*cc02d7e2SAndroid Build Coastguard Worker int num_rpcs = 100; 156*cc02d7e2SAndroid Build Coastguard Worker __block BOOL address_removed = FALSE; 157*cc02d7e2SAndroid Build Coastguard Worker __block BOOL address_readded = FALSE; 158*cc02d7e2SAndroid Build Coastguard Worker for (int i = 0; i < num_rpcs; ++i) { 159*cc02d7e2SAndroid Build Coastguard Worker [completeExpectations 160*cc02d7e2SAndroid Build Coastguard Worker addObject:[self expectationWithDescription: 161*cc02d7e2SAndroid Build Coastguard Worker [NSString stringWithFormat:@"Received trailer for RPC %d", i]]]; 162*cc02d7e2SAndroid Build Coastguard Worker 163*cc02d7e2SAndroid Build Coastguard Worker RMTSimpleRequest *request = [RMTSimpleRequest message]; 164*cc02d7e2SAndroid Build Coastguard Worker request.responseType = RMTPayloadType_Compressable; 165*cc02d7e2SAndroid Build Coastguard Worker request.responseSize = 314159; 166*cc02d7e2SAndroid Build Coastguard Worker request.payload.body = [NSMutableData dataWithLength:271828]; 167*cc02d7e2SAndroid Build Coastguard Worker 168*cc02d7e2SAndroid Build Coastguard Worker GRPCUnaryProtoCall *call = [_service 169*cc02d7e2SAndroid Build Coastguard Worker unaryCallWithMessage:request 170*cc02d7e2SAndroid Build Coastguard Worker responseHandler:[[MacTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil 171*cc02d7e2SAndroid Build Coastguard Worker messageCallback:^(id message) { 172*cc02d7e2SAndroid Build Coastguard Worker if (message) { 173*cc02d7e2SAndroid Build Coastguard Worker RMTSimpleResponse *expectedResponse = 174*cc02d7e2SAndroid Build Coastguard Worker [RMTSimpleResponse message]; 175*cc02d7e2SAndroid Build Coastguard Worker expectedResponse.payload.type = RMTPayloadType_Compressable; 176*cc02d7e2SAndroid Build Coastguard Worker expectedResponse.payload.body = 177*cc02d7e2SAndroid Build Coastguard Worker [NSMutableData dataWithLength:314159]; 178*cc02d7e2SAndroid Build Coastguard Worker XCTAssertEqualObjects(message, expectedResponse); 179*cc02d7e2SAndroid Build Coastguard Worker } 180*cc02d7e2SAndroid Build Coastguard Worker } 181*cc02d7e2SAndroid Build Coastguard Worker closeCallback:^(NSDictionary *trailingMetadata, NSError *error) { 182*cc02d7e2SAndroid Build Coastguard Worker @synchronized(self) { 183*cc02d7e2SAndroid Build Coastguard Worker if (error == nil && !address_removed) { 184*cc02d7e2SAndroid Build Coastguard Worker system([[NSString 185*cc02d7e2SAndroid Build Coastguard Worker stringWithFormat:@"sudo ifconfig lo0 -alias %@", 186*cc02d7e2SAndroid Build Coastguard Worker [[self class] hostAddress]] 187*cc02d7e2SAndroid Build Coastguard Worker UTF8String]); 188*cc02d7e2SAndroid Build Coastguard Worker address_removed = YES; 189*cc02d7e2SAndroid Build Coastguard Worker } else if (error != nil && !address_readded) { 190*cc02d7e2SAndroid Build Coastguard Worker system([[NSString 191*cc02d7e2SAndroid Build Coastguard Worker stringWithFormat:@"sudo ifconfig lo0 alias %@", 192*cc02d7e2SAndroid Build Coastguard Worker [[self class] hostAddress]] 193*cc02d7e2SAndroid Build Coastguard Worker UTF8String]); 194*cc02d7e2SAndroid Build Coastguard Worker address_readded = YES; 195*cc02d7e2SAndroid Build Coastguard Worker } 196*cc02d7e2SAndroid Build Coastguard Worker } 197*cc02d7e2SAndroid Build Coastguard Worker [completeExpectations[i] fulfill]; 198*cc02d7e2SAndroid Build Coastguard Worker }] 199*cc02d7e2SAndroid Build Coastguard Worker callOptions:nil]; 200*cc02d7e2SAndroid Build Coastguard Worker [calls addObject:call]; 201*cc02d7e2SAndroid Build Coastguard Worker } 202*cc02d7e2SAndroid Build Coastguard Worker 203*cc02d7e2SAndroid Build Coastguard Worker for (int i = 0; i < num_rpcs; ++i) { 204*cc02d7e2SAndroid Build Coastguard Worker GRPCUnaryProtoCall *call = calls[i]; 205*cc02d7e2SAndroid Build Coastguard Worker [call start]; 206*cc02d7e2SAndroid Build Coastguard Worker [NSThread sleepForTimeInterval:0.1f]; 207*cc02d7e2SAndroid Build Coastguard Worker } 208*cc02d7e2SAndroid Build Coastguard Worker [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; 209*cc02d7e2SAndroid Build Coastguard Worker} 210*cc02d7e2SAndroid Build Coastguard Worker 211*cc02d7e2SAndroid Build Coastguard Worker- (void)testNetworkFlapWithV1API { 212*cc02d7e2SAndroid Build Coastguard Worker NSMutableArray *completeExpectations = [NSMutableArray array]; 213*cc02d7e2SAndroid Build Coastguard Worker int num_rpcs = 100; 214*cc02d7e2SAndroid Build Coastguard Worker __block BOOL address_removed = FALSE; 215*cc02d7e2SAndroid Build Coastguard Worker __block BOOL address_readded = FALSE; 216*cc02d7e2SAndroid Build Coastguard Worker for (int i = 0; i < num_rpcs; ++i) { 217*cc02d7e2SAndroid Build Coastguard Worker [completeExpectations 218*cc02d7e2SAndroid Build Coastguard Worker addObject:[self expectationWithDescription: 219*cc02d7e2SAndroid Build Coastguard Worker [NSString stringWithFormat:@"Received response for RPC %d", i]]]; 220*cc02d7e2SAndroid Build Coastguard Worker 221*cc02d7e2SAndroid Build Coastguard Worker RMTSimpleRequest *request = [RMTSimpleRequest message]; 222*cc02d7e2SAndroid Build Coastguard Worker request.responseType = RMTPayloadType_Compressable; 223*cc02d7e2SAndroid Build Coastguard Worker request.responseSize = 314159; 224*cc02d7e2SAndroid Build Coastguard Worker request.payload.body = [NSMutableData dataWithLength:271828]; 225*cc02d7e2SAndroid Build Coastguard Worker 226*cc02d7e2SAndroid Build Coastguard Worker [_service unaryCallWithRequest:request 227*cc02d7e2SAndroid Build Coastguard Worker handler:^(RMTSimpleResponse *response, NSError *error) { 228*cc02d7e2SAndroid Build Coastguard Worker @synchronized(self) { 229*cc02d7e2SAndroid Build Coastguard Worker if (error == nil && !address_removed) { 230*cc02d7e2SAndroid Build Coastguard Worker system([[NSString stringWithFormat:@"sudo ifconfig lo0 -alias %@", 231*cc02d7e2SAndroid Build Coastguard Worker [[self class] hostAddress]] 232*cc02d7e2SAndroid Build Coastguard Worker UTF8String]); 233*cc02d7e2SAndroid Build Coastguard Worker address_removed = YES; 234*cc02d7e2SAndroid Build Coastguard Worker } else if (error != nil && !address_readded) { 235*cc02d7e2SAndroid Build Coastguard Worker system([[NSString stringWithFormat:@"sudo ifconfig lo0 alias %@", 236*cc02d7e2SAndroid Build Coastguard Worker [[self class] hostAddress]] 237*cc02d7e2SAndroid Build Coastguard Worker UTF8String]); 238*cc02d7e2SAndroid Build Coastguard Worker address_readded = YES; 239*cc02d7e2SAndroid Build Coastguard Worker } 240*cc02d7e2SAndroid Build Coastguard Worker } 241*cc02d7e2SAndroid Build Coastguard Worker 242*cc02d7e2SAndroid Build Coastguard Worker [completeExpectations[i] fulfill]; 243*cc02d7e2SAndroid Build Coastguard Worker }]; 244*cc02d7e2SAndroid Build Coastguard Worker 245*cc02d7e2SAndroid Build Coastguard Worker [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; 246*cc02d7e2SAndroid Build Coastguard Worker } 247*cc02d7e2SAndroid Build Coastguard Worker} 248*cc02d7e2SAndroid Build Coastguard Worker 249*cc02d7e2SAndroid Build Coastguard Worker@end 250