Add assumption failure new interface to Aggreggation

Test: unit tests
Bug: None
Change-Id: I0d5903121445496d3e15da9b0c57c0d7a2a2416d
diff --git a/invocation_interfaces/com/android/tradefed/result/TestResult.java b/invocation_interfaces/com/android/tradefed/result/TestResult.java
index daee50c..1b26db6 100644
--- a/invocation_interfaces/com/android/tradefed/result/TestResult.java
+++ b/invocation_interfaces/com/android/tradefed/result/TestResult.java
@@ -208,6 +208,7 @@
         int ignored = 0;
         int incomplete = 0;
 
+        TestStatus lastStatus = null;
         for (TestResult attempt : results) {
             mergedResult.mProtoMetrics.putAll(attempt.getProtoMetrics());
             mergedResult.mMetrics.putAll(attempt.getMetrics());
@@ -238,6 +239,7 @@
                     ignored++;
                     break;
             }
+            lastStatus = attempt.getStatus();
         }
 
         switch (strategy) {
@@ -258,7 +260,13 @@
                         mergedResult.setStatus(TestStatus.INCOMPLETE);
                     }
                 } else {
-                    mergedResult.setStatus(TestStatus.FAILURE);
+                    if (TestStatus.ASSUMPTION_FAILURE.equals(lastStatus)) {
+                        mergedResult.setStatus(TestStatus.ASSUMPTION_FAILURE);
+                    } else if (TestStatus.IGNORED.equals(lastStatus)) {
+                        mergedResult.setStatus(TestStatus.IGNORED);
+                    } else {
+                        mergedResult.setStatus(TestStatus.FAILURE);
+                    }
                 }
                 break;
             default:
diff --git a/invocation_interfaces/com/android/tradefed/result/TestRunResult.java b/invocation_interfaces/com/android/tradefed/result/TestRunResult.java
index a3fdc1e..3f35209 100644
--- a/invocation_interfaces/com/android/tradefed/result/TestRunResult.java
+++ b/invocation_interfaces/com/android/tradefed/result/TestRunResult.java
@@ -307,6 +307,10 @@
         updateTestResult(test, TestStatus.ASSUMPTION_FAILURE, FailureDescription.create(trace));
     }
 
+    public void testAssumptionFailure(TestDescription test, FailureDescription failure) {
+        updateTestResult(test, TestStatus.ASSUMPTION_FAILURE, failure);
+    }
+
     public void testIgnored(TestDescription test) {
         updateTestResult(test, TestStatus.IGNORED, null);
     }
diff --git a/src/com/android/tradefed/result/CollectingTestListener.java b/src/com/android/tradefed/result/CollectingTestListener.java
index d9ec6ec..a51d2ae 100644
--- a/src/com/android/tradefed/result/CollectingTestListener.java
+++ b/src/com/android/tradefed/result/CollectingTestListener.java
@@ -311,6 +311,12 @@
     }
 
     @Override
+    public void testAssumptionFailure(TestDescription test, FailureDescription failure) {
+        setCountDirty();
+        mCurrentTestRunResult.testAssumptionFailure(test, failure);
+    }
+
+    @Override
     public void testIgnored(TestDescription test) {
         setCountDirty();
         mCurrentTestRunResult.testIgnored(test);
diff --git a/src/com/android/tradefed/result/ResultForwarder.java b/src/com/android/tradefed/result/ResultForwarder.java
index ba38e54..c651405 100644
--- a/src/com/android/tradefed/result/ResultForwarder.java
+++ b/src/com/android/tradefed/result/ResultForwarder.java
@@ -341,6 +341,20 @@
     }
 
     @Override
