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