From 280f670b2086aeb457d5195166b429b47a664bab Mon Sep 17 00:00:00 2001 From: Siva Velusamy Date: Mon, 16 Jul 2012 15:33:51 -0700 Subject: Allow junit tests to be run on multiple devices. Currently we allow launching an activity on multiple devices from a single launch configuration. This CL adds support for running Junit tests on all connected devices/emulators from a single launch config. At the UI level, all test results now show up as children of per device test suites. The changes are primarily in 3 different areas: - In ddmlib, the main change is to save the device name on which a particular test was run. This information is saved in the TestIdentifier that is created per test case. - In ADT, the general launch action (IAndroidLaunchAction) is modified to support launching on multiple devices. This simply loops over the existing launch action for each device for Activity Launch or Empty Launch. The Junit Launch Action is modified to launch a single Junit UI and collects the results from all devices and passes it on to the Junit UI. - ADT's ITestRunListener's are modified to look at the device on which a test was run and add results in the appropriate per device test suite. Change-Id: I936c2db2398fcad16544794441dedc714de9bea8 --- .../testrunner/InstrumentationResultParser.java | 29 +++++++-- .../ddmlib/testrunner/RemoteAndroidTestRunner.java | 2 +- .../android/ddmlib/testrunner/TestIdentifier.java | 75 ++++++++++++++++------ .../InstrumentationResultParserTest.java | 6 +- 4 files changed, 84 insertions(+), 28 deletions(-) (limited to 'ddms') diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java index 5885de4..2a65699 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java @@ -22,6 +22,7 @@ import com.android.ddmlib.MultiLineReceiver; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -145,6 +146,9 @@ public class InstrumentationResultParser extends MultiLineReceiver { } } + /** Device on which this test was run. */ + private final String mDeviceName; + /** the name to provide to {@link ITestRunListener#testRunStarted(String, int)} */ private final String mTestRunName; @@ -214,10 +218,24 @@ public class InstrumentationResultParser extends MultiLineReceiver { * @param runName the test run name to provide to * {@link ITestRunListener#testRunStarted(String, int)} * @param listeners informed of test results as the tests are executing + * @param deviceName name of the device on which this test is running, null if unknown */ - public InstrumentationResultParser(String runName, Collection listeners) { + public InstrumentationResultParser(String runName, Collection listeners, + String deviceName) { mTestRunName = runName; mTestListeners = new ArrayList(listeners); + mDeviceName = deviceName; + } + + /** + * Creates the InstrumentationResultParser. + * + * @param runName the test run name to provide to + * {@link ITestRunListener#testRunStarted(String, int)} + * @param listeners informed of test results as the tests are executing + */ + public InstrumentationResultParser(String runName, Collection listeners) { + this(runName, listeners, null); } /** @@ -228,9 +246,7 @@ public class InstrumentationResultParser extends MultiLineReceiver { * @param listener informed of test results as the tests are executing */ public InstrumentationResultParser(String runName, ITestRunListener listener) { - mTestRunName = runName; - mTestListeners = new ArrayList(1); - mTestListeners.add(listener); + this(runName, Collections.singletonList(listener), null); } /** @@ -443,7 +459,8 @@ public class InstrumentationResultParser extends MultiLineReceiver { return; } reportTestRunStarted(testInfo); - TestIdentifier testId = new TestIdentifier(testInfo.mTestClass, testInfo.mTestName); + TestIdentifier testId = new TestIdentifier(testInfo.mTestClass, testInfo.mTestName, + mDeviceName); Map metrics; switch (testInfo.mCode) { @@ -553,7 +570,7 @@ public class InstrumentationResultParser extends MultiLineReceiver { // received test start msg, but not test complete // assume test caused this, report as test failure TestIdentifier testId = new TestIdentifier(mLastTestResult.mTestClass, - mLastTestResult.mTestName); + mLastTestResult.mTestName, mDeviceName); for (ITestRunListener listener : mTestListeners) { listener.testFailed(ITestRunListener.TestFailure.ERROR, testId, String.format("%1$s. Reason: '%2$s'. %3$s", INCOMPLETE_TEST_ERR_MSG_PREFIX, diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java index 124df7d..65ed3c0 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java @@ -256,7 +256,7 @@ public class RemoteAndroidTestRunner implements IRemoteAndroidTestRunner { Log.i(LOG_TAG, String.format("Running %1$s on %2$s", runCaseCommandStr, mRemoteDevice.getSerialNumber())); String runName = mRunName == null ? mPackageName : mRunName; - mParser = new InstrumentationResultParser(runName, listeners); + mParser = new InstrumentationResultParser(runName, listeners, mRemoteDevice.getName()); try { mRemoteDevice.executeShellCommand(runCaseCommandStr, mParser, mMaxTimeToOutputResponse); diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java index f0cf4c8..00295e7 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java @@ -23,20 +23,33 @@ public class TestIdentifier { private final String mClassName; private final String mTestName; + private final String mDeviceName; /** * Creates a test identifier. * * @param className fully qualified class name of the test. Cannot be null. * @param testName name of the test. Cannot be null. + * @param deviceName device on which the test was run. */ - public TestIdentifier(String className, String testName) { + public TestIdentifier(String className, String testName, String deviceName) { if (className == null || testName == null) { throw new IllegalArgumentException("className and testName must " + "be non-null"); } mClassName = className; mTestName = testName; + mDeviceName = deviceName; + } + + /** + * Creates a test identifier. + * + * @param className fully qualified class name of the test. Cannot be null. + * @param testName name of the test. Cannot be null. + */ + public TestIdentifier(String className, String testName) { + this(className, testName, null); } /** @@ -54,31 +67,57 @@ public class TestIdentifier { } /** - * Tests equality by comparing class and method name. + * Returns the name of the device on which the test was run if available, null otherwise. */ - @Override - public boolean equals(Object other) { - if (!(other instanceof TestIdentifier)) { - return false; - } - TestIdentifier otherTest = (TestIdentifier)other; - return getClassName().equals(otherTest.getClassName()) && - getTestName().equals(otherTest.getTestName()); + public String getDeviceName() { + return mDeviceName; } - /** - * Generates hashCode based on class and method name. - */ @Override public int hashCode() { - return getClassName().hashCode() * 31 + getTestName().hashCode(); + final int prime = 31; + int result = 1; + result = prime * result + ((mClassName == null) ? 0 : mClassName.hashCode()); + result = prime * result + ((mDeviceName == null) ? 0 : mDeviceName.hashCode()); + result = prime * result + ((mTestName == null) ? 0 : mTestName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TestIdentifier other = (TestIdentifier) obj; + if (mClassName == null) { + if (other.mClassName != null) + return false; + } else if (!mClassName.equals(other.mClassName)) + return false; + if (mDeviceName == null) { + if (other.mDeviceName != null) + return false; + } else if (!mDeviceName.equals(other.mDeviceName)) + return false; + if (mTestName == null) { + if (other.mTestName != null) + return false; + } else if (!mTestName.equals(other.mTestName)) + return false; + return true; } - /** - * Generates user friendly string. - */ @Override public String toString() { - return String.format("%s#%s", getClassName(), getTestName()); + String deviceName = getDeviceName(); + String name = String.format("%s#%s", getClassName(), getTestName()); + if (deviceName != null) { + name += String.format(" (%s)", deviceName); + } + + return name; } } diff --git a/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java b/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java index 0bbb20e..148f329 100644 --- a/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java +++ b/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java @@ -18,11 +18,11 @@ package com.android.ddmlib.testrunner; import com.android.ddmlib.testrunner.ITestRunListener.TestFailure; +import junit.framework.TestCase; + import org.easymock.Capture; import org.easymock.EasyMock; -import junit.framework.TestCase; - import java.util.Collections; import java.util.Map; @@ -40,7 +40,7 @@ public class InstrumentationResultParserTest extends TestCase { private static final String CLASS_NAME = "com.test.FooTest"; private static final String TEST_NAME = "testFoo"; private static final String STACK_TRACE = "java.lang.AssertionFailedException"; - private static final TestIdentifier TEST_ID = new TestIdentifier(CLASS_NAME, TEST_NAME); + private static final TestIdentifier TEST_ID = new TestIdentifier(CLASS_NAME, TEST_NAME, null); /** * @param name - test name -- cgit v1.1