1 /* 2 * Copyright (C) 2010 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.testtype; 17 18 import com.android.cts.util.AbiUtils; 19 import com.android.ddmlib.Log; 20 import com.android.ddmlib.testrunner.TestIdentifier; 21 import com.android.tradefed.util.xml.AbstractXmlParser; 22 23 import org.xml.sax.Attributes; 24 import org.xml.sax.helpers.DefaultHandler; 25 26 import java.util.HashMap; 27 import java.util.HashSet; 28 import java.util.Iterator; 29 import java.util.Map; 30 import java.util.Set; 31 import java.util.Stack; 32 33 /** 34 * Parser for CTS test case XML. 35 * <p/> 36 * Dumb parser that just retrieves data from in the test case xml and stuff it into a 37 * {@link TestPackageDef}. Currently performs limited error checking. 38 */ 39 public class TestPackageXmlParser extends AbstractXmlParser { 40 41 private static final String LOG_TAG = "TestPackageXmlParser"; 42 43 private final boolean mIncludeKnownFailures; 44 45 private Map<String, TestPackageDef> mPackageDefs = new HashMap<String, TestPackageDef>(); 46 47 /** 48 * @param includeKnownFailures Whether to run tests which are known to fail. 49 */ 50 public TestPackageXmlParser(boolean includeKnownFailures) { 51 mIncludeKnownFailures = includeKnownFailures; 52 } 53 54 /** 55 * SAX callback object. Handles parsing data from the xml tags. 56 * <p/> 57 * Expected structure: 58 * <TestPackage> 59 * <TestSuite ...> 60 * <TestCase> 61 * <Test> 62 */ 63 private class TestPackageHandler extends DefaultHandler { 64 65 private static final String TEST_PACKAGE_TAG = "TestPackage"; 66 private static final String TEST_SUITE_TAG = "TestSuite"; 67 private static final String TEST_CASE_TAG = "TestCase"; 68 private static final String TEST_TAG = "Test"; 69 70 // holds current class name segments 71 private Stack<String> mClassNameStack = new Stack<String>(); 72 73 @Override 74 public void startElement(String uri, String localName, String name, Attributes attributes) { 75 if (TEST_PACKAGE_TAG.equals(localName)) { 76 final String appPackageName = attributes.getValue("appPackageName"); 77 final String testPackageNameSpace = attributes.getValue("appNameSpace"); 78 final String packageName = attributes.getValue("name"); 79 final String runnerName = attributes.getValue("runner"); 80 final String jarPath = attributes.getValue("jarPath"); 81 final String javaPackageFilter = attributes.getValue("javaPackageFilter"); 82 final String targetBinaryName = attributes.getValue("targetBinaryName"); 83 final String targetNameSpace = attributes.getValue("targetNameSpace"); 84 final String runTimeArgs = attributes.getValue("runtimeArgs"); 85 final String testType = getTestType(attributes); 86 87 for (String abiName : AbiUtils.getAbisSupportedByCts()) { 88 Abi abi = new Abi(abiName, AbiUtils.getBitness(abiName)); 89 TestPackageDef packageDef = new TestPackageDef(); 90 packageDef.setAppPackageName(appPackageName); 91 packageDef.setAppNameSpace(testPackageNameSpace); 92 packageDef.setName(packageName); 93 packageDef.setRunner(runnerName); 94 packageDef.setTestType(testType); 95 packageDef.setJarPath(jarPath); 96 packageDef.setRunTimeArgs(runTimeArgs); 97 if (!"".equals(javaPackageFilter)) { 98 packageDef.setTestPackageName(javaPackageFilter); 99 } 100 packageDef.setTargetBinaryName(targetBinaryName); 101 packageDef.setTargetNameSpace(targetNameSpace); 102 packageDef.setAbi(abi); 103 mPackageDefs.put(abiName, packageDef); 104 } 105 106 // reset the class name 107 mClassNameStack = new Stack<String>(); 108 } else if (TEST_SUITE_TAG.equals(localName)) { 109 String packageSegment = attributes.getValue("name"); 110 if (packageSegment != null) { 111 mClassNameStack.push(packageSegment); 112 } else { 113 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 114 TEST_SUITE_TAG)); 115 } 116 } else if (TEST_CASE_TAG.equals(localName)) { 117 String classSegment = attributes.getValue("name"); 118 if (classSegment != null) { 119 mClassNameStack.push(classSegment); 120 } else { 121 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 122 TEST_CASE_TAG)); 123 } 124 } else if (TEST_TAG.equals(localName)) { 125 String methodName = attributes.getValue("name"); 126 if (mPackageDefs.isEmpty()) { 127 Log.e(LOG_TAG, String.format( 128 "Invalid XML: encountered a '%s' tag not enclosed within a '%s' tag", 129 TEST_TAG, TEST_PACKAGE_TAG)); 130 } else if (methodName == null) { 131 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 132 TEST_TAG)); 133 } else { 134 // build class name from package segments 135 StringBuilder classNameBuilder = new StringBuilder(); 136 for (Iterator<String> iter = mClassNameStack.iterator(); iter.hasNext(); ) { 137 classNameBuilder.append(iter.next()); 138 if (iter.hasNext()) { 139 classNameBuilder.append("."); 140 } 141 } 142 int timeout = -1; 143 String timeoutStr = attributes.getValue("timeout"); 144 if (timeoutStr != null) { 145 timeout = Integer.parseInt(timeoutStr); 146 } 147 boolean isKnownFailure = "failure".equals(attributes.getValue("expectation")); 148 if (!isKnownFailure || mIncludeKnownFailures) { 149 String abiList = attributes.getValue("abis"); 150 Set<String> abis = new HashSet<String>(); 151 if (abiList == null) { 152 // If no specification, add all supported abis 153 abis.addAll(AbiUtils.getAbisSupportedByCts()); 154 } else { 155 for (String abi : abiList.split(",")) { 156 // Else only add the abi which are supported 157 abis.add(abi.trim()); 158 } 159 } 160 for (String abi : abis) { 161 TestIdentifier testId = new TestIdentifier( 162 classNameBuilder.toString(), methodName); 163 mPackageDefs.get(abi).addTest(testId, timeout); 164 } 165 } 166 } 167 } 168 169 } 170 171 private String getTestType(Attributes attributes) { 172 if (parseBoolean(attributes.getValue("hostSideOnly"))) { 173 return TestPackageDef.HOST_SIDE_ONLY_TEST; 174 } else if (parseBoolean(attributes.getValue("vmHostTest"))) { 175 return TestPackageDef.VM_HOST_TEST; 176 } else { 177 return attributes.getValue("testType"); 178 } 179 } 180 181 @Override 182 public void endElement (String uri, String localName, String qName) { 183 if (TEST_SUITE_TAG.equals(localName) || TEST_CASE_TAG.equals(localName)) { 184 mClassNameStack.pop(); 185 } 186 } 187 188 /** 189 * Parse a boolean attribute value 190 */ 191 private boolean parseBoolean(final String stringValue) { 192 return stringValue != null && 193 Boolean.parseBoolean(stringValue); 194 } 195 } 196 197 @Override 198 protected DefaultHandler createXmlHandler() { 199 return new TestPackageHandler(); 200 } 201 202 /** 203 * @return the set of {@link TestPackageDef} containing data parsed from xml 204 */ 205 public Set<TestPackageDef> getTestPackageDefs() { 206 return new HashSet<>(mPackageDefs.values()); 207 } 208 } 209