1 /* 2 * Copyright (C) 2020 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.result; 17 18 import com.android.tradefed.log.LogUtil.CLog; 19 import com.android.tradefed.result.error.ErrorIdentifier; 20 import com.android.tradefed.result.proto.TestRecordProto; 21 22 import javax.annotation.Nullable; 23 24 /** 25 * The class describing a failure information in Trade Federation. This class contains the debugging 26 * information and context of the failure that helps understanding the issue. 27 */ 28 public class FailureDescription { 29 // The error message generated from the failure 30 private String mErrorMessage; 31 // Optional: The category of the failure 32 private @Nullable TestRecordProto.FailureStatus mFailureStatus = 33 TestRecordProto.FailureStatus.UNSET; 34 // Optional: Context of the action in progress during the failure 35 private @Nullable ActionInProgress mActionInProgress = ActionInProgress.UNSET; 36 // Optional: A free-formed text that help debugging the failure 37 private @Nullable String mDebugHelpMessage = null; 38 // Optional: The exception that triggered the failure 39 private @Nullable Throwable mCause = null; 40 // Whether or not the error is retriable by Tradefed auto-retry. By Default we retry it all. 41 private boolean mRetriable = true; 42 // Test Feature: whether or not to rerun the full run in case of run failure. 43 private boolean mRunFailureReRunAll = true; 44 45 // Error identifiers 46 // Optional: The error identifier and its code 47 private @Nullable ErrorIdentifier mErrorId = null; 48 // Optional: The class that raised the error 49 private @Nullable String mOrigin = null; 50 FailureDescription()51 FailureDescription() {} 52 53 /** 54 * Set the {@link com.android.tradefed.result.proto.TestRecordProto.FailureStatus} associated 55 * with the failure. 56 */ setFailureStatus(TestRecordProto.FailureStatus status)57 public FailureDescription setFailureStatus(TestRecordProto.FailureStatus status) { 58 mFailureStatus = status; 59 if (mErrorId != null && mFailureStatus != mErrorId.status()) { 60 CLog.w( 61 "Failure: %s, status set to %s, not aligned with errorId: %s (%s)", 62 this, mFailureStatus, mErrorId, mErrorId.status()); 63 } 64 return this; 65 } 66 67 /** Returns the FailureStatus associated with the failure. Can be null. */ getFailureStatus()68 public @Nullable TestRecordProto.FailureStatus getFailureStatus() { 69 if (TestRecordProto.FailureStatus.UNSET.equals(mFailureStatus)) { 70 return null; 71 } 72 return mFailureStatus; 73 } 74 75 /** Sets the action in progress during the failure. */ setActionInProgress(ActionInProgress action)76 public FailureDescription setActionInProgress(ActionInProgress action) { 77 mActionInProgress = action; 78 return this; 79 } 80 81 /** Returns the action in progress during the failure. Can be null. */ getActionInProgress()82 public @Nullable ActionInProgress getActionInProgress() { 83 return mActionInProgress; 84 } 85 86 /** Sets the debug help message for the failure. */ setDebugHelpMessage(String message)87 public FailureDescription setDebugHelpMessage(String message) { 88 mDebugHelpMessage = message; 89 return this; 90 } 91 92 /** Returns the debug help message. Can be null. */ getDebugHelpMessage()93 public @Nullable String getDebugHelpMessage() { 94 return mDebugHelpMessage; 95 } 96 97 /** Sets the exception that caused the failure if any. */ setCause(Throwable cause)98 public FailureDescription setCause(Throwable cause) { 99 mCause = cause; 100 return this; 101 } 102 103 /** Returns the exception that caused the failure. Can be null. */ getCause()104 public @Nullable Throwable getCause() { 105 return mCause; 106 } 107 108 /** Sets whether or not the failure is retriable. */ setRetriable(boolean retriable)109 public FailureDescription setRetriable(boolean retriable) { 110 mRetriable = retriable; 111 return this; 112 } 113 114 /** Returns whether or not the error is retriable or not. */ isRetriable()115 public boolean isRetriable() { 116 return mRetriable; 117 } 118 119 /** Sets whether or not to rerun the full run when a run failure occurs. */ setFullRerun(boolean fullRerun)120 public FailureDescription setFullRerun(boolean fullRerun) { 121 mRunFailureReRunAll = fullRerun; 122 return this; 123 } 124 125 /** Returns whether or not we need to retry the full run or not. */ rerunFull()126 public boolean rerunFull() { 127 return mRunFailureReRunAll; 128 } 129 130 /** Sets the {@link ErrorIdentifier} representing the failure. */ setErrorIdentifier(ErrorIdentifier errorId)131 public FailureDescription setErrorIdentifier(ErrorIdentifier errorId) { 132 mErrorId = errorId; 133 if (getFailureStatus() == null && errorId != null) { 134 mFailureStatus = errorId.status(); 135 } 136 return this; 137 } 138 139 /** Returns the {@link ErrorIdentifier} representing the failure. Can be null. */ getErrorIdentifier()140 public ErrorIdentifier getErrorIdentifier() { 141 return mErrorId; 142 } 143 144 /** Sets the origin of the error. */ setOrigin(String origin)145 public FailureDescription setOrigin(String origin) { 146 mOrigin = origin; 147 return this; 148 } 149 150 /** Returns the origin of the error. Can be null. */ getOrigin()151 public String getOrigin() { 152 return mOrigin; 153 } 154 155 /** Sets the error message. */ setErrorMessage(String errorMessage)156 public void setErrorMessage(String errorMessage) { 157 mErrorMessage = errorMessage; 158 } 159 160 /** Returns the error message associated with the failure. */ getErrorMessage()161 public String getErrorMessage() { 162 return mErrorMessage; 163 } 164 165 /** 166 * A formatted way of displaying the error and some details. 167 */ getFormattedErrorMessage()168 public String getFormattedErrorMessage() { 169 StringBuilder s = new StringBuilder(); 170 if (mErrorId != null) { 171 s.append("["); 172 s.append(mErrorId.name()); 173 s.append("|"); 174 s.append(mErrorId.code()); 175 s.append("|"); 176 s.append(mErrorId.status()); 177 s.append("] "); 178 } 179 s.append(this.toString()); 180 return s.toString(); 181 } 182 183 @Override toString()184 public String toString() { 185 // For backward compatibility of result interface, toString falls back to the simple message 186 return mErrorMessage; 187 } 188 189 /** 190 * Create a {@link FailureDescription} based on the error message generated from the failure. 191 * 192 * @param errorMessage The error message from the failure. 193 * @return the created {@link FailureDescription} 194 */ create(String errorMessage)195 public static FailureDescription create(String errorMessage) { 196 return create(errorMessage, TestRecordProto.FailureStatus.UNSET); 197 } 198 199 /** 200 * Create a {@link FailureDescription} based on the error message generated from the failure. 201 * 202 * @param errorMessage The error message from the failure. 203 * @param status The status associated with the failure. 204 * @return the created {@link FailureDescription} 205 */ create( String errorMessage, @Nullable TestRecordProto.FailureStatus status)206 public static FailureDescription create( 207 String errorMessage, @Nullable TestRecordProto.FailureStatus status) { 208 FailureDescription info = new FailureDescription(); 209 info.mErrorMessage = errorMessage; 210 info.mFailureStatus = status; 211 return info; 212 } 213 214 @Override hashCode()215 public int hashCode() { 216 final int prime = 31; 217 int result = 1; 218 result = prime * result + ((mActionInProgress == null) ? 0 : mActionInProgress.hashCode()); 219 result = prime * result + ((mDebugHelpMessage == null) ? 0 : mDebugHelpMessage.hashCode()); 220 result = prime * result + ((mErrorMessage == null) ? 0 : mErrorMessage.hashCode()); 221 result = prime * result + ((mFailureStatus == null) ? 0 : mFailureStatus.hashCode()); 222 return result; 223 } 224 225 @Override equals(Object obj)226 public boolean equals(Object obj) { 227 if (this == obj) { 228 return true; 229 } 230 if (obj == null) { 231 return false; 232 } 233 if (getClass() != obj.getClass()) { 234 return false; 235 } 236 FailureDescription other = (FailureDescription) obj; 237 if (mActionInProgress != other.mActionInProgress) { 238 return false; 239 } 240 if (mDebugHelpMessage == null) { 241 if (other.mDebugHelpMessage != null) { 242 return false; 243 } 244 } else if (!mDebugHelpMessage.equals(other.mDebugHelpMessage)) { 245 return false; 246 } 247 if (mErrorMessage == null) { 248 if (other.mErrorMessage != null) { 249 return false; 250 } 251 } else if (!mErrorMessage.equals(other.mErrorMessage)) { 252 return false; 253 } 254 if (mFailureStatus != other.mFailureStatus) { 255 return false; 256 } 257 return true; 258 } 259 } 260