Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(580)

Side by Side Diff: build/android/pylib/host_driven/setup.py

Issue 19537004: [Android] Converts host driven tests to common test_dispatcher (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@sharding_refactoring
Patch Set: Converts --official-build into a boolean flag Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Runs the Python tests (relies on using the Java test runner).""" 5 """Setup for instrumentation host-driven tests."""
6 6
7 import logging 7 import logging
8 import os 8 import os
9 import sys 9 import sys
10 import types 10 import types
11 11
12 from pylib import android_commands 12 import test_case
13 from pylib.base import base_test_result 13 import test_info_collection
14 from pylib.instrumentation import test_options 14 import test_runner
15 from pylib.instrumentation import test_package
16 from pylib.instrumentation import test_runner
17 from pylib.utils import report_results
18
19 import python_test_base
20 from python_test_sharder import PythonTestSharder
21 from test_info_collection import TestInfoCollection
22 15
23 16
24 def _GetPythonFiles(root, files): 17 def _GetPythonFiles(root, files):
25 """Returns all files from |files| that end in 'Test.py'. 18 """Returns all files from |files| that end in 'Test.py'.
26 19
27 Args: 20 Args:
28 root: A directory name with python files. 21 root: A directory name with python files.
29 files: A list of file names. 22 files: A list of file names.
30 23
31 Returns: 24 Returns:
32 A list with all Python driven test file paths. 25 A list with all python files that match the testing naming scheme.
33 """ 26 """
34 return [os.path.join(root, f) for f in files if f.endswith('Test.py')] 27 return [os.path.join(root, f) for f in files if f.endswith('Test.py')]
35 28
36 29
37 def _InferImportNameFromFile(python_file): 30 def _InferImportNameFromFile(python_file):
38 """Given a file, infer the import name for that file. 31 """Given a file, infer the import name for that file.
39 32
40 Example: /usr/foo/bar/baz.py -> baz. 33 Example: /usr/foo/bar/baz.py -> baz.
41 34
42 Args: 35 Args:
43 python_file: path to the Python file, ostensibly to import later. 36 python_file: Path to the Python file, ostensibly to import later.
44 37
45 Returns: 38 Returns:
46 The module name for the given file. 39 The module name for the given file.
47 """ 40 """
48 return os.path.splitext(os.path.basename(python_file))[0] 41 return os.path.splitext(os.path.basename(python_file))[0]
49 42
50 43
51 def DispatchPythonTests(options): 44 def _GetTestModules(host_driven_test_root, is_official_build):
52 """Dispatches the Python tests. If there are multiple devices, use sharding. 45 """Retrieve a list of python modules that match the testing naming scheme.
53 46
54 Args: 47 Walks the location of host-driven tests, imports them, and provides the list
55 options: command line options.
56
57 Returns:
58 A tuple of (base_test_result.TestRunResults object, exit code)
59
60 Raises:
61 Exception: If there are no attached devices.
62 """
63
64 attached_devices = android_commands.GetAttachedDevices()
65 if not attached_devices:
66 raise Exception('You have no devices attached or visible!')
67 if options.test_device:
68 attached_devices = [options.test_device]
69
70 test_collection = TestInfoCollection()
71 all_tests = _GetAllTests(options.python_test_root, options.official_build)
72 test_collection.AddTests(all_tests)
73 test_names = [t.qualified_name for t in all_tests]
74 logging.debug('All available tests: ' + str(test_names))
75
76 available_tests = test_collection.GetAvailableTests(
77 options.annotations, options.exclude_annotations, options.test_filter)
78
79 if not available_tests:
80 logging.warning('No Python tests to run with current args.')
81 return (base_test_result.TestRunResults(), 0)
82
83 test_names = [t.qualified_name for t in available_tests]
84 logging.debug('Final list of tests to run: ' + str(test_names))
85
86 # Copy files to each device before running any tests.
87 for device_id in attached_devices:
88 logging.debug('Pushing files to device %s', device_id)
89 test_pkg = test_package.TestPackage(options.test_apk_path,
90 options.test_apk_jar_path)
91 instrumentation_options = test_options.InstrumentationOptions(
92 options.build_type,
93 options.tool,
94 options.cleanup_test_files,
95 options.push_deps,
96 options.annotations,
97 options.exclude_annotations,
98 options.test_filter,
99 options.test_data,
100 options.save_perf_json,
101 options.screenshot_failures,
102 options.disable_assertions,
103 options.wait_for_debugger,
104 options.test_apk,
105 options.test_apk_path,
106 options.test_apk_jar_path)
107 test_files_copier = test_runner.TestRunner(instrumentation_options,
108 device_id, 0, test_pkg, [])
109 test_files_copier.InstallTestPackage()
110 if options.push_deps:
111 logging.info('Pushing data deps to device.')
112 test_files_copier.PushDataDeps()
113 else:
114 logging.warning('Skipping pushing data deps to device.')
115
116 # Actually run the tests.
117 if len(attached_devices) > 1 and options.wait_for_debugger:
118 logging.warning('Debugger can not be sharded, '
119 'using first available device')
120 attached_devices = attached_devices[:1]
121 logging.debug('Running Python tests')
122 sharder = PythonTestSharder(attached_devices, available_tests, options)
123 test_results = sharder.RunShardedTests()
124
125 if not test_results.DidRunPass():
126 return (test_results, 1)
127
128 return (test_results, 0)
129
130
131 def _GetTestModules(python_test_root, is_official_build):
132 """Retrieve a sorted list of pythonDrivenTests.
133
134 Walks the location of pythonDrivenTests, imports them, and provides the list
135 of imported modules to the caller. 48 of imported modules to the caller.
136 49
137 Args: 50 Args:
138 python_test_root: the path to walk, looking for pythonDrivenTests 51 host_driven_test_root: The path to walk, looking for the
139 is_official_build: whether to run only those tests marked 'official' 52 pythonDrivenTests or host_driven_tests directory
53 is_official_build: Whether to run only those tests marked 'official'
140 54
141 Returns: 55 Returns:
142 A list of Python modules which may have zero or more tests. 56 A list of python modules under |host_driven_test_root| which match the
57 testing naming scheme. Each module should define one or more classes that
58 derive from HostDrivenTestCase.
143 """ 59 """
144 # By default run all python tests under pythonDrivenTests. 60 # By default run all host-driven tests under pythonDrivenTests or
145 python_test_file_list = [] 61 # host_driven_tests.
146 for root, _, files in os.walk(python_test_root): 62 host_driven_test_file_list = []
63 for root, _, files in os.walk(host_driven_test_root):
147 if (root.endswith('host_driven_tests') or 64 if (root.endswith('host_driven_tests') or
148 root.endswith('pythonDrivenTests') or 65 root.endswith('pythonDrivenTests') or
149 (is_official_build and root.endswith('pythonDrivenTests/official'))): 66 (is_official_build and (root.endswith('pythonDrivenTests/official') or
150 python_test_file_list += _GetPythonFiles(root, files) 67 root.endswith('host_driven_tests/official')))):
151 python_test_file_list.sort() 68 host_driven_test_file_list += _GetPythonFiles(root, files)
69 host_driven_test_file_list.sort()
152 70
153 test_module_list = [_GetModuleFromFile(test_file) 71 test_module_list = [_GetModuleFromFile(test_file)
154 for test_file in python_test_file_list] 72 for test_file in host_driven_test_file_list]
155 return test_module_list 73 return test_module_list
156 74
157 75
158 def _GetModuleFromFile(python_file): 76 def _GetModuleFromFile(python_file):
159 """Gets the module associated with a file by importing it. 77 """Gets the python module associated with a file by importing it.
160 78
161 Args: 79 Args:
162 python_file: file to import 80 python_file: File to import.
163 81
164 Returns: 82 Returns:
165 The module object. 83 The module object.
166 """ 84 """
167 sys.path.append(os.path.dirname(python_file)) 85 sys.path.append(os.path.dirname(python_file))
168 import_name = _InferImportNameFromFile(python_file) 86 import_name = _InferImportNameFromFile(python_file)
169 return __import__(import_name) 87 return __import__(import_name)
170 88
171 89
172 def _GetTestsFromClass(test_class): 90 def _GetTestsFromClass(test_case_class, **kwargs):
173 """Create a list of test objects for each test method on this class. 91 """Returns one test object for each test method in |test_case_class|.
174 92
175 Test methods are methods on the class which begin with 'test'. 93 Test methods are methods on the class which begin with 'test'.
176 94
177 Args: 95 Args:
178 test_class: class object which contains zero or more test methods. 96 test_case_class: Class derived from HostDrivenTestCase which contains zero
97 or more test methods.
98 kwargs: Keyword args to pass into the constructor of test cases.
179 99
180 Returns: 100 Returns:
181 A list of test objects, each of which is bound to one test. 101 A list of test case objects, each initialized for a particular test method.
182 """ 102 """
183 test_names = [m for m in dir(test_class) 103 test_names = [m for m in dir(test_case_class)
184 if _IsTestMethod(m, test_class)] 104 if _IsTestMethod(m, test_case_class)]
185 return map(test_class, test_names) 105 return [test_case_class(name, **kwargs) for name in test_names]
186 106
187 107
188 def _GetTestClassesFromModule(test_module): 108 def _GetTestsFromModule(test_module, **kwargs):
109 """Gets a list of test objects from |test_module|.
110
111 Args:
112 test_module: Module from which to get the set of test methods.
113 kwargs: Keyword args to pass into the constructor of test cases.
114
115 Returns:
116 A list of test case objects each initialized for a particular test method
117 defined in |test_module|.
118 """
119
189 tests = [] 120 tests = []
190 for name in dir(test_module): 121 for name in dir(test_module):
191 attr = getattr(test_module, name) 122 attr = getattr(test_module, name)
192 if _IsTestClass(attr): 123 if _IsTestCaseClass(attr):
193 tests.extend(_GetTestsFromClass(attr)) 124 tests.extend(_GetTestsFromClass(attr, **kwargs))
194 return tests 125 return tests
195 126
196 127
197 def _IsTestClass(test_class): 128 def _IsTestCaseClass(test_class):
198 return (type(test_class) is types.TypeType and 129 return (type(test_class) is types.TypeType and
199 issubclass(test_class, python_test_base.PythonTestBase) and 130 issubclass(test_class, test_case.HostDrivenTestCase) and
200 test_class is not python_test_base.PythonTestBase) 131 test_class is not test_case.HostDrivenTestCase)
201 132
202 133
203 def _IsTestMethod(attrname, test_case_class): 134 def _IsTestMethod(attrname, test_case_class):
204 """Checks whether this is a valid test method. 135 """Checks whether this is a valid test method.
205 136
206 Args: 137 Args:
207 attrname: the method name. 138 attrname: The method name.
208 test_case_class: the test case class. 139 test_case_class: The test case class.
209 140
210 Returns: 141 Returns:
211 True if test_case_class.'attrname' is callable and it starts with 'test'; 142 True if test_case_class.'attrname' is callable and it starts with 'test';
212 False otherwise. 143 False otherwise.
213 """ 144 """
214 attr = getattr(test_case_class, attrname) 145 attr = getattr(test_case_class, attrname)
215 return callable(attr) and attrname.startswith('test') 146 return callable(attr) and attrname.startswith('test')
216 147
217 148
218 def _GetAllTests(test_root, is_official_build): 149 def _GetAllTests(test_root, is_official_build, **kwargs):
219 """Retrieve a list of Python test modules and their respective methods. 150 """Retrieve a list of host-driven tests defined under |test_root|.
220 151
221 Args: 152 Args:
222 test_root: path which contains Python-driven test files 153 test_root: Path which contains host-driven test files.
223 is_official_build: whether this is an official build 154 is_official_build: Whether this is an official build.
155 kwargs: Keyword args to pass into the constructor of test cases.
224 156
225 Returns: 157 Returns:
226 List of test case objects for all available test methods. 158 List of test case objects, one for each available test method.
227 """ 159 """
228 if not test_root: 160 if not test_root:
229 return [] 161 return []
230 all_tests = [] 162 all_tests = []
231 test_module_list = _GetTestModules(test_root, is_official_build) 163 test_module_list = _GetTestModules(test_root, is_official_build)
232 for module in test_module_list: 164 for module in test_module_list:
233 all_tests.extend(_GetTestClassesFromModule(module)) 165 all_tests.extend(_GetTestsFromModule(module, **kwargs))
234 return all_tests 166 return all_tests
167
168
169 def InstrumentationSetup(host_driven_test_root, official_build,
170 instrumentation_options):
171 """Creates a list of host-driven instrumentation tests and a runner factory.
172
173 Args:
174 host_driven_test_root: Directory where the host-driven tests are.
175 official_build: True if this is an official build.
176 instrumentation_options: An InstrumentationOptions object.
177
178 Returns:
179 A tuple of (TestRunnerFactory, tests).
180 """
181
182 test_collection = test_info_collection.TestInfoCollection()
183 all_tests = _GetAllTests(
184 host_driven_test_root, official_build,
185 instrumentation_options=instrumentation_options)
186 test_collection.AddTests(all_tests)
187
188 available_tests = test_collection.GetAvailableTests(
189 instrumentation_options.annotations,
190 instrumentation_options.exclude_annotations,
191 instrumentation_options.test_filter)
192 logging.debug('All available tests: ' + str(
193 [t.tagged_name for t in available_tests]))
194
195 def TestRunnerFactory(device, shard_index):
196 return test_runner.HostDrivenTestRunner(
197 device, shard_index,
198 instrumentation_options.tool,
199 instrumentation_options.build_type,
200 instrumentation_options.push_deps,
201 instrumentation_options.cleanup_test_files)
202
203 return (TestRunnerFactory, available_tests)
OLDNEW
« no previous file with comments | « build/android/pylib/host_driven/run_python_tests.py ('k') | build/android/pylib/host_driven/test_case.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698