| OLD | NEW |
| 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 """Takes care of sharding the python-drive tests in multiple devices.""" | 5 """Takes care of sharding the python-drive tests in multiple devices.""" |
| 6 | 6 |
| 7 import copy |
| 7 import logging | 8 import logging |
| 8 import multiprocessing | 9 import multiprocessing |
| 9 | 10 |
| 10 from python_test_caller import CallPythonTest | 11 from python_test_caller import CallPythonTest |
| 11 from run_java_tests import FatalTestException | 12 from run_java_tests import FatalTestException |
| 12 import sharded_tests_queue | 13 import sharded_tests_queue |
| 13 from test_result import TestResults | 14 from test_result import TestResults |
| 14 | 15 |
| 15 | 16 |
| 16 def SetTestsContainer(tests_container): | 17 def SetTestsContainer(tests_container): |
| (...skipping 26 matching lines...) Expand all Loading... |
| 43 class PythonTestRunner(object): | 44 class PythonTestRunner(object): |
| 44 """Thin wrapper around a list of PythonTestBase instances. | 45 """Thin wrapper around a list of PythonTestBase instances. |
| 45 | 46 |
| 46 This is meant to be a long-lived object which can run multiple Python tests | 47 This is meant to be a long-lived object which can run multiple Python tests |
| 47 within its lifetime. Tests will receive the device_id and shard_index. | 48 within its lifetime. Tests will receive the device_id and shard_index. |
| 48 | 49 |
| 49 The shard index affords the ability to create unique port numbers (e.g. | 50 The shard index affords the ability to create unique port numbers (e.g. |
| 50 DEFAULT_PORT + shard_index) if the test so wishes. | 51 DEFAULT_PORT + shard_index) if the test so wishes. |
| 51 """ | 52 """ |
| 52 | 53 |
| 53 def __init__(self, device_id, shard_index): | 54 def __init__(self, options): |
| 54 """Constructor. | 55 """Constructor. |
| 55 | 56 |
| 56 Args: | 57 Args: |
| 57 device_id: ID of the device which this test will talk to. | 58 options: Options to use for setting up tests. |
| 58 shard_index: shard index, used to create such as unique port numbers. | |
| 59 """ | 59 """ |
| 60 self.device_id = device_id | 60 self.options = options |
| 61 self.shard_index = shard_index | |
| 62 | 61 |
| 63 def RunTests(self): | 62 def RunTests(self): |
| 64 """Runs tests from the shared pool of tests, aggregating results. | 63 """Runs tests from the shared pool of tests, aggregating results. |
| 65 | 64 |
| 66 Returns: | 65 Returns: |
| 67 A list of test results for all of the tests which this runner executed. | 66 A list of test results for all of the tests which this runner executed. |
| 68 """ | 67 """ |
| 69 tests = PythonTestSharder.tests_container | 68 tests = PythonTestSharder.tests_container |
| 70 | 69 |
| 71 results = [] | 70 results = [] |
| 72 for t in tests: | 71 for t in tests: |
| 73 res = CallPythonTest(t, self.device_id, self.shard_index) | 72 res = CallPythonTest(t, self.options) |
| 74 results.append(res) | 73 results.append(res) |
| 75 | 74 |
| 76 return TestResults.FromTestResults(results) | 75 return TestResults.FromTestResults(results) |
| 77 | 76 |
| 78 | 77 |
| 79 class PythonTestSharder(object): | 78 class PythonTestSharder(object): |
| 80 """Runs Python tests in parallel on multiple devices. | 79 """Runs Python tests in parallel on multiple devices. |
| 81 | 80 |
| 82 This is lifted more or less wholesale from BaseTestRunner. | 81 This is lifted more or less wholesale from BaseTestRunner. |
| 83 | 82 |
| 84 Under the covers, it creates a pool of long-lived PythonTestRunners, which | 83 Under the covers, it creates a pool of long-lived PythonTestRunners, which |
| 85 execute tests from the pool of tests. | 84 execute tests from the pool of tests. |
| 86 | 85 |
| 87 Args: | 86 Args: |
| 88 attached_devices: a list of device IDs attached to the host. | 87 attached_devices: a list of device IDs attached to the host. |
| 89 shard_retries: number of retries for any given test. | |
| 90 available_tests: a list of tests to run which subclass PythonTestBase. | 88 available_tests: a list of tests to run which subclass PythonTestBase. |
| 89 options: Options to use for setting up tests. |
| 91 | 90 |
| 92 Returns: | 91 Returns: |
| 93 An aggregated list of test results. | 92 An aggregated list of test results. |
| 94 """ | 93 """ |
| 95 tests_container = None | 94 tests_container = None |
| 96 | 95 |
| 97 def __init__(self, attached_devices, shard_retries, available_tests): | 96 def __init__(self, attached_devices, available_tests, options): |
| 97 self.options = options |
| 98 self.attached_devices = attached_devices | 98 self.attached_devices = attached_devices |
| 99 self.retries = shard_retries | 99 self.retries = options.shard_retries |
| 100 self.tests = available_tests | 100 self.tests = available_tests |
| 101 | 101 |
| 102 def _SetupSharding(self, tests): | 102 def _SetupSharding(self, tests): |
| 103 """Creates the shared pool of tests and makes it available to test runners. | 103 """Creates the shared pool of tests and makes it available to test runners. |
| 104 | 104 |
| 105 Args: | 105 Args: |
| 106 tests: the list of tests which will be consumed by workers. | 106 tests: the list of tests which will be consumed by workers. |
| 107 """ | 107 """ |
| 108 SetTestsContainer(sharded_tests_queue.ShardedTestsQueue( | 108 SetTestsContainer(sharded_tests_queue.ShardedTestsQueue( |
| 109 len(self.attached_devices), tests)) | 109 len(self.attached_devices), tests)) |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 Returns: | 171 Returns: |
| 172 A list of PythonTestRunners, one for each device. | 172 A list of PythonTestRunners, one for each device. |
| 173 """ | 173 """ |
| 174 test_runners = [] | 174 test_runners = [] |
| 175 for index, device in enumerate(attached_devices): | 175 for index, device in enumerate(attached_devices): |
| 176 logging.warning('*' * 80) | 176 logging.warning('*' * 80) |
| 177 logging.warning('Creating shard %d for %s', index, device) | 177 logging.warning('Creating shard %d for %s', index, device) |
| 178 logging.warning('*' * 80) | 178 logging.warning('*' * 80) |
| 179 # Bind the PythonTestRunner to a device & shard index. Give it the | 179 # Bind the PythonTestRunner to a device & shard index. Give it the |
| 180 # runnable which it will use to actually execute the tests. | 180 # runnable which it will use to actually execute the tests. |
| 181 test_runner = PythonTestRunner(device, index) | 181 test_options = copy.deepcopy(self.options) |
| 182 test_options.ensure_value('device_id', device) |
| 183 test_options.ensure_value('shard_index', index) |
| 184 test_runner = PythonTestRunner(test_options) |
| 182 test_runners.append(test_runner) | 185 test_runners.append(test_runner) |
| 183 | 186 |
| 184 return test_runners | 187 return test_runners |
| 185 | 188 |
| 186 def _GetTestsToRetry(self, available_tests, failed_tests): | 189 def _GetTestsToRetry(self, available_tests, failed_tests): |
| 187 """Infers a list of tests to retry from failed tests and available tests. | 190 """Infers a list of tests to retry from failed tests and available tests. |
| 188 | 191 |
| 189 Args: | 192 Args: |
| 190 available_tests: a list of tests which subclass PythonTestBase. | 193 available_tests: a list of tests which subclass PythonTestBase. |
| 191 failed_tests: a list of SingleTestResults representing failed tests. | 194 failed_tests: a list of SingleTestResults representing failed tests. |
| 192 | 195 |
| 193 Returns: | 196 Returns: |
| 194 A list of test objects which correspond to test names found in | 197 A list of test objects which correspond to test names found in |
| 195 failed_tests, or an empty list if there is no correspondence. | 198 failed_tests, or an empty list if there is no correspondence. |
| 196 """ | 199 """ |
| 197 failed_test_names = map(lambda t: t.test_name, failed_tests) | 200 failed_test_names = map(lambda t: t.test_name, failed_tests) |
| 198 tests_to_retry = [t for t in available_tests | 201 tests_to_retry = [t for t in available_tests |
| 199 if t.qualified_name in failed_test_names] | 202 if t.qualified_name in failed_test_names] |
| 200 return tests_to_retry | 203 return tests_to_retry |
| OLD | NEW |