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 21 import xml.dom.minidom 22 import xml.parsers 23 24 # local imports 25 import errors 26 import logger 27 import xml_suite_helper 28 29 30 class 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 120 def 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