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