1#!/usr/bin/python2.4
2#
3#
4# Copyright 2008, 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"""Parser for test definition xml files."""
19
20# Python imports
21import xml.dom.minidom
22import xml.parsers
23
24# local imports
25import errors
26import logger
27import xml_suite_helper
28
29
30class TestDefinitions(object):
31  """Accessor for a test definitions xml file data.
32
33  See test_defs.xsd for expected format.
34  """
35
36  def __init__(self):
37    # dictionary of test name to tests
38    self._testname_map = {}
39
40  def __iter__(self):
41    ordered_list = []
42    for k in sorted(self._testname_map):
43      ordered_list.append(self._testname_map[k])
44    return iter(ordered_list)
45
46  def Parse(self, file_path):
47    """Parse the test suite data from from given file path.
48
49    Args:
50      file_path: absolute file path to parse
51    Raises:
52      ParseError if file_path cannot be parsed
53    """
54    try:
55      doc = xml.dom.minidom.parse(file_path)
56      self._ParseDoc(doc)
57    except IOError:
58      logger.Log("test file %s does not exist" % file_path)
59      raise errors.ParseError
60    except xml.parsers.expat.ExpatError:
61      logger.Log("Error Parsing xml file: %s " %  file_path)
62      raise errors.ParseError
63    except errors.ParseError, e:
64      logger.Log("Error Parsing xml file: %s Reason: %s" %  (file_path, e.msg))
65      raise e
66
67  def ParseString(self, xml_string):
68    """Alternate parse method that accepts a string of the xml data."""
69    doc = xml.dom.minidom.parseString(xml_string)
70    # TODO: catch exceptions and raise ParseError
71    return self._ParseDoc(doc)
72
73  def _ParseDoc(self, doc):
74    root_element = self._GetRootElement(doc)
75    suite_parser = xml_suite_helper.XmlSuiteParser()
76    for element in root_element.childNodes:
77      if element.nodeType != xml.dom.Node.ELEMENT_NODE:
78        continue
79      test_suite = suite_parser.Parse(element)
80      if test_suite:
81        self._AddTest(test_suite)
82
83  def _GetRootElement(self, doc):
84    root_elements = doc.getElementsByTagName("test-definitions")
85    if len(root_elements) != 1:
86      error_msg = "expected 1 and only one test-definitions tag"
87      raise errors.ParseError(msg=error_msg)
88    return root_elements[0]
89
90  def _AddTest(self, test):
91    """Adds a test to this TestManifest.
92
93    If a test already exists with the same name, it overrides it.
94
95    Args:
96      test: TestSuite to add
97    """
98    if self.GetTest(test.GetName()) is not None:
99      logger.SilentLog("Overriding test definition %s" % test.GetName())
100    self._testname_map[test.GetName()] = test
101
102  def GetTests(self):
103    return self._testname_map.values()
104
105  def GetContinuousTests(self):
106    con_tests = []
107    for test in self.GetTests():
108      if test.IsContinuous():
109        con_tests.append(test)
110    return con_tests
111
112  def GetTestsInSuite(self, suite):
113    """Return list of tests in given suite."""
114    return [t for t in self.GetTests() if t.GetSuite() == suite]
115
116  def GetTest(self, name):
117    return self._testname_map.get(name, None)
118
119
120def Parse(file_path):
121  """Parses out a TestDefinitions from given path to xml file.
122
123  Args:
124    file_path: string absolute file path
125  Returns:
126    a TestDefinitions object containing data parsed from file_path
127  Raises:
128    ParseError if xml format is not recognized
129  """
130  tests_result = TestDefinitions()
131  tests_result.Parse(file_path)
132  return tests_result
133