• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ddmlib.Log;
19 import com.android.tradefed.result.TestResult;
20 
21 import org.kxml2.io.KXmlSerializer;
22 import org.xmlpull.v1.XmlPullParser;
23 import org.xmlpull.v1.XmlPullParserException;
24 
25 import java.io.IOException;
26 
27 /**
28  * Data structure that represents a "Test" result XML element.
29  */
30 class Test extends AbstractXmlPullParser {
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 SUMMARY_TAG = "Summary";
40     private static final String DETAILS_TAG = "Details";
41     private static final String VALUEARRAY_TAG = "ValueArray";
42     private static final String VALUE_TAG = "Value";
43     private static final String TARGET_ATTR = "target";
44     private static final String SCORETYPE_ATTR = "scoreType";
45     private static final String UNIT_ATTR = "unit";
46     private static final String SOURCE_ATTR = "source";
47     // separators for the message from PTS
48     private static final String LOG_SEPARATOR = "\\+\\+\\+";
49     private static final String LOG_ELEM_SEPARATOR = "\\|";
50 
51     private String mName;
52     private CtsTestStatus mResult;
53     private String mStartTime;
54     private String mEndTime;
55     private String mMessage;
56     private String mStackTrace;
57     // summary and details passed from pts
58     private String mSummary;
59     private String mDetails;
60 
61     /**
62      * Create an empty {@link Test}
63      */
Test()64     public Test() {
65     }
66 
67     /**
68      * Create a {@link Test} from a {@link TestResult}.
69      *
70      * @param name
71      */
Test(String name)72     public Test(String name) {
73         mName = name;
74         mResult = CtsTestStatus.NOT_EXECUTED;
75         mStartTime = TimeUtil.getTimestamp();
76         updateEndTime();
77     }
78 
79     /**
80      * Set the name of this {@link Test}
81      */
setName(String name)82     public void setName(String name) {
83         mName = name;
84     }
85 
86     /**
87      * Get the name of this {@link Test}
88      */
getName()89     public String getName() {
90         return mName;
91     }
92 
getResult()93     public CtsTestStatus getResult() {
94         return mResult;
95     }
96 
getMessage()97     public String getMessage() {
98         return mMessage;
99     }
100 
setMessage(String message)101     public void setMessage(String message) {
102         mMessage = message;
103     }
104 
getStartTime()105     public String getStartTime() {
106         return mStartTime;
107     }
108 
getEndTime()109     public String getEndTime() {
110         return mEndTime;
111     }
112 
getStackTrace()113     public String getStackTrace() {
114         return mStackTrace;
115     }
116 
setStackTrace(String stackTrace)117     public void setStackTrace(String stackTrace) {
118 
119         mStackTrace = sanitizeStackTrace(stackTrace);
120         mMessage = getFailureMessageFromStackTrace(mStackTrace);
121     }
122 
getSummary()123     public String getSummary() {
124         return mSummary;
125     }
126 
setSummary(String summary)127     public void setSummary(String summary) {
128         mSummary = summary;
129     }
130 
getDetails()131     public String getDetails() {
132         return mDetails;
133     }
134 
setDetails(String details)135     public void setDetails(String details) {
136         mDetails = details;
137     }
138 
updateEndTime()139     public void updateEndTime() {
140         mEndTime = TimeUtil.getTimestamp();
141     }
142 
setResultStatus(CtsTestStatus status)143     public void setResultStatus(CtsTestStatus status) {
144         mResult = status;
145     }
146 
147     /**
148      * Serialize this object and all its contents to XML.
149      *
150      * @param serializer
151      * @throws IOException
152      */
serialize(KXmlSerializer serializer)153     public void serialize(KXmlSerializer serializer)
154             throws IOException {
155         serializer.startTag(CtsXmlResultReporter.ns, TAG);
156         serializer.attribute(CtsXmlResultReporter.ns, NAME_ATTR, getName());
157         serializer.attribute(CtsXmlResultReporter.ns, RESULT_ATTR, mResult.getValue());
158         serializer.attribute(CtsXmlResultReporter.ns, STARTTIME_ATTR, mStartTime);
159         serializer.attribute(CtsXmlResultReporter.ns, ENDTIME_ATTR, mEndTime);
160 
161         if (mMessage != null) {
162             serializer.startTag(CtsXmlResultReporter.ns, SCENE_TAG);
163             serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR, mMessage);
164             if (mStackTrace != null) {
165                 serializer.startTag(CtsXmlResultReporter.ns, STACK_TAG);
166                 serializer.text(mStackTrace);
167                 serializer.endTag(CtsXmlResultReporter.ns, STACK_TAG);
168             }
169             serializer.endTag(CtsXmlResultReporter.ns, SCENE_TAG);
170         }
171         if (mSummary != null) {
172             // <Summary message = "screen copies per sec" scoretype="higherBetter" unit="fps">
173             // 23938.82978723404</Summary>
174             PerfResultSummary summary = parseSummary(mSummary);
175             if (summary != null) {
176                 serializer.startTag(CtsXmlResultReporter.ns, SUMMARY_TAG);
177                 serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR, summary.mMessage);
178                 if (summary.mTarget.length() != 0 && !summary.mTarget.equals(" ")) {
179                     serializer.attribute(CtsXmlResultReporter.ns, TARGET_ATTR, summary.mTarget);
180                 }
181                 serializer.attribute(CtsXmlResultReporter.ns, SCORETYPE_ATTR, summary.mType);
182                 serializer.attribute(CtsXmlResultReporter.ns, UNIT_ATTR, summary.mUnit);
183                 serializer.text(summary.mValue);
184                 serializer.endTag(CtsXmlResultReporter.ns, SUMMARY_TAG);
185                 // add details only if summary is present
186                 // <Details>
187                 //   <ValueArray source=”com.android.pts.dram.BandwidthTest#doRunMemcpy:98”
188                 //                    message=”measure1” unit="ms" scoretype="higherBetter">
189                 //     <Value>0.0</Value>
190                 //     <Value>0.1</Value>
191                 //   </ValueArray>
192                 // </Details>
193                 if (mDetails != null) {
194                     PerfResultDetail[] ds = parseDetails(mDetails);
195                     serializer.startTag(CtsXmlResultReporter.ns, DETAILS_TAG);
196                         for (PerfResultDetail d : ds) {
197                             if (d == null) {
198                                 continue;
199                             }
200                             serializer.startTag(CtsXmlResultReporter.ns, VALUEARRAY_TAG);
201                             serializer.attribute(CtsXmlResultReporter.ns, SOURCE_ATTR, d.mSource);
202                             serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR,
203                                     d.mMessage);
204                             serializer.attribute(CtsXmlResultReporter.ns, SCORETYPE_ATTR, d.mType);
205                             serializer.attribute(CtsXmlResultReporter.ns, UNIT_ATTR, d.mUnit);
206                             for (String v : d.mValues) {
207                                 if (v == null) {
208                                     continue;
209                                 }
210                                 serializer.startTag(CtsXmlResultReporter.ns, VALUE_TAG);
211                                 serializer.text(v);
212                                 serializer.endTag(CtsXmlResultReporter.ns, VALUE_TAG);
213                             }
214                             serializer.endTag(CtsXmlResultReporter.ns, VALUEARRAY_TAG);
215                         }
216                     serializer.endTag(CtsXmlResultReporter.ns, DETAILS_TAG);
217                 }
218             }
219         }
220         serializer.endTag(CtsXmlResultReporter.ns, TAG);
221     }
222 
223     /**
224      *  class containing performance result.
225      */
226     public static class PerfResultCommon {
227         public String mMessage;
228         public String mType;
229         public String mUnit;
230     }
231 
232     private class PerfResultSummary extends PerfResultCommon {
233         public String mTarget;
234         public String mValue;
235     }
236 
237     private class PerfResultDetail extends PerfResultCommon {
238         public String mSource;
239         public String[] mValues;
240     }
241 
parseSummary(String summary)242     private PerfResultSummary parseSummary(String summary) {
243         String[] elems = summary.split(LOG_ELEM_SEPARATOR);
244         PerfResultSummary r = new PerfResultSummary();
245         if (elems.length < 5) {
246             Log.w(TAG, "wrong message " + summary);
247             return null;
248         }
249         r.mMessage = elems[0];
250         r.mTarget = elems[1];
251         r.mType = elems[2];
252         r.mUnit = elems[3];
253         r.mValue = elems[4];
254         return r;
255     }
256 
parseDetails(String details)257     private PerfResultDetail[] parseDetails(String details) {
258         String[] arrays = details.split(LOG_SEPARATOR);
259         PerfResultDetail[] rs = new PerfResultDetail[arrays.length];
260         for (int i = 0; i < arrays.length; i++) {
261             String[] elems = arrays[i].split(LOG_ELEM_SEPARATOR);
262             if (elems.length < 5) {
263                 Log.w(TAG, "wrong message " + arrays[i]);
264                 continue;
265             }
266             PerfResultDetail r = new PerfResultDetail();
267             r.mSource = elems[0];
268             r.mMessage = elems[1];
269             r.mType = elems[2];
270             r.mUnit = elems[3];
271             r.mValues = elems[4].split(" ");
272             rs[i] = r;
273         }
274         return rs;
275     }
276 
277     /**
278      * Strip out any invalid XML characters that might cause the report to be unviewable.
279      * http://www.w3.org/TR/REC-xml/#dt-character
280      */
sanitizeStackTrace(String trace)281     private static String sanitizeStackTrace(String trace) {
282         if (trace != null) {
283             return trace.replaceAll("[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD]", "");
284         } else {
285             return null;
286         }
287     }
288 
289     /**
290      * Gets the failure message to show from the stack trace.
291      * <p/>
292      * Exposed for unit testing
293      *
294      * @param stack the full stack trace
295      * @return the failure message
296      */
getFailureMessageFromStackTrace(String stack)297     static String getFailureMessageFromStackTrace(String stack) {
298         // return the first two lines of stack as failure message
299         int endPoint = stack.indexOf('\n');
300         if (endPoint != -1) {
301             int nextLine = stack.indexOf('\n', endPoint + 1);
302             if (nextLine != -1) {
303                 return stack.substring(0, nextLine);
304             }
305         }
306         return stack;
307     }
308 
309     /**
310      * Populates this class with test result data parsed from XML.
311      *
312      * @param parser the {@link XmlPullParser}. Expected to be pointing at start
313      *            of a Test tag
314      */
315     @Override
parse(XmlPullParser parser)316     void parse(XmlPullParser parser) throws XmlPullParserException, IOException {
317         if (!parser.getName().equals(TAG)) {
318             throw new XmlPullParserException(String.format(
319                     "invalid XML: Expected %s tag but received %s", TAG, parser.getName()));
320         }
321         setName(getAttribute(parser, NAME_ATTR));
322         mResult = CtsTestStatus.getStatus(getAttribute(parser, RESULT_ATTR));
323         mStartTime = getAttribute(parser, STARTTIME_ATTR);
324         mEndTime = getAttribute(parser, ENDTIME_ATTR);
325 
326         int eventType = parser.next();
327         while (eventType != XmlPullParser.END_DOCUMENT) {
328             if (eventType == XmlPullParser.START_TAG && parser.getName().equals(SCENE_TAG)) {
329                 mMessage = getAttribute(parser, MESSAGE_ATTR);
330             } else if (eventType == XmlPullParser.START_TAG && parser.getName().equals(STACK_TAG)) {
331                 mStackTrace = parser.nextText();
332             } else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG)) {
333                 return;
334             }
335             eventType = parser.next();
336         }
337     }
338 }
339