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.cts.tradefed.testtype.CtsTest;
     19 import com.android.cts.tradefed.util.CtsHostStore;
     20 import com.android.cts.util.AbiUtils;
     21 import com.android.ddmlib.testrunner.TestIdentifier;
     22 import com.android.tradefed.log.LogUtil.CLog;
     23 
     24 import org.kxml2.io.KXmlSerializer;
     25 import org.xmlpull.v1.XmlPullParser;
     26 import org.xmlpull.v1.XmlPullParserException;
     27 
     28 import java.io.IOException;
     29 import java.util.Collection;
     30 import java.util.Collections;
     31 import java.util.Deque;
     32 import java.util.HashMap;
     33 import java.util.LinkedList;
     34 import java.util.List;
     35 import java.util.Map;
     36 import java.util.regex.Matcher;
     37 import java.util.regex.Pattern;
     38 
     39 /**
     40  * Data structure for a CTS test package result.
     41  * <p/>
     42  * Provides methods to serialize to XML.
     43  */
     44 class TestPackageResult extends AbstractXmlPullParser {
     45 
     46     static final String TAG = "TestPackage";
     47 
     48     public static final String CTS_RESULT_KEY = "CTS_TEST_RESULT";
     49 
     50     private static final String DIGEST_ATTR = "digest";
     51     private static final String APP_PACKAGE_NAME_ATTR = "appPackageName";
     52     private static final String NAME_ATTR = "name";
     53     private static final String ABI_ATTR = "abi";
     54     private static final String ns = CtsXmlResultReporter.ns;
     55     private static final String SIGNATURE_TEST_PKG = "android.tests.sigtest";
     56 
     57     private static final Pattern mCtsLogPattern = Pattern.compile("(.*)\\+\\+\\+\\+(.*)");
     58 
     59     private String mDeviceSerial;
     60     private String mAppPackageName;
     61     private String mName;
     62     private String mAbi;
     63     private String mDigest;
     64 
     65     private Map<String, String> mMetrics = new HashMap<String, String>();
     66     private Map<TestIdentifier, Map<String, String>> mTestMetrics = new HashMap<TestIdentifier, Map<String, String>>();
     67 
     68     private TestSuite mSuiteRoot = new TestSuite(null);
     69 
     70     public void setDeviceSerial(String deviceSerial) {
     71         mDeviceSerial = deviceSerial;
     72     }
     73 
     74     public String getDeviceSerial() {
     75         return mDeviceSerial;
     76     }
     77 
     78     public String getId() {
     79         return AbiUtils.createId(getAbi(), getAppPackageName());
     80     }
     81 
     82     public void setAppPackageName(String appPackageName) {
     83         mAppPackageName = appPackageName;
     84     }
     85 
     86     public String getAppPackageName() {
     87         return mAppPackageName;
     88     }
     89 
     90     public void setName(String name) {
     91         mName = name;
     92     }
     93 
     94     public String getName() {
     95         return mName;
     96     }
     97 
     98     public void setAbi(String abi) {
     99         mAbi = abi;
    100     }
    101 
    102     public String getAbi() {
    103         return mAbi;
    104     }
    105 
    106     public void setDigest(String digest) {
    107         mDigest = digest;
    108     }
    109 
    110     public String getDigest() {
    111         return mDigest;
    112     }
    113 
    114     /**
    115      * Return the {@link TestSuite}s
    116      */
    117     public Collection<TestSuite> getTestSuites() {
    118         return mSuiteRoot.getTestSuites();
    119     }
    120 
    121     /**
    122      * Adds a test result to this test package
    123      *
    124      * @param testId
    125      */
    126     public Test insertTest(TestIdentifier testId) {
    127         return findTest(testId, true);
    128     }
    129 
    130     private Test findTest(TestIdentifier testId, boolean insertIfMissing) {
    131         List<String> classNameSegments = new LinkedList<String>();
    132         Collections.addAll(classNameSegments, testId.getClassName().split("\\."));
    133         if (classNameSegments.size() <= 0) {
    134             CLog.e("Unrecognized package name format for test class '%s'",
    135                     testId.getClassName());
    136             // should never happen
    137             classNameSegments.add("UnknownTestClass");
    138         }
    139         String testCaseName = classNameSegments.remove(classNameSegments.size() - 1);
    140         return mSuiteRoot.findTest(classNameSegments, testCaseName, testId.getTestName(), insertIfMissing);
    141     }
    142 
    143 
    144     /**
    145      * Find the test result for given {@link TestIdentifier}.
    146      * @param testId
    147      * @return the {@link Test} or <code>null</code>
    148      */
    149     public Test findTest(TestIdentifier testId) {
    150         return findTest(testId, false);
    151     }
    152 
    153     /**
    154      * Serialize this object and all its contents to XML.
    155      *
    156      * @param serializer
    157      * @throws IOException
    158      */
    159     public void serialize(KXmlSerializer serializer) throws IOException {
    160         serializer.startTag(ns, TAG);
    161         serializeAttribute(serializer, NAME_ATTR, mName);
    162         serializeAttribute(serializer, APP_PACKAGE_NAME_ATTR, mAppPackageName);
    163         serializeAttribute(serializer, ABI_ATTR, mAbi);
    164         serializeAttribute(serializer, DIGEST_ATTR, getDigest());
    165         if (SIGNATURE_TEST_PKG.equals(mName)) {
    166             serializer.attribute(ns, "signatureCheck", "true");
    167         }
    168         mSuiteRoot.serialize(serializer);
    169         serializer.endTag(ns, TAG);
    170     }
    171 
    172     /**
    173      * Helper method to serialize attributes.
    174      * Can handle null values. Useful for cases where test package has not been fully populated
    175      * such as when unit testing.
    176      *
    177      * @param attrName
    178      * @param attrValue
    179      * @throws IOException
    180      */
    181     private void serializeAttribute(KXmlSerializer serializer, String attrName, String attrValue)
    182             throws IOException {
    183         attrValue = attrValue == null ? "" : attrValue;
    184         serializer.attribute(ns, attrName, attrValue);
    185     }
    186 
    187     /**
    188      * Populates this class with package result data parsed from XML.
    189      *
    190      * @param parser the {@link XmlPullParser}. Expected to be pointing at start
    191      *            of TestPackage tag
    192      */
    193     @Override
    194     void parse(XmlPullParser parser) throws XmlPullParserException, IOException {
    195         if (!parser.getName().equals(TAG)) {
    196             throw new XmlPullParserException(String.format(
    197                     "invalid XML: Expected %s tag but received %s", TAG, parser.getName()));
    198         }
    199         setAppPackageName(getAttribute(parser, APP_PACKAGE_NAME_ATTR));
    200         setName(getAttribute(parser, NAME_ATTR));
    201         setAbi(getAttribute(parser, ABI_ATTR));
    202         setDigest(getAttribute(parser, DIGEST_ATTR));
    203         int eventType = parser.getEventType();
    204         while (eventType != XmlPullParser.END_DOCUMENT) {
    205             if (eventType == XmlPullParser.START_TAG && parser.getName().equals(TestSuite.TAG)) {
    206                 TestSuite suite = new TestSuite();
    207                 suite.parse(parser);
    208                 mSuiteRoot.insertSuite(suite);
    209             }
    210             if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG)) {
    211                 return;
    212             }
    213             eventType = parser.next();
    214         }
    215     }
    216 
    217     /**
    218      * Return a list of {@link TestIdentifier}s contained in this result with the given status
    219      *
    220      * @param resultFilter the {@link CtsTestStatus} to filter by
    221      * @return a collection of {@link TestIdentifier}s
    222      */
    223     public Collection<TestIdentifier> getTestsWithStatus(CtsTestStatus resultFilter) {
    224         Collection<TestIdentifier> tests = new LinkedList<TestIdentifier>();
    225         Deque<String> suiteNames = new LinkedList<String>();
    226         mSuiteRoot.addTestsWithStatus(tests, suiteNames, resultFilter);
    227         return tests;
    228     }
    229 
    230     /**
    231      * Populate values in this package result from run metrics
    232      * @param metrics A map of metrics from the completed test run.
    233      */
    234     public void populateMetrics(Map<String, String> metrics) {
    235         String name = metrics.get(CtsTest.PACKAGE_NAME_METRIC);
    236         if (name != null) {
    237             setName(name);
    238         }
    239         String abi = metrics.get(CtsTest.PACKAGE_ABI_METRIC);
    240         if (abi != null) {
    241             setAbi(abi);
    242         }
    243         String digest = metrics.get(CtsTest.PACKAGE_DIGEST_METRIC);
    244         if (digest != null) {
    245             setDigest(digest);
    246         }
    247         mMetrics.putAll(metrics);
    248 
    249         // Collect performance results
    250         for (TestIdentifier test : mTestMetrics.keySet()) {
    251             // device test can have performance results in test metrics
    252             String perfResult = mTestMetrics.get(test).get(CTS_RESULT_KEY);
    253             // host test should be checked in CtsHostStore.
    254             if (perfResult == null) {
    255                 perfResult = CtsHostStore.removeCtsResult(mDeviceSerial, mAbi, test.toString());
    256             }
    257             if (perfResult != null) {
    258                 // CTS result is passed in Summary++++Details format.
    259                 // Extract Summary and Details, and pass them.
    260                 Matcher m = mCtsLogPattern.matcher(perfResult);
    261                 if (m.find()) {
    262                     Test result = findTest(test);
    263                     result.setResultStatus(CtsTestStatus.PASS);
    264                     result.setSummary(m.group(1));
    265                     result.setDetails(m.group(2));
    266                 } else {
    267                     CLog.e("CTS Result unrecognizable:" + perfResult);
    268                 }
    269             }
    270         }
    271     }
    272 
    273     /**
    274      * Report the given test as a failure.
    275      *
    276      * @param test
    277      * @param status
    278      * @param trace
    279      */
    280     public void reportTestFailure(TestIdentifier test, CtsTestStatus status, String trace) {
    281         Test result = findTest(test);
    282         result.setResultStatus(status);
    283         result.setStackTrace(trace);
    284     }
    285 
    286     /**
    287      * Report that the given test has completed.
    288      *
    289      * @param test The {@link TestIdentifier} of the completed test.
    290      * @param testMetrics A map holding metrics about the completed test, if any.
    291      */
    292     public void reportTestEnded(TestIdentifier test, Map<String, String> testMetrics) {
    293         Test result = findTest(test);
    294         if (!result.getResult().equals(CtsTestStatus.FAIL)) {
    295             result.setResultStatus(CtsTestStatus.PASS);
    296         }
    297         result.updateEndTime();
    298         if (mTestMetrics.containsKey(test)) {
    299             CLog.e("Test metrics already contains key: " + test);
    300         }
    301         mTestMetrics.put(test, testMetrics);
    302         CLog.i("Test metrics:" + testMetrics);
    303     }
    304 
    305     /**
    306      * Return the number of tests with given status
    307      *
    308      * @param status
    309      * @return the total number of tests with given status
    310      */
    311     public int countTests(CtsTestStatus status) {
    312         return mSuiteRoot.countTests(status);
    313     }
    314 
    315     /**
    316      * @return A map holding the metrics from the test run.
    317      */
    318     public Map<String, String> getMetrics() {
    319         return mMetrics;
    320     }
    321 
    322 }
    323