1#!/usr/bin/python2.4
2#
3#
4# Copyright 2009, The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18"""Utility to parse suite info from xml."""
19
20# Python imports
21import xml.dom.minidom
22import xml.parsers
23
24# local imports
25import errors
26import logger
27import host_test
28import instrumentation_test
29import native_test
30
31
32class XmlSuiteParser(object):
33  """Parses XML attributes common to all TestSuite's."""
34
35  # common attributes
36  _NAME_ATTR = 'name'
37  _BUILD_ATTR = 'build_path'
38  _CONTINUOUS_ATTR = 'continuous'
39  _SUITE_ATTR = 'suite'
40  _DESCRIPTION_ATTR = 'description'
41  _EXTRA_BUILD_ARGS_ATTR = 'extra_build_args'
42  _FULL_MAKE_ATTR = 'full_make'
43  _GRANTED_PERMISSIONS_ATTR = 'granted_permissions'
44
45  def Parse(self, element):
46    """Populates common suite attributes from given suite xml element.
47
48    Args:
49      element: xml node to parse
50    Raises:
51      ParseError if a required attribute is missing.
52    Returns:
53      parsed test suite or None
54    """
55    parser = None
56    if element.nodeName == InstrumentationParser.TAG_NAME:
57      parser = InstrumentationParser()
58    elif element.nodeName == NativeParser.TAG_NAME:
59      parser = NativeParser()
60    elif element.nodeName == HostParser.TAG_NAME:
61      parser = HostParser()
62    else:
63      logger.Log('Unrecognized tag %s found' % element.nodeName)
64      return None
65    test_suite = parser.Parse(element)
66    return test_suite
67
68  def _ParseCommonAttributes(self, suite_element, test_suite):
69    test_suite.SetName(self._ParseAttribute(suite_element, self._NAME_ATTR,
70                                            True))
71    test_suite.SetBuildPath(self._ParseAttribute(suite_element,
72                                                 self._BUILD_ATTR, True))
73    test_suite.SetContinuous(self._ParseAttribute(suite_element,
74                                                  self._CONTINUOUS_ATTR,
75                                                  False, default_value=False))
76    test_suite.SetIsGrantedPermissions(self._ParseAttribute(suite_element,
77                                                  self._GRANTED_PERMISSIONS_ATTR,
78                                                  False, default_value=True))
79    test_suite.SetSuite(self._ParseAttribute(suite_element, self._SUITE_ATTR, False,
80                                           default_value=None))
81    test_suite.SetDescription(self._ParseAttribute(suite_element,
82                                                   self._DESCRIPTION_ATTR,
83                                                   False,
84                                                   default_value=''))
85    test_suite.SetExtraBuildArgs(self._ParseAttribute(
86        suite_element, self._EXTRA_BUILD_ARGS_ATTR, False, default_value=''))
87    test_suite.SetIsFullMake(self._ParseAttribute(
88        suite_element, self._FULL_MAKE_ATTR, False, default_value=False))
89
90
91  def _ParseAttribute(self, suite_element, attribute_name, mandatory,
92                      default_value=None):
93    if suite_element.hasAttribute(attribute_name):
94      value = suite_element.getAttribute(attribute_name)
95      if default_value in (True, False):
96        value = value.lower() == "true"
97    elif mandatory:
98      error_msg = ('Could not find attribute %s in %s' %
99                   (attribute_name, self.TAG_NAME))
100      raise errors.ParseError(msg=error_msg)
101    else:
102      value = default_value
103    return value
104
105
106class InstrumentationParser(XmlSuiteParser):
107  """Parses instrumentation suite attributes from xml."""
108
109  # for legacy reasons, the xml tag name for java (device) tests is 'test'
110  TAG_NAME = 'test'
111
112  _PKG_ATTR = 'package'
113  _RUNNER_ATTR = 'runner'
114  _CLASS_ATTR = 'class'
115  _TARGET_ATTR = 'coverage_target'
116
117  def Parse(self, suite_element):
118    """Creates suite and populate with data from xml element."""
119    suite = instrumentation_test.InstrumentationTestSuite()
120    XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
121    suite.SetPackageName(self._ParseAttribute(suite_element, self._PKG_ATTR,
122                                              True))
123    suite.SetRunnerName(self._ParseAttribute(
124        suite_element, self._RUNNER_ATTR, False,
125        instrumentation_test.InstrumentationTestSuite.DEFAULT_RUNNER))
126    suite.SetClassName(self._ParseAttribute(suite_element, self._CLASS_ATTR,
127                                            False))
128    suite.SetTargetName(self._ParseAttribute(suite_element, self._TARGET_ATTR,
129                                             False))
130    return suite
131
132
133class NativeParser(XmlSuiteParser):
134  """Parses native suite attributes from xml."""
135
136  TAG_NAME = 'test-native'
137
138  def Parse(self, suite_element):
139    """Creates suite and populate with data from xml element."""
140    suite = native_test.NativeTestSuite()
141    XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
142    return suite
143
144
145class HostParser(XmlSuiteParser):
146  """Parses host suite attributes from xml."""
147
148  TAG_NAME = 'test-host'
149
150  _CLASS_ATTR = 'class'
151  # TODO: consider obsoleting in favor of parsing the Android.mk to find the
152  # jar name
153  _JAR_ATTR = 'jar_name'
154
155  def Parse(self, suite_element):
156    """Creates suite and populate with data from xml element."""
157    suite = host_test.HostTestSuite()
158    XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
159    suite.SetClassName(self._ParseAttribute(suite_element, self._CLASS_ATTR,
160                                            True))
161    suite.SetJarName(self._ParseAttribute(suite_element, self._JAR_ATTR, True))
162    return suite
163