Merge "Address ddms logger in verbose mode"
diff --git a/src/com/android/tradefed/device/INativeDevice.java b/src/com/android/tradefed/device/INativeDevice.java
index 79c6f8c..99a1b04 100644
--- a/src/com/android/tradefed/device/INativeDevice.java
+++ b/src/com/android/tradefed/device/INativeDevice.java
@@ -1313,4 +1313,16 @@
* returned by {@link System#currentTimeMillis()}.
*/
public long getLastExpectedRebootTimeMillis();
+
+ /**
+ * Fetch and return the list of tombstones from the devices. Requires root.
+ *
+ * <p>method is best-effort so if one tombstone fails to be pulled for any reason it will be
+ * missing from the list. Only a {@link DeviceNotAvailableException} will terminate the method
+ * early.
+ *
+ * @return A list of tombstone files, empty if no tombstone.
+ * @see <a href="https://source.android.com/devices/tech/debug">Tombstones documentation</a>
+ */
+ public List<File> getTombstones() throws DeviceNotAvailableException;
}
diff --git a/src/com/android/tradefed/device/NativeDevice.java b/src/com/android/tradefed/device/NativeDevice.java
index 5cd16be..92c2c83 100644
--- a/src/com/android/tradefed/device/NativeDevice.java
+++ b/src/com/android/tradefed/device/NativeDevice.java
@@ -183,6 +183,9 @@
/** Pattern to find an executable file. */
private static final Pattern EXE_FILE = Pattern.compile("^[-l]r.x.+");
+ /** Path of the device containing the tombstones */
+ private static final String TOMBSTONE_PATH = "/data/tombstones/";
+
/** The time in ms to wait for a command to complete. */
private long mCmdTimeout = 2 * 60 * 1000L;
/** The time in ms to wait for a 'long' command to complete. */
@@ -4364,6 +4367,23 @@
return mLastTradefedRebootTime;
}
+ /** {@inheritDoc} */
+ @Override
+ public List<File> getTombstones() throws DeviceNotAvailableException {
+ List<File> tombstones = new ArrayList<>();
+ if (!isAdbRoot()) {
+ CLog.w("Device was not root, cannot collect tombstones.");
+ return tombstones;
+ }
+ for (String tombName : getChildren(TOMBSTONE_PATH)) {
+ File tombFile = pullFile(TOMBSTONE_PATH + tombName);
+ if (tombFile != null) {
+ tombstones.add(tombFile);
+ }
+ }
+ return tombstones;
+ }
+
/** Validate that pid is an integer and not empty. */
private boolean checkValidPid(String output) {
if (output.isEmpty()) {
diff --git a/src/com/android/tradefed/result/proto/ProtoResultParser.java b/src/com/android/tradefed/result/proto/ProtoResultParser.java
index 3363053..8f5ecd6 100644
--- a/src/com/android/tradefed/result/proto/ProtoResultParser.java
+++ b/src/com/android/tradefed/result/proto/ProtoResultParser.java
@@ -251,7 +251,6 @@
if (!anyDescription.is(Context.class)) {
throw new RuntimeException("Expected Any description of type Context");
}
- log("Test module started proto");
try {
IInvocationContext moduleContext =
InvocationContext.fromProto(anyDescription.unpack(Context.class));
diff --git a/src/com/android/tradefed/sandbox/SandboxConfigUtil.java b/src/com/android/tradefed/sandbox/SandboxConfigUtil.java
index 3caa7b1..34d3e30 100644
--- a/src/com/android/tradefed/sandbox/SandboxConfigUtil.java
+++ b/src/com/android/tradefed/sandbox/SandboxConfigUtil.java
@@ -87,7 +87,9 @@
}
CommandResult result = runUtil.runTimedCmd(DUMP_TIMEOUT, mCmdArgs.toArray(new String[0]));
CLog.d("stdout: %s", result.getStdout());
- CLog.d("stderr: %s", result.getStderr());
+ if (result.getStderr() != null && !result.getStderr().isEmpty()) {
+ CLog.d("stderr: %s", result.getStderr());
+ }
if (CommandStatus.SUCCESS.equals(result.getStatus())) {
return destination;
}
diff --git a/src/com/android/tradefed/sandbox/TradefedSandbox.java b/src/com/android/tradefed/sandbox/TradefedSandbox.java
index dfa544c..92fe045 100644
--- a/src/com/android/tradefed/sandbox/TradefedSandbox.java
+++ b/src/com/android/tradefed/sandbox/TradefedSandbox.java
@@ -297,7 +297,8 @@
mEventParser = new SubprocessTestResultsParser(listener, true, context);
commandLine = commandLine + " --no-" + SandboxOptions.USE_PROTO_REPORTER;
}
- String[] args = QuotationAwareTokenizer.tokenizeLine(commandLine);
+ String[] args =
+ QuotationAwareTokenizer.tokenizeLine(commandLine, /* No Logging */ false);
mGlobalConfig = dumpGlobalConfig(config, new HashSet<>());
try (InputStreamSource source = new FileInputStreamSource(mGlobalConfig)) {
listener.testLog("sandbox-global-config", LogDataType.XML, source);
diff --git a/src/com/android/tradefed/testtype/DeviceTestCase.java b/src/com/android/tradefed/testtype/DeviceTestCase.java
index 4914a91..16de6d0 100644
--- a/src/com/android/tradefed/testtype/DeviceTestCase.java
+++ b/src/com/android/tradefed/testtype/DeviceTestCase.java
@@ -15,7 +15,6 @@
*/
package com.android.tradefed.testtype;
-import com.android.ddmlib.Log;
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -49,7 +48,6 @@
ITestFilterReceiver,
ITestAnnotationFilterReceiver {
- private static final String LOG_TAG = "DeviceTestCase";
private ITestDevice mDevice;
private TestFilterHelper mFilterHelper;
@@ -349,9 +347,6 @@
}
superClass = superClass.getSuperclass();
}
- if (mMethodNames.size() == 0) {
- Log.w(LOG_TAG, String.format("No tests found in %s", theClass.getName()));
- }
}
return mMethodNames;
}
diff --git a/src/com/android/tradefed/testtype/HostTest.java b/src/com/android/tradefed/testtype/HostTest.java
index f6c9160..af30957 100644
--- a/src/com/android/tradefed/testtype/HostTest.java
+++ b/src/com/android/tradefed/testtype/HostTest.java
@@ -569,13 +569,16 @@
}
private void runTestCases(ITestInvocationListener listener) throws DeviceNotAvailableException {
+ Set<String> skippedTests = new LinkedHashSet<>();
for (Object obj : getTestMethods()) {
if (IRemoteTest.class.isInstance(obj)) {
IRemoteTest test = (IRemoteTest) obj;
runRemoteTest(listener, test);
} else if (TestSuite.class.isInstance(obj)) {
TestSuite junitTest = (TestSuite) obj;
- runJUnit3Tests(listener, junitTest, junitTest.getName());
+ if (!runJUnit3Tests(listener, junitTest, junitTest.getName())) {
+ skippedTests.add(junitTest.getName());
+ }
} else if (Description.class.isInstance(obj)) {
// Running in a full JUnit4 manner, no downgrade to JUnit3 {@link Test}
Description desc = (Description) obj;
@@ -587,6 +590,7 @@
String.format("%s is not a supported test", obj));
}
}
+ CLog.v("The following classes were skipped due to no test cases found: %s", skippedTests);
}
private void runRemoteTest(ITestInvocationListener listener, IRemoteTest test)
@@ -604,14 +608,16 @@
test.run(listener);
}
- private void runJUnit3Tests(
+ /** Returns True if some tests were executed, false otherwise. */
+ private boolean runJUnit3Tests(
ITestInvocationListener listener, TestSuite junitTest, String className)
throws DeviceNotAvailableException {
if (mCollectTestsOnly) {
// Collect only mode, fake the junit test execution.
- listener.testRunStarted(className, junitTest.countTestCases());
+ int testCount = junitTest.countTestCases();
+ listener.testRunStarted(className, testCount);
HashMap<String, Metric> empty = new HashMap<>();
- for (int i = 0; i < junitTest.countTestCases(); i++) {
+ for (int i = 0; i < testCount; i++) {
Test t = junitTest.testAt(i);
// Test does not have a getName method.
// using the toString format instead: <testName>(className)
@@ -622,8 +628,13 @@
}
HashMap<String, Metric> emptyMap = new HashMap<>();
listener.testRunEnded(0, emptyMap);
+ if (testCount > 0) {
+ return true;
+ } else {
+ return false;
+ }
} else {
- JUnitRunUtil.runTest(listener, junitTest, className);
+ return JUnitRunUtil.runTest(listener, junitTest, className);
}
}
diff --git a/src/com/android/tradefed/testtype/JUnitRunUtil.java b/src/com/android/tradefed/testtype/JUnitRunUtil.java
index dd0c544..95180f2 100644
--- a/src/com/android/tradefed/testtype/JUnitRunUtil.java
+++ b/src/com/android/tradefed/testtype/JUnitRunUtil.java
@@ -16,7 +16,6 @@
package com.android.tradefed.testtype;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.JUnitToInvocationResultForwarder;
@@ -33,16 +32,15 @@
*/
public class JUnitRunUtil {
- public static void runTest(ITestInvocationListener listener, Test junitTest)
+ public static boolean runTest(ITestInvocationListener listener, Test junitTest)
throws DeviceNotAvailableException {
- runTest(listener, junitTest, junitTest.getClass().getName());
+ return runTest(listener, junitTest, junitTest.getClass().getName());
}
- public static void runTest(ITestInvocationListener listener, Test junitTest,
- String runName) throws DeviceNotAvailableException {
+ public static boolean runTest(ITestInvocationListener listener, Test junitTest, String runName)
+ throws DeviceNotAvailableException {
if (junitTest.countTestCases() == 0) {
- CLog.v("Skipping empty test case %s", runName);
- return;
+ return false;
}
listener.testRunStarted(runName, junitTest.countTestCases());
long startTime = System.currentTimeMillis();
@@ -60,5 +58,6 @@
listener.testRunEnded(
System.currentTimeMillis() - startTime, new HashMap<String, Metric>());
}
+ return true;
}
}
diff --git a/src/com/android/tradefed/testtype/NativeCodeCoverageListener.java b/src/com/android/tradefed/testtype/NativeCodeCoverageListener.java
index 8d54a51..b1b6c8d 100644
--- a/src/com/android/tradefed/testtype/NativeCodeCoverageListener.java
+++ b/src/com/android/tradefed/testtype/NativeCodeCoverageListener.java
@@ -40,7 +40,7 @@
* A {@link ResultForwarder} that will pull native coverage measurements off of the device and log
* them as test artifacts.
*/
-final class NativeCodeCoverageListener extends ResultForwarder {
+public final class NativeCodeCoverageListener extends ResultForwarder {
private static final String NATIVE_COVERAGE_DEVICE_PATH = "/data/misc/trace";
private static final String COVERAGE_FILE_LIST_COMMAND =
diff --git a/src/com/android/tradefed/testtype/suite/ITestSuite.java b/src/com/android/tradefed/testtype/suite/ITestSuite.java
index fd3c900..b44c3c8 100644
--- a/src/com/android/tradefed/testtype/suite/ITestSuite.java
+++ b/src/com/android/tradefed/testtype/suite/ITestSuite.java
@@ -833,11 +833,6 @@
// to carry these extra data.
cleanUpSuiteSetup();
- /** Randomize all the modules to be ran if random-order is set while sharding.*/
- if (mRandomOrder) {
- randomizeTestModules(splitModules, mRandomSeed);
- }
-
// create an association of one ITestSuite <=> one ModuleDefinition as the smallest
// execution unit supported.
List<IRemoteTest> splitTests = new ArrayList<>();
diff --git a/tests/src/com/android/tradefed/device/NativeDeviceTest.java b/tests/src/com/android/tradefed/device/NativeDeviceTest.java
index 28e24ab..27d5ce6 100644
--- a/tests/src/com/android/tradefed/device/NativeDeviceTest.java
+++ b/tests/src/com/android/tradefed/device/NativeDeviceTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import com.android.ddmlib.AdbCommandRejectedException;
@@ -2579,4 +2580,34 @@
};
assertFalse(mTestDevice.isExecutable("/system"));
}
+
+ /** Test {@link NativeDevice#getTombstones()}. */
+ @Test
+ public void testGetTombstones_notRoot() throws Exception {
+ TestableAndroidNativeDevice spy = Mockito.spy(mTestDevice);
+ doReturn(false).when(spy).isAdbRoot();
+
+ EasyMock.replay(mMockIDevice);
+ List<File> result = spy.getTombstones();
+ assertEquals(0, result.size());
+ EasyMock.verify(mMockIDevice);
+ }
+
+ /** Test {@link NativeDevice#getTombstones()}. */
+ @Test
+ public void testGetTombstones() throws Exception {
+ TestableAndroidNativeDevice spy = Mockito.spy(mTestDevice);
+ doReturn(true).when(spy).isAdbRoot();
+
+ String[] tombs = new String[] {"tomb1", "tomb2"};
+ doReturn(tombs).when(spy).getChildren("/data/tombstones/");
+
+ doReturn(new File("tomb1_test")).when(spy).pullFile("/data/tombstones/tomb1");
+ doReturn(new File("tomb2_test")).when(spy).pullFile("/data/tombstones/tomb2");
+
+ EasyMock.replay(mMockIDevice);
+ List<File> result = spy.getTombstones();
+ assertEquals(2, result.size());
+ EasyMock.verify(mMockIDevice);
+ }
}