• 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
19#import <XCTest/XCTest.h>
20
21NSTimeInterval const kWaitTime = 30;
22int const kNumIterations = 1;
23
24@interface GrpcIosTestUITests : XCTestCase
25@end
26
27@implementation GrpcIosTestUITests {
28  XCUIApplication *testApp;
29  XCUIApplication *settingsApp;
30}
31
32- (void)setUp {
33  self.continueAfterFailure = NO;
34  [[[XCUIApplication alloc] init] launch];
35  testApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"io.grpc.GrpcIosTest"];
36  [testApp activate];
37  // Reset RPC counter
38  [self pressButton:@"Reset counter"];
39
40  settingsApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.Preferences"];
41  [settingsApp activate];
42  [NSThread sleepForTimeInterval:1];
43  // Go back to the first page of Settings.
44  XCUIElement *backButton = settingsApp.navigationBars.buttons.firstMatch;
45  while (backButton.exists && backButton.isHittable) {
46    NSLog(@"Tapping back button");
47    [backButton tap];
48  }
49  XCTAssert([settingsApp.navigationBars[@"Settings"] waitForExistenceWithTimeout:kWaitTime]);
50  NSLog(@"Turning off airplane mode");
51  // Turn off airplane mode
52  [self setAirplaneMode:NO];
53
54  // Turn on wifi
55  NSLog(@"Turning on wifi");
56  [self setWifi:YES];
57}
58
59- (void)tearDown {
60}
61
62- (void)doUnaryCall {
63  [testApp activate];
64  [self pressButton:@"Unary call"];
65}
66
67- (void)do10UnaryCalls {
68  [testApp activate];
69  [self pressButton:@"10 Unary calls"];
70}
71
72- (void)pressButton:(NSString *)name {
73  // Wait for button to be visible
74  while (![testApp.buttons[name] exists] || ![testApp.buttons[name] isHittable]) {
75    [NSThread sleepForTimeInterval:1];
76  }
77  // Wait until all events in run loop have been processed
78  while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true) == kCFRunLoopRunHandledSource);
79
80  NSLog(@"Pressing button: %@", name);
81  [testApp.buttons[name] tap];
82}
83
84- (void)expectCallSuccess {
85  XCTAssert([testApp.staticTexts[@"Call done"] waitForExistenceWithTimeout:kWaitTime]);
86}
87
88- (void)expectCallFailed {
89  XCTAssert([testApp.staticTexts[@"Call failed"] waitForExistenceWithTimeout:kWaitTime]);
90}
91
92- (void)expectCallSuccessOrFailed {
93  NSDate *startTime = [NSDate date];
94  while (![testApp.staticTexts[@"Call done"] exists] &&
95         ![testApp.staticTexts[@"Call failed"] exists]) {
96    XCTAssertLessThan([[NSDate date] timeIntervalSinceDate:startTime], kWaitTime);
97    [NSThread sleepForTimeInterval:1];
98  }
99}
100
101- (void)setAirplaneMode:(BOOL)to {
102  [settingsApp activate];
103  XCUIElement *mySwitch = settingsApp.tables.element.cells.switches[@"Airplane Mode"];
104  BOOL from = [(NSString *)mySwitch.value boolValue];
105  NSLog(@"Setting airplane from: %d to: %d", from, to);
106  if (from != to) {
107    [mySwitch tap];
108    // wait for network change to finish
109    [NSThread sleepForTimeInterval:5];
110  }
111  XCTAssert([(NSString *)mySwitch.value boolValue] == to);
112}
113- (void)setWifi:(BOOL)to {
114  [settingsApp activate];
115  [settingsApp.tables.element.cells.staticTexts[@"Wi-Fi"] tap];
116  XCUIElement *wifiSwitch = settingsApp.tables.cells.switches[@"Wi-Fi"];
117  BOOL from = [(NSString *)wifiSwitch.value boolValue];
118  NSLog(@"Setting wifi from: %d to: %d", from, to);
119  if (from != to) {
120    [wifiSwitch tap];
121    // wait for wifi networks to be detected
122    [NSThread sleepForTimeInterval:10];
123  }
124  // Go back to the first page of Settings.
125  XCUIElement *backButton = settingsApp.navigationBars.buttons.firstMatch;
126  [backButton tap];
127}
128
129- (int)getRandomNumberBetween:(int)min max:(int)max {
130  return min + arc4random_uniform((max - min + 1));
131}
132
133- (void)testBackgroundBeforeCall {
134  NSLog(@"%s", __func__);
135  // Open test app
136  [testApp activate];
137  // Send test app to background
138  [XCUIDevice.sharedDevice pressButton:XCUIDeviceButtonHome];
139
140  // Wait a bit
141  int sleepTime = [self getRandomNumberBetween:5 max:10];
142  NSLog(@"Sleeping for %d seconds", sleepTime);
143  [NSThread sleepForTimeInterval:sleepTime];
144
145  // Bring test app to foreground and make a unary call. Call should succeed
146  [self doUnaryCall];
147  [self expectCallSuccess];
148}
149
150- (void)testBackgroundDuringStreamingCall {
151  NSLog(@"%s", __func__);
152  // Open test app and start a streaming call
153  [testApp activate];
154  [self pressButton:@"Start streaming call"];
155
156  // Send test app to background
157  [XCUIDevice.sharedDevice pressButton:XCUIDeviceButtonHome];
158
159  // Wait a bit
160  int sleepTime = [self getRandomNumberBetween:5 max:10];
161  NSLog(@"Sleeping for %d seconds", sleepTime);
162  [NSThread sleepForTimeInterval:sleepTime];
163
164  // Bring test app to foreground and make a streaming call. Call should succeed.
165  [testApp activate];
166  [self pressButton:@"Send Message"];
167  [self pressButton:@"Stop streaming call"];
168  [self expectCallSuccess];
169}
170
171- (void)testCallAfterNetworkFlap {
172  NSLog(@"%s", __func__);
173  // Open test app and make a unary call. Channel to server should be open after this.
174  [self doUnaryCall];
175  [self expectCallSuccess];
176
177  // Toggle airplane mode on and off
178  [self setAirplaneMode:YES];
179  [self setAirplaneMode:NO];
180
181  // Bring test app to foreground and make a unary call. The call should succeed
182  [self doUnaryCall];
183  [self expectCallSuccess];
184}
185
186- (void)testCallWhileNetworkDown {
187  NSLog(@"%s", __func__);
188  // Open test app and make a unary call. Channel to server should be open after this.
189  [self doUnaryCall];
190  [self expectCallSuccess];
191
192  // Turn on airplane mode
193  [self setAirplaneMode:YES];
194  // Turn off wifi
195  [self setWifi:NO];
196
197  // Unary call should fail
198  [self doUnaryCall];
199  [self expectCallFailed];
200
201  // Turn off airplane mode
202  [self setAirplaneMode:NO];
203  // Turn on wifi
204  [self setWifi:YES];
205
206  // Unary call should succeed
207  [self doUnaryCall];
208  [self expectCallSuccess];
209}
210
211- (void)testSwitchApp {
212  NSLog(@"%s", __func__);
213  // Open test app and make a unary call. Channel to server should be open after this.
214  [self doUnaryCall];
215  [self expectCallSuccess];
216
217  // Send test app to background
218  [XCUIDevice.sharedDevice pressButton:XCUIDeviceButtonHome];
219
220  // Open stocks app
221  XCUIApplication *stocksApp =
222      [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.stocks"];
223  [stocksApp activate];
224  // Ensure that stocks app is running in the foreground
225  XCTAssert([stocksApp waitForState:XCUIApplicationStateRunningForeground timeout:5]);
226  // Wait a bit
227  int sleepTime = [self getRandomNumberBetween:5 max:10];
228  NSLog(@"Sleeping for %d seconds", sleepTime);
229  [NSThread sleepForTimeInterval:sleepTime];
230  [stocksApp terminate];
231
232  // Make another unary call
233  [self doUnaryCall];
234  [self expectCallSuccess];
235}
236
237- (void)testNetworkFlapDuringStreamingCall {
238  NSLog(@"%s", __func__);
239  // Open test app and make a unary call. Channel to server should be open after this.
240  [self doUnaryCall];
241  [self expectCallSuccess];
242  // Start streaming call and send a message
243  [self pressButton:@"Start streaming call"];
244  [self pressButton:@"Send Message"];
245
246  // Toggle network on and off
247  [self setAirplaneMode:YES];
248  [self setWifi:NO];
249  [self setAirplaneMode:NO];
250  [self setWifi:YES];
251
252  [testApp activate];
253  [self pressButton:@"Stop streaming call"];
254  // The call will fail if the stream gets a read error, else the call will succeed.
255  [self expectCallSuccessOrFailed];
256
257  // Make another unary call, it should succeed
258  [self doUnaryCall];
259  [self expectCallSuccess];
260}
261
262- (void)testConcurrentCalls {
263  NSLog(@"%s", __func__);
264
265  // Press button to start 10 unary calls
266  [self do10UnaryCalls];
267
268  // Toggle airplane mode on and off
269  [self setAirplaneMode:YES];
270  [self setAirplaneMode:NO];
271
272  // 10 calls should have completed
273  [testApp activate];
274  XCTAssert([testApp.staticTexts[@"Calls completed: 10"] waitForExistenceWithTimeout:kWaitTime]);
275}
276
277- (void)invokeTest {
278  for (int i = 0; i < kNumIterations; i++) {
279    [super invokeTest];
280  }
281}
282
283- (void)testUnaryCallTurnOffWifi {
284  NSLog(@"%s", __func__);
285  // Open test app and make a unary call. Channel to server should be open after this.
286  [self doUnaryCall];
287  [self expectCallSuccess];
288
289  // Turn off wifi
290  [self setWifi:NO];
291
292  // Phone should switch to cellular connection, call should succeed
293  [self doUnaryCall];
294  [self expectCallSuccess];
295
296  // Turn on wifi
297  [self setWifi:YES];
298
299  // Call should succeed after turning wifi back on
300  [self doUnaryCall];
301  [self expectCallSuccess];
302}
303
304- (void)testStreamingCallTurnOffWifi {
305  NSLog(@"%s", __func__);
306  // Open test app and make a unary call. Channel to server should be open after this.
307  [self doUnaryCall];
308  [self expectCallSuccess];
309
310  // Start streaming call and send a message
311  [self pressButton:@"Start streaming call"];
312  [self pressButton:@"Send Message"];
313
314  // Turn off wifi
315  [self setWifi:NO];
316
317  // Phone should switch to cellular connection, this results in the call failing
318  [testApp activate];
319  [self pressButton:@"Stop streaming call"];
320  [self expectCallFailed];
321
322  // Turn on wifi
323  [self setWifi:YES];
324
325  // Call should succeed after turning wifi back on
326  [self doUnaryCall];
327  [self expectCallSuccess];
328}
329
330@end
331