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