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
44  def Parse(self, element):
45    """Populates common suite attributes from given suite xml element.
46
47    Args:
48      element: xml node to parse
49    Raises:
50      ParseError if a required attribute is missing.
51    Returns:
52      parsed test suite or None
53    """
54    parser = None
55    if element.nodeName == InstrumentationParser.TAG_NAME:
56      parser = InstrumentationParser()
57    elif element.nodeName == NativeParser.TAG_NAME:
58      parser = NativeParser()
59    elif element.nodeName == HostParser.TAG_NAME:
60      parser = HostParser()
61    else:
62      logger.Log('Unrecognized tag %s found' % element.nodeName)
63      return None
64    test_suite = parser.Parse(element)
65    return test_suite
66
67  def _ParseCommonAttributes(self, suite_element, test_suite):
68    test_suite.SetName(self._ParseAttribute(suite_element, self._NAME_ATTR,
69                                            True))
70    test_suite.SetBuildPath(self._ParseAttribute(suite_element,
71                                                 self._BUILD_ATTR, True))
72    test_suite.SetContinuous(self._ParseAttribute(suite_element,
73                                                  self._CONTINUOUS_ATTR,
74                                                  False, default_value=False))
75    test_suite.SetSuite(self._ParseAttribute(suite_element, self._SUITE_ATTR, False,
76                                           default_value=None))
77    test_suite.SetDescription(self._ParseAttribute(suite_element,
78                                                   self._DESCRIPTION_ATTR,
79                                                   False,
80                                                   default_value=''))
81    test_suite.SetExtraBuildArgs(self._ParseAttribute(
82        suite_element, self._EXTRA_BUILD_ARGS_ATTR, False, default_value=''))
83    test_suite.SetIsFullMake(self._ParseAttribute(
84        suite_element, self._FULL_MAKE_ATTR, False, default_value=False))
85
86
87  def _ParseAttribute(self, suite_element, attribute_name, mandatory,
88                      default_value=None):
89    if suite_element.hasAttribute(attribute_name):
90      value = suite_element.getAttribute(attribute_name)
91    elif mandatory:
92      error_msg = ('Could not find attribute %s in %s' %
93                   (attribute_name, self.TAG_NAME))
94      raise errors.ParseError(msg=error_msg)
95    else:
96      value = default_value
97    return value
98
99
100class InstrumentationParser(XmlSuiteParser):
101  """Parses instrumentation suite attributes from xml."""
102
103  # for legacy reasons, the xml tag name for java (device) tests is 'test'
104  TAG_NAME = 'test'
105
106  _PKG_ATTR = 'package'
107  _RUNNER_ATTR = 'runner'
108  _CLASS_ATTR = 'class'
109  _TARGET_ATTR = 'coverage_target'
110
111  def Parse(self, suite_element):
112    """Creates suite and populate with data from xml element."""
113    suite = instrumentation_test.InstrumentationTestSuite()
114    XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
115    suite.SetPackageName(self._ParseAttribute(suite_element, self._PKG_ATTR,
116                                              True))
117    suite.SetRunnerName(self._ParseAttribute(
118        suite_element, self._RUNNER_ATTR, False,
119        instrumentation_test.InstrumentationTestSuite.DEFAULT_RUNNER))
120    suite.SetClassName(self._ParseAttribute(suite_element, self._CLASS_ATTR,
121                                            False))
122    suite.SetTargetName(self._ParseAttribute(suite_element, self._TARGET_ATTR,
123                                             False))
124    return suite
125
126
127class NativeParser(XmlSuiteParser):
128  """Parses native suite attributes from xml."""
129
130  TAG_NAME = 'test-native'
131
132  def Parse(self, suite_element):
133    """Creates suite and populate with data from xml element."""
134    suite = native_test.NativeTestSuite()
135    XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
136    return suite
137
138
139class HostParser(XmlSuiteParser):
140  """Parses host suite attributes from xml."""
141
142  TAG_NAME = 'test-host'
143
144  _CLASS_ATTR = 'class'
145  # TODO: consider obsoleting in favor of parsing the Android.mk to find the
146  # jar name
147  _JAR_ATTR = 'jar_name'
148
149  def Parse(self, suite_element):
150    """Creates suite and populate with data from xml element."""
151    suite = host_test.HostTestSuite()
152    XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite)
153    suite.SetClassName(self._ParseAttribute(suite_element, self._CLASS_ATTR,
154                                            True))
155    suite.SetJarName(self._ParseAttribute(suite_element, self._JAR_ATTR, True))
156    return suite
157