blob: 4c55ebada362ad2f0df6088386cb1bba6aef729d [file] [log] [blame]
/*
* Copyright (C) 2014 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.IDevice;
import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.ITestRunListener;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.result.ITestInvocationListener;
import junit.framework.TestCase;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/**
* Unit tests for {@link InstrumentationFileTest}.
*/
public class InstrumentationFileTestTest extends TestCase {
private static final String TEST_PACKAGE_VALUE = "com.foo";
/** The {@link InstrumentationFileTest} under test, with all dependencies mocked out */
private InstrumentationFileTest mInstrumentationFileTest;
private ITestDevice mMockTestDevice;
private ITestInvocationListener mMockListener;
private InstrumentationTest mMockITest;
private File mTestFile;
@Override
protected void setUp() throws Exception {
super.setUp();
mTestFile = null;
IDevice mockIDevice = EasyMock.createMock(IDevice.class);
mMockTestDevice = EasyMock.createMock(ITestDevice.class);
mMockListener = EasyMock.createMock(ITestInvocationListener.class);
EasyMock.expect(mMockTestDevice.getIDevice()).andStubReturn(mockIDevice);
EasyMock.expect(mMockTestDevice.getSerialNumber()).andStubReturn("serial");
// mock out InstrumentationTest that will be used to create InstrumentationFileTest
mMockITest = new InstrumentationTest() {
@Override
protected String queryRunnerName() {
return "runner";
}
};
mMockITest.setDevice(mMockTestDevice);
mMockITest.setPackageName(TEST_PACKAGE_VALUE);
}
/**
* Test normal run scenario with a single test.
*/
@SuppressWarnings("unchecked")
public void testRun_singleSuccessfulTest() throws DeviceNotAvailableException,
ConfigurationException {
final Collection<TestIdentifier> testsList = new ArrayList<>(1);
final TestIdentifier test = new TestIdentifier("ClassFoo", "methodBar");
testsList.add(test);
// verify the mock listener is passed through to the runner
RunTestAnswer runTestResponse = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner,
ITestRunListener listener) {
listener.testRunStarted(TEST_PACKAGE_VALUE, 1);
listener.testStarted(test);
listener.testEnded(test, Collections.EMPTY_MAP);
listener.testRunEnded(0, Collections.EMPTY_MAP);
return true;
}
};
setRunTestExpectations(runTestResponse);
mInstrumentationFileTest = new InstrumentationFileTest(mMockITest, testsList, true, -1) {
@Override
InstrumentationTest createInstrumentationTest() {
return mMockITest;
}
@Override
boolean pushFileToTestDevice(File file, String destinationPath)
throws DeviceNotAvailableException {
// simulate successful push and store created file
mTestFile = file;
// verify that the content of the testFile contains all expected tests
verifyTestFile(testsList);
return true;
}
@Override
void deleteTestFileFromDevice(String pathToFile) throws DeviceNotAvailableException {
//ignore
}
};
// mock successful test run lifecycle
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 1);
mMockListener.testStarted(EasyMock.eq(test), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(0, Collections.EMPTY_MAP);
EasyMock.replay(mMockListener, mMockTestDevice);
mInstrumentationFileTest.run(mMockListener);
assertEquals(mMockTestDevice, mMockITest.getDevice());
}
/**
* Test re-run scenario when 1 out of 3 tests fails to complete but is successful after re-run
*/
@SuppressWarnings("unchecked")
public void testRun_reRunOneFailedToCompleteTest()
throws DeviceNotAvailableException, ConfigurationException {
final Collection<TestIdentifier> testsList = new ArrayList<>(1);
final TestIdentifier test1 = new TestIdentifier("ClassFoo1", "methodBar1");
final TestIdentifier test2 = new TestIdentifier("ClassFoo2", "methodBar2");
final TestIdentifier test3 = new TestIdentifier("ClassFoo3", "methodBar3");
testsList.add(test1);
testsList.add(test2);
testsList.add(test3);
// verify the test1 is completed and test2 was started but never finished
RunTestAnswer firstRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
// first test started and ended successfully
listener.testRunStarted(TEST_PACKAGE_VALUE, 2);
listener.testStarted(test1);
listener.testEnded(test1, Collections.EMPTY_MAP);
listener.testRunEnded(1, Collections.EMPTY_MAP);
// second test started but never finished
listener.testStarted(test2);
return true;
}
};
setRunTestExpectations(firstRunAnswer);
// now expect second run to rerun remaining test3 and test2
RunTestAnswer secondRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
// third test started and ended successfully
listener.testRunStarted(TEST_PACKAGE_VALUE, 2);
listener.testStarted(test3);
listener.testEnded(test3, Collections.EMPTY_MAP);
listener.testRunEnded(1, Collections.EMPTY_MAP);
// second test is rerun but completed successfully this time
listener.testStarted(test2);
listener.testEnded(test2, Collections.EMPTY_MAP);
listener.testRunEnded(1, Collections.EMPTY_MAP);
return true;
}
};
setRunTestExpectations(secondRunAnswer);
mInstrumentationFileTest = new InstrumentationFileTest(mMockITest, testsList, true, -1) {
@Override
InstrumentationTest createInstrumentationTest() {
return mMockITest;
}
@Override
boolean pushFileToTestDevice(File file, String destinationPath)
throws DeviceNotAvailableException {
// simulate successful push and store created file
mTestFile = file;
// verify that the content of the testFile contains all expected tests
verifyTestFile(testsList);
return true;
}
@Override
void deleteTestFileFromDevice(String pathToFile) throws DeviceNotAvailableException {
//ignore
}
};
// First run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 2);
// expect test1 to start and finish successfully
mMockListener.testStarted(EasyMock.eq(test1), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test1), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
// expect test2 to start but never finish
mMockListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
// Second run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 2);
// expect test3 to start and finish successfully
mMockListener.testStarted(EasyMock.eq(test3), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test3), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
// expect to rerun test2 successfully
mMockListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test2), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
EasyMock.replay(mMockListener, mMockTestDevice);
mInstrumentationFileTest.run(mMockListener);
assertEquals(mMockTestDevice, mMockITest.getDevice());
}
/**
* Test re-run scenario when 2 remaining tests fail to complete and need to be run serially
*/
@SuppressWarnings("unchecked")
public void testRun_serialReRunOfTwoFailedToCompleteTests()
throws DeviceNotAvailableException, ConfigurationException {
final Collection<TestIdentifier> testsList = new ArrayList<>(1);
final TestIdentifier test1 = new TestIdentifier("ClassFoo1", "methodBar1");
final TestIdentifier test2 = new TestIdentifier("ClassFoo2", "methodBar2");
testsList.add(test1);
testsList.add(test2);
// verify the test1 and test2 started but never completed
RunTestAnswer firstRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
// first and second tests started but never completed
listener.testRunStarted(TEST_PACKAGE_VALUE, 2);
listener.testStarted(test1);
listener.testStarted(test2);
// verify that the content of the testFile contains all expected tests
verifyTestFile(testsList);
return true;
}
};
setRunTestExpectations(firstRunAnswer);
// verify successful serial execution of test1
RunTestAnswer firstSerialRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
// first test started and ended successfully in serial mode
listener.testRunStarted(TEST_PACKAGE_VALUE, 1);
listener.testStarted(test1);
listener.testEnded(test1, Collections.EMPTY_MAP);
listener.testRunEnded(1, Collections.EMPTY_MAP);
return true;
}
};
setRunTestExpectations(firstSerialRunAnswer);
// verify successful serial execution of test2
RunTestAnswer secdondSerialRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
// Second test started and ended successfully in serial mode
listener.testRunStarted(TEST_PACKAGE_VALUE, 1);
listener.testStarted(test2);
listener.testEnded(test2, Collections.EMPTY_MAP);
listener.testRunEnded(1, Collections.EMPTY_MAP);
return true;
}
};
setRunTestExpectations(secdondSerialRunAnswer);
mInstrumentationFileTest = new InstrumentationFileTest(mMockITest, testsList, true, -1) {
@Override
InstrumentationTest createInstrumentationTest() {
return mMockITest;
}
@Override
boolean pushFileToTestDevice(File file, String destinationPath)
throws DeviceNotAvailableException {
// simulate successful push and store created file
mTestFile = file;
return true;
}
@Override
void deleteTestFileFromDevice(String pathToFile) throws DeviceNotAvailableException {
//ignore
}
};
// First run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 2);
// expect test1 and test 2 to start but never finish
mMockListener.testStarted(EasyMock.eq(test1), EasyMock.anyLong());
mMockListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
// re-run test1 and test2 serially
// first serial re-run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 1);
// expect test1 to start and finish successfully
mMockListener.testStarted(EasyMock.eq(test1), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test1), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
// first serial re-run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 1);
// expect test2 to start and finish successfully
mMockListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test2), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
EasyMock.replay(mMockListener, mMockTestDevice);
mInstrumentationFileTest.run(mMockListener);
assertEquals(mMockTestDevice, mMockITest.getDevice());
// test file is expected to be null since we defaulted to serial test execution
assertEquals(null, mMockITest.getTestFilePathOnDevice());
}
/**
* Test no serial re-run tests fail to complete.
*/
@SuppressWarnings("unchecked")
public void testRun_noSerialReRun()
throws DeviceNotAvailableException, ConfigurationException {
final Collection<TestIdentifier> testsList = new ArrayList<>(1);
final TestIdentifier test1 = new TestIdentifier("ClassFoo1", "methodBar1");
final TestIdentifier test2 = new TestIdentifier("ClassFoo2", "methodBar2");
testsList.add(test1);
testsList.add(test2);
// verify the test1 and test2 started but never completed
RunTestAnswer firstRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
// first and second tests started but never completed
listener.testRunStarted(TEST_PACKAGE_VALUE, 2);
listener.testStarted(test1);
listener.testStarted(test2);
// verify that the content of the testFile contains all expected tests
verifyTestFile(testsList);
return true;
}
};
setRunTestExpectations(firstRunAnswer);
mInstrumentationFileTest = new InstrumentationFileTest(mMockITest, testsList, false, -1) {
@Override
InstrumentationTest createInstrumentationTest() {
return mMockITest;
}
@Override
boolean pushFileToTestDevice(File file, String destinationPath)
throws DeviceNotAvailableException {
// simulate successful push and store created file
mTestFile = file;
return true;
}
@Override
void deleteTestFileFromDevice(String pathToFile) throws DeviceNotAvailableException {
//ignore
}
};
// First run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 2);
// expect test1 and test 2 to start but never finish
mMockListener.testStarted(EasyMock.eq(test1), EasyMock.anyLong());
mMockListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
EasyMock.replay(mMockListener, mMockTestDevice);
mInstrumentationFileTest.run(mMockListener);
assertEquals(mMockTestDevice, mMockITest.getDevice());
}
/**
* Test attempting times exceed max attempts.
*/
@SuppressWarnings("unchecked")
public void testRun_exceedMaxAttempts()
throws DeviceNotAvailableException, ConfigurationException {
final ArrayList<TestIdentifier> testsList = new ArrayList<>(1);
final TestIdentifier test1 = new TestIdentifier("ClassFoo1", "methodBar1");
final TestIdentifier test2 = new TestIdentifier("ClassFoo2", "methodBar2");
final TestIdentifier test3 = new TestIdentifier("ClassFoo3", "methodBar3");
final TestIdentifier test4 = new TestIdentifier("ClassFoo4", "methodBar4");
final TestIdentifier test5 = new TestIdentifier("ClassFoo5", "methodBar5");
final TestIdentifier test6 = new TestIdentifier("ClassFoo6", "methodBar6");
testsList.add(test1);
testsList.add(test2);
testsList.add(test3);
testsList.add(test4);
testsList.add(test5);
testsList.add(test6);
final ArrayList<TestIdentifier> expectedTestsList = new ArrayList<>(testsList);
// test1 fininshed, test2 started but not finished.
RunTestAnswer firstRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
listener.testRunStarted(TEST_PACKAGE_VALUE, 6);
// first test started and ended successfully
listener.testStarted(test1);
listener.testEnded(test1, Collections.EMPTY_MAP);
listener.testRunEnded(1, Collections.EMPTY_MAP);
// second test started but never finished
listener.testStarted(test2);
// verify that the content of the testFile contains all expected tests
verifyTestFile(expectedTestsList);
return true;
}
};
setRunTestExpectations(firstRunAnswer);
// test2 finished, test3 started but not finished.
RunTestAnswer secondRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
// test2 started and ended successfully
listener.testRunStarted(TEST_PACKAGE_VALUE, 5);
listener.testStarted(test2);
listener.testEnded(test2, Collections.EMPTY_MAP);
listener.testRunEnded(1, Collections.EMPTY_MAP);
// test3 started but never finished
listener.testStarted(test3);
// verify that the content of the testFile contains all expected tests
verifyTestFile(expectedTestsList.subList(1, expectedTestsList.size()));
return true;
}
};
setRunTestExpectations(secondRunAnswer);
// test3 finished, test4 started but not finished.
RunTestAnswer thirdRunAnswer = new RunTestAnswer() {
@Override
public Boolean answer(IRemoteAndroidTestRunner runner, ITestRunListener listener) {
// test3 started and ended successfully
listener.testRunStarted(TEST_PACKAGE_VALUE, 4);
listener.testStarted(test3);
listener.testEnded(test3, Collections.EMPTY_MAP);
listener.testRunEnded(1, Collections.EMPTY_MAP);
// test4 started but never finished
listener.testStarted(test4);
// verify that the content of the testFile contains all expected tests
verifyTestFile(expectedTestsList.subList(2, expectedTestsList.size()));
return true;
}
};
setRunTestExpectations(thirdRunAnswer);
mInstrumentationFileTest = new InstrumentationFileTest(mMockITest, testsList, false, 3) {
@Override
InstrumentationTest createInstrumentationTest() {
return mMockITest;
}
@Override
boolean pushFileToTestDevice(File file, String destinationPath)
throws DeviceNotAvailableException {
// simulate successful push and store created file
mTestFile = file;
return true;
}
@Override
void deleteTestFileFromDevice(String pathToFile) throws DeviceNotAvailableException {
//ignore
}
};
// First run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 6);
mMockListener.testStarted(EasyMock.eq(test1), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test1), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
mMockListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
// Second run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 5);
mMockListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test2), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
mMockListener.testStarted(EasyMock.eq(test3), EasyMock.anyLong());
// Third run:
mMockListener.testRunStarted(TEST_PACKAGE_VALUE, 4);
mMockListener.testStarted(EasyMock.eq(test3), EasyMock.anyLong());
mMockListener.testEnded(
EasyMock.eq(test3), EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
mMockListener.testRunEnded(1, Collections.EMPTY_MAP);
mMockListener.testStarted(EasyMock.eq(test4), EasyMock.anyLong());
// MAX_ATTEMPTS is 3, so there will be no forth run.
EasyMock.replay(mMockListener, mMockTestDevice);
mInstrumentationFileTest.run(mMockListener);
assertEquals(mMockTestDevice, mMockITest.getDevice());
}
/**
* Helper class that verifies tetFile's content match the expected list of test to be run
* @param testsList list of test to be executed
*/
private void verifyTestFile(Collection<TestIdentifier> testsList) {
// fail if the file was never created
assertNotNull(mTestFile);
try (BufferedReader br = new BufferedReader(new FileReader(mTestFile))) {
String line;
while ((line = br.readLine()) != null) {
String[] str = line.split("#");
TestIdentifier test = new TestIdentifier(str[0], str[1]);
assertTrue(String.format(
"Test with class name: %s and method name: %s does not exists",
test.getClassName(), test.getTestName()), testsList.contains(test));
}
} catch (IOException e) {
// fail if the file is corrupt in any way
fail("failed reading test file");
}
}
/**
* Helper class for providing an EasyMock {@link IAnswer} to a
* {@link ITestDevice#runInstrumentationTests(IRemoteAndroidTestRunner, Collection)} call.
*/
private static abstract class RunTestAnswer implements IAnswer<Boolean> {
@Override
public Boolean answer() throws Throwable {
Object[] args = EasyMock.getCurrentArguments();
return answer((IRemoteAndroidTestRunner) args[0], (ITestRunListener) args[1]);
}
public abstract Boolean answer(IRemoteAndroidTestRunner runner,
ITestRunListener listener) throws DeviceNotAvailableException;
}
private void setRunTestExpectations(RunTestAnswer runTestResponse)
throws DeviceNotAvailableException {
EasyMock.expect(mMockTestDevice
.runInstrumentationTests((IRemoteAndroidTestRunner) EasyMock.anyObject(),
(ITestRunListener) EasyMock.anyObject())).andAnswer(runTestResponse);
}
}