Start forwarding the new invoc failure event
Test: unit tests
Bug: 153374987
Change-Id: Iec1e7e9cd85462c40b9ad08d674bcafe0e288f6e
diff --git a/invocation_interfaces/com/android/tradefed/result/ITestInvocationListener.java b/invocation_interfaces/com/android/tradefed/result/ITestInvocationListener.java
index ed8e1b7..462f375 100644
--- a/invocation_interfaces/com/android/tradefed/result/ITestInvocationListener.java
+++ b/invocation_interfaces/com/android/tradefed/result/ITestInvocationListener.java
@@ -79,7 +79,7 @@
*
* @param failure the {@link FailureDescription} describing the cause of the failure
*/
- public default void invocationFailed(FailureDescription failure) {
+ default void invocationFailed(FailureDescription failure) {
if (failure.getCause() != null) {
invocationFailed(failure.getCause());
} else {
diff --git a/src/com/android/tradefed/invoker/ShardListener.java b/src/com/android/tradefed/invoker/ShardListener.java
index 2f06de0..71ad448 100644
--- a/src/com/android/tradefed/invoker/ShardListener.java
+++ b/src/com/android/tradefed/invoker/ShardListener.java
@@ -95,6 +95,15 @@
}
}
+ /** {@inheritDoc} */
+ @Override
+ public void invocationFailed(FailureDescription failure) {
+ super.invocationFailed(failure);
+ synchronized (mMasterListener) {
+ mMasterListener.invocationFailed(failure);
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/com/android/tradefed/invoker/ShardMasterResultForwarder.java b/src/com/android/tradefed/invoker/ShardMasterResultForwarder.java
index 3be9f37..1e4b985 100644
--- a/src/com/android/tradefed/invoker/ShardMasterResultForwarder.java
+++ b/src/com/android/tradefed/invoker/ShardMasterResultForwarder.java
@@ -17,6 +17,7 @@
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.FailureDescription;
import com.android.tradefed.result.ILogSaverListener;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.InputStreamSource;
@@ -90,6 +91,13 @@
super.invocationFailed(cause);
}
+ /** {@inheritDoc} */
+ @Override
+ public void invocationFailed(FailureDescription failure) {
+ // one of the shards failed. Fail the whole invocation
+ super.invocationFailed(failure);
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/com/android/tradefed/result/CollectingTestListener.java b/src/com/android/tradefed/result/CollectingTestListener.java
index d9ec6ec..230805e 100644
--- a/src/com/android/tradefed/result/CollectingTestListener.java
+++ b/src/com/android/tradefed/result/CollectingTestListener.java
@@ -152,6 +152,12 @@
// ignore
}
+ /** {@inheritDoc} */
+ @Override
+ public void invocationFailed(FailureDescription failure) {
+ // ignore
+ }
+
@Override
public void testModuleStarted(IInvocationContext moduleContext) {
mCurrentModuleContext = moduleContext;
diff --git a/src/com/android/tradefed/result/proto/ProtoResultReporter.java b/src/com/android/tradefed/result/proto/ProtoResultReporter.java
index 4e77622..d070fcc 100644
--- a/src/com/android/tradefed/result/proto/ProtoResultReporter.java
+++ b/src/com/android/tradefed/result/proto/ProtoResultReporter.java
@@ -67,6 +67,7 @@
private IInvocationContext mContext;
private Throwable mInvocationFailure = null;
+ private FailureDescription mInvocationFailureDescription = null;
/** Whether or not a testModuleStart had currently been called. */
private boolean mModuleInProgress = false;
@@ -177,6 +178,11 @@
}
@Override
+ public void invocationFailed(FailureDescription failure) {
+ mInvocationFailureDescription = failure;
+ }
+
+ @Override
public final void invocationEnded(long elapsedTime) {
if (mModuleInProgress) {
// If we had a module in progress, and a new module start occurs, complete the call
@@ -188,21 +194,9 @@
// Update the context in case it changed
mInvocationRecordBuilder.setDescription(Any.pack(mContext.toProto()));
- if (mInvocationFailure != null) {
- DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
- if (mInvocationFailure.getMessage() != null) {
- debugBuilder.setErrorMessage(mInvocationFailure.getMessage());
- }
- debugBuilder.setTrace(StreamUtil.getStackTrace(mInvocationFailure));
- DebugInfoContext.Builder debugContext = DebugInfoContext.newBuilder();
- try {
- debugContext.setErrorType(SerializationUtil.serializeToString(mInvocationFailure));
- } catch (IOException e) {
- CLog.e("Failed to serialize the invocation failure:");
- CLog.e(e);
- }
- debugBuilder.setDebugInfoContext(debugContext);
- mInvocationRecordBuilder.setDebugInfo(debugBuilder);
+ DebugInfo invocationFailure = handleInvocationFailure();
+ if (invocationFailure != null) {
+ mInvocationRecordBuilder.setDebugInfo(invocationFailure);
}
// Finalize the protobuf handling: where to put the results.
@@ -516,4 +510,39 @@
}
return logFileBuilder.build();
}
+
+ private DebugInfo handleInvocationFailure() {
+ DebugInfo.Builder debugBuilder = DebugInfo.newBuilder();
+ Throwable baseException = null;
+ if (mInvocationFailureDescription != null) {
+ baseException = mInvocationFailureDescription.getCause();
+ }
+ if (baseException == null) {
+ baseException = mInvocationFailure;
+ }
+ // TODO: Handle FailureDescription without getCause.
+ if (baseException == null) {
+ // No invocation failure
+ return null;
+ }
+
+ if (baseException.getMessage() != null) {
+ debugBuilder.setErrorMessage(baseException.getMessage());
+ }
+ debugBuilder.setTrace(StreamUtil.getStackTrace(baseException));
+ if (mInvocationFailureDescription != null
+ && mInvocationFailureDescription.getFailureStatus() != null) {
+ debugBuilder.setFailureStatus(mInvocationFailureDescription.getFailureStatus());
+ }
+ DebugInfoContext.Builder debugContext = DebugInfoContext.newBuilder();
+ try {
+ debugContext.setErrorType(SerializationUtil.serializeToString(baseException));
+ } catch (IOException e) {
+ CLog.e("Failed to serialize the invocation failure:");
+ CLog.e(e);
+ }
+ debugBuilder.setDebugInfoContext(debugContext);
+
+ return debugBuilder.build();
+ }
}
diff --git a/tests/src/com/android/tradefed/result/proto/ProtoResultReporterTest.java b/tests/src/com/android/tradefed/result/proto/ProtoResultReporterTest.java
index b3f0bfe..f4e3949 100644
--- a/tests/src/com/android/tradefed/result/proto/ProtoResultReporterTest.java
+++ b/tests/src/com/android/tradefed/result/proto/ProtoResultReporterTest.java
@@ -22,13 +22,18 @@
import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.invoker.InvocationContext;
import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
+import com.android.tradefed.result.FailureDescription;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.result.LogFile;
import com.android.tradefed.result.TestDescription;
import com.android.tradefed.result.proto.TestRecordProto.ChildReference;
+import com.android.tradefed.result.proto.TestRecordProto.DebugInfo;
+import com.android.tradefed.result.proto.TestRecordProto.DebugInfoContext;
+import com.android.tradefed.result.proto.TestRecordProto.FailureStatus;
import com.android.tradefed.result.proto.TestRecordProto.TestRecord;
import com.android.tradefed.result.proto.TestRecordProto.TestStatus;
import com.android.tradefed.testtype.suite.ModuleDefinition;
+import com.android.tradefed.util.SerializationUtil;
import com.android.tradefed.util.proto.TfMetricProtoUtil;
import org.junit.Before;
@@ -145,6 +150,35 @@
assertEquals("run failure", run1.getDebugInfo().getErrorMessage());
}
+ /** Test an invocation with the proto invocation failure being populated. */
+ @Test
+ public void testInvocationFailure() throws Exception {
+ // Invocation start
+ mReporter.invocationStarted(mInvocationContext);
+ // Invocation ends
+ FailureDescription invocationFailure = FailureDescription.create("error");
+ invocationFailure.setFailureStatus(FailureStatus.INFRA_FAILURE);
+ invocationFailure.setCause(new NullPointerException("error"));
+ mReporter.invocationFailed(invocationFailure);
+ mReporter.invocationEnded(500L);
+
+ // ------ Verify that everything was populated ------
+ assertNotNull(mFinalRecord.getTestRecordId());
+ assertNotNull(mFinalRecord.getStartTime().getSeconds());
+ assertNotNull(mFinalRecord.getEndTime().getSeconds());
+ assertNotNull(mFinalRecord.getDebugInfo());
+
+ DebugInfo invocFailure = mFinalRecord.getDebugInfo();
+ assertEquals("error", invocFailure.getErrorMessage());
+ assertEquals(FailureStatus.INFRA_FAILURE, invocFailure.getFailureStatus());
+ assertNotNull(invocFailure.getDebugInfoContext());
+ DebugInfoContext debugContext = invocFailure.getDebugInfoContext();
+ String serializedException = debugContext.getErrorType();
+ NullPointerException npe =
+ (NullPointerException) SerializationUtil.deserialize(serializedException);
+ assertEquals("error", npe.getMessage());
+ }
+
/** Helper to create a module context. */
private IInvocationContext createModuleContext(String moduleId) {
IInvocationContext context = new InvocationContext();