blob: b705cc7501efb705d736610b267424fd7d886a3f [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cts;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Builder of test plan and also provides serialization for a test plan.
*/
public class TestSessionBuilder extends XMLResourceHandler {
// defined for external document, which is from the configuration files
// this should keep synchronized with the format of the configuration files
private static final String TAG_TEST_SUITE = "TestSuite";
private static final String TAG_TEST_CASE = "TestCase";
public static final String TAG_TEST = "Test";
// attribute name define
public static final String ATTRIBUTE_SIGNATURE_CHECK = "signatureCheck";
public static final String ATTRIBUTE_REFERENCE_APP_TEST = "referenceAppTest";
public static final String ATTRIBUTE_PRIORITY = "priority";
private static final String ATTRIBUTE_NAME = "name";
private static final String ATTRIBUTE_RUNNER = "runner";
private static final String ATTRIBUTE_JAR_PATH = "jarPath";
private static final String ATTRIBUTE_APP_NAME_SPACE = "appNameSpace";
private static final String ATTRIBUTE_APP_PACKAGE_NAME = "appPackageName";
private static final String ATTRIBUTE_TARGET_NAME_SPACE = "targetNameSpace";
private static final String ATTRIBUTE_TARGET_BINARY_NAME = "targetBinaryName";
private static final String ATTRIBUTE_TYPE = "type";
private static final String ATTRIBUTE_METHOD = "method";
private static final String ATTRIBUTE_CONTROLLER = "HostController";
private static final String ATTRIBUTE_KNOWN_FAILURE = "KnownFailure";
private static final String ATTRIBUTE_HOST_SIDE_ONLY = "hostSideOnly";
private static final String ATTRIBUTE_VERSION = "version";
private static final String ATTRIBUTE_FRAMEWORK_VERSION = "AndroidFramework";
private static final String ATTRIBUTE_APK_TO_TEST_NAME = "apkToTestName";
private static final String ATTRIBUTE_PACKAGE_TO_TEST = "packageToTest";
private static TestSessionBuilder sInstance;
private DocumentBuilder mDocBuilder;
public static TestSessionBuilder getInstance()
throws ParserConfigurationException {
if (sInstance == null) {
sInstance = new TestSessionBuilder();
}
return sInstance;
}
private TestSessionBuilder() throws ParserConfigurationException {
mDocBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
}
/**
* Create TestSession via TestPlan XML configuration file.
*
* @param config TestPlan XML configuration file
* @return TestSession
*/
public TestSession build(final String config) throws SAXException, IOException,
TestPlanNotFoundException, TestNotFoundException, NoSuchAlgorithmException {
File file = new File(config);
if (!file.exists()) {
throw new TestPlanNotFoundException();
}
Document doc = mDocBuilder.parse(file);
// parse device configuration
int numOfRequiredDevices = 1; // default is 1
try {
Node deviceConfigNode = doc.getElementsByTagName(
TestPlan.Tag.REQUIRED_DEVICE).item(0);
numOfRequiredDevices = getAttributeValue(deviceConfigNode,
TestPlan.Attribute.AMOUNT);
} catch (Exception e) {
}
Collection<TestPackage> packages = loadPackages(doc);
if (packages.size() == 0) {
throw new TestNotFoundException("No valid package in test plan.");
}
String planFileName = file.getName();
int index = planFileName.indexOf(".");
String planName;
if (index != -1) {
planName = planFileName.substring(0, planFileName.indexOf("."));
} else{
planName = planFileName;
}
TestSessionLog sessionLog = new TestSessionLog(packages, planName);
TestSession ts = new TestSession(sessionLog, numOfRequiredDevices);
return ts;
}
/**
* Load TestPackages from a TestPlan DOM doc.
*
* @param doc TestPlan DOM Document
* @return loaded test package from TestPlan DOM Document
*/
private Collection<TestPackage> loadPackages(Document doc)
throws SAXException, IOException, NoSuchAlgorithmException {
ArrayList<TestPackage> packages = new ArrayList<TestPackage>();
NodeList packageList = doc.getElementsByTagName(TestPlan.Tag.ENTRY);
ArrayList<String> removedPkgList = new ArrayList<String>();
for (int i = 0; i < packageList.getLength(); i++) {
Node pNode = packageList.item(i);
String uri = getStringAttributeValue(pNode, TestPlan.Attribute.URI);
String list = getStringAttributeValue(pNode, TestPlan.Attribute.EXCLUDE);
ArrayList<String> excludedList = null;
if ((list != null) && (list.length() != 0)) {
excludedList = getStrArrayList(list);
}
String packageBinaryName = HostConfig.getInstance().getPackageBinaryName(uri);
if (packageBinaryName != null) {
String xmlConfigFilePath =
HostConfig.getInstance().getCaseRepository().getXmlPath(packageBinaryName);
File xmlFile = new File(xmlConfigFilePath);
TestPackage pkg = loadPackage(xmlFile, excludedList);
if (pkg instanceof SignatureCheckPackage) {
// insert the signature check package
// to the head of the list
packages.add(0, pkg);
} else {
packages.add(pkg);
}
} else{
removedPkgList.add(uri);
}
}
if (removedPkgList.size() != 0) {
CUIOutputStream.println("The following package(s) doesn't exist:");
for (String pkgName : removedPkgList) {
CUIOutputStream.println(" " + pkgName);
}
}
return packages;
}
/**
* Load TestPackage via Package XML configuration file.
*
* @param packageConfigFile test package XML file
* @param excludedList The list containing the excluded suites and sub types.
* @return loaded TestPackage from test package XML configuration file
*/
public TestPackage loadPackage(final File packageConfigFile, ArrayList<String> excludedList)
throws SAXException, IOException, NoSuchAlgorithmException {
Node pNode = mDocBuilder.parse(packageConfigFile).getDocumentElement();
String appBinaryName, targetNameSpace, targetBinaryName, version, frameworkVersion,
runner, jarPath, appNameSpace, appPackageName, hostSideOnly;
NodeList suiteList = pNode.getChildNodes();
appBinaryName = getStringAttributeValue(pNode, ATTRIBUTE_NAME);
targetNameSpace = getStringAttributeValue(pNode, ATTRIBUTE_TARGET_NAME_SPACE);
targetBinaryName = getStringAttributeValue(pNode, ATTRIBUTE_TARGET_BINARY_NAME);
version = getStringAttributeValue(pNode, ATTRIBUTE_VERSION);
frameworkVersion = getStringAttributeValue(pNode, ATTRIBUTE_FRAMEWORK_VERSION);
runner = getStringAttributeValue(pNode, ATTRIBUTE_RUNNER);
jarPath = getStringAttributeValue(pNode, ATTRIBUTE_JAR_PATH);
appNameSpace = getStringAttributeValue(pNode, ATTRIBUTE_APP_NAME_SPACE);
appPackageName = getStringAttributeValue(pNode, ATTRIBUTE_APP_PACKAGE_NAME);
hostSideOnly = getStringAttributeValue(pNode, ATTRIBUTE_HOST_SIDE_ONLY);
String signature = getStringAttributeValue(pNode, ATTRIBUTE_SIGNATURE_CHECK);
String referenceAppTest = getStringAttributeValue(pNode, ATTRIBUTE_REFERENCE_APP_TEST);
TestPackage pkg = null;
if ("true".equals(referenceAppTest)) {
String apkToTestName = getStringAttributeValue(pNode, ATTRIBUTE_APK_TO_TEST_NAME);
String packageUnderTest = getStringAttributeValue(pNode, ATTRIBUTE_PACKAGE_TO_TEST);
pkg = new ReferenceAppTestPackage(runner, appBinaryName, targetNameSpace,
targetBinaryName, version, frameworkVersion, jarPath,
appNameSpace, appPackageName,
apkToTestName, packageUnderTest);
} else if ("true".equals(signature)) {
pkg = new SignatureCheckPackage(runner, appBinaryName, targetNameSpace,
targetBinaryName, version, frameworkVersion, jarPath,
appNameSpace, appPackageName);
} else if ("true".equals(hostSideOnly)) {
pkg = new HostSideOnlyPackage(appBinaryName, version, frameworkVersion,
jarPath, appPackageName);
} else {
pkg = new TestPackage(runner, appBinaryName, targetNameSpace, targetBinaryName,
version, frameworkVersion, jarPath, appNameSpace, appPackageName);
}
for (int i = 0; i < suiteList.getLength(); i++) {
Node sNode = suiteList.item(i);
if (sNode.getNodeType() == Document.ELEMENT_NODE
&& TAG_TEST_SUITE.equals(sNode.getNodeName())) {
String fullSuiteName = getFullSuiteName(sNode);
if (checkFullMatch(excludedList, fullSuiteName) == false) {
ArrayList<String> excludedCaseList =
getExcludedList(excludedList, fullSuiteName);
TestSuite suite = loadSuite(pkg, sNode, excludedCaseList);
if ((suite.getTestCases().size() != 0) || (suite.getSubSuites().size() != 0)) {
pkg.addTestSuite(suite);
}
} else {
Log.d("suite=" + fullSuiteName + " is fully excluded");
}
}
}
return pkg;
}
/**
* Get string ArrayList from string.
*
* @param str The given string.
* @return The list.
*/
private ArrayList<String> getStrArrayList(String str) {
if ((str == null) || (str.length() == 0)) {
return null;
}
String[] list = str.split(TestPlan.EXCLUDE_SEPARATOR);
if ((list == null) || (list.length == 0)) {
return null;
}
ArrayList<String> result = new ArrayList<String>();
for (String s : list) {
result.add(s);
}
return result;
}
/**
* Get excluded list from a list by offered expectation.
*
* @param excludedList The list containing excluded items.
* @param expectation The expectations.
* @return The excluded list.
*/
private ArrayList<String> getExcludedList(ArrayList<String> excludedList, String expectation) {
if ((excludedList == null) || (excludedList.size() == 0)) {
return null;
}
ArrayList<String> list = new ArrayList<String>();
for (String str : excludedList) {
if (str.startsWith(expectation)) {
list.add(str);
}
}
if (list.size() == 0) {
return null;
} else {
return list;
}
}
/**
* Check if the expectation is fully matched among a list.
*
* @param list The array list.
* @param expectation The expectation.
* @return If there is full match of expectation among the list, return true;
* else, return false.
*/
private boolean checkFullMatch(ArrayList<String> list, String expectation) {
if ((list == null) || (list.size() == 0)) {
return false;
}
for (String str : list) {
if (str.equals(expectation)) {
return true;
}
}
return false;
}
/**
* Load TestSuite via suite node. Package Name is used to output test result.
*
* @param pkg TestPackage
* @param sNode suite node
* @param excludedCaseList The list containing the excluded cases and sub types.
* @return TestSuite
*/
private TestSuite loadSuite(final TestPackage pkg, Node sNode,
ArrayList<String> excludedCaseList) {
NodeList cNodes = sNode.getChildNodes();
String fullSuiteName = getFullSuiteName(sNode);
String suiteName = getStringAttributeValue(sNode, TestPlan.Attribute.NAME);
TestSuite suite = new TestSuite(pkg, suiteName, fullSuiteName);
for (int i = 0; i < cNodes.getLength(); i++) {
Node cNode = cNodes.item(i);
if (cNode.getNodeType() == Document.ELEMENT_NODE) {
if (cNode.getNodeName().equals(TAG_TEST_SUITE)) {
String subSuiteName = getFullSuiteName(cNode);
if (checkFullMatch(excludedCaseList, subSuiteName) == false) {
ArrayList<String> excludedList = getExcludedList(excludedCaseList,
subSuiteName);
TestSuite subSuite = loadSuite(pkg, cNode, excludedList);
if ((subSuite.getTestCases().size() != 0)
|| (subSuite.getSubSuites().size() != 0)) {
suite.addSubSuite(subSuite);
}
} else {
Log.d("suite=" + subSuiteName + " is fully excluded");
}
} else if (cNode.getNodeName().equals(TAG_TEST_CASE)) {
String cName = getStringAttributeValue(cNode, ATTRIBUTE_NAME);
String priority = getStringAttributeValue(cNode, ATTRIBUTE_PRIORITY);
TestCase testCase = new TestCase(suite, cName, priority);
String fullCaseName = fullSuiteName + "." + testCase.getName();
if (checkFullMatch(excludedCaseList, fullCaseName) == false) {
NodeList mNodes = cNode.getChildNodes();
for (int t = 0; t < mNodes.getLength(); t ++) {
Node testNode = mNodes.item(t);
if ((testNode.getNodeType() == Document.ELEMENT_NODE)
&& (testNode.getNodeName().equals(TAG_TEST))) {
String cType = getStringAttributeValue(testNode, ATTRIBUTE_TYPE);
String name = getStringAttributeValue(testNode, ATTRIBUTE_METHOD);
String description = getStringAttributeValue(testNode,
ATTRIBUTE_CONTROLLER);
String knownFailure = getStringAttributeValue(testNode,
ATTRIBUTE_KNOWN_FAILURE);
String fullJarPath =
HostConfig.getInstance().getCaseRepository().getRoot()
+ File.separator + pkg.getJarPath();
Test test = null;
if (pkg.isHostSideOnly()) {
test = new HostSideOnlyTest(testCase, name, cType,
knownFailure,
TestSessionLog.CTS_RESULT_CODE_NOT_EXECUTED);
description = test.getFullName();
} else {
test = new Test(testCase, name, cType,
knownFailure,
TestSessionLog.CTS_RESULT_CODE_NOT_EXECUTED);
}
TestController controller =
genTestControler(fullJarPath, description);
test.setTestController(controller);
if (!checkFullMatch(excludedCaseList, test.getFullName())) {
testCase.addTest(test);
} else {
Log.d("Test=" + test.getFullName() + " is excluded");
}
}
}
if (testCase.getTests().size() != 0) {
suite.addTestCase(testCase);
}
} else {
Log.d("case=" + fullCaseName + " is fully excluded");
}
}
}
}
return suite;
}
/**
* Generate controller according to the description string.
*
* @return The test controller.
*/
public TestController genTestControler(String jarPath, String description) {
if ((jarPath == null) || (jarPath.length() == 0)
|| (description == null) || (description.length() == 0)) {
return null;
}
String packageName = description.substring(0, description.lastIndexOf("."));
String className = description.substring(packageName.length() + 1,
description.lastIndexOf(Test.METHOD_SEPARATOR));
String methodName = description.substring(
description.lastIndexOf(Test.METHOD_SEPARATOR) + 1,
description.length());
return new TestController(jarPath, packageName, className, methodName);
}
/**
* Get the full suite name of the specified suite node. Since the test
* suite can be nested, so the full name of a tests suite is combined
* with his name and his ancestor suite's names.
*
* @param node The specified suite node.
* @return The full name of the given suite node.
*/
private String getFullSuiteName(Node node) {
StringBuilder buf = new StringBuilder();
buf.append(getStringAttributeValue(node, TestPlan.Attribute.NAME));
Node parent = node.getParentNode();
while (parent != null) {
if (parent.getNodeType() == Document.ELEMENT_NODE
&& parent.getNodeName() == TAG_TEST_SUITE) {
buf.insert(0, ".");
buf.insert(0, getStringAttributeValue(parent, TestPlan.Attribute.NAME));
}
parent = parent.getParentNode();
}
return buf.toString();
}
/**
* Create TestPlan which contain a series TestPackages.
*
* @param planName test plan name
* @param packageNames Package names to be added
* @param selectedResult The selected result mapping selected
* package with selected removal result.
*/
public void serialize(String planName,
ArrayList<String> packageNames, HashMap<String, ArrayList<String>> selectedResult)
throws ParserConfigurationException, FileNotFoundException,
TransformerFactoryConfigurationError, TransformerException {
File plan = new File(HostConfig.getInstance().getPlanRepository()
.getPlanPath(planName));
if (plan.exists()) {
Log.e("Plan " + planName + " already exist, please use another name!",
null);
return;
}
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument();
Node root = doc.createElement(TestPlan.Tag.TEST_PLAN);
setAttribute(doc, root, ATTRIBUTE_VERSION, "1.0");
doc.appendChild(root);
// append device configure node
Node deviceConfigNode = doc.createElement(TestPlan.Tag.PLAN_SETTING);
root.appendChild(deviceConfigNode);
// append test packages
for (String pName : packageNames) {
if (selectedResult.containsKey(pName)) {
Node entryNode = doc.createElement(TestPlan.Tag.ENTRY);
setAttribute(doc, entryNode, TestPlan.Attribute.URI, pName);
ArrayList<String> excluded = selectedResult.get(pName);
if ((excluded != null) && (excluded.size() != 0)) {
String excludedList = "";
for (String str : excluded) {
excludedList += str + TestPlan.EXCLUDE_SEPARATOR;
}
setAttribute(doc, entryNode, TestPlan.Attribute.EXCLUDE, excludedList);
}
root.appendChild(entryNode);
}
}
writeToFile(plan, doc);
}
}