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