Ensure run failure is forwarded properly

If we mix test run failures in modules, ensure it forwards
the appropriate results.

Test: unit tests
Bug: 151777641
Change-Id: Ia7bdbcf87e068c7efd453d220f9984fc0a1fa737
diff --git a/src/com/android/tradefed/result/CollectingTestListener.java b/src/com/android/tradefed/result/CollectingTestListener.java
index 5aaba96..7f46ee1 100644
--- a/src/com/android/tradefed/result/CollectingTestListener.java
+++ b/src/com/android/tradefed/result/CollectingTestListener.java
@@ -252,6 +252,13 @@
 
     /** {@inheritDoc} */
     @Override
+    public void testRunFailed(FailureDescription failure) {
+        setCountDirty();
+        mCurrentTestRunResult.testRunFailed(failure);
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public void testRunStopped(long elapsedTime) {
         setCountDirty();
         mCurrentTestRunResult.testRunStopped(elapsedTime);
diff --git a/src/com/android/tradefed/retry/ResultAggregator.java b/src/com/android/tradefed/retry/ResultAggregator.java
index f957a8f..011fc26 100644
--- a/src/com/android/tradefed/retry/ResultAggregator.java
+++ b/src/com/android/tradefed/retry/ResultAggregator.java
@@ -155,8 +155,9 @@
             mPureRunResultForAgg.clear();
         }
 
+        // Reset the reporting since we start a new module
+        mShouldReportFailure = true;
         if (mDetailedRunResults != null) {
-            mShouldReportFailure = true;
             forwardDetailedFailure();
         }
 
@@ -309,7 +310,6 @@
             expectedTestCount += result.getExpectedTestCount();
             resultNames.add(result.getName());
         }
-
         // Forward all the results aggregated
         mAggregatedForwarder.testRunStarted(
                 getCurrentRunResults().getName(),
diff --git a/tests/src/com/android/tradefed/retry/ResultAggregatorTest.java b/tests/src/com/android/tradefed/retry/ResultAggregatorTest.java
index 998e1f4..e371896 100644
--- a/tests/src/com/android/tradefed/retry/ResultAggregatorTest.java
+++ b/tests/src/com/android/tradefed/retry/ResultAggregatorTest.java
@@ -386,6 +386,122 @@
     }
 
     @Test
+    public void testForwarding_runFailure_aggregation() {
+        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.testEnded(
+                EasyMock.eq(test1),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mDetailedListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
+        mDetailedListener.testFailed(test2, "I failed. retry me.");
+        mDetailedListener.testEnded(
+                EasyMock.eq(test2),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        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.testFailed(test2, "I failed. retry me.");
+        mDetailedListener.testEnded(
+                EasyMock.eq(test2),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mDetailedListener.testRunEnded(450L, new HashMap<String, Metric>());
+        mDetailedListener.testModuleEnded();
+
+        mDetailedListener.testModuleStarted(mModuleContext);
+        mDetailedListener.testRunStarted(
+                EasyMock.eq("run2"), EasyMock.eq(1), EasyMock.eq(0), EasyMock.anyLong());
+        mDetailedListener.testRunFailed(EasyMock.eq(FailureDescription.create("run fail")));
+        mDetailedListener.testRunEnded(450L, new HashMap<String, Metric>());
+
+        // 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.testEnded(
+                EasyMock.eq(test1),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mAggListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
+        mAggListener.testFailed(
+                test2,
+                new MultiFailureDescription(
+                        FailureDescription.create("I failed. retry me."),
+                        FailureDescription.create("I failed. retry me.")));
+        mAggListener.testEnded(
+                EasyMock.eq(test2),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mAggListener.testRunEnded(450L, new HashMap<String, Metric>());
+        mAggListener.testModuleEnded();
+
+        mAggListener.testModuleStarted(mModuleContext);
+        mAggListener.testRunStarted(
+                EasyMock.eq("run2"), EasyMock.eq(1), EasyMock.eq(0), EasyMock.anyLong());
+        mAggListener.testRunFailed(EasyMock.eq(FailureDescription.create("run fail")));
+        mAggListener.testRunEnded(450L, new HashMap<String, Metric>());
+
+        mAggListener.testModuleEnded();
+        mDetailedListener.testModuleEnded();
+        mAggListener.invocationEnded(500L);
+        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.testEnded(test1, new HashMap<String, Metric>());
+        mAggregator.testStarted(test2);
+        mAggregator.testFailed(test2, "I failed. retry me.");
+        mAggregator.testEnded(test2, new HashMap<String, Metric>());
+        mAggregator.testRunEnded(450L, new HashMap<String, Metric>());
+        mAggregator.testRunStarted("run1", 2, 1);
+        mAggregator.testStarted(test2);
+        mAggregator.testFailed(test2, "I failed. retry me.");
+        mAggregator.testEnded(test2, new HashMap<String, Metric>());
+        mAggregator.testRunEnded(450L, new HashMap<String, Metric>());
+        mAggregator.testModuleEnded();
+
+        mAggregator.testModuleStarted(mModuleContext);
+        mAggregator.testRunStarted("run2", 1, 0);
+        mAggregator.testRunFailed(FailureDescription.create("run fail"));
+        mAggregator.testRunEnded(450L, new HashMap<String, Metric>());
+        mAggregator.testModuleEnded();
+        mAggregator.invocationEnded(500L);
+        EasyMock.verify(mAggListener, mDetailedListener);
+        assertNull(mAggregator.getInvocationMetricRunError());
+    }
+
+    @Test
     public void testForwarding_noModules() {
         TestDescription test1 = new TestDescription("classname", "test1");
         TestDescription test2 = new TestDescription("classname", "test2");