/* * * Copyright 2019 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #import NSTimeInterval const kWaitTime = 30; int const kNumIterations = 1; @interface GrpcIosTestUITests : XCTestCase @end @implementation GrpcIosTestUITests { XCUIApplication *testApp; XCUIApplication *settingsApp; } - (void)setUp { self.continueAfterFailure = NO; [[[XCUIApplication alloc] init] launch]; testApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"io.grpc.GrpcIosTest"]; [testApp activate]; // Reset RPC counter [self pressButton:@"Reset counter"]; settingsApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.Preferences"]; [settingsApp activate]; [NSThread sleepForTimeInterval:1]; // Go back to the first page of Settings. XCUIElement *backButton = settingsApp.navigationBars.buttons.firstMatch; while (backButton.exists && backButton.isHittable) { NSLog(@"Tapping back button"); [backButton tap]; } XCTAssert([settingsApp.navigationBars[@"Settings"] waitForExistenceWithTimeout:kWaitTime]); NSLog(@"Turning off airplane mode"); // Turn off airplane mode [self setAirplaneMode:NO]; // Turn on wifi NSLog(@"Turning on wifi"); [self setWifi:YES]; } - (void)tearDown { } - (void)doUnaryCall { [testApp activate]; [self pressButton:@"Unary call"]; } - (void)do10UnaryCalls { [testApp activate]; [self pressButton:@"10 Unary calls"]; } - (void)pressButton:(NSString *)name { // Wait for button to be visible while (![testApp.buttons[name] exists] || ![testApp.buttons[name] isHittable]) { [NSThread sleepForTimeInterval:1]; } // Wait until all events in run loop have been processed while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true) == kCFRunLoopRunHandledSource) ; NSLog(@"Pressing button: %@", name); [testApp.buttons[name] tap]; } - (void)expectCallSuccess { XCTAssert([testApp.staticTexts[@"Call done"] waitForExistenceWithTimeout:kWaitTime]); } - (void)expectCallFailed { XCTAssert([testApp.staticTexts[@"Call failed"] waitForExistenceWithTimeout:kWaitTime]); } - (void)expectCallSuccessOrFailed { NSDate *startTime = [NSDate date]; while (![testApp.staticTexts[@"Call done"] exists] && ![testApp.staticTexts[@"Call failed"] exists]) { XCTAssertLessThan([[NSDate date] timeIntervalSinceDate:startTime], kWaitTime); [NSThread sleepForTimeInterval:1]; } } - (void)setAirplaneMode:(BOOL)to { [settingsApp activate]; XCUIElement *mySwitch = settingsApp.tables.element.cells.switches[@"Airplane Mode"]; BOOL from = [(NSString *)mySwitch.value boolValue]; NSLog(@"Setting airplane from: %d to: %d", from, to); if (from != to) { [mySwitch tap]; // wait for network change to finish [NSThread sleepForTimeInterval:5]; } XCTAssert([(NSString *)mySwitch.value boolValue] == to); } - (void)setWifi:(BOOL)to { [settingsApp activate]; [settingsApp.tables.element.cells.staticTexts[@"Wi-Fi"] tap]; XCUIElement *wifiSwitch = settingsApp.tables.cells.switches[@"Wi-Fi"]; BOOL from = [(NSString *)wifiSwitch.value boolValue]; NSLog(@"Setting wifi from: %d to: %d", from, to); if (from != to) { [wifiSwitch tap]; // wait for wifi networks to be detected [NSThread sleepForTimeInterval:10]; } // Go back to the first page of Settings. XCUIElement *backButton = settingsApp.navigationBars.buttons.firstMatch; [backButton tap]; } - (int)getRandomNumberBetween:(int)min max:(int)max { return min + arc4random_uniform((max - min + 1)); } - (void)testBackgroundBeforeCall { NSLog(@"%s", __func__); // Open test app [testApp activate]; // Send test app to background [XCUIDevice.sharedDevice pressButton:XCUIDeviceButtonHome]; // Wait a bit int sleepTime = [self getRandomNumberBetween:5 max:10]; NSLog(@"Sleeping for %d seconds", sleepTime); [NSThread sleepForTimeInterval:sleepTime]; // Bring test app to foreground and make a unary call. Call should succeed [self doUnaryCall]; [self expectCallSuccess]; } - (void)testBackgroundDuringStreamingCall { NSLog(@"%s", __func__); // Open test app and start a streaming call [testApp activate]; [self pressButton:@"Start streaming call"]; // Send test app to background [XCUIDevice.sharedDevice pressButton:XCUIDeviceButtonHome]; // Wait a bit int sleepTime = [self getRandomNumberBetween:5 max:10]; NSLog(@"Sleeping for %d seconds", sleepTime); [NSThread sleepForTimeInterval:sleepTime]; // Bring test app to foreground and make a streaming call. Call should succeed. [testApp activate]; [self pressButton:@"Send Message"]; [self pressButton:@"Stop streaming call"]; [self expectCallSuccess]; } - (void)testCallAfterNetworkFlap { NSLog(@"%s", __func__); // Open test app and make a unary call. Channel to server should be open after this. [self doUnaryCall]; [self expectCallSuccess]; // Toggle airplane mode on and off [self setAirplaneMode:YES]; [self setAirplaneMode:NO]; // Bring test app to foreground and make a unary call. The call should succeed [self doUnaryCall]; [self expectCallSuccess]; } - (void)testCallWhileNetworkDown { NSLog(@"%s", __func__); // Open test app and make a unary call. Channel to server should be open after this. [self doUnaryCall]; [self expectCallSuccess]; // Turn on airplane mode [self setAirplaneMode:YES]; // Turn off wifi [self setWifi:NO]; // Unary call should fail [self doUnaryCall]; [self expectCallFailed]; // Turn off airplane mode [self setAirplaneMode:NO]; // Turn on wifi [self setWifi:YES]; // Unary call should succeed [self doUnaryCall]; [self expectCallSuccess]; } - (void)testSwitchApp { NSLog(@"%s", __func__); // Open test app and make a unary call. Channel to server should be open after this. [self doUnaryCall]; [self expectCallSuccess]; // Send test app to background [XCUIDevice.sharedDevice pressButton:XCUIDeviceButtonHome]; // Open stocks app XCUIApplication *stocksApp = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.stocks"]; [stocksApp activate]; // Ensure that stocks app is running in the foreground XCTAssert([stocksApp waitForState:XCUIApplicationStateRunningForeground timeout:5]); // Wait a bit int sleepTime = [self getRandomNumberBetween:5 max:10]; NSLog(@"Sleeping for %d seconds", sleepTime); [NSThread sleepForTimeInterval:sleepTime]; [stocksApp terminate]; // Make another unary call [self doUnaryCall]; [self expectCallSuccess]; } - (void)testNetworkFlapDuringStreamingCall { NSLog(@"%s", __func__); // Open test app and make a unary call. Channel to server should be open after this. [self doUnaryCall]; [self expectCallSuccess]; // Start streaming call and send a message [self pressButton:@"Start streaming call"]; [self pressButton:@"Send Message"]; // Toggle network on and off [self setAirplaneMode:YES]; [self setWifi:NO]; [self setAirplaneMode:NO]; [self setWifi:YES]; [testApp activate]; [self pressButton:@"Stop streaming call"]; // The call will fail if the stream gets a read error, else the call will succeed. [self expectCallSuccessOrFailed]; // Make another unary call, it should succeed [self doUnaryCall]; [self expectCallSuccess]; } - (void)testConcurrentCalls { NSLog(@"%s", __func__); // Press button to start 10 unary calls [self do10UnaryCalls]; // Toggle airplane mode on and off [self setAirplaneMode:YES]; [self setAirplaneMode:NO]; // 10 calls should have completed [testApp activate]; XCTAssert([testApp.staticTexts[@"Calls completed: 10"] waitForExistenceWithTimeout:kWaitTime]); } - (void)invokeTest { for (int i = 0; i < kNumIterations; i++) { [super invokeTest]; } } - (void)testUnaryCallTurnOffWifi { NSLog(@"%s", __func__); // Open test app and make a unary call. Channel to server should be open after this. [self doUnaryCall]; [self expectCallSuccess]; // Turn off wifi [self setWifi:NO]; // Phone should switch to cellular connection, call should succeed [self doUnaryCall]; [self expectCallSuccess]; // Turn on wifi [self setWifi:YES]; // Call should succeed after turning wifi back on [self doUnaryCall]; [self expectCallSuccess]; } - (void)testStreamingCallTurnOffWifi { NSLog(@"%s", __func__); // Open test app and make a unary call. Channel to server should be open after this. [self doUnaryCall]; [self expectCallSuccess]; // Start streaming call and send a message [self pressButton:@"Start streaming call"]; [self pressButton:@"Send Message"]; // Turn off wifi [self setWifi:NO]; // Phone should switch to cellular connection, this results in the call failing [testApp activate]; [self pressButton:@"Stop streaming call"]; [self expectCallFailed]; // Turn on wifi [self setWifi:YES]; // Call should succeed after turning wifi back on [self doUnaryCall]; [self expectCallSuccess]; } @end