• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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;
17 
18 import java.io.File;
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.security.NoSuchAlgorithmException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashMap;
25 
26 import javax.xml.parsers.DocumentBuilder;
27 import javax.xml.parsers.DocumentBuilderFactory;
28 import javax.xml.parsers.ParserConfigurationException;
29 import javax.xml.transform.TransformerException;
30 import javax.xml.transform.TransformerFactoryConfigurationError;
31 
32 import org.w3c.dom.Document;
33 import org.w3c.dom.Node;
34 import org.w3c.dom.NodeList;
35 import org.xml.sax.SAXException;
36 
37 /**
38  * Builder of test plan and also provides serialization for a test plan.
39  */
40 public class TestSessionBuilder extends XMLResourceHandler {
41     // defined for external document, which is from the configuration files
42     // this should keep synchronized with the format of the configuration files
43 
44     private static final String TAG_TEST_SUITE = "TestSuite";
45     private static final String TAG_TEST_CASE = "TestCase";
46     public static final String TAG_TEST = "Test";
47 
48     // attribute name define
49     public static final String ATTRIBUTE_SIGNATURE_CHECK = "signatureCheck";
50     public static final String ATTRIBUTE_REFERENCE_APP_TEST = "referenceAppTest";
51     public static final String ATTRIBUTE_PRIORITY = "priority";
52 
53     private static final String ATTRIBUTE_NAME = "name";
54     private static final String ATTRIBUTE_RUNNER = "runner";
55     private static final String ATTRIBUTE_JAR_PATH = "jarPath";
56     private static final String ATTRIBUTE_APP_NAME_SPACE = "appNameSpace";
57     public static final String ATTRIBUTE_APP_PACKAGE_NAME = "appPackageName";
58     private static final String ATTRIBUTE_TARGET_NAME_SPACE = "targetNameSpace";
59     private static final String ATTRIBUTE_TARGET_BINARY_NAME = "targetBinaryName";
60     private static final String ATTRIBUTE_TYPE = "type";
61     private static final String ATTRIBUTE_CONTROLLER = "HostController";
62     private static final String ATTRIBUTE_KNOWN_FAILURE = "KnownFailure";
63     private static final String ATTRIBUTE_HOST_SIDE_ONLY = "hostSideOnly";
64     private static final String ATTRIBUTE_VERSION = "version";
65     private static final String ATTRIBUTE_FRAMEWORK_VERSION = "AndroidFramework";
66     private static final String ATTRIBUTE_APK_TO_TEST_NAME = "apkToTestName";
67     private static final String ATTRIBUTE_PACKAGE_TO_TEST = "packageToTest";
68     private static TestSessionBuilder sInstance;
69 
70     private DocumentBuilder mDocBuilder;
71 
getInstance()72     public static TestSessionBuilder getInstance()
73             throws ParserConfigurationException {
74         if (sInstance == null) {
75             sInstance = new TestSessionBuilder();
76         }
77 
78         return sInstance;
79     }
80 
TestSessionBuilder()81     private TestSessionBuilder() throws ParserConfigurationException {
82         mDocBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
83     }
84 
85     /**
86      * Create TestSession via TestSessionLog.
87      *
88      * @param log The test session log.
89      * @return The test session.
90      */
build(TestSessionLog log)91     public TestSession build(TestSessionLog log) {
92         if (log == null) {
93             return null;
94         }
95         return new TestSession(log, 1);
96     }
97 
98     /**
99      * Create TestSession via TestPlan XML configuration file.
100      *
101      * @param config TestPlan XML configuration file.
102      * @return TestSession.
103      */
build(final String config)104     public TestSession build(final String config) throws SAXException, IOException,
105             TestPlanNotFoundException, TestNotFoundException, NoSuchAlgorithmException {
106         File file = new File(config);
107         if (!file.exists()) {
108             throw new TestPlanNotFoundException();
109         }
110         Document doc = mDocBuilder.parse(file);
111 
112         // parse device configuration
113         int numOfRequiredDevices = 1; // default is 1
114         try {
115             Node deviceConfigNode = doc.getElementsByTagName(
116                     TestPlan.Tag.REQUIRED_DEVICE).item(0);
117             numOfRequiredDevices = getAttributeValue(deviceConfigNode,
118                     TestPlan.Attribute.AMOUNT);
119         } catch (Exception e) {
120         }
121 
122         Collection<TestPackage> packages = loadPackages(doc);
123         if (packages.size() == 0) {
124             throw new TestNotFoundException("No valid package in test plan.");
125         }
126 
127         String planFileName = file.getName();
128         int index = planFileName.indexOf(".");
129         String planName;
130         if (index != -1) {
131             planName = planFileName.substring(0, planFileName.indexOf("."));
132         } else{
133             planName = planFileName;
134         }
135 
136         TestSessionLog sessionLog = new TestSessionLog(packages, planName);
137         TestSession ts = new TestSession(sessionLog, numOfRequiredDevices);
138         return ts;
139     }
140 
141     /**
142      * Load TestPackages from a TestPlan DOM doc.
143      *
144      * @param doc TestPlan DOM Document
145      * @return loaded test package from TestPlan DOM Document
146      */
loadPackages(Document doc)147     private Collection<TestPackage> loadPackages(Document doc)
148                 throws SAXException, IOException, NoSuchAlgorithmException {
149 
150         ArrayList<TestPackage> packages = new ArrayList<TestPackage>();
151         NodeList packageList = doc.getElementsByTagName(TestPlan.Tag.ENTRY);
152         ArrayList<String> removedPkgList = new ArrayList<String>();
153         for (int i = 0; i < packageList.getLength(); i++) {
154             Node pNode = packageList.item(i);
155             String uri = getStringAttributeValue(pNode, TestPlan.Attribute.URI);
156             String list = getStringAttributeValue(pNode, TestPlan.Attribute.EXCLUDE);
157             ArrayList<String> excludedList = null;
158             if ((list != null) && (list.length() != 0)) {
159                 excludedList = getStrArrayList(list);
160             }
161 
162             String packageBinaryName = HostConfig.getInstance().getPackageBinaryName(uri);
163             if (packageBinaryName != null) {
164                 String xmlConfigFilePath =
165                        HostConfig.getInstance().getCaseRepository().getXmlPath(packageBinaryName);
166                 File xmlFile = new File(xmlConfigFilePath);
167                 TestPackage pkg = loadPackage(xmlFile, excludedList);
168                 if (pkg instanceof SignatureCheckPackage) {
169                     // insert the signature check package
170                     // to the head of the list
171                     packages.add(0, pkg);
172                 } else {
173                     packages.add(pkg);
174                 }
175             } else{
176                 removedPkgList.add(uri);
177             }
178         }
179         if (removedPkgList.size() != 0) {
180             CUIOutputStream.println("The following package(s) doesn't exist:");
181             for (String pkgName : removedPkgList) {
182                 CUIOutputStream.println("    " + pkgName);
183             }
184         }
185         return packages;
186     }
187 
188     /**
189      * Load TestPackage via Package XML configuration file.
190      *
191      * @param packageConfigFile test package XML file
192      * @param excludedList The list containing the excluded suites and sub types.
193      * @return loaded TestPackage from test package XML configuration file
194      */
loadPackage(final File packageConfigFile, ArrayList<String> excludedList)195     public TestPackage loadPackage(final File packageConfigFile, ArrayList<String> excludedList)
196                                 throws SAXException, IOException, NoSuchAlgorithmException {
197         Node pNode = mDocBuilder.parse(packageConfigFile).getDocumentElement();
198         return loadPackage(pNode, excludedList);
199     }
200 
201     /**
202      * Load TestPackage via Package XML configuration file.
203      *
204      * @param pkgNode the test package node in the XML file
205      * @param excludedList The list containing the excluded suites and sub types.
206      * @return loaded TestPackage from test package XML configuration file
207      */
loadPackage(final Node pkgNode, ArrayList<String> excludedList)208     public TestPackage loadPackage(final Node pkgNode, ArrayList<String> excludedList)
209                                 throws NoSuchAlgorithmException {
210 
211         String appBinaryName, targetNameSpace, targetBinaryName, version, frameworkVersion,
212                runner, jarPath, appNameSpace, appPackageName, hostSideOnly;
213         NodeList suiteList = pkgNode.getChildNodes();
214 
215         appBinaryName = getStringAttributeValue(pkgNode, ATTRIBUTE_NAME);
216         targetNameSpace = getStringAttributeValue(pkgNode, ATTRIBUTE_TARGET_NAME_SPACE);
217         targetBinaryName = getStringAttributeValue(pkgNode, ATTRIBUTE_TARGET_BINARY_NAME);
218         version = getStringAttributeValue(pkgNode, ATTRIBUTE_VERSION);
219         frameworkVersion = getStringAttributeValue(pkgNode, ATTRIBUTE_FRAMEWORK_VERSION);
220         runner = getStringAttributeValue(pkgNode, ATTRIBUTE_RUNNER);
221         jarPath = getStringAttributeValue(pkgNode, ATTRIBUTE_JAR_PATH);
222         appNameSpace = getStringAttributeValue(pkgNode, ATTRIBUTE_APP_NAME_SPACE);
223         appPackageName = getStringAttributeValue(pkgNode, ATTRIBUTE_APP_PACKAGE_NAME);
224         hostSideOnly = getStringAttributeValue(pkgNode, ATTRIBUTE_HOST_SIDE_ONLY);
225         String signature = getStringAttributeValue(pkgNode, ATTRIBUTE_SIGNATURE_CHECK);
226         String referenceAppTest = getStringAttributeValue(pkgNode, ATTRIBUTE_REFERENCE_APP_TEST);
227         TestPackage pkg = null;
228 
229         if ("true".equals(referenceAppTest)) {
230             String apkToTestName = getStringAttributeValue(pkgNode, ATTRIBUTE_APK_TO_TEST_NAME);
231             String packageUnderTest = getStringAttributeValue(pkgNode, ATTRIBUTE_PACKAGE_TO_TEST);
232             pkg = new ReferenceAppTestPackage(runner, appBinaryName, targetNameSpace,
233                     targetBinaryName, version, frameworkVersion, jarPath,
234                     appNameSpace, appPackageName,
235                     apkToTestName, packageUnderTest);
236         } else if ("true".equals(signature)) {
237             pkg = new SignatureCheckPackage(runner, appBinaryName, targetNameSpace,
238                     targetBinaryName, version, frameworkVersion, jarPath,
239                     appNameSpace, appPackageName);
240         } else if ("true".equals(hostSideOnly)) {
241             pkg = new HostSideOnlyPackage(appBinaryName, version, frameworkVersion,
242                     jarPath, appPackageName);
243         } else {
244             pkg = new TestPackage(runner, appBinaryName, targetNameSpace, targetBinaryName,
245                     version, frameworkVersion, jarPath, appNameSpace, appPackageName);
246         }
247 
248         for (int i = 0; i < suiteList.getLength(); i++) {
249             Node sNode = suiteList.item(i);
250             if (sNode.getNodeType() == Document.ELEMENT_NODE
251                     && TAG_TEST_SUITE.equals(sNode.getNodeName())) {
252                 String fullSuiteName = getFullSuiteName(sNode);
253                 if (checkFullMatch(excludedList, fullSuiteName) == false) {
254                     ArrayList<String> excludedCaseList =
255                                           getExcludedList(excludedList, fullSuiteName);
256                     TestSuite suite = loadSuite(pkg, sNode, excludedCaseList);
257                     if ((suite.getTestCases().size() != 0) || (suite.getSubSuites().size() != 0)) {
258                         pkg.addTestSuite(suite);
259                     }
260                 } else {
261                     Log.d("suite=" + fullSuiteName + " is fully excluded");
262                 }
263             }
264         }
265 
266         return pkg;
267     }
268 
269     /**
270      * Get string ArrayList from string.
271      *
272      * @param str The given string.
273      * @return The list.
274      */
getStrArrayList(String str)275     private ArrayList<String> getStrArrayList(String str) {
276         if ((str == null) || (str.length() == 0)) {
277             return null;
278         }
279 
280         String[] list = str.split(TestPlan.EXCLUDE_SEPARATOR);
281         if ((list == null) || (list.length == 0)) {
282             return null;
283         }
284 
285         ArrayList<String> result = new ArrayList<String>();
286         for (String s : list) {
287             result.add(s);
288         }
289 
290         return result;
291     }
292 
293     /**
294      * Get excluded list from a list by offered expectation.
295      *
296      * @param excludedList The list containing excluded items.
297      * @param expectation The expectations.
298      * @return The excluded list.
299      */
getExcludedList(ArrayList<String> excludedList, String expectation)300     private ArrayList<String> getExcludedList(ArrayList<String> excludedList, String expectation) {
301         if ((excludedList == null) || (excludedList.size() == 0)) {
302             return null;
303         }
304 
305         ArrayList<String> list = new ArrayList<String>();
306         for (String str : excludedList) {
307             if (str.startsWith(expectation)) {
308                 list.add(str);
309             }
310         }
311 
312         if (list.size() == 0) {
313             return null;
314         } else {
315             return list;
316         }
317     }
318 
319     /**
320      * Check if the expectation is fully matched among a list.
321      *
322      * @param list The array list.
323      * @param expectation The expectation.
324      * @return If there is full match of expectation among the list, return true;
325      *         else, return false.
326      */
checkFullMatch(ArrayList<String> list, String expectation)327     private boolean checkFullMatch(ArrayList<String> list, String expectation) {
328         if ((list == null) || (list.size() == 0)) {
329             return false;
330         }
331 
332         for (String str : list) {
333             if (str.equals(expectation)) {
334                 return true;
335             }
336         }
337 
338         return false;
339     }
340 
341     /**
342      * Load TestSuite via suite node. Package Name is used to output test result.
343      *
344      * @param pkg TestPackage
345      * @param sNode suite node
346      * @param excludedCaseList The list containing the excluded cases and sub types.
347      * @return TestSuite
348      */
loadSuite(final TestPackage pkg, Node sNode, ArrayList<String> excludedCaseList)349     private TestSuite loadSuite(final TestPackage pkg, Node sNode,
350                                 ArrayList<String> excludedCaseList) {
351         NodeList cNodes = sNode.getChildNodes();
352         String fullSuiteName = getFullSuiteName(sNode);
353         String suiteName = getStringAttributeValue(sNode, TestPlan.Attribute.NAME);
354         TestSuite suite = new TestSuite(pkg, suiteName, fullSuiteName);
355 
356         for (int i = 0; i < cNodes.getLength(); i++) {
357             Node cNode = cNodes.item(i);
358             if (cNode.getNodeType() == Document.ELEMENT_NODE) {
359                 if (cNode.getNodeName().equals(TAG_TEST_SUITE)) {
360                     String subSuiteName = getFullSuiteName(cNode);
361                     if (checkFullMatch(excludedCaseList, subSuiteName) == false) {
362                         ArrayList<String> excludedList = getExcludedList(excludedCaseList,
363                                                              subSuiteName);
364                         TestSuite subSuite = loadSuite(pkg, cNode, excludedList);
365                         if ((subSuite.getTestCases().size() != 0)
366                             || (subSuite.getSubSuites().size() != 0)) {
367                             suite.addSubSuite(subSuite);
368                         }
369                     } else {
370                         Log.d("suite=" + subSuiteName + " is fully excluded");
371                     }
372                 } else if (cNode.getNodeName().equals(TAG_TEST_CASE)) {
373                     String cName = getStringAttributeValue(cNode, ATTRIBUTE_NAME);
374                     String priority = getStringAttributeValue(cNode, ATTRIBUTE_PRIORITY);
375 
376                     TestCase testCase = new TestCase(suite, cName, priority);
377                     String fullCaseName = fullSuiteName + "." + testCase.getName();
378                     if (checkFullMatch(excludedCaseList, fullCaseName) == false) {
379                         NodeList mNodes = cNode.getChildNodes();
380                         for (int t = 0; t < mNodes.getLength(); t ++) {
381                             Node testNode = mNodes.item(t);
382                             if ((testNode.getNodeType() == Document.ELEMENT_NODE)
383                                     && (testNode.getNodeName().equals(TAG_TEST))) {
384                                 Test test = loadTest(pkg, testCase, testNode);
385                                 if (!checkFullMatch(excludedCaseList, test.getFullName())) {
386                                     testCase.addTest(test);
387                                 } else {
388                                     Log.d("Test=" + test.getFullName() + " is excluded");
389                                 }
390                             }
391                         }
392                         if (testCase.getTests().size() != 0) {
393                             suite.addTestCase(testCase);
394                         }
395                     } else {
396                         Log.d("case=" + fullCaseName + " is fully excluded");
397                     }
398                 }
399             }
400         }
401 
402         return suite;
403     }
404 
405     /**
406      * Load test via test node.
407      *
408      * @param pkg The test package.
409      * @param testCase The test case.
410      * @param testNode The test node.
411      * @return The test loaded.
412      */
loadTest(final TestPackage pkg, TestCase testCase, Node testNode)413     private Test loadTest(final TestPackage pkg, TestCase testCase,
414             Node testNode) {
415         String cType = getStringAttributeValue(testNode, ATTRIBUTE_TYPE);
416         String name = getStringAttributeValue(testNode, ATTRIBUTE_NAME);
417         String description = getStringAttributeValue(testNode,
418                 ATTRIBUTE_CONTROLLER);
419         String knownFailure = getStringAttributeValue(testNode,
420                 ATTRIBUTE_KNOWN_FAILURE);
421         String fullJarPath =
422             HostConfig.getInstance().getCaseRepository().getRoot()
423             + File.separator + pkg.getJarPath();
424         CtsTestResult testResult = loadTestResult(testNode);
425         Test test = null;
426         if (pkg.isHostSideOnly()) {
427             test = new HostSideOnlyTest(testCase, name, cType,
428                     knownFailure,
429                     CtsTestResult.CODE_NOT_EXECUTED);
430             description = test.getFullName();
431         } else {
432             test = new Test(testCase, name, cType,
433                     knownFailure,
434                     CtsTestResult.CODE_NOT_EXECUTED);
435         }
436 
437         TestController controller =
438             genTestControler(fullJarPath, description);
439         test.setTestController(controller);
440         if (testResult != null) {
441             test.addResult(testResult);
442         }
443         return test;
444     }
445 
446     /**
447      * Load the CTS test result from the test node.
448      *
449      * @param testNode The test node.
450      * @return The CTS test result.
451      */
loadTestResult(Node testNode)452     private CtsTestResult loadTestResult(Node testNode) {
453         String result = getStringAttributeValue(testNode,
454                 TestSessionLog.ATTRIBUTE_RESULT);
455 
456         String failedMessage = null;
457         String stackTrace = null;
458         NodeList nodes = testNode.getChildNodes();
459         for (int i = 0; i < nodes.getLength(); i ++) {
460             Node rNode = nodes.item(i);
461             if ((rNode.getNodeType() == Document.ELEMENT_NODE)
462                     && (rNode.getNodeName().equals(TestSessionLog.TAG_FAILED_SCENE))) {
463                 failedMessage = getStringAttributeValue(rNode, TestSessionLog.TAG_FAILED_MESSAGE);
464                 stackTrace = getStringAttributeValue(rNode, TestSessionLog.TAG_STACK_TRACE);
465                 if (stackTrace == null) {
466                     NodeList sNodeList = rNode.getChildNodes();
467                     for (int j = 0; j < sNodeList.getLength(); j ++) {
468                         Node sNode = sNodeList.item(i);
469                         if ((sNode.getNodeType() == Document.ELEMENT_NODE)
470                                 && (sNode.getNodeName().equals(TestSessionLog.TAG_STACK_TRACE))) {
471                             stackTrace = sNode.getTextContent();
472                         }
473                     }
474                 }
475                 break;
476             }
477         }
478 
479         CtsTestResult testResult = null;
480         if (result != null) {
481             try {
482                 testResult = new CtsTestResult(result, failedMessage, stackTrace);
483             } catch (InvalidTestResultStringException e) {
484             }
485         }
486 
487         return testResult;
488     }
489 
490     /**
491      * Generate controller according to the description string.
492      *
493      * @return The test controller.
494      */
genTestControler(String jarPath, String description)495     public TestController genTestControler(String jarPath, String description) {
496         if ((jarPath == null) || (jarPath.length() == 0)
497                 || (description == null) || (description.length() == 0)) {
498             return null;
499         }
500 
501         String packageName = description.substring(0, description.lastIndexOf("."));
502         String className   = description.substring(packageName.length() + 1,
503                              description.lastIndexOf(Test.METHOD_SEPARATOR));
504         String methodName  = description.substring(
505                              description.lastIndexOf(Test.METHOD_SEPARATOR) + 1,
506                              description.length());
507 
508         return new TestController(jarPath, packageName, className, methodName);
509     }
510 
511     /**
512      * Get the full suite name of the specified suite node. Since the test
513      * suite can be nested, so the full name of a tests suite is combined
514      * with his name and his ancestor suite's names.
515      *
516      * @param node The specified suite node.
517      * @return The full name of the given suite node.
518      */
getFullSuiteName(Node node)519     private String getFullSuiteName(Node node) {
520         StringBuilder buf = new StringBuilder();
521         buf.append(getStringAttributeValue(node, TestPlan.Attribute.NAME));
522 
523         Node parent = node.getParentNode();
524         while (parent != null) {
525             if (parent.getNodeType() == Document.ELEMENT_NODE
526                     && parent.getNodeName() == TAG_TEST_SUITE) {
527                 buf.insert(0, ".");
528                 buf.insert(0, getStringAttributeValue(parent, TestPlan.Attribute.NAME));
529             }
530 
531             parent = parent.getParentNode();
532         }
533 
534         return buf.toString();
535     }
536 
537     /**
538      * Create TestPlan which contain a series TestPackages.
539      *
540      * @param planName test plan name
541      * @param packageNames Package names to be added
542      * @param selectedResult The selected result mapping selected
543      *                       package with selected removal result.
544      */
serialize(String planName, ArrayList<String> packageNames, HashMap<String, ArrayList<String>> selectedResult)545     public void serialize(String planName,
546             ArrayList<String> packageNames, HashMap<String, ArrayList<String>> selectedResult)
547             throws ParserConfigurationException, FileNotFoundException,
548             TransformerFactoryConfigurationError, TransformerException {
549         File plan = new File(HostConfig.getInstance().getPlanRepository()
550                 .getPlanPath(planName));
551         if (plan.exists()) {
552             Log.e("Plan " + planName + " already exist, please use another name!",
553                     null);
554             return;
555         }
556 
557         Document doc = DocumentBuilderFactory.newInstance()
558                 .newDocumentBuilder().newDocument();
559         Node root = doc.createElement(TestPlan.Tag.TEST_PLAN);
560         setAttribute(doc, root, ATTRIBUTE_VERSION, "1.0");
561         doc.appendChild(root);
562 
563         // append device configure node
564         Node deviceConfigNode = doc.createElement(TestPlan.Tag.PLAN_SETTING);
565 
566         root.appendChild(deviceConfigNode);
567 
568         // append test packages
569         for (String pName : packageNames) {
570             if (selectedResult.containsKey(pName)) {
571                 Node entryNode = doc.createElement(TestPlan.Tag.ENTRY);
572 
573                 setAttribute(doc, entryNode, TestPlan.Attribute.URI, pName);
574                 ArrayList<String> excluded = selectedResult.get(pName);
575                 if ((excluded != null) && (excluded.size() != 0)) {
576                     String excludedList = "";
577                     for (String str : excluded) {
578                         excludedList += str + TestPlan.EXCLUDE_SEPARATOR;
579                     }
580                     setAttribute(doc, entryNode, TestPlan.Attribute.EXCLUDE, excludedList);
581                 }
582                 root.appendChild(entryNode);
583             }
584         }
585 
586         writeToFile(plan, doc);
587     }
588 
589 }
590