• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.tradefed.testtype.suite;
17 
18 import com.android.tradefed.device.DeviceNotAvailableException;
19 import com.android.tradefed.device.ITestDevice;
20 import com.android.tradefed.log.ITestLogger;
21 import com.android.tradefed.log.LogUtil.CLog;
22 import com.android.tradefed.result.ITestInvocationListener;
23 import com.android.tradefed.result.InputStreamSource;
24 import com.android.tradefed.result.LogDataType;
25 import com.android.tradefed.result.TestDescription;
26 import com.android.tradefed.util.IRunUtil;
27 import com.android.tradefed.util.RunUtil;
28 
29 import com.google.common.annotations.VisibleForTesting;
30 
31 import java.util.List;
32 
33 /**
34  * Listener used to take action such as screenshot, bugreport, logcat collection upon a test failure
35  * when requested.
36  */
37 public class TestFailureListener implements ITestInvocationListener {
38 
39     private List<ITestDevice> mListDevice;
40     private ITestLogger mLogger;
41     // Settings for the whole invocation
42     private boolean mBugReportOnFailure;
43     private boolean mRebootOnFailure;
44 
45     // module specific values
46     private boolean mModuleBugReportOnFailure = true;
47 
TestFailureListener( List<ITestDevice> devices, boolean bugReportOnFailure, boolean rebootOnFailure)48     public TestFailureListener(
49             List<ITestDevice> devices, boolean bugReportOnFailure, boolean rebootOnFailure) {
50         mListDevice = devices;
51         mBugReportOnFailure = bugReportOnFailure;
52         mRebootOnFailure = rebootOnFailure;
53     }
54 
55     /** {@inheritDoc} */
56     @Override
testFailed(TestDescription test, String trace)57     public void testFailed(TestDescription test, String trace) {
58         CLog.i("FailureListener.testFailed %s %b", test.toString(), mBugReportOnFailure);
59         for (ITestDevice device : mListDevice) {
60             captureFailure(device, test);
61         }
62     }
63 
64     /** Capture the appropriate logs for one device for one test failure. */
captureFailure(ITestDevice device, TestDescription test)65     private void captureFailure(ITestDevice device, TestDescription test) {
66         String serial = device.getSerialNumber();
67         if (mBugReportOnFailure && mModuleBugReportOnFailure) {
68             if (!device.logBugreport(
69                     String.format("%s-%s-bugreport", test.toString(), serial), mLogger)) {
70                 CLog.e("Failed to capture bugreport for %s failure on %s.", test, serial);
71             }
72         }
73         if (mRebootOnFailure) {
74             try {
75                 // Rebooting on all failures can hide legitimate issues and platform instabilities,
76                 // therefore only allowed on "user-debug" and "eng" builds.
77                 if ("user".equals(device.getProperty("ro.build.type"))) {
78                     CLog.e("Reboot-on-failure should only be used during development," +
79                             " this is a\" user\" build device");
80                 } else {
81                     device.reboot();
82                 }
83             } catch (DeviceNotAvailableException e) {
84                 CLog.e(e);
85                 CLog.e("Device %s became unavailable while rebooting", serial);
86             }
87         }
88     }
89 
90     /** Join on all the logcat capturing threads to ensure they terminate. */
join()91     public void join() {
92         // Reset the module config to use the invocation settings by default.
93         mModuleBugReportOnFailure = true;
94     }
95 
96     /**
97      * Forward the log to the logger, do not do it from whitin the #testLog callback as if
98      * TestFailureListener is part of the chain, it will results in an infinite loop.
99      */
testLogForward( String dataName, LogDataType dataType, InputStreamSource dataStream)100     public void testLogForward(
101             String dataName, LogDataType dataType, InputStreamSource dataStream) {
102         mLogger.testLog(dataName, dataType, dataStream);
103     }
104 
105     @Override
testLog(String dataName, LogDataType dataType, InputStreamSource dataStream)106     public void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) {
107         // Explicitly do nothing on testLog
108     }
109 
110     /**
111      * Get the default {@link IRunUtil} instance
112      */
113     @VisibleForTesting
getRunUtil()114     IRunUtil getRunUtil() {
115         return RunUtil.getDefault();
116     }
117 
118     /**
119      * Allows to override the invocation settings of capture on failure by the module specific
120      * configurations.
121      *
122      * @param bugreportOnFailure true to capture a bugreport on test failure. False otherwise.
123      */
applyModuleConfiguration(boolean bugreportOnFailure)124     public void applyModuleConfiguration(boolean bugreportOnFailure) {
125         mModuleBugReportOnFailure = bugreportOnFailure;
126     }
127 
128     /** Sets where the logs should be saved. */
setLogger(ITestLogger logger)129     public void setLogger(ITestLogger logger) {
130         mLogger = logger;
131     }
132 }
133