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 = false; 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("%s %s with %d test%s", (isRepeatModule) ? "Continuing" : "Starting", id, 85 mTotalTestsInModule, (mTotalTestsInModule > 1) ? "s" : ""); 86 } 87 88 /** 89 * {@inheritDoc} 90 */ 91 @Override testStarted(TestDescription test)92 public void testStarted(TestDescription test) { 93 mTestFailed = false; 94 mTestSkipped = false; 95 mCurrentTestNum++; 96 } 97 98 /** 99 * {@inheritDoc} 100 */ 101 @Override testFailed(TestDescription test, String trace)102 public void testFailed(TestDescription test, String trace) { 103 logProgress("%s fail: %s", test, trace); 104 mTestFailed = true; 105 mFailedTests++; 106 } 107 108 /** 109 * {@inheritDoc} 110 */ 111 @Override testIgnored(TestDescription test)112 public void testIgnored(TestDescription test) { 113 logProgress("%s ignore", test); 114 mTestSkipped = true; 115 } 116 117 /** 118 * {@inheritDoc} 119 */ 120 @Override testAssumptionFailure(TestDescription test, String trace)121 public void testAssumptionFailure(TestDescription test, String trace) { 122 logProgress("%s skip", test); 123 mTestSkipped = true; 124 } 125 126 /** 127 * {@inheritDoc} 128 */ 129 @Override testEnded(TestDescription test, HashMap<String, Metric> testMetrics)130 public void testEnded(TestDescription test, HashMap<String, Metric> testMetrics) { 131 if (!mTestFailed && !mTestSkipped) { 132 logProgress("%s pass", test); 133 mPassedTests++; 134 } 135 } 136 137 /** 138 * {@inheritDoc} 139 */ 140 @Override testRunFailed(String errorMessage)141 public void testRunFailed(String errorMessage) { 142 logMessage(errorMessage); 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override testRunEnded(long elapsedTime, Map<String, String> metrics)149 public void testRunEnded(long elapsedTime, Map<String, String> metrics) { 150 testRunEnded(elapsedTime, TfMetricProtoUtil.upgradeConvert(metrics)); 151 } 152 153 /** 154 * {@inheritDoc} 155 */ 156 @Override testRunEnded(long elapsedTime, HashMap<String, Metric> metrics)157 public void testRunEnded(long elapsedTime, HashMap<String, Metric> metrics) { 158 mNotExecutedTests = Math.max(mTotalTestsInModule - mCurrentTestNum, 0); 159 String status = mNotExecutedTests > 0 ? "failed" : "completed"; 160 logMessage("%s %s in %s. %d passed, %d failed, %d not executed", 161 mModuleId, 162 status, 163 TimeUtil.formatElapsedTime(elapsedTime), 164 mPassedTests, 165 mFailedTests, 166 mNotExecutedTests); 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override testRunStopped(long elapsedTime)173 public void testRunStopped(long elapsedTime) { 174 logMessage("%s stopped (%s)", mModuleId, TimeUtil.formatElapsedTime(elapsedTime)); 175 } 176 177 /** 178 * Print out message with test execution status. 179 */ logProgress(String format, Object... args)180 private void logProgress(String format, Object... args) { 181 format = String.format("[%s %s %s] %s", progress(), mModuleId, mDeviceSerial, format); 182 log(format, args); 183 } 184 185 /** 186 * Print out message to the console 187 */ logMessage(String format, Object... args)188 private void logMessage(String format, Object... args) { 189 format = String.format("[%s] %s", mDeviceSerial, format); 190 log(format, args); 191 } 192 193 /** 194 * Print out to the console or log silently when mQuietOutput is true. 195 */ log(String format, Object... args)196 private void log(String format, Object... args) { 197 if (mQuietOutput) { 198 CLog.i(format, args); 199 } else { 200 CLog.logAndDisplay(LogLevel.INFO, format, args); 201 } 202 } 203 204 /** 205 * {@inheritDoc} 206 */ 207 @Override clone()208 public IShardableListener clone() { 209 ConsoleReporter clone = new ConsoleReporter(); 210 OptionCopier.copyOptionsNoThrow(this, clone); 211 return clone; 212 } 213 214 /** 215 * Return a string containing the percentage complete of module test execution. 216 */ progress()217 private String progress() { 218 return String.format("%d/%d", mCurrentTestNum, mTotalTestsInModule); 219 } 220 getDeviceSerial()221 String getDeviceSerial() { 222 return mDeviceSerial; 223 } 224 getTestFailed()225 boolean getTestFailed() { 226 return mTestFailed; 227 } 228 getModuleId()229 String getModuleId() { 230 return mModuleId; 231 } 232 getCurrentTestNum()233 int getCurrentTestNum() { 234 return mCurrentTestNum; 235 } 236 getTotalTestsInModule()237 int getTotalTestsInModule() { 238 return mTotalTestsInModule; 239 } 240 getPassedTests()241 int getPassedTests() { 242 return mPassedTests; 243 } 244 getFailedTests()245 int getFailedTests() { 246 return mFailedTests; 247 } 248 } 249