1 /* 2 * Copyright (C) 2016 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 17 package com.android.compatibility.common.tradefed.result; 18 19 import com.android.ddmlib.Log; 20 import com.android.ddmlib.Log.LogLevel; 21 import com.android.ddmlib.testrunner.TestIdentifier; 22 import com.android.tradefed.build.IBuildInfo; 23 import com.android.tradefed.config.Option; 24 import com.android.tradefed.config.OptionClass; 25 import com.android.tradefed.config.OptionCopier; 26 import com.android.tradefed.log.LogUtil.CLog; 27 import com.android.tradefed.result.IShardableListener; 28 import com.android.tradefed.result.StubTestInvocationListener; 29 import com.android.tradefed.util.TimeUtil; 30 31 import java.util.Map; 32 33 /** 34 * Write test progress to the test console. 35 */ 36 public class ConsoleReporter extends StubTestInvocationListener implements IShardableListener { 37 38 private static final String UNKNOWN_DEVICE = "unknown_device"; 39 40 @Option(name = "quiet-output", description = "Mute display of test results.") 41 private boolean mQuietOutput = false; 42 43 private String mDeviceSerial = UNKNOWN_DEVICE; 44 private boolean mTestFailed; 45 private String mModuleId; 46 private int mCurrentTestNum; 47 private int mTotalTestsInModule; 48 private int mPassedTests; 49 private int mFailedTests; 50 private int mNotExecutedTests; 51 52 /** 53 * {@inheritDoc} 54 */ 55 @Override 56 public void invocationStarted(IBuildInfo buildInfo) { 57 if (buildInfo == null) { 58 CLog.w("buildInfo should not be null"); 59 return; 60 } 61 // Escape any "%" signs in the device serial. 62 mDeviceSerial = buildInfo.getDeviceSerial().replace("%", "%%"); 63 } 64 65 /** 66 * {@inheritDoc} 67 */ 68 @Override 69 public void testRunStarted(String id, int numTests) { 70 if (mModuleId == null || !mModuleId.equals(id)) { 71 mModuleId = id; 72 mTotalTestsInModule = numTests; 73 // Reset counters 74 mCurrentTestNum = 0; 75 mPassedTests = 0; 76 mFailedTests = 0; 77 mNotExecutedTests = 0; 78 mTestFailed = false; 79 logMessage("Starting %s with %d test%s", 80 id, mTotalTestsInModule, (mTotalTestsInModule > 1) ? "s" : ""); 81 } else { 82 if (mNotExecutedTests == 0) { 83 mTotalTestsInModule += numTests; 84 } else { 85 mTotalTestsInModule += Math.max(0, numTests - mNotExecutedTests); 86 } 87 logMessage("Continuing %s with %d test%s", 88 id, mTotalTestsInModule, (mTotalTestsInModule > 1) ? "s" : ""); 89 } 90 } 91 92 /** 93 * {@inheritDoc} 94 */ 95 @Override 96 public void testStarted(TestIdentifier test) { 97 mTestFailed = false; 98 mCurrentTestNum++; 99 } 100 101 /** 102 * {@inheritDoc} 103 */ 104 @Override 105 public void testFailed(TestIdentifier test, String trace) { 106 logProgress("%s fail: %s", test, trace); 107 mTestFailed = true; 108 mFailedTests++; 109 } 110 111 /** 112 * {@inheritDoc} 113 */ 114 @Override 115 public void testIgnored(TestIdentifier test) { 116 mCurrentTestNum--; 117 logProgress("%s ignore", test); 118 } 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override 124 public void testAssumptionFailure(TestIdentifier test, String trace) { 125 logProgress("%s failed assumption: %s", test, trace); 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override 132 public void testEnded(TestIdentifier test, Map<String, String> testMetrics) { 133 if (!mTestFailed) { 134 logProgress("%s pass", test); 135 mPassedTests++; 136 } 137 } 138 139 /** 140 * {@inheritDoc} 141 */ 142 @Override 143 public void testRunFailed(String errorMessage) { 144 logMessage(errorMessage); 145 } 146 147 148 /** 149 * {@inheritDoc} 150 */ 151 @Override 152 public void testRunEnded(long elapsedTime, Map<String, String> metrics) { 153 mNotExecutedTests = Math.max(mTotalTestsInModule - mCurrentTestNum, 0); 154 String status = mNotExecutedTests > 0 ? "failed" : "completed"; 155 logMessage("%s %s in %s. %d passed, %d failed, %d not executed", 156 mModuleId, 157 status, 158 TimeUtil.formatElapsedTime(elapsedTime), 159 mPassedTests, 160 mFailedTests, 161 mNotExecutedTests); 162 } 163 164 /** 165 * {@inheritDoc} 166 */ 167 @Override 168 public void testRunStopped(long elapsedTime) { 169 logMessage("%s stopped (%s)", mModuleId, TimeUtil.formatElapsedTime(elapsedTime)); 170 } 171 172 /** 173 * Print out message with test execution status. 174 */ 175 private void logProgress(String format, Object... args) { 176 format = String.format("[%s %s %s] %s", progress(), mModuleId, mDeviceSerial, format); 177 log(format, args); 178 } 179 180 /** 181 * Print out message to the console 182 */ 183 private void logMessage(String format, Object... args) { 184 format = String.format("[%s] %s", mDeviceSerial, format); 185 log(format, args); 186 } 187 188 /** 189 * Print out to the console or log silently when mQuietOutput is true. 190 */ 191 private void log(String format, Object... args) { 192 if (mQuietOutput) { 193 CLog.i(format, args); 194 } else { 195 CLog.logAndDisplay(LogLevel.INFO, format, args); 196 } 197 } 198 199 /** 200 * {@inheritDoc} 201 */ 202 @Override 203 public IShardableListener clone() { 204 ConsoleReporter clone = new ConsoleReporter(); 205 OptionCopier.copyOptionsNoThrow(this, clone); 206 return clone; 207 } 208 209 /** 210 * Return a string containing the percentage complete of module test execution. 211 */ 212 private String progress() { 213 return String.format("%d/%d", mCurrentTestNum, mTotalTestsInModule); 214 } 215 216 String getDeviceSerial() { 217 return mDeviceSerial; 218 } 219 220 boolean getTestFailed() { 221 return mTestFailed; 222 } 223 224 String getModuleId() { 225 return mModuleId; 226 } 227 228 int getCurrentTestNum() { 229 return mCurrentTestNum; 230 } 231 232 int getTotalTestsInModule() { 233 return mTotalTestsInModule; 234 } 235 236 int getPassedTests() { 237 return mPassedTests; 238 } 239 240 int getFailedTests() { 241 return mFailedTests; 242 } 243 } 244