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

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: Attempts to clean up comments in host_driven/setup.py Created 7 years, 5 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 from instrumentation_test_case import InstrumentationHostDrivenTestCase
13 from pylib.base import base_test_result 13 import test_info_collection
14 from pylib.instrumentation import test_package 14 import test_runner
15 from pylib.instrumentation import test_runner
16 from pylib.utils import report_results
17
18 import python_test_base
19 from python_test_sharder import PythonTestSharder
20 from test_info_collection import TestInfoCollection
21 15
22 16
23 def _GetPythonFiles(root, files): 17 def _GetPythonFiles(root, files):
24 """Returns all files from |files| that end in 'Test.py'. 18 """Returns all files from |files| that end in 'Test.py'.
25 19
26 Args: 20 Args:
27 root: A directory name with python files. 21 root: A directory name with python files.
28 files: A list of file names. 22 files: A list of file names.
29 23
30 Returns: 24 Returns:
31 A list with all Python driven test file paths. 25 A list with all python files that match the testing naming scheme.
32 """ 26 """
33 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')]
34 28
35 29
36 def _InferImportNameFromFile(python_file): 30 def _InferImportNameFromFile(python_file):
37 """Given a file, infer the import name for that file. 31 """Given a file, infer the import name for that file.
38 32
39 Example: /usr/foo/bar/baz.py -> baz. 33 Example: /usr/foo/bar/baz.py -> baz.
40 34
41 Args: 35 Args:
42 python_file: path to the Python file, ostensibly to import later. 36 python_file: Path to the Python file, ostensibly to import later.
43 37
44 Returns: 38 Returns:
45 The module name for the given file. 39 The module name for the given file.
46 """ 40 """
47 return os.path.splitext(os.path.basename(python_file))[0] 41 return os.path.splitext(os.path.basename(python_file))[0]
48 42
49 43
50 def DispatchPythonTests(options): 44 def _GetTestModules(host_driven_test_root, is_official_build):
51 """Dispatches the Python tests. If there are multiple devices, use sharding. 45 """Retrieve a list of python modules that match the testing naming scheme.
52 46
53 Args: 47 Walks the location of host-driven tests, imports them, and provides the list
54 options: command line options.
55
56 Returns:
57 A tuple of (base_test_result.TestRunResults object, exit code)
58
59 Raises:
60 Exception: If there are no attached devices.
61 """
62
63 attached_devices = android_commands.GetAttachedDevices()
64 if not attached_devices:
65 raise Exception('You have no devices attached or visible!')
66 if options.test_device:
67 attached_devices = [options.test_device]
68
69 test_collection = TestInfoCollection()
70 all_tests = _GetAllTests(options.python_test_root, options.official_build)
71 test_collection.AddTests(all_tests)
72 test_names = [t.qualified_name for t in all_tests]
73 logging.debug('All available tests: ' + str(test_names))
74
75 available_tests = test_collection.GetAvailableTests(
76 options.annotations, options.exclude_annotations, options.test_filter)
77
78 if not available_tests:
79 logging.warning('No Python tests to run with current args.')
80 return (base_test_result.TestRunResults(), 0)
81
82 test_names = [t.qualified_name for t in available_tests]
83 logging.debug('Final list of tests to run: ' + str(test_names))
84
85 # Copy files to each device before running any tests.
86 for device_id in attached_devices:
87 logging.debug('Pushing files to device %s', device_id)
88 test_pkg = test_package.TestPackage(options.test_apk_path,
89 options.test_apk_jar_path)
90 test_files_copier = test_runner.TestRunner(
91 options.build_type, options.test_data, options.install_apk,
92 options.save_perf_json, options.screenshot_failures, options.tool,
93 options.wait_for_debugger, options.disable_assertions,
94 options.push_deps, options.cleanup_test_files, device_id, 0, test_pkg,
95 [])
96 test_files_copier.InstallTestPackage()
97 if options.push_deps:
98 logging.info('Pushing data deps to device.')
99 test_files_copier.PushDataDeps()
100 else:
101 logging.warning('Skipping pushing data deps to device.')
102
103 # Actually run the tests.
104 if len(attached_devices) > 1 and options.wait_for_debugger:
105 logging.warning('Debugger can not be sharded, '
106 'using first available device')
107 attached_devices = attached_devices[:1]
108 logging.debug('Running Python tests')
109 sharder = PythonTestSharder(attached_devices, available_tests, options)
110 test_results = sharder.RunShardedTests()
111
112 if not test_results.DidRunPass():
113 return (test_results, 1)
114
115 return (test_results, 0)
116
117
118 def _GetTestModules(python_test_root, is_official_build):
119 """Retrieve a sorted list of pythonDrivenTests.
120
121 Walks the location of pythonDrivenTests, imports them, and provides the list
122 of imported modules to the caller. 48 of imported modules to the caller.
123 49
124 Args: 50 Args:
125 python_test_root: the path to walk, looking for pythonDrivenTests 51 host_driven_test_root: The path to walk, looking for the
126 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'
127 54
128 Returns: 55 Returns:
129 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.
130 """ 59 """
131 # By default run all python tests under pythonDrivenTests. 60 # By default run all host-driven tests under pythonDrivenTests or
132 python_test_file_list = [] 61 # host_driven_tests.
133 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):
134 if (root.endswith('host_driven_tests') or 64 if (root.endswith('host_driven_tests') or
135 root.endswith('pythonDrivenTests') or 65 root.endswith('pythonDrivenTests') or
136 (is_official_build and root.endswith('pythonDrivenTests/official'))): 66 (is_official_build and root.endswith('pythonDrivenTests/official'))):
137 python_test_file_list += _GetPythonFiles(root, files) 67 host_driven_test_file_list += _GetPythonFiles(root, files)
138 python_test_file_list.sort() 68 host_driven_test_file_list.sort()
139 69
140 test_module_list = [_GetModuleFromFile(test_file) 70 test_module_list = [_GetModuleFromFile(test_file)
141 for test_file in python_test_file_list] 71 for test_file in host_driven_test_file_list]
142 return test_module_list 72 return test_module_list
143 73
144 74
145 def _GetModuleFromFile(python_file): 75 def _GetModuleFromFile(python_file):
146 """Gets the module associated with a file by importing it. 76 """Gets the python module associated with a file by importing it.
147 77
148 Args: 78 Args:
149 python_file: file to import 79 python_file: File to import.
150 80
151 Returns: 81 Returns:
152 The module object. 82 The module object.
153 """ 83 """
154 sys.path.append(os.path.dirname(python_file)) 84 sys.path.append(os.path.dirname(python_file))
155 import_name = _InferImportNameFromFile(python_file) 85 import_name = _InferImportNameFromFile(python_file)
156 return __import__(import_name) 86 return __import__(import_name)
157 87
158 88
159 def _GetTestsFromClass(test_class): 89 def _GetTestsFromClass(test_case_class, extra_args):
160 """Create a list of test objects for each test method on this class. 90 """Returns one test object for each test method in |test_case_class|.
161 91
162 Test methods are methods on the class which begin with 'test'. 92 Test methods are methods on the class which begin with 'test'.
163 93
164 Args: 94 Args:
165 test_class: class object which contains zero or more test methods. 95 test_case_class: Class derived from HostDrivenTestCase which contains zero
96 or more test methods.
97 extra_args: List of extra args to pass into the constructor of the test case
98 class to create each test object.
166 99
167 Returns: 100 Returns:
168 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.
169 """ 102 """
170 test_names = [m for m in dir(test_class) 103 test_names = [m for m in dir(test_case_class)
171 if _IsTestMethod(m, test_class)] 104 if _IsTestMethod(m, test_case_class)]
172 return map(test_class, test_names) 105 return [test_case_class(name, *extra_args) for name in test_names]
173 106
174 107
175 def _GetTestClassesFromModule(test_module): 108 def _GetTestsFromModule(test_module, extra_args):
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 extra_args: List of extra args to pass into the constructor of the
114 test cases.
115
116 Returns:
117 A list of test case objects each initialized for a particular test method
118 defined in |test_module|.
119 """
120
176 tests = [] 121 tests = []
177 for name in dir(test_module): 122 for name in dir(test_module):
178 attr = getattr(test_module, name) 123 attr = getattr(test_module, name)
179 if _IsTestClass(attr): 124 if _IsTestCaseClass(attr):
180 tests.extend(_GetTestsFromClass(attr)) 125 tests.extend(_GetTestsFromClass(attr, extra_args))
181 return tests 126 return tests
182 127
183 128
184 def _IsTestClass(test_class): 129 def _IsTestCaseClass(test_class, base_class=InstrumentationHostDrivenTestCase):
185 return (type(test_class) is types.TypeType and 130 return (type(test_class) is types.TypeType and
186 issubclass(test_class, python_test_base.PythonTestBase) and 131 issubclass(test_class, base_class) and
187 test_class is not python_test_base.PythonTestBase) 132 test_class is not base_class)
188 133
189 134
190 def _IsTestMethod(attrname, test_case_class): 135 def _IsTestMethod(attrname, test_case_class):
191 """Checks whether this is a valid test method. 136 """Checks whether this is a valid test method.
192 137
193 Args: 138 Args:
194 attrname: the method name. 139 attrname: The method name.
195 test_case_class: the test case class. 140 test_case_class: The test case class.
196 141
197 Returns: 142 Returns:
198 True if test_case_class.'attrname' is callable and it starts with 'test'; 143 True if test_case_class.'attrname' is callable and it starts with 'test';
199 False otherwise. 144 False otherwise.
200 """ 145 """
201 attr = getattr(test_case_class, attrname) 146 attr = getattr(test_case_class, attrname)
202 return callable(attr) and attrname.startswith('test') 147 return callable(attr) and attrname.startswith('test')
203 148
204 149
205 def _GetAllTests(test_root, is_official_build): 150 def _GetAllTests(test_root, is_official_build, extra_args):
206 """Retrieve a list of Python test modules and their respective methods. 151 """Retrieve a list of host-driven tests defined under |test_root|.
207 152
208 Args: 153 Args:
209 test_root: path which contains Python-driven test files 154 test_root: Path which contains host-driven test files.
210 is_official_build: whether this is an official build 155 is_official_build: Whether this is an official build.
156 extra_args: List of extra args to pass to the constructor of the test case.
211 157
212 Returns: 158 Returns:
213 List of test case objects for all available test methods. 159 List of test case objects, one for each available test method.
214 """ 160 """
215 if not test_root: 161 if not test_root:
216 return [] 162 return []
217 all_tests = [] 163 all_tests = []
218 test_module_list = _GetTestModules(test_root, is_official_build) 164 test_module_list = _GetTestModules(test_root, is_official_build)
219 for module in test_module_list: 165 for module in test_module_list:
220 all_tests.extend(_GetTestClassesFromModule(module)) 166 all_tests.extend(_GetTestsFromModule(module, extra_args))
221 return all_tests 167 return all_tests
168
169
170 def InstrumentationSetup(host_driven_test_root, official_build, annotations,
171 exclude_annotations, test_filter, tool, build_type,
172 push_deps, cleanup_test_files, test_apk_path,
173 test_apk_jar_path, test_data, install_apk,
174 save_perf_json, screenshot_failures,
175 wait_for_debugger, disable_assertions):
176 """Creates a list of host-driven instrumentation tests and a runner factory.
177
178 Args:
179 host_driven_test_root: Directory where the host-driven tests are.
180 official_build: True if this is an official build.
181 annotations: Annotations for the tests.
182 exclude_annotations: Any annotations to exclude from running.
183 test_filter: Filter string for tests.
184 tool: Name of the Valgrind tool.
185 build_type: 'Release' or 'Debug'.
186 push_deps: If True, push all dependencies to the device.
187 cleanup_test_files: If True, cleanup test files on device.
188 test_apk_path: Path to the test apk file.
189 test_apk_jar_path: Path to the accompanying jar file.
190 test_data: Location of the test data.
191 install_apk: Re-installs the apk if opted.
192 save_perf_json: Whether or not to save the JSON file from UI perf tests.
193 screenshot_failures: Take a screenshot for a test failure
194 wait_for_debugger: Blocks until the debugger is connected.
195 disable_assertions: Whether to disable java assertions on the device.
196
197 Returns:
198 A tuple of (TestRunnerFactory, tests).
199 """
200
201 test_collection = test_info_collection.TestInfoCollection()
202 all_tests = _GetAllTests(
203 host_driven_test_root, official_build, [
204 test_apk_path, test_apk_jar_path, test_data, install_apk,
205 save_perf_json, screenshot_failures, tool, wait_for_debugger,
206 disable_assertions])
207 test_collection.AddTests(all_tests)
208
209 available_tests = test_collection.GetAvailableTests(
210 annotations, exclude_annotations, test_filter)
211 logging.debug('All available tests: ' + str(
212 [t.tagged_name for t in available_tests]))
213
214 def TestRunnerFactory(device, shard_index):
215 return test_runner.HostDrivenTestRunner(
216 device, shard_index, tool, build_type, push_deps, cleanup_test_files)
217
218 return (TestRunnerFactory, available_tests)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698