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