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