• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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