blob: 11894cbac50f15b44cffeb3e9b9c856740e13e42 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* 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.
*/
package com.android.tradefed.testtype;
import com.android.ddmlib.Log;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestResult.TestStatus;
import com.android.tradefed.TestAppConstants;
import com.android.tradefed.config.OptionSetter;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.DeviceUnresponsiveException;
import com.android.tradefed.device.ITestDevice.RecoveryMode;
import com.android.tradefed.device.RemoteAndroidDevice;
import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.util.KeyguardControllerState;
import com.android.tradefed.util.RunUtil;
import org.easymock.EasyMock;
import java.io.IOException;
/**
* Functional tests for {@link InstrumentationTest}.
*/
public class InstrumentationTestFuncTest extends DeviceTestCase {
private static final String LOG_TAG = "InstrumentationTestFuncTest";
private static final long SHELL_TIMEOUT = 2500;
private static final int TEST_TIMEOUT = 2000;
private static final long WAIT_FOR_DEVICE_AVAILABLE = 5 * 60 * 1000;
/** The {@link InstrumentationTest} under test */
private InstrumentationTest mInstrumentationTest;
private ITestInvocationListener mMockListener;
@Override
protected void setUp() throws Exception {
super.setUp();
mInstrumentationTest = new InstrumentationTest();
mInstrumentationTest.setPackageName(TestAppConstants.TESTAPP_PACKAGE);
mInstrumentationTest.setDevice(getDevice());
// use no timeout by default
mInstrumentationTest.setShellTimeout(-1);
// set to no rerun by default
mInstrumentationTest.setRerunMode(false);
mMockListener = EasyMock.createStrictMock(ITestInvocationListener.class);
getDevice().disableKeyguard();
}
/**
* Test normal run scenario with a single passed test result.
*/
public void testRun() throws DeviceNotAvailableException {
Log.i(LOG_TAG, "testRun");
TestIdentifier expectedTest = new TestIdentifier(TestAppConstants.TESTAPP_CLASS,
TestAppConstants.PASSED_TEST_METHOD);
mInstrumentationTest.setClassName(TestAppConstants.TESTAPP_CLASS);
mInstrumentationTest.setMethodName(TestAppConstants.PASSED_TEST_METHOD);
mInstrumentationTest.setTestTimeout(TEST_TIMEOUT);
mInstrumentationTest.setShellTimeout(SHELL_TIMEOUT);
mMockListener.testRunStarted(TestAppConstants.TESTAPP_PACKAGE, 1);
mMockListener.testStarted(EasyMock.eq(expectedTest));
mMockListener.testEnded(EasyMock.eq(expectedTest), EasyMock.anyObject());
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
EasyMock.replay(mMockListener);
mInstrumentationTest.run(mMockListener);
EasyMock.verify(mMockListener);
}
/**
* Test normal run scenario with a single failed test result.
*/
public void testRun_testFailed() throws DeviceNotAvailableException {
Log.i(LOG_TAG, "testRun_testFailed");
TestIdentifier expectedTest = new TestIdentifier(TestAppConstants.TESTAPP_CLASS,
TestAppConstants.FAILED_TEST_METHOD);
mInstrumentationTest.setClassName(TestAppConstants.TESTAPP_CLASS);
mInstrumentationTest.setMethodName(TestAppConstants.FAILED_TEST_METHOD);
mInstrumentationTest.setTestTimeout(TEST_TIMEOUT);
mInstrumentationTest.setShellTimeout(SHELL_TIMEOUT);
mMockListener.testRunStarted(
EasyMock.eq(TestAppConstants.TESTAPP_PACKAGE), EasyMock.anyInt());
mMockListener.testStarted(EasyMock.eq(expectedTest));
mMockListener.testFailed(
EasyMock.eq(expectedTest),
EasyMock.contains("junit.framework.AssertionFailedError: test failed"));
mMockListener.testEnded(EasyMock.eq(expectedTest), EasyMock.anyObject());
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
EasyMock.replay(mMockListener);
mInstrumentationTest.run(mMockListener);
EasyMock.verify(mMockListener);
}
/**
* Test run scenario where test process crashes.
*/
public void testRun_testCrash() throws DeviceNotAvailableException {
Log.i(LOG_TAG, "testRun_testCrash");
TestIdentifier expectedTest = new TestIdentifier(TestAppConstants.TESTAPP_CLASS,
TestAppConstants.CRASH_TEST_METHOD);
mInstrumentationTest.setClassName(TestAppConstants.TESTAPP_CLASS);
mInstrumentationTest.setMethodName(TestAppConstants.CRASH_TEST_METHOD);
mInstrumentationTest.setTestTimeout(TEST_TIMEOUT);
mInstrumentationTest.setShellTimeout(SHELL_TIMEOUT);
mMockListener.testRunStarted(TestAppConstants.TESTAPP_PACKAGE, 1);
mMockListener.testStarted(EasyMock.eq(expectedTest));
if (getDevice().getApiLevel() <= 23) {
// Before N handling of instrumentation crash is slightly different.
mMockListener.testFailed(
EasyMock.eq(expectedTest), EasyMock.contains("RuntimeException"));
mMockListener.testEnded(EasyMock.eq(expectedTest), EasyMock.anyObject());
mMockListener.testRunFailed(
EasyMock.eq("Instrumentation run failed due to 'java.lang.RuntimeException'"));
} else {
mMockListener.testFailed(
EasyMock.eq(expectedTest), EasyMock.contains("Process crashed."));
mMockListener.testEnded(EasyMock.eq(expectedTest), EasyMock.anyObject());
mMockListener.testRunFailed(
EasyMock.eq("Instrumentation run failed due to 'Process crashed.'"));
}
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
EasyMock.replay(mMockListener);
mInstrumentationTest.run(mMockListener);
EasyMock.verify(mMockListener);
}
/**
* Test run scenario where test run hangs indefinitely, and times out.
*/
public void testRun_testTimeout() throws DeviceNotAvailableException {
Log.i(LOG_TAG, "testRun_testTimeout");
RecoveryMode initMode = getDevice().getRecoveryMode();
getDevice().setRecoveryMode(RecoveryMode.NONE);
try {
TestIdentifier expectedTest =
new TestIdentifier(
TestAppConstants.TESTAPP_CLASS, TestAppConstants.TIMEOUT_TEST_METHOD);
mInstrumentationTest.setClassName(TestAppConstants.TESTAPP_CLASS);
mInstrumentationTest.setMethodName(TestAppConstants.TIMEOUT_TEST_METHOD);
mInstrumentationTest.setShellTimeout(SHELL_TIMEOUT);
mInstrumentationTest.setTestTimeout(TEST_TIMEOUT);
mMockListener.testRunStarted(
EasyMock.eq(TestAppConstants.TESTAPP_PACKAGE), EasyMock.anyInt());
mMockListener.testStarted(EasyMock.eq(expectedTest));
mMockListener.testFailed(
EasyMock.eq(expectedTest),
EasyMock.contains(
String.format(
"Failed to receive adb shell test output within %s ms",
SHELL_TIMEOUT)));
mMockListener.testEnded(EasyMock.eq(expectedTest), EasyMock.anyObject());
mMockListener.testRunFailed(
EasyMock.contains(
String.format(
"Failed to receive adb shell test output within %s ms",
SHELL_TIMEOUT)));
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
EasyMock.replay(mMockListener);
mInstrumentationTest.run(mMockListener);
EasyMock.verify(mMockListener);
} finally {
getDevice().setRecoveryMode(initMode);
RunUtil.getDefault().sleep(500);
}
}
/**
* Test run scenario where device reboots during test run.
*/
public void testRun_deviceReboot() throws Exception {
Log.i(LOG_TAG, "testRun_deviceReboot");
TestIdentifier expectedTest = new TestIdentifier(TestAppConstants.TESTAPP_CLASS,
TestAppConstants.TIMEOUT_TEST_METHOD);
mInstrumentationTest.setClassName(TestAppConstants.TESTAPP_CLASS);
mInstrumentationTest.setMethodName(TestAppConstants.TIMEOUT_TEST_METHOD);
mMockListener.testRunStarted(TestAppConstants.TESTAPP_PACKAGE, 1);
mMockListener.testStarted(EasyMock.eq(expectedTest));
mMockListener.testFailed(EasyMock.eq(expectedTest), EasyMock.anyObject());
mMockListener.testEnded(EasyMock.eq(expectedTest), EasyMock.anyObject());
mMockListener.testRunFailed(
EasyMock.eq("Test run failed to complete. Expected 1 tests, received 0"));
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
EasyMock.replay(mMockListener);
// fork off a thread to do the reboot
Thread rebootThread =
new Thread() {
@Override
public void run() {
// wait for test run to begin
try {
// Give time to the instrumentation to start
Thread.sleep(2000);
getDevice().reboot();
} catch (InterruptedException e) {
Log.w(LOG_TAG, "interrupted");
} catch (DeviceNotAvailableException dnae) {
Log.w(LOG_TAG, "Device did not come back online after reboot");
}
}
};
rebootThread.setName("InstrumentationTestFuncTest#testRun_deviceReboot");
rebootThread.start();
RecoveryMode initMode = getDevice().getRecoveryMode();
getDevice().setRecoveryMode(RecoveryMode.NONE);
try {
mInstrumentationTest.run(mMockListener);
// Remote device will not throw the DUE because of the different recovery path.
if (!(getDevice() instanceof RemoteAndroidDevice)) {
fail("Should have thrown an exception.");
}
} catch (DeviceUnresponsiveException expected) {
// expected
} finally {
getDevice().setRecoveryMode(initMode);
}
rebootThread.join(WAIT_FOR_DEVICE_AVAILABLE);
EasyMock.verify(mMockListener);
// Give some time after device available so that keyguard disabled is picked up.
RunUtil.getDefault().sleep(5000);
// now we check that the keyguard is dismissed.
KeyguardControllerState kcs = getDevice().getKeyguardState();
if (kcs != null) {
assertFalse("Keyguard is showing when it should not.", kcs.isKeyguardShowing());
} else {
assertTrue(runUITests());
}
}
/**
* Test run scenario where device runtime resets during test run.
* <p/>
* TODO: this test probably belongs more in TestDeviceFuncTest
*/
public void testRun_deviceRuntimeReset() throws Exception {
Log.i(LOG_TAG, "testRun_deviceRuntimeReset");
TestIdentifier expectedTest = new TestIdentifier(TestAppConstants.TESTAPP_CLASS,
TestAppConstants.TIMEOUT_TEST_METHOD);
mInstrumentationTest.setShellTimeout(SHELL_TIMEOUT);
mInstrumentationTest.setTestTimeout(TEST_TIMEOUT);
mInstrumentationTest.setClassName(TestAppConstants.TESTAPP_CLASS);
mInstrumentationTest.setMethodName(TestAppConstants.TIMEOUT_TEST_METHOD);
mMockListener.testRunStarted(
EasyMock.eq(TestAppConstants.TESTAPP_PACKAGE), EasyMock.anyInt());
mMockListener.testStarted(EasyMock.eq(expectedTest));
EasyMock.expectLastCall().anyTimes();
mMockListener.testFailed(EasyMock.eq(expectedTest), EasyMock.anyObject());
EasyMock.expectLastCall().anyTimes();
mMockListener.testEnded(EasyMock.eq(expectedTest), EasyMock.anyObject());
EasyMock.expectLastCall().anyTimes();
mMockListener.testRunFailed(EasyMock.anyObject());
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
EasyMock.replay(mMockListener);
// fork off a thread to do the runtime reset
Thread resetThread =
new Thread() {
@Override
public void run() {
// wait for test run to begin
try {
Thread.sleep(1000);
Runtime.getRuntime()
.exec(
String.format(
"adb -s %s shell stop",
getDevice().getIDevice().getSerialNumber()));
Thread.sleep(500);
Runtime.getRuntime()
.exec(
String.format(
"adb -s %s shell start",
getDevice().getIDevice().getSerialNumber()));
} catch (InterruptedException e) {
Log.w(LOG_TAG, "interrupted");
} catch (IOException e) {
Log.w(LOG_TAG, "IOException when rebooting");
}
}
};
resetThread.setName("InstrumentationTestFuncTest#testRun_deviceRuntimeReset");
resetThread.start();
mInstrumentationTest.run(mMockListener);
resetThread.join(WAIT_FOR_DEVICE_AVAILABLE);
EasyMock.verify(mMockListener);
RunUtil.getDefault().sleep(5000);
getDevice().waitForDeviceAvailable();
}
/**
* Run the test app UI tests and return true if they all pass.
*/
private boolean runUITests() throws DeviceNotAvailableException {
InstrumentationTest uiTest = new InstrumentationTest();
uiTest.setPackageName(TestAppConstants.UITESTAPP_PACKAGE);
uiTest.setDevice(getDevice());
CollectingTestListener uilistener = new CollectingTestListener();
uiTest.run(uilistener);
return TestAppConstants.UI_TOTAL_TESTS == uilistener.getNumTestsInState(TestStatus.PASSED);
}
/**
* Test running all the tests with rerun on. At least one method will cause run to stop
* (currently TIMEOUT_TEST_METHOD and CRASH_TEST_METHOD). Verify that results are recorded for
* all tests in the suite.
*/
public void testRun_rerun() throws Exception {
Log.i(LOG_TAG, "testRun_rerun");
// run all tests in class
RecoveryMode initMode = getDevice().getRecoveryMode();
getDevice().setRecoveryMode(RecoveryMode.NONE);
try {
mInstrumentationTest.setClassName(TestAppConstants.TESTAPP_CLASS);
mInstrumentationTest.setRerunMode(true);
mInstrumentationTest.setShellTimeout(SHELL_TIMEOUT);
mInstrumentationTest.setTestTimeout(TEST_TIMEOUT);
CollectingTestListener listener = new CollectingTestListener();
mInstrumentationTest.run(listener);
assertEquals(TestAppConstants.TOTAL_TEST_CLASS_TESTS, listener.getNumTotalTests());
assertEquals(
TestAppConstants.TOTAL_TEST_CLASS_PASSED_TESTS,
listener.getNumTestsInState(TestStatus.PASSED));
} finally {
getDevice().setRecoveryMode(initMode);
}
}
/**
* Test a run that crashes when collecting tests.
* <p/>
* Expect run to proceed, but be reported as a run failure
*/
public void testRun_rerunCrash() throws Exception {
Log.i(LOG_TAG, "testRun_rerunCrash");
mInstrumentationTest.setClassName(TestAppConstants.CRASH_ON_INIT_TEST_CLASS);
mInstrumentationTest.setMethodName(TestAppConstants.CRASH_ON_INIT_TEST_METHOD);
mInstrumentationTest.setRerunMode(false);
mInstrumentationTest.setShellTimeout(SHELL_TIMEOUT);
mInstrumentationTest.setTestTimeout(TEST_TIMEOUT);
CollectingTestListener listener = new CollectingTestListener();
mInstrumentationTest.run(listener);
assertEquals(0, listener.getNumTotalTests());
assertNotNull(listener.getCurrentRunResults());
assertEquals(TestAppConstants.TESTAPP_PACKAGE, listener.getCurrentRunResults().getName());
assertTrue(listener.getCurrentRunResults().isRunFailure());
assertTrue(listener.getCurrentRunResults().isRunComplete());
}
/**
* Test a run that hangs when collecting tests.
* <p/>
* Expect a run failure to be reported
*/
public void testRun_rerunHang() throws Exception {
Log.i(LOG_TAG, "testRun_rerunHang");
RecoveryMode initMode = getDevice().getRecoveryMode();
getDevice().setRecoveryMode(RecoveryMode.NONE);
try {
OptionSetter setter = new OptionSetter(mInstrumentationTest);
setter.setOptionValue("collect-tests-timeout", Long.toString(SHELL_TIMEOUT));
mInstrumentationTest.setClassName(TestAppConstants.HANG_ON_INIT_TEST_CLASS);
mInstrumentationTest.setRerunMode(false);
mInstrumentationTest.setShellTimeout(SHELL_TIMEOUT);
mInstrumentationTest.setTestTimeout(TEST_TIMEOUT);
CollectingTestListener listener = new CollectingTestListener();
mInstrumentationTest.run(listener);
assertEquals(0, listener.getNumTotalTests());
assertEquals(
TestAppConstants.TESTAPP_PACKAGE, listener.getCurrentRunResults().getName());
assertTrue(listener.getCurrentRunResults().isRunFailure());
assertTrue(listener.getCurrentRunResults().isRunComplete());
} finally {
getDevice().setRecoveryMode(initMode);
}
}
}