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