DO NOT MERGE: Protect against system checkers RuntimeException
a system checker runtime exception would kill the
invocation, changing this to only consider the
system checker failed.
If the root cause of the RuntimeException was a device
issue, a DNAE would eventually be triggered and properly
clean up the invocation.
Test: unit tests
run cts, manually fail a checker
Bug: 111752857
Change-Id: I3e2f5772b92e62a9dac377c47a8aab4eaed479e2
(cherry picked from commit 528eaf7d6c996309cdf558b9b6f698ad572d5bd5)
diff --git a/src/com/android/tradefed/testtype/suite/ITestSuite.java b/src/com/android/tradefed/testtype/suite/ITestSuite.java
index cbf1305..c72ba11 100644
--- a/src/com/android/tradefed/testtype/suite/ITestSuite.java
+++ b/src/com/android/tradefed/testtype/suite/ITestSuite.java
@@ -535,7 +535,13 @@
continue;
}
- StatusCheckerResult result = checker.preExecutionCheck(device);
+ StatusCheckerResult result = new StatusCheckerResult(CheckStatus.FAILED);
+ try {
+ result = checker.preExecutionCheck(device);
+ } catch (RuntimeException e) {
+ // Catch RuntimeException to avoid leaking throws that go to the invocation.
+ result.setErrorMessage(e.getMessage());
+ }
if (!CheckStatus.SUCCESS.equals(result.getStatus())) {
String errorMessage =
(result.getErrorMessage() == null) ? "" : result.getErrorMessage();
@@ -577,7 +583,13 @@
continue;
}
- StatusCheckerResult result = checker.postExecutionCheck(device);
+ StatusCheckerResult result = new StatusCheckerResult(CheckStatus.FAILED);
+ try {
+ result = checker.postExecutionCheck(device);
+ } catch (RuntimeException e) {
+ // Catch RuntimeException to avoid leaking throws that go to the invocation.
+ result.setErrorMessage(e.getMessage());
+ }
if (!CheckStatus.SUCCESS.equals(result.getStatus())) {
String errorMessage =
(result.getErrorMessage() == null) ? "" : result.getErrorMessage();
diff --git a/tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java b/tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java
index f70f1f0..cd73b60 100644
--- a/tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java
@@ -289,6 +289,35 @@
/**
* Test for {@link ITestSuite#run(ITestInvocationListener)} when the System status checker is
+ * failing with a runtime exception. RuntimeException is interpreted as a checker failure.
+ */
+ @Test
+ public void testRun_failedSystemChecker_runtimeException() throws Exception {
+ final byte[] fakeData = "fakeData".getBytes();
+ InputStreamSource fakeSource = new ByteArrayInputStreamSource(fakeData);
+ List<ISystemStatusChecker> sysChecker = new ArrayList<ISystemStatusChecker>();
+ sysChecker.add(mMockSysChecker);
+ mTestSuite.setSystemStatusChecker(sysChecker);
+
+ EasyMock.expect(mMockSysChecker.preExecutionCheck(EasyMock.eq(mMockDevice)))
+ .andThrow(new RuntimeException("I failed."));
+ EasyMock.expect(mMockDevice.getBugreport()).andReturn(fakeSource).times(2);
+ mMockListener.testLog(
+ (String) EasyMock.anyObject(),
+ EasyMock.eq(LogDataType.BUGREPORT),
+ EasyMock.eq(fakeSource));
+ EasyMock.expectLastCall().times(2);
+
+ EasyMock.expect(mMockSysChecker.postExecutionCheck(EasyMock.eq(mMockDevice)))
+ .andThrow(new RuntimeException("I failed post."));
+ expectTestRun(mMockListener);
+ replayMocks();
+ mTestSuite.run(mMockListener);
+ verifyMocks();
+ }
+
+ /**
+ * Test for {@link ITestSuite#run(ITestInvocationListener)} when the System status checker is
* passing pre-check but failing post-check and we enable reporting a failure for it.
*/
@Test