3 * Copyright 2019 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "StressTests.h"
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 <RemoteTest/Messages.pbobjc.h>
25 #import <RemoteTest/Test.pbobjc.h>
26 #import <RemoteTest/Test.pbrpc.h>
27 #import <RxLibrary/GRXBufferedPipe.h>
28 #import <RxLibrary/GRXWriter+Immediate.h>
30 #import <grpc/support/log.h>
32 #define TEST_TIMEOUT 32
34 extern const char *kCFStreamVarName;
36 // Convenience class to use blocks as callbacks
37 @interface MacTestsBlockCallbacks : NSObject<GRPCProtoResponseHandler>
39 - (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
40 messageCallback:(void (^)(id))messageCallback
41 closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback;
45 @implementation MacTestsBlockCallbacks {
46 void (^_initialMetadataCallback)(NSDictionary *);
47 void (^_messageCallback)(id);
48 void (^_closeCallback)(NSDictionary *, NSError *);
49 dispatch_queue_t _dispatchQueue;
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);
64 - (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
65 if (_initialMetadataCallback) {
66 _initialMetadataCallback(initialMetadata);
70 - (void)didReceiveProtoMessage:(GPBMessage *)message {
71 if (_messageCallback) {
72 _messageCallback(message);
76 - (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
78 _closeCallback(trailingMetadata, error);
82 - (dispatch_queue_t)dispatchQueue {
83 return _dispatchQueue;
88 @implementation StressTests {
89 RMTTestService *_service;
96 + (NSString *)hostAddress {
100 + (NSString *)PEMRootCertificates {
104 + (NSString *)hostNameOverride {
108 - (int32_t)encodingOverhead {
113 setenv(kCFStreamVarName, "1", 1);
117 self.continueAfterFailure = NO;
119 [GRPCCall resetHostSettings];
121 GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
122 options.transportType = [[self class] transportType];
123 options.PEMRootCertificates = [[self class] PEMRootCertificates];
124 options.hostNameOverride = [[self class] hostNameOverride];
125 _service = [RMTTestService serviceWithHost:[[self class] host] callOptions:options];
126 system([[NSString stringWithFormat:@"sudo ifconfig lo0 alias %@", [[self class] hostAddress]]
131 system([[NSString stringWithFormat:@"sudo ifconfig lo0 -alias %@", [[self class] hostAddress]]
135 + (GRPCTransportType)transportType {
136 return GRPCTransportTypeChttp2BoringSSL;
139 - (void)testNetworkFlapWithV2API {
140 NSMutableArray *completeExpectations = [NSMutableArray array];
141 NSMutableArray *calls = [NSMutableArray array];
143 __block BOOL address_removed = FALSE;
144 __block BOOL address_readded = FALSE;
145 for (int i = 0; i < num_rpcs; ++i) {
146 [completeExpectations
147 addObject:[self expectationWithDescription:
148 [NSString stringWithFormat:@"Received trailer for RPC %d", i]]];
150 RMTSimpleRequest *request = [RMTSimpleRequest message];
151 request.responseType = RMTPayloadType_Compressable;
152 request.responseSize = 314159;
153 request.payload.body = [NSMutableData dataWithLength:271828];
155 GRPCUnaryProtoCall *call = [_service
156 unaryCallWithMessage:request
157 responseHandler:[[MacTestsBlockCallbacks alloc] initWithInitialMetadataCallback:nil
158 messageCallback:^(id message) {
160 RMTSimpleResponse *expectedResponse =
161 [RMTSimpleResponse message];
162 expectedResponse.payload.type = RMTPayloadType_Compressable;
163 expectedResponse.payload.body =
164 [NSMutableData dataWithLength:314159];
165 XCTAssertEqualObjects(message, expectedResponse);
168 closeCallback:^(NSDictionary *trailingMetadata, NSError *error) {
170 @synchronized(self) {
171 if (error == nil && !address_removed) {
173 stringWithFormat:@"sudo ifconfig lo0 -alias %@",
174 [[self class] hostAddress]]
176 address_removed = YES;
177 } else if (error != nil && !address_readded) {
179 [NSString stringWithFormat:@"sudo ifconfig lo0 alias %@",
180 [[self class] hostAddress]]
182 address_readded = YES;
185 [completeExpectations[i] fulfill];
188 [calls addObject:call];
191 for (int i = 0; i < num_rpcs; ++i) {
192 GRPCUnaryProtoCall *call = calls[i];
194 [NSThread sleepForTimeInterval:0.1f];
196 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
199 - (void)testNetworkFlapWithV1API {
200 NSMutableArray *completeExpectations = [NSMutableArray array];
202 __block BOOL address_removed = FALSE;
203 __block BOOL address_readded = FALSE;
204 for (int i = 0; i < num_rpcs; ++i) {
205 [completeExpectations
206 addObject:[self expectationWithDescription:
207 [NSString stringWithFormat:@"Received response for RPC %d", i]]];
209 RMTSimpleRequest *request = [RMTSimpleRequest message];
210 request.responseType = RMTPayloadType_Compressable;
211 request.responseSize = 314159;
212 request.payload.body = [NSMutableData dataWithLength:271828];
214 [_service unaryCallWithRequest:request
215 handler:^(RMTSimpleResponse *response, NSError *error) {
216 @synchronized(self) {
217 if (error == nil && !address_removed) {
218 system([[NSString stringWithFormat:@"sudo ifconfig lo0 -alias %@",
219 [[self class] hostAddress]]
221 address_removed = YES;
222 } else if (error != nil && !address_readded) {
223 system([[NSString stringWithFormat:@"sudo ifconfig lo0 alias %@",
224 [[self class] hostAddress]]
226 address_readded = YES;
230 [completeExpectations[i] fulfill];
233 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];