+    public void testAssumptionFailure(TestDescription test, FailureDescription failure) {
+        for (ITestInvocationListener listener : mListeners) {
+            try {
+                listener.testAssumptionFailure(test, failure);
+            } catch (RuntimeException e) {
+                CLog.e(
+                        "Exception while invoking %s#testAssumptionFailure",
+                        listener.getClass().getName());
+                CLog.e(e);
+            }
+        }
+    }
+
+    @Override
     public void testIgnored(TestDescription test) {
         for (ITestInvocationListener listener : mListeners) {
             try {
diff --git a/src/com/android/tradefed/retry/ResultAggregator.java b/src/com/android/tradefed/retry/ResultAggregator.java
index 43848fd..b028bdf 100644
--- a/src/com/android/tradefed/retry/ResultAggregator.java
+++ b/src/com/android/tradefed/retry/ResultAggregator.java
@@ -257,6 +257,12 @@
     }
 
     @Override
+    public void testAssumptionFailure(TestDescription test, FailureDescription failure) {
+        super.testAssumptionFailure(test, failure);
+        mDetailedForwarder.testAssumptionFailure(test, failure);
+    }
+
+    @Override
     public void testFailed(TestDescription test, String trace) {
         super.testFailed(test, trace);
         mDetailedForwarder.testFailed(test, trace);
diff --git a/tests/src/com/android/tradefed/retry/ResultAggregatorTest.java b/tests/src/com/android/tradefed/retry/ResultAggregatorTest.java
index 43aaa7a..bd17c87 100644
--- a/tests/src/com/android/tradefed/retry/ResultAggregatorTest.java
+++ b/tests/src/com/android/tradefed/retry/ResultAggregatorTest.java
@@ -211,6 +211,135 @@
     }
 
     @Test
+    public void testForwarding_assumptionFailure() {
+        mDetailedListener = EasyMock.createStrictMock(ITestDetailedReceiver.class);
+        LogFile test1Log = new LogFile("test1", "url", LogDataType.TEXT);
+        LogFile test2LogBefore = new LogFile("test2-before", "url", LogDataType.TEXT);
+        LogFile test2LogAfter = new LogFile("test2-after", "url", LogDataType.TEXT);
+        LogFile testRun1LogBefore = new LogFile("test-run1-before", "url", LogDataType.TEXT);
+        LogFile testRun1LogAfter = new LogFile("test-run1-after", "url", LogDataType.TEXT);
+        LogFile beforeEnd = new LogFile("path", "url", LogDataType.TEXT);
+        LogFile betweenAttemptsLog = new LogFile("between-attempts", "url", LogDataType.TEXT);
+        LogFile moduleLog = new LogFile("module-log", "url", LogDataType.TEXT);
+        TestDescription test1 = new TestDescription("classname", "test1");
+        TestDescription test2 = new TestDescription("classname", "test2");
+        ILogSaver logger = EasyMock.createMock(ILogSaver.class);
+
+        EasyMock.expect(mDetailedListener.supportGranularResults()).andStubReturn(true);
+
+        // Invocation level
+        mAggListener.setLogSaver(logger);
+        mAggListener.invocationStarted(mInvocationContext);
+        EasyMock.expect(mAggListener.getSummary()).andStubReturn(null);
+        mDetailedListener.setLogSaver(logger);
+        mDetailedListener.invocationStarted(mInvocationContext);
+        EasyMock.expect(mDetailedListener.getSummary()).andStubReturn(null);
+
+        mAggListener.testModuleStarted(mModuleContext);
+        mDetailedListener.testModuleStarted(mModuleContext);
+
+        // Detailed receives the breakdown
+        mDetailedListener.testRunStarted(
+                EasyMock.eq("run1"), EasyMock.eq(2), EasyMock.eq(0), EasyMock.anyLong());
+        mDetailedListener.testStarted(EasyMock.eq(test1), EasyMock.anyLong());
+        mDetailedListener.logAssociation("test1-log", test1Log);
+        mDetailedListener.testEnded(
+                EasyMock.eq(test1),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mDetailedListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
+        mDetailedListener.logAssociation("test2-before-log", test2LogBefore);
+        mDetailedListener.testFailed(test2, FailureDescription.create("I failed. retry me."));
+        mDetailedListener.logAssociation("test2-after-log", test2LogAfter);
+        mDetailedListener.testEnded(
+                EasyMock.eq(test2),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mDetailedListener.logAssociation("test-run1-before-log", testRun1LogBefore);
+        mDetailedListener.logAssociation("test-run1-after-log", testRun1LogAfter);
+        mDetailedListener.testRunEnded(450L, new HashMap<String, Metric>());
+        mDetailedListener.testRunStarted(
+                EasyMock.eq("run1"), EasyMock.eq(2), EasyMock.eq(1), EasyMock.anyLong());
+        mDetailedListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
+        mDetailedListener.testAssumptionFailure(
+                EasyMock.eq(test2), EasyMock.eq(FailureDescription.create("Assump failure")));
+        mDetailedListener.testEnded(
+                EasyMock.eq(test2),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mDetailedListener.testRunEnded(450L, new HashMap<String, Metric>());
+        mDetailedListener.logAssociation("between-attempts", betweenAttemptsLog);
+        mDetailedListener.logAssociation("module-log", moduleLog);
+
+        // Aggregated listeners receives the aggregated results
+        mAggListener.testRunStarted(
+                EasyMock.eq("run1"), EasyMock.eq(2), EasyMock.eq(0), EasyMock.anyLong());
+        mAggListener.testStarted(EasyMock.eq(test1), EasyMock.anyLong());
+        mAggListener.logAssociation("test1-log", test1Log);
+        mAggListener.testEnded(
+                EasyMock.eq(test1),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mAggListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
+        mAggListener.testAssumptionFailure(
+                EasyMock.eq(test2), (FailureDescription) EasyMock.anyObject());
+        mAggListener.logAssociation("test2-before-log", test2LogBefore);
+        mAggListener.logAssociation("test2-after-log", test2LogAfter);
+        mAggListener.testEnded(
+                EasyMock.eq(test2),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mAggListener.logAssociation("test-run1-before-log", testRun1LogBefore);
+        mAggListener.logAssociation("test-run1-after-log", testRun1LogAfter);
+        mAggListener.testRunEnded(450L, new HashMap<String, Metric>());
+        mAggListener.logAssociation("between-attempts", betweenAttemptsLog);
+        mAggListener.logAssociation("module-log", moduleLog);
+        mAggListener.testModuleEnded();
+        mDetailedListener.testModuleEnded();
+        mAggListener.logAssociation("before-end", beforeEnd);
+        mAggListener.invocationEnded(500L);
+        mDetailedListener.logAssociation("before-end", beforeEnd);
+        mDetailedListener.invocationEnded(500L);
+
+        EasyMock.replay(mAggListener, mDetailedListener);
+        mAggregator =
+                new TestableResultAggregator(
+                        Arrays.asList(mAggListener, mDetailedListener),
+                        RetryStrategy.RETRY_ANY_FAILURE);
+        mAggregator.setLogSaver(logger);
+        mAggregator.invocationStarted(mInvocationContext);
+        mAggregator.testModuleStarted(mModuleContext);
+        // Attempt 1
+        mAggregator.testRunStarted("run1", 2, 0);
+        mAggregator.testStarted(test1);
+        mAggregator.logAssociation("test1-log", test1Log);
+        mAggregator.testEnded(test1, new HashMap<String, Metric>());
+        mAggregator.testStarted(test2);
+        mAggregator.logAssociation("test2-before-log", test2LogBefore);
+        mAggregator.testFailed(test2, FailureDescription.create("I failed. retry me."));
+        mAggregator.logAssociation("test2-after-log", test2LogAfter);
+        mAggregator.testEnded(test2, new HashMap<String, Metric>());
+        mAggregator.logAssociation("test-run1-before-log", testRun1LogBefore);
+        mAggregator.testRunFailed("run fail");
+        mAggregator.logAssociation("test-run1-after-log", testRun1LogAfter);
+        mAggregator.testRunEnded(450L, new HashMap<String, Metric>());
+        mAggregator.logAssociation("between-attempts", betweenAttemptsLog);
+        // Attempt 2
+        mAggregator.testRunStarted("run1", 2, 1);
+        mAggregator.testStarted(test2);
+        mAggregator.testAssumptionFailure(test2, FailureDescription.create("Assump failure"));
+        mAggregator.testEnded(test2, new HashMap<String, Metric>());
+        mAggregator.testRunEnded(450L, new HashMap<String, Metric>());
+
+        mAggregator.logAssociation("module-log", moduleLog);
+        mAggregator.testModuleEnded();
+        mAggregator.logAssociation("before-end", beforeEnd);
+        mAggregator.invocationEnded(500L);
+        EasyMock.verify(mAggListener, mDetailedListener);
+        assertEquals("run fail", mAggregator.getInvocationMetricRunError());
+    }
+
+    @Test
     public void testForwarding_runFailure() {
         mDetailedListener = EasyMock.createStrictMock(ITestDetailedReceiver.class);
         TestDescription test1 = new TestDescription("classname", "test1");