1 /* 2 * Copyright (C) 2011 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.cts.tradefed.result; 17 18 import com.android.tradefed.result.TestResult; 19 20 import org.kxml2.io.KXmlSerializer; 21 import org.xmlpull.v1.XmlPullParser; 22 import org.xmlpull.v1.XmlPullParserException; 23 24 import java.io.IOException; 25 26 /** 27 * Data structure that represents a "Test" result XML element. 28 */ 29 class Test extends AbstractXmlPullParser { 30 31 static final String TAG = "Test"; 32 private static final String NAME_ATTR = "name"; 33 private static final String MESSAGE_ATTR = "message"; 34 private static final String ENDTIME_ATTR = "endtime"; 35 private static final String STARTTIME_ATTR = "starttime"; 36 private static final String RESULT_ATTR = "result"; 37 private static final String SCENE_TAG = "FailedScene"; 38 private static final String STACK_TAG = "StackTrace"; 39 private static final String DETAILS_TAG = "Details"; 40 41 private String mName; 42 private CtsTestStatus mResult; 43 private String mStartTime; 44 private String mEndTime; 45 private String mMessage; 46 private String mStackTrace; 47 // details passed from pts 48 private String mDetails; 49 50 /** 51 * Create an empty {@link Test} 52 */ 53 public Test() { 54 } 55 56 /** 57 * Create a {@link Test} from a {@link TestResult}. 58 * 59 * @param name 60 */ 61 public Test(String name) { 62 mName = name; 63 mResult = CtsTestStatus.NOT_EXECUTED; 64 mStartTime = TimeUtil.getTimestamp(); 65 updateEndTime(); 66 } 67 68 /** 69 * Set the name of this {@link Test} 70 */ 71 public void setName(String name) { 72 mName = name; 73 } 74 75 /** 76 * Get the name of this {@link Test} 77 */ 78 public String getName() { 79 return mName; 80 } 81 82 public CtsTestStatus getResult() { 83 return mResult; 84 } 85 86 public String getMessage() { 87 return mMessage; 88 } 89 90 public void setMessage(String message) { 91 mMessage = message; 92 } 93 94 public String getStartTime() { 95 return mStartTime; 96 } 97 98 public String getEndTime() { 99 return mEndTime; 100 } 101 102 public String getStackTrace() { 103 return mStackTrace; 104 } 105 106 public void setStackTrace(String stackTrace) { 107 108 mStackTrace = sanitizeStackTrace(stackTrace); 109 mMessage = getFailureMessageFromStackTrace(mStackTrace); 110 } 111 112 public String getDetails() { 113 return mDetails; 114 } 115 116 public void setDetails(String details) { 117 mDetails = details; 118 } 119 120 public void updateEndTime() { 121 mEndTime = TimeUtil.getTimestamp(); 122 } 123 124 public void setResultStatus(CtsTestStatus status) { 125 mResult = status; 126 } 127 128 /** 129 * Serialize this object and all its contents to XML. 130 * 131 * @param serializer 132 * @throws IOException 133 */ 134 public void serialize(KXmlSerializer serializer) 135 throws IOException { 136 serializer.startTag(CtsXmlResultReporter.ns, TAG); 137 serializer.attribute(CtsXmlResultReporter.ns, NAME_ATTR, getName()); 138 serializer.attribute(CtsXmlResultReporter.ns, RESULT_ATTR, mResult.getValue()); 139 serializer.attribute(CtsXmlResultReporter.ns, STARTTIME_ATTR, mStartTime); 140 serializer.attribute(CtsXmlResultReporter.ns, ENDTIME_ATTR, mEndTime); 141 142 if (mMessage != null) { 143 serializer.startTag(CtsXmlResultReporter.ns, SCENE_TAG); 144 serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR, mMessage); 145 if (mStackTrace != null) { 146 serializer.startTag(CtsXmlResultReporter.ns, STACK_TAG); 147 serializer.text(mStackTrace); 148 serializer.endTag(CtsXmlResultReporter.ns, STACK_TAG); 149 } 150 if (mDetails != null) { 151 serializer.startTag(CtsXmlResultReporter.ns, DETAILS_TAG); 152 serializer.text(mDetails); 153 serializer.endTag(CtsXmlResultReporter.ns, DETAILS_TAG); 154 } 155 serializer.endTag(CtsXmlResultReporter.ns, SCENE_TAG); 156 } 157 serializer.endTag(CtsXmlResultReporter.ns, TAG); 158 } 159 160 /** 161 * Strip out any invalid XML characters that might cause the report to be unviewable. 162 * http://www.w3.org/TR/REC-xml/#dt-character 163 */ 164 private static String sanitizeStackTrace(String trace) { 165 if (trace != null) { 166 return trace.replaceAll("[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD]", ""); 167 } else { 168 return null; 169 } 170 } 171 172 /** 173 * Gets the failure message to show from the stack trace. 174 * <p/> 175 * Exposed for unit testing 176 * 177 * @param stack the full stack trace 178 * @return the failure message 179 */ 180 static String getFailureMessageFromStackTrace(String stack) { 181 // return the first two lines of stack as failure message 182 int endPoint = stack.indexOf('\n'); 183 if (endPoint != -1) { 184 int nextLine = stack.indexOf('\n', endPoint + 1); 185 if (nextLine != -1) { 186 return stack.substring(0, nextLine); 187 } 188 } 189 return stack; 190 } 191 192 /** 193 * Populates this class with test result data parsed from XML. 194 * 195 * @param parser the {@link XmlPullParser}. Expected to be pointing at start 196 * of a Test tag 197 */ 198 @Override 199 void parse(XmlPullParser parser) throws XmlPullParserException, IOException { 200 if (!parser.getName().equals(TAG)) { 201 throw new XmlPullParserException(String.format( 202 "invalid XML: Expected %s tag but received %s", TAG, parser.getName())); 203 } 204 setName(getAttribute(parser, NAME_ATTR)); 205 mResult = CtsTestStatus.getStatus(getAttribute(parser, RESULT_ATTR)); 206 mStartTime = getAttribute(parser, STARTTIME_ATTR); 207 mEndTime = getAttribute(parser, ENDTIME_ATTR); 208 209 int eventType = parser.next(); 210 while (eventType != XmlPullParser.END_DOCUMENT) { 211 if (eventType == XmlPullParser.START_TAG && parser.getName().equals(SCENE_TAG)) { 212 mMessage = getAttribute(parser, MESSAGE_ATTR); 213 } else if (eventType == XmlPullParser.START_TAG && parser.getName().equals(STACK_TAG)) { 214 mStackTrace = parser.nextText(); 215 } else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG)) { 216 return; 217 } 218 eventType = parser.next(); 219 } 220 } 221 } 222