Home | History | Annotate | Download | only in result
      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
     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 cts
     58     private String mSummary;
     59     private String mDetails;
     60 
     61     /**
     62      * Create an empty {@link Test}
     63      */
     64     public Test() {
     65     }
     66 
     67     /**
     68      * Create a {@link Test} from a {@link TestResult}.
     69      *
     70      * @param name
     71      */
     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      */
     82     public void setName(String name) {
     83         mName = name;
     84     }
     85 
     86     /**
     87      * Get the name of this {@link Test}
     88      */
     89     public String getName() {
     90         return mName;
     91     }
     92 
     93     public CtsTestStatus getResult() {
     94         return mResult;
     95     }
     96 
     97     public String getMessage() {
     98         return mMessage;
     99     }
    100 
    101     public void setMessage(String message) {
    102         mMessage = message;
    103     }
    104 
    105     public String getStartTime() {
    106         return mStartTime;
    107     }
    108 
    109     public String getEndTime() {
    110         return mEndTime;
    111     }
    112 
    113     public String getStackTrace() {
    114         return mStackTrace;
    115     }
    116 
    117     public void setStackTrace(String stackTrace) {
    118 
    119         mStackTrace = sanitizeStackTrace(stackTrace);
    120         mMessage = getFailureMessageFromStackTrace(mStackTrace);
    121     }
    122 
    123     public String getSummary() {
    124         return mSummary;
    125     }
    126 
    127     public void setSummary(String summary) {
    128         mSummary = summary;
    129     }
    130 
    131     public String getDetails() {
    132         return mDetails;
    133     }
    134 
    135     public void setDetails(String details) {
    136         mDetails = details;
    137     }
    138 
    139     public void updateEndTime() {
    140         mEndTime = TimeUtil.getTimestamp();
    141     }
    142 
    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      */
    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.cts.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 
    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 
    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      */
    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      */
    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
    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