blob: 2cdcfa87c054ba6aed7e78a056d0840ab53fddac [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001#!/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
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080018"""Parser for test definition xml files."""
19
The Android Open Source Project52d4c302009-03-03 19:29:09 -080020# Python imports
21import xml.dom.minidom
22import xml.parsers
The Android Open Source Project52d4c302009-03-03 19:29:09 -080023
24# local imports
The Android Open Source Project52d4c302009-03-03 19:29:09 -080025import errors
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080026import logger
27
The Android Open Source Project52d4c302009-03-03 19:29:09 -080028
29class TestDefinitions(object):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080030 """Accessor for a test definitions xml file data.
31
32 Expected format is:
33 <test-definitions>
34 <test
35 name=""
36 package=""
37 [runner=""]
38 [class=""]
39 [coverage_target=""]
40 [build_path=""]
Niko Catania2e990b92009-04-02 16:52:26 -070041 [continuous=false]
42 [description=""]
43 />
44 <test-native
45 name=""
46 build_path=""
47 [continuous=false]
48 [description=""]
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080049 />
50 <test ...
51 </test-definitions>
52
53 TODO: add format checking.
The Android Open Source Project52d4c302009-03-03 19:29:09 -080054 """
55
56 # tag/attribute constants
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080057 _TEST_TAG_NAME = "test"
Niko Catania2e990b92009-04-02 16:52:26 -070058 _TEST_NATIVE_TAG_NAME = "test-native"
The Android Open Source Project52d4c302009-03-03 19:29:09 -080059
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080060 def __init__(self):
The Android Open Source Project52d4c302009-03-03 19:29:09 -080061 # dictionary of test name to tests
62 self._testname_map = {}
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080063
The Android Open Source Project52d4c302009-03-03 19:29:09 -080064 def __iter__(self):
Niko Catania2e990b92009-04-02 16:52:26 -070065 ordered_list = []
66 for k in sorted(self._testname_map):
67 ordered_list.append(self._testname_map[k])
68 return iter(ordered_list)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080069
The Android Open Source Project52d4c302009-03-03 19:29:09 -080070 def Parse(self, file_path):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080071 """Parse the test suite data from from given file path.
72
73 Args:
74 file_path: absolute file path to parse
75 Raises:
76 ParseError if file_path cannot be parsed
77 """
The Android Open Source Project52d4c302009-03-03 19:29:09 -080078 try:
79 doc = xml.dom.minidom.parse(file_path)
80 except IOError:
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080081 logger.Log("test file %s does not exist" % file_path)
The Android Open Source Project52d4c302009-03-03 19:29:09 -080082 raise errors.ParseError
83 except xml.parsers.expat.ExpatError:
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080084 logger.Log("Error Parsing xml file: %s " % file_path)
The Android Open Source Project52d4c302009-03-03 19:29:09 -080085 raise errors.ParseError
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080086 self._ParseDoc(doc)
87
The Android Open Source Project52d4c302009-03-03 19:29:09 -080088 def ParseString(self, xml_string):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080089 """Alternate parse method that accepts a string of the xml data."""
The Android Open Source Project52d4c302009-03-03 19:29:09 -080090 doc = xml.dom.minidom.parseString(xml_string)
91 # TODO: catch exceptions and raise ParseError
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080092 return self._ParseDoc(doc)
The Android Open Source Project52d4c302009-03-03 19:29:09 -080093
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -080094 def _ParseDoc(self, doc):
The Android Open Source Project52d4c302009-03-03 19:29:09 -080095 suite_elements = doc.getElementsByTagName(self._TEST_TAG_NAME)
96
97 for suite_element in suite_elements:
98 test = self._ParseTestSuite(suite_element)
99 self._AddTest(test)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800100
Niko Catania2e990b92009-04-02 16:52:26 -0700101 suite_elements = doc.getElementsByTagName(self._TEST_NATIVE_TAG_NAME)
102
103 for suite_element in suite_elements:
104 test = self._ParseNativeTestSuite(suite_element)
105 self._AddTest(test)
106
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800107 def _ParseTestSuite(self, suite_element):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800108 """Parse the suite element.
109
110 Returns:
111 a TestSuite object, populated with parsed data
112 """
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800113 test = TestSuite(suite_element)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800114 return test
115
Niko Catania2e990b92009-04-02 16:52:26 -0700116 def _ParseNativeTestSuite(self, suite_element):
117 """Parse the native test element.
118
119 Returns:
120 a TestSuite object, populated with parsed data
121 Raises:
122 ParseError if some required attribute is missing.
123 """
124 test = TestSuite(suite_element, native=True)
125 return test
126
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800127 def _AddTest(self, test):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800128 """Adds a test to this TestManifest.
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800129
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800130 If a test already exists with the same name, it overrides it.
131
132 Args:
133 test: TestSuite to add
134 """
135 self._testname_map[test.GetName()] = test
136
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800137 def GetTests(self):
138 return self._testname_map.values()
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800139
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800140 def GetContinuousTests(self):
141 con_tests = []
142 for test in self.GetTests():
143 if test.IsContinuous():
144 con_tests.append(test)
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800145 return con_tests
146
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800147 def GetTest(self, name):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800148 return self._testname_map.get(name, None)
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800149
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800150class TestSuite(object):
151 """Represents one test suite definition parsed from xml."""
152
153 _NAME_ATTR = "name"
154 _PKG_ATTR = "package"
155 _RUNNER_ATTR = "runner"
156 _CLASS_ATTR = "class"
157 _TARGET_ATTR = "coverage_target"
158 _BUILD_ATTR = "build_path"
159 _CONTINUOUS_ATTR = "continuous"
Niko Catania2e990b92009-04-02 16:52:26 -0700160 _DESCRIPTION_ATTR = "description"
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700161 _EXTRA_MAKE_ARGS_ATTR = "extra_make_args"
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800162
163 _DEFAULT_RUNNER = "android.test.InstrumentationTestRunner"
164
Niko Catania2e990b92009-04-02 16:52:26 -0700165 def __init__(self, suite_element, native=False):
166 """Populates this instance's data from given suite xml element.
167 Raises:
168 ParseError if some required attribute is missing.
169 """
170 self._native = native
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800171 self._name = suite_element.getAttribute(self._NAME_ATTR)
Niko Catania2e990b92009-04-02 16:52:26 -0700172
173 if self._native:
174 # For native runs, _BUILD_ATTR is required
175 if not suite_element.hasAttribute(self._BUILD_ATTR):
176 logger.Log("Error: %s is missing required build_path attribute" %
177 self._name)
178 raise errors.ParseError
179 else:
180 self._package = suite_element.getAttribute(self._PKG_ATTR)
181
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800182 if suite_element.hasAttribute(self._RUNNER_ATTR):
183 self._runner = suite_element.getAttribute(self._RUNNER_ATTR)
184 else:
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800185 self._runner = self._DEFAULT_RUNNER
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800186 if suite_element.hasAttribute(self._CLASS_ATTR):
187 self._class = suite_element.getAttribute(self._CLASS_ATTR)
188 else:
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800189 self._class = None
190 if suite_element.hasAttribute(self._TARGET_ATTR):
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800191 self._target_name = suite_element.getAttribute(self._TARGET_ATTR)
192 else:
193 self._target_name = None
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800194 if suite_element.hasAttribute(self._BUILD_ATTR):
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800195 self._build_path = suite_element.getAttribute(self._BUILD_ATTR)
196 else:
197 self._build_path = None
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800198 if suite_element.hasAttribute(self._CONTINUOUS_ATTR):
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800199 self._continuous = suite_element.getAttribute(self._CONTINUOUS_ATTR)
200 else:
201 self._continuous = False
Niko Catania2e990b92009-04-02 16:52:26 -0700202 if suite_element.hasAttribute(self._DESCRIPTION_ATTR):
203 self._description = suite_element.getAttribute(self._DESCRIPTION_ATTR)
204 else:
205 self._description = ""
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700206 if suite_element.hasAttribute(self._EXTRA_MAKE_ARGS_ATTR):
207 self._extra_make_args = suite_element.getAttribute(
208 self._EXTRA_MAKE_ARGS_ATTR)
209 else:
210 self._extra_make_args = ""
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800211
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800212 def GetName(self):
213 return self._name
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800214
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800215 def GetPackageName(self):
216 return self._package
217
218 def GetRunnerName(self):
219 return self._runner
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800220
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800221 def GetClassName(self):
222 return self._class
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800223
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800224 def GetTargetName(self):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800225 """Retrieve module that this test is targeting.
226
227 Used for generating code coverage metrics.
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800228 """
229 return self._target_name
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800230
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800231 def GetBuildPath(self):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800232 """Returns the build path of this test, relative to source tree root."""
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800233 return self._build_path
234
235 def IsContinuous(self):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800236 """Returns true if test is flagged as being part of the continuous tests"""
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800237 return self._continuous
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800238
Niko Catania2e990b92009-04-02 16:52:26 -0700239 def IsNative(self):
240 """Returns true if test is a native one."""
241 return self._native
242
243 def GetDescription(self):
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700244 """Returns a description if available, an empty string otherwise."""
Niko Catania2e990b92009-04-02 16:52:26 -0700245 return self._description
246
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700247 def GetExtraMakeArgs(self):
248 """Returns the extra make args if available, an empty string otherwise."""
249 return self._extra_make_args
250
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800251def Parse(file_path):
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800252 """Parses out a TestDefinitions from given path to xml file.
253
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800254 Args:
255 file_path: string absolute file path
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -0800256 Returns:
257 a TestDefinitions object containing data parsed from file_path
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800258 Raises:
259 ParseError if xml format is not recognized
260 """
261 tests_result = TestDefinitions()
262 tests_result.Parse(file_path)
263 return tests_result