Prepare the updated aggregation logic

Set it under a flag disabled for now.

Test: unit tests
Bug: 167643555
Change-Id: Id68e67c3f05c80308eb1f81e500e082f12939cbb
diff --git a/javatests/com/android/tradefed/retry/ResultAggregatorTest.java b/javatests/com/android/tradefed/retry/ResultAggregatorTest.java
index c9de42d..46a8689 100644
--- a/javatests/com/android/tradefed/retry/ResultAggregatorTest.java
+++ b/javatests/com/android/tradefed/retry/ResultAggregatorTest.java
@@ -240,6 +240,147 @@
     }
 
     @Test
+    public void testForwarding_newResult() throws Exception {
+        LogFile beforeModule = new LogFile("before-module", "url", LogDataType.TEXT);
+        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");
+
+        EasyMock.expect(mDetailedListener.supportGranularResults()).andStubReturn(true);
+
+        // Invocation level
+        mAggListener.setLogSaver(mLogger);
+        mAggListener.invocationStarted(mInvocationContext);
+        EasyMock.expect(mAggListener.getSummary()).andStubReturn(null);
+        mDetailedListener.setLogSaver(mLogger);
+        mDetailedListener.invocationStarted(mInvocationContext);
+        EasyMock.expect(mDetailedListener.getSummary()).andStubReturn(null);
+        mDetailedListener.logAssociation("before-module-log", beforeModule);
+
+        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.testRunFailed("run fail");
+        mDetailedListener.logAssociation("test-run1-after-log", testRun1LogAfter);
+        mDetailedListener.testRunEnded(450L, new HashMap<String, Metric>());
+        mDetailedListener.logAssociation("between-attempts", betweenAttemptsLog);
+        mDetailedListener.testRunStarted(
+                EasyMock.eq("run1"), EasyMock.eq(2), EasyMock.eq(1), EasyMock.anyLong());
+        mDetailedListener.testStarted(EasyMock.eq(test2), EasyMock.anyLong());
+        mDetailedListener.testEnded(
+                EasyMock.eq(test2),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+        mDetailedListener.testRunEnded(450L, new HashMap<String, Metric>());
+        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.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-module-log", beforeModule);
+        mAggListener.logAssociation("before-end", beforeEnd);
+        mAggListener.invocationEnded(500L);
+        mDetailedListener.logAssociation("before-end", beforeEnd);
+        mDetailedListener.invocationEnded(500L);
+        EasyMock.expect(
+                        mLogger.saveLogData(
+                                EasyMock.contains("aggregated-events"),
+                                EasyMock.eq(LogDataType.TF_EVENTS),
+                                EasyMock.anyObject()))
+                .andReturn(null);
+        EasyMock.expect(
+                        mLogger.saveLogData(
+                                EasyMock.contains("detailed-events"),
+                                EasyMock.eq(LogDataType.TF_EVENTS),
+                                EasyMock.anyObject()))
+                .andReturn(null);
+
+        EasyMock.replay(mAggListener, mDetailedListener, mLogger);
+        mAggregator =
+                new TestableResultAggregator(
+                        Arrays.asList(mAggListener, mDetailedListener),
+                        RetryStrategy.RETRY_ANY_FAILURE);
+        mAggregator.setUpdatedReporting(true);
+        mAggregator.setLogSaver(mLogger);
+        mAggregator.invocationStarted(mInvocationContext);
+        mAggregator.logAssociation("before-module-log", beforeModule);
+        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.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, mLogger);
+        assertNull(mAggregator.getInvocationMetricRunError());
+    }
+
+    @Test
     public void testForwarding_assumptionFailure() throws Exception {
         mDetailedListener = EasyMock.createStrictMock(ITestDetailedReceiver.class);
         LogFile test1Log = new LogFile("test1", "url", LogDataType.TEXT);
diff --git a/src/com/android/tradefed/retry/ResultAggregator.java b/src/com/android/tradefed/retry/ResultAggregator.java
index 7b00f90..6aeb604 100644
--- a/src/com/android/tradefed/retry/ResultAggregator.java
+++ b/src/com/android/tradefed/retry/ResultAggregator.java
@@ -75,6 +75,8 @@
     // Since we store some of the module level events, ensure the logs order is maintained.
     private Map<String, LogFile> mDetailedModuleLogs = new LinkedHashMap<>();
 
+    private boolean mUpdatedDetailedReporting = false;
+
     // In some configuration of non-module retry, all attempts of runs might not be adjacent. We
     // track that a special handling needs to be applied for this case.
     private boolean mUnorderedRetry = true;
@@ -123,6 +125,11 @@
         setMergeStrategy(mergeStrategy);
     }
 
+    /** Sets the new reporting. */
+    public void setUpdatedReporting(boolean updatedReporting) {
+        mUpdatedDetailedReporting = updatedReporting;
+    }
+
     /** {@inheritDoc} */
     @Override
     public void invocationStarted(IInvocationContext context) {
@@ -244,20 +251,22 @@
             }
         }
 
-        if (mDetailedRunResults != null) {
-            if (mDetailedRunResults.getName().equals(name)) {
-                if (!mDetailedRunResults.isRunFailure()) {
-                    if (RetryStrategy.RETRY_ANY_FAILURE.equals(mRetryStrategy)) {
-                        mShouldReportFailure = false;
+        if (!mUpdatedDetailedReporting) {
+            if (mDetailedRunResults != null) {
+                if (mDetailedRunResults.getName().equals(name)) {
+                    if (!mDetailedRunResults.isRunFailure()) {
+                        if (RetryStrategy.RETRY_ANY_FAILURE.equals(mRetryStrategy)) {
+                            mShouldReportFailure = false;
+                        }
                     }
+                    mDetailedForwarder.testRunEnded(
+                            mDetailedRunResults.getElapsedTime(),
+                            mDetailedRunResults.getRunProtoMetrics());
+                    mDetailedRunResults = null;
+                } else {
+                    mShouldReportFailure = true;
+                    forwardDetailedFailure();
                 }
-                mDetailedForwarder.testRunEnded(
-                        mDetailedRunResults.getElapsedTime(),
-                        mDetailedRunResults.getRunProtoMetrics());
-                mDetailedRunResults = null;
-            } else {
-                mShouldReportFailure = true;
-                forwardDetailedFailure();
             }
         }
         super.testRunStarted(name, testCount, attemptNumber, startTime);
@@ -268,12 +277,18 @@
     public void testRunFailed(String errorMessage) {
         super.testRunFailed(errorMessage);
         // Don't forward here to the detailed forwarder in case we need to clear it.
+        if (mUpdatedDetailedReporting) {
+            mDetailedForwarder.testRunFailed(errorMessage);
+        }
     }
 
     @Override
     public void testRunFailed(FailureDescription failure) {
         super.testRunFailed(failure);
         // Don't forward here to the detailed forwarder in case we need to clear it.
+        if (mUpdatedDetailedReporting) {
+            mDetailedForwarder.testRunFailed(failure);
+        }
     }
 
     @Override
@@ -340,14 +355,18 @@
     @Override
     public void testRunEnded(long elapsedTime, HashMap<String, Metric> runMetrics) {
         super.testRunEnded(elapsedTime, runMetrics);
-        mDetailedRunResults = getCurrentRunResults();
-        if (mDetailedRunResults.isRunFailure()) {
-            FailureDescription currentFailure = mDetailedRunResults.getRunFailureDescription();
-            if (currentFailure instanceof MultiFailureDescription) {
-                mAllDetailedFailures.addAll(
-                        ((MultiFailureDescription) currentFailure).getFailures());
-            } else {
-                mAllDetailedFailures.add(currentFailure);
+        if (mUpdatedDetailedReporting) {
+            mDetailedForwarder.testRunEnded(elapsedTime, runMetrics);
+        } else {
+            mDetailedRunResults = getCurrentRunResults();
+            if (mDetailedRunResults.isRunFailure()) {
+                FailureDescription currentFailure = mDetailedRunResults.getRunFailureDescription();
+                if (currentFailure instanceof MultiFailureDescription) {
+                    mAllDetailedFailures.addAll(
+                            ((MultiFailureDescription) currentFailure).getFailures());
+                } else {
+                    mAllDetailedFailures.add(currentFailure);
+                }
             }
         }
 
@@ -363,11 +382,13 @@
 
     @Override
     public void testModuleEnded() {
-        forwardDetailedFailure();
-        for (Entry<String, LogFile> assos : mDetailedModuleLogs.entrySet()) {
-            mDetailedForwarder.logAssociation(assos.getKey(), assos.getValue());
+        if (!mUpdatedDetailedReporting) {
+            forwardDetailedFailure();
+            for (Entry<String, LogFile> assos : mDetailedModuleLogs.entrySet()) {
+                mDetailedForwarder.logAssociation(assos.getKey(), assos.getValue());
+            }
+            mDetailedModuleLogs.clear();
         }
-        mDetailedModuleLogs.clear();
         mModuleInProgress = false;
         super.testModuleEnded();
         // We still forward the testModuleEnd to the detailed reporters