HostGTest: Handle test failures properly
GTest runs return 1 if there are any test failures, but HostGTest fails
to parse any test output at all when this happens, making it appear as
if the whole test command had failed.
Bug: 123529934
Bug: 120164166
Test: m -j tradefed-all &&
tools/tradefederation/core/tests/run_tradefed_aosp_presubmit.sh
Test: 'cd external/avb && atest libavb_host_unittest' (which currently
has some failing test cases) now reports the test failures correctly,
instead of saying the whole test run errored out.
Change-Id: Iabf93e1debe075819f3edcc7720104786bf7d26a
Merged-In: Iabf93e1debe075819f3edcc7720104786bf7d26a
diff --git a/src/com/android/tradefed/util/CommandResult.java b/src/com/android/tradefed/util/CommandResult.java
index e3393d3..867ecb7 100644
--- a/src/com/android/tradefed/util/CommandResult.java
+++ b/src/com/android/tradefed/util/CommandResult.java
@@ -24,6 +24,7 @@
private CommandStatus mCmdStatus = CommandStatus.TIMED_OUT;
private String mStdout = null;
private String mStderr = null;
+ private Integer mExitCode = null;
/**
* Create a {@link CommandResult} with the default {@link CommandStatus#TIMED_OUT} status.
@@ -78,4 +79,17 @@
public void setStderr(String stderr) {
mStderr = stderr;
}
-}
\ No newline at end of file
+
+ /**
+ * Get the exit/return code produced by command.
+ *
+ * @return the exit code or <code>null</code> if it is unset
+ */
+ public Integer getExitCode() {
+ return mExitCode;
+ }
+
+ public void setExitCode(int exitCode) {
+ mExitCode = exitCode;
+ }
+}
diff --git a/src/com/android/tradefed/util/RunUtil.java b/src/com/android/tradefed/util/RunUtil.java
index 8737a0c..03bf49e 100644
--- a/src/com/android/tradefed/util/RunUtil.java
+++ b/src/com/android/tradefed/util/RunUtil.java
@@ -137,9 +137,9 @@
@Override
public CommandResult runTimedCmd(final long timeout, OutputStream stdout,
OutputStream stderr, final String... command) {
- final CommandResult result = new CommandResult();
- IRunUtil.IRunnableResult osRunnable = createRunnableResult(result, stdout, stderr, command);
+ RunnableResult osRunnable = createRunnableResult(stdout, stderr, command);
CommandStatus status = runTimed(timeout, osRunnable, true);
+ CommandResult result = osRunnable.getResult();
result.setStatus(status);
return result;
}
@@ -149,12 +149,9 @@
* command.
*/
@VisibleForTesting
- IRunUtil.IRunnableResult createRunnableResult(
- CommandResult result,
- OutputStream stdout,
- OutputStream stderr,
- String... command) {
- return new RunnableResult(result, null, createProcessBuilder(command), stdout, stderr);
+ RunnableResult createRunnableResult(
+ OutputStream stdout, OutputStream stderr, String... command) {
+ return new RunnableResult(null, createProcessBuilder(command), stdout, stderr);
}
/** {@inheritDoc} */
@@ -220,10 +217,9 @@
@Override
public CommandResult runTimedCmdWithInput(final long timeout, String input,
final List<String> command) {
- final CommandResult result = new CommandResult();
- IRunUtil.IRunnableResult osRunnable = new RunnableResult(result, input,
- createProcessBuilder(command));
+ RunnableResult osRunnable = new RunnableResult(input, createProcessBuilder(command));
CommandStatus status = runTimed(timeout, osRunnable, true);
+ CommandResult result = osRunnable.getResult();
result.setStatus(status);
return result;
}
@@ -233,10 +229,9 @@
*/
@Override
public CommandResult runTimedCmdSilently(final long timeout, final String... command) {
- final CommandResult result = new CommandResult();
- IRunUtil.IRunnableResult osRunnable = new RunnableResult(result, null,
- createProcessBuilder(command));
+ RunnableResult osRunnable = new RunnableResult(null, createProcessBuilder(command));
CommandStatus status = runTimed(timeout, osRunnable, false);
+ CommandResult result = osRunnable.getResult();
result.setStatus(status);
return result;
}
@@ -537,9 +532,8 @@
private final Object mLock = new Object();
private boolean mCancelled = false;
- RunnableResult(final CommandResult result, final String input,
- final ProcessBuilder processBuilder) {
- this(result, input, processBuilder, null, null);
+ RunnableResult(final String input, final ProcessBuilder processBuilder) {
+ this(input, processBuilder, null, null);
}
/**
@@ -548,14 +542,13 @@
* streams are null, default behavior of using a buffer will be used.
*/
RunnableResult(
- final CommandResult result,
final String input,
final ProcessBuilder processBuilder,
OutputStream stdoutStream,
OutputStream stderrStream) {
mProcessBuilder = processBuilder;
mInput = input;
- mCommandResult = result;
+ mCommandResult = new CommandResult();
// Ensure the outputs are never null
mCommandResult.setStdout("");
mCommandResult.setStderr("");
@@ -576,6 +569,10 @@
}
}
+ public CommandResult getResult() {
+ return mCommandResult;
+ }
+
/** Start a {@link Process} based on the {@link ProcessBuilder}. */
@VisibleForTesting
Process startProcess() throws IOException {
@@ -624,7 +621,7 @@
}
}
// Wait for process to complete.
- int rc = Integer.MIN_VALUE;
+ Integer rc = null;
try {
try {
rc = mProcess.waitFor();
@@ -638,25 +635,27 @@
CLog.d("stderr read thread %s still alive.", stderrThread.toString());
}
} finally {
+ mCommandResult.setExitCode(rc);
+
// Write out the streams to the result.
if (stdOut instanceof ByteArrayOutputStream) {
mCommandResult.setStdout(((ByteArrayOutputStream)stdOut).toString("UTF-8"));
} else {
- mCommandResult.setStdout("redirected to " +
- stdOut.getClass().getSimpleName());
+ mCommandResult.setStdout(
+ "redirected to " + stdOut.getClass().getSimpleName());
}
if (stdErr instanceof ByteArrayOutputStream) {
mCommandResult.setStderr(((ByteArrayOutputStream)stdErr).toString("UTF-8"));
} else {
- mCommandResult.setStderr("redirected to " +
- stdErr.getClass().getSimpleName());
+ mCommandResult.setStderr(
+ "redirected to " + stdErr.getClass().getSimpleName());
}
}
} finally {
mCountDown.countDown();
}
- if (rc == 0) {
+ if (rc != null && rc == 0) {
return true;
} else {
CLog.d("%s command failed. return code %d", mProcessBuilder.command(), rc);
diff --git a/tests/src/com/android/tradefed/util/RunUtilTest.java b/tests/src/com/android/tradefed/util/RunUtilTest.java
index 2fe1336..78b6e14 100644
--- a/tests/src/com/android/tradefed/util/RunUtilTest.java
+++ b/tests/src/com/android/tradefed/util/RunUtilTest.java
@@ -71,12 +71,9 @@
}
@Override
- IRunnableResult createRunnableResult(
- CommandResult result,
- OutputStream stdout,
- OutputStream stderr,
- String... command) {
- IRunnableResult real = super.createRunnableResult(result, stdout, stderr, command);
+ RunnableResult createRunnableResult(
+ OutputStream stdout, OutputStream stderr, String... command) {
+ RunnableResult real = super.createRunnableResult(stdout, stderr, command);
mMockRunnableResult = (RunnableResult) Mockito.spy(real);
try {
if (mShouldThrow) {
@@ -484,6 +481,15 @@
assertEquals(expected + "\n", result.getStdout());
}
+ public void testGotExitCodeFromCommand() {
+ RunUtil testRunUtil = new RunUtil();
+ CommandResult result =
+ testRunUtil.runTimedCmd(VERY_LONG_TIMEOUT_MS, "/bin/bash", "-c", "exit 2");
+ assertEquals("", result.getStdout());
+ assertEquals("", result.getStderr());
+ assertEquals(2, (int) result.getExitCode());
+ }
+
/**
* Implementation of {@link Process} to simulate a success of 'echo Test' without actually
* calling the underlying system.