1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.testtype.suite; 17 18 import com.android.ddmlib.Log.LogLevel; 19 import com.android.tradefed.log.LogUtil.CLog; 20 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 21 import com.android.tradefed.result.CollectingTestListener; 22 import com.android.tradefed.result.ILogSaverListener; 23 import com.android.tradefed.result.ITestInvocationListener; 24 import com.android.tradefed.result.InputStreamSource; 25 import com.android.tradefed.result.LogDataType; 26 import com.android.tradefed.result.LogFile; 27 import com.android.tradefed.result.LogSaverResultForwarder; 28 import com.android.tradefed.result.TestDescription; 29 import com.android.tradefed.result.TestRunResult; 30 import com.android.tradefed.testtype.IRemoteTest; 31 32 import java.util.HashMap; 33 34 /** 35 * Listener attached to each {@link IRemoteTest} of each module in order to collect the list of 36 * results. 37 */ 38 public class ModuleListener extends CollectingTestListener { 39 40 private boolean mSkip = false; 41 private boolean mTestFailed = false; 42 private int mTestsRan = 1; 43 private ITestInvocationListener mMainListener; 44 private boolean mHasFailed = false; 45 46 private boolean mCollectTestsOnly = false; 47 /** Track runs in progress for logging purpose */ 48 private boolean mRunInProgress = false; 49 50 /** Constructor. */ ModuleListener(ITestInvocationListener listener)51 public ModuleListener(ITestInvocationListener listener) { 52 mMainListener = listener; 53 mRunInProgress = false; 54 setIsAggregrateMetrics(true); 55 } 56 57 /** Sets whether or not we are only collecting the tests. */ setCollectTestsOnly(boolean collectTestsOnly)58 public void setCollectTestsOnly(boolean collectTestsOnly) { 59 mCollectTestsOnly = collectTestsOnly; 60 } 61 62 @Override testRunStarted(String name, int numTests, int attemptNumber)63 public void testRunStarted(String name, int numTests, int attemptNumber) { 64 mRunInProgress = true; 65 // In case of retry of the same run, do not add the expected count again. This allows 66 // situation where test runner has a built-in retry (like InstrumentationTest) and calls 67 // testRunStart several times to be counted properly. 68 if (getTestRunAtAttempt(name, attemptNumber) != null) { 69 numTests = 0; 70 } 71 super.testRunStarted(name, numTests, attemptNumber); 72 if (attemptNumber != 0) { 73 mTestsRan = 1; 74 } 75 } 76 77 /** {@inheritDoc} */ 78 @Override testRunFailed(String errorMessage)79 public void testRunFailed(String errorMessage) { 80 mHasFailed = true; 81 CLog.d("ModuleListener.testRunFailed(%s)", errorMessage); 82 super.testRunFailed(errorMessage); 83 } 84 85 /** {@inheritDoc} */ 86 @Override testRunEnded(long elapsedTime, HashMap<String, Metric> runMetrics)87 public void testRunEnded(long elapsedTime, HashMap<String, Metric> runMetrics) { 88 super.testRunEnded(elapsedTime, runMetrics); 89 mRunInProgress = false; 90 } 91 92 /** Returns whether or not the listener session has failed. */ hasFailed()93 public boolean hasFailed() { 94 return mHasFailed; 95 } 96 97 /** {@inheritDoc} */ 98 @Override testStarted(TestDescription test, long startTime)99 public void testStarted(TestDescription test, long startTime) { 100 if (!mCollectTestsOnly) { 101 CLog.d("ModuleListener.testStarted(%s)", test.toString()); 102 } 103 mTestFailed = false; 104 super.testStarted(test, startTime); 105 if (mSkip) { 106 super.testIgnored(test); 107 } 108 } 109 110 /** Helper to log the test passed if it didn't fail. */ logTestPassed(String testName)111 private void logTestPassed(String testName) { 112 if (!mTestFailed && !mCollectTestsOnly) { 113 CLog.logAndDisplay( 114 LogLevel.INFO, "[%d/%d] %s pass", mTestsRan, getExpectedTests(), testName); 115 } 116 mTestsRan++; 117 } 118 119 /** {@inheritDoc} */ 120 @Override testEnded(TestDescription test, HashMap<String, Metric> testMetrics)121 public void testEnded(TestDescription test, HashMap<String, Metric> testMetrics) { 122 testEnded(test, System.currentTimeMillis(), testMetrics); 123 } 124 125 /** {@inheritDoc} */ 126 @Override testEnded(TestDescription test, long endTime, HashMap<String, Metric> testMetrics)127 public void testEnded(TestDescription test, long endTime, HashMap<String, Metric> testMetrics) { 128 logTestPassed(test.toString()); 129 super.testEnded(test, endTime, testMetrics); 130 } 131 132 /** {@inheritDoc} */ 133 @Override testFailed(TestDescription test, String trace)134 public void testFailed(TestDescription test, String trace) { 135 if (mSkip) { 136 return; 137 } 138 CLog.logAndDisplay( 139 LogLevel.INFO, 140 "[%d/%d] %s fail:\n%s", 141 mTestsRan, 142 getExpectedTests(), 143 test.toString(), 144 trace); 145 mTestFailed = true; 146 super.testFailed(test, trace); 147 } 148 149 /** Whether or not to mark all the test cases skipped. */ setMarkTestsSkipped(boolean skip)150 public void setMarkTestsSkipped(boolean skip) { 151 mSkip = skip; 152 } 153 154 /** {@inheritDoc} */ 155 @Override testLog(String dataName, LogDataType dataType, InputStreamSource dataStream)156 public void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) { 157 if (mMainListener instanceof LogSaverResultForwarder) { 158 // If the listener is a log saver, we should simply forward the testLog not save again. 159 ((LogSaverResultForwarder) mMainListener) 160 .testLogForward(dataName, dataType, dataStream); 161 } else { 162 super.testLog(dataName, dataType, dataStream); 163 } 164 } 165 166 /** {@inheritDoc} */ 167 @Override testLogSaved( String dataName, LogDataType dataType, InputStreamSource dataStream, LogFile logFile)168 public void testLogSaved( 169 String dataName, LogDataType dataType, InputStreamSource dataStream, LogFile logFile) { 170 // Forward to CollectingTestListener to store the logs 171 super.testLogSaved(dataName, dataType, dataStream, logFile); 172 // Forward to the main listener so logs are properly reported to the end result_reporters. 173 if (mMainListener instanceof ILogSaverListener) { 174 ((ILogSaverListener) mMainListener) 175 .testLogSaved(dataName, dataType, dataStream, logFile); 176 } 177 } 178 179 /** {@inheritDoc} */ 180 @Override logAssociation(String dataName, LogFile logFile)181 public void logAssociation(String dataName, LogFile logFile) { 182 if (mRunInProgress) { 183 super.logAssociation(dataName, logFile); 184 } else { 185 // If no runs are in progress, any logs is reported at the module level. 186 if (mMainListener instanceof ILogSaverListener) { 187 ((ILogSaverListener) mMainListener).logAssociation(dataName, logFile); 188 } 189 } 190 } 191 192 /** 193 * Check if any runs in the given attempt have incompleted (aka "run failure"). 194 * 195 * @param attemptNumber indicates which attempt should the test runs come from. 196 * @return true if any of the runs in the given attempt has crashed. 197 */ hasRunCrashedAtAttempt(int attemptNumber)198 public boolean hasRunCrashedAtAttempt(int attemptNumber) { 199 for (String runName : getTestRunNames()) { 200 TestRunResult run = getTestRunAtAttempt(runName, attemptNumber); 201 if (run != null && run.isRunFailure()) { 202 return true; 203 } 204 } 205 return false; 206 } 207 } 208