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.compatibility.common.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 */ TestPackageXmlParser(boolean includeKnownFailures)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 * <TestInstance> (optional) 63 */ 64 private class TestPackageHandler extends DefaultHandler { 65 66 private static final String TEST_PACKAGE_TAG = "TestPackage"; 67 private static final String TEST_SUITE_TAG = "TestSuite"; 68 private static final String TEST_CASE_TAG = "TestCase"; 69 private static final String TEST_TAG = "Test"; 70 private static final String TEST_INSTANCE_TAG = "TestInstance"; 71 72 // holds current class name segments 73 private Stack<String> mClassNameStack = new Stack<String>(); 74 private TestIdentifier mTestId; 75 76 @Override startElement(String uri, String localName, String name, Attributes attributes)77 public void startElement(String uri, String localName, String name, Attributes attributes) { 78 if (TEST_PACKAGE_TAG.equals(localName)) { 79 final String appPackageName = attributes.getValue("appPackageName"); 80 final String testPackageNameSpace = attributes.getValue("appNameSpace"); 81 final String packageName = attributes.getValue("name"); 82 final String runnerName = attributes.getValue("runner"); 83 final String jarPath = attributes.getValue("jarPath"); 84 final String javaPackageFilter = attributes.getValue("javaPackageFilter"); 85 final String targetBinaryName = attributes.getValue("targetBinaryName"); 86 final String targetNameSpace = attributes.getValue("targetNameSpace"); 87 final String runTimeArgs = attributes.getValue("runtimeArgs"); 88 final String testType = getTestType(attributes); 89 90 for (String abiName : AbiUtils.getAbisSupportedByCompatibility()) { 91 Abi abi = new Abi(abiName, AbiUtils.getBitness(abiName)); 92 TestPackageDef packageDef = new TestPackageDef(); 93 packageDef.setAppPackageName(appPackageName); 94 packageDef.setAppNameSpace(testPackageNameSpace); 95 packageDef.setName(packageName); 96 packageDef.setRunner(runnerName); 97 packageDef.setTestType(testType); 98 packageDef.setJarPath(jarPath); 99 packageDef.setRunTimeArgs(runTimeArgs); 100 if (!"".equals(javaPackageFilter)) { 101 packageDef.setTestPackageName(javaPackageFilter); 102 } 103 packageDef.setTargetBinaryName(targetBinaryName); 104 packageDef.setTargetNameSpace(targetNameSpace); 105 packageDef.setAbi(abi); 106 mPackageDefs.put(abiName, packageDef); 107 } 108 109 // reset the class name 110 mClassNameStack = new Stack<String>(); 111 } else if (TEST_SUITE_TAG.equals(localName)) { 112 String packageSegment = attributes.getValue("name"); 113 if (packageSegment != null) { 114 mClassNameStack.push(packageSegment); 115 } else { 116 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 117 TEST_SUITE_TAG)); 118 } 119 } else if (TEST_CASE_TAG.equals(localName)) { 120 String classSegment = attributes.getValue("name"); 121 if (classSegment != null) { 122 mClassNameStack.push(classSegment); 123 } else { 124 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 125 TEST_CASE_TAG)); 126 } 127 } else if (TEST_TAG.equals(localName)) { 128 String methodName = attributes.getValue("name"); 129 if (mPackageDefs.isEmpty()) { 130 Log.e(LOG_TAG, String.format( 131 "Invalid XML: encountered a '%s' tag not enclosed within a '%s' tag", 132 TEST_TAG, TEST_PACKAGE_TAG)); 133 } else if (methodName == null) { 134 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 135 TEST_TAG)); 136 } else { 137 // build class name from package segments 138 StringBuilder classNameBuilder = new StringBuilder(); 139 for (Iterator<String> iter = mClassNameStack.iterator(); iter.hasNext(); ) { 140 classNameBuilder.append(iter.next()); 141 if (iter.hasNext()) { 142 classNameBuilder.append("."); 143 } 144 } 145 mTestId = new TestIdentifier(classNameBuilder.toString(), methodName); 146 int timeout = -1; 147 String timeoutStr = attributes.getValue("timeout"); 148 if (timeoutStr != null) { 149 timeout = Integer.parseInt(timeoutStr); 150 } 151 boolean isKnownFailure = "failure".equals(attributes.getValue("expectation")); 152 if (!isKnownFailure || mIncludeKnownFailures) { 153 String abiList = attributes.getValue("abis"); 154 Set<String> abis = new HashSet<String>(); 155 if (abiList == null) { 156 // If no specification, add all supported abis 157 abis.addAll(AbiUtils.getAbisSupportedByCompatibility()); 158 } else { 159 for (String abi : abiList.split(",")) { 160 // Else only add the abi which are supported 161 abis.add(abi.trim()); 162 } 163 } 164 for (String abi : abis) { 165 mPackageDefs.get(abi).addTest(mTestId, timeout); 166 } 167 } 168 } 169 } else if (TEST_INSTANCE_TAG.equals(localName)) { 170 if (mTestId != null) { 171 final Map<String, String> instanceArguments = genAttributeMap(attributes); 172 for (TestPackageDef packageDef : mPackageDefs.values()) { 173 if (packageDef.getTests().contains(mTestId)) { 174 packageDef.addTestInstance(mTestId, instanceArguments); 175 } 176 } 177 } else { 178 Log.e(LOG_TAG, String.format( 179 "Invalid XML: encountered a '%s' tag not enclosed within a '%s' tag", 180 TEST_INSTANCE_TAG, TEST_TAG)); 181 } 182 } 183 } 184 getTestType(Attributes attributes)185 private String getTestType(Attributes attributes) { 186 if (parseBoolean(attributes.getValue("hostSideOnly"))) { 187 return TestPackageDef.HOST_SIDE_ONLY_TEST; 188 } else if (parseBoolean(attributes.getValue("vmHostTest"))) { 189 return TestPackageDef.VM_HOST_TEST; 190 } else { 191 return attributes.getValue("testType"); 192 } 193 } 194 195 @Override endElement(String uri, String localName, String qName)196 public void endElement (String uri, String localName, String qName) { 197 if (TEST_SUITE_TAG.equals(localName) || TEST_CASE_TAG.equals(localName)) { 198 mClassNameStack.pop(); 199 } else if (TEST_TAG.equals(localName)) { 200 mTestId = null; 201 } 202 } 203 204 /** 205 * Parse a boolean attribute value 206 */ parseBoolean(final String stringValue)207 private boolean parseBoolean(final String stringValue) { 208 return stringValue != null && 209 Boolean.parseBoolean(stringValue); 210 } 211 genAttributeMap(Attributes attributes)212 private Map<String, String> genAttributeMap(Attributes attributes) { 213 final Map<String, String> attribMap = new HashMap<String, String>(); 214 for (int i = 0; i < attributes.getLength(); ++i) { 215 final String localName = attributes.getLocalName(i); 216 final String namespace = attributes.getURI(i); 217 final String fullyQualifiedName = 218 (namespace.isEmpty()) ? (localName) : (namespace + ":" + localName); 219 220 attribMap.put(fullyQualifiedName, attributes.getValue(i)); 221 } 222 return attribMap; 223 } 224 } 225 226 @Override createXmlHandler()227 protected DefaultHandler createXmlHandler() { 228 return new TestPackageHandler(); 229 } 230 231 /** 232 * @return the set of {@link TestPackageDef} containing data parsed from xml 233 */ getTestPackageDefs()234 public Set<TestPackageDef> getTestPackageDefs() { 235 return new HashSet<>(mPackageDefs.values()); 236 } 237 } 238