| 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 | 5 |
| 6 import android_commands | 6 import android_commands |
| 7 import logging | 7 import logging |
| 8 import multiprocessing | 8 import multiprocessing |
| 9 | 9 |
| 10 from android_commands import errors | 10 from android_commands import errors |
| 11 from forwarder import Forwarder |
| 11 from test_result import TestResults | 12 from test_result import TestResults |
| 12 | 13 |
| 13 | 14 |
| 14 def _ShardedTestRunnable(test): | 15 def _ShardedTestRunnable(test): |
| 15 """Standalone function needed by multiprocessing.Pool.""" | 16 """Standalone function needed by multiprocessing.Pool.""" |
| 16 log_format = '[' + test.device + '] # %(asctime)-15s: %(message)s' | 17 log_format = '[' + test.device + '] # %(asctime)-15s: %(message)s' |
| 17 if logging.getLogger().handlers: | 18 if logging.getLogger().handlers: |
| 18 logging.getLogger().handlers[0].setFormatter(logging.Formatter(log_format)) | 19 logging.getLogger().handlers[0].setFormatter(logging.Formatter(log_format)) |
| 19 else: | 20 else: |
| 20 logging.basicConfig(format=log_format) | 21 logging.basicConfig(format=log_format) |
| 21 # Handle SystemExit here since python has a bug to exit current process | 22 # Handle SystemExit here since python has a bug to exit current process |
| 22 try: | 23 try: |
| 23 return test.Run() | 24 return test.Run() |
| 24 except SystemExit: | 25 except SystemExit: |
| 25 return TestResults() | 26 return TestResults() |
| 26 | 27 |
| 28 |
| 27 def SetTestsContainer(tests_container): | 29 def SetTestsContainer(tests_container): |
| 28 """Sets tests container. | 30 """Sets tests container. |
| 29 | 31 |
| 30 multiprocessing.Queue can't be pickled across processes, so we need to set | 32 multiprocessing.Queue can't be pickled across processes, so we need to set |
| 31 this as a 'global', per process, via multiprocessing.Pool. | 33 this as a 'global', per process, via multiprocessing.Pool. |
| 32 """ | 34 """ |
| 33 BaseTestSharder.tests_container = tests_container | 35 BaseTestSharder.tests_container = tests_container |
| 34 | 36 |
| 35 | 37 |
| 36 class BaseTestSharder(object): | 38 class BaseTestSharder(object): |
| 37 """Base class for sharding tests across multiple devices. | 39 """Base class for sharding tests across multiple devices. |
| 38 | 40 |
| 39 Args: | 41 Args: |
| 40 attached_devices: A list of attached devices. | 42 attached_devices: A list of attached devices. |
| 41 """ | 43 """ |
| 42 # See more in SetTestsContainer. | 44 # See more in SetTestsContainer. |
| 43 tests_container = None | 45 tests_container = None |
| 44 | 46 |
| 45 def __init__(self, attached_devices): | 47 def __init__(self, attached_devices, build_type='Debug'): |
| 46 self.attached_devices = attached_devices | 48 self.attached_devices = attached_devices |
| 47 # Worst case scenario: a device will drop offline per run, so we need | 49 # Worst case scenario: a device will drop offline per run, so we need |
| 48 # to retry until we're out of devices. | 50 # to retry until we're out of devices. |
| 49 self.retries = len(self.attached_devices) | 51 self.retries = len(self.attached_devices) |
| 50 self.tests = [] | 52 self.tests = [] |
| 53 self.build_type = build_type |
| 51 | 54 |
| 52 def CreateShardedTestRunner(self, device, index): | 55 def CreateShardedTestRunner(self, device, index): |
| 53 """Factory function to create a suite-specific test runner. | 56 """Factory function to create a suite-specific test runner. |
| 54 | 57 |
| 55 Args: | 58 Args: |
| 56 device: Device serial where this shard will run | 59 device: Device serial where this shard will run |
| 57 index: Index of this device in the pool. | 60 index: Index of this device in the pool. |
| 58 | 61 |
| 59 Returns: | 62 Returns: |
| 60 An object of BaseTestRunner type (that can provide a "Run()" method). | 63 An object of BaseTestRunner type (that can provide a "Run()" method). |
| 61 """ | 64 """ |
| 62 pass | 65 pass |
| 63 | 66 |
| 64 def SetupSharding(self, tests): | 67 def SetupSharding(self, tests): |
| 65 """Called before starting the shards.""" | 68 """Called before starting the shards.""" |
| 66 pass | 69 Forwarder.KillHost(self.build_type) |
| 67 | 70 |
| 68 def OnTestsCompleted(self, test_runners, test_results): | 71 def OnTestsCompleted(self, test_runners, test_results): |
| 69 """Notifies that we completed the tests.""" | 72 """Notifies that we completed the tests.""" |
| 70 pass | 73 Forwarder.KillHost(self.build_type) |
| 71 | 74 |
| 72 def RunShardedTests(self): | 75 def RunShardedTests(self): |
| 73 """Runs the tests in all connected devices. | 76 """Runs the tests in all connected devices. |
| 74 | 77 |
| 75 Returns: | 78 Returns: |
| 76 A TestResults object. | 79 A TestResults object. |
| 77 """ | 80 """ |
| 78 logging.warning('*' * 80) | 81 logging.warning('*' * 80) |
| 79 logging.warning('Sharding in ' + str(len(self.attached_devices)) + | 82 logging.warning('Sharding in ' + str(len(self.attached_devices)) + |
| 80 ' devices.') | 83 ' devices.') |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 for t in test_results.GetAllBroken(): | 136 for t in test_results.GetAllBroken(): |
| 134 self.tests += [t.name] | 137 self.tests += [t.name] |
| 135 if not self.tests: | 138 if not self.tests: |
| 136 break | 139 break |
| 137 else: | 140 else: |
| 138 # We ran out retries, possibly out of healthy devices. | 141 # We ran out retries, possibly out of healthy devices. |
| 139 # There's no recovery at this point. | 142 # There's no recovery at this point. |
| 140 raise Exception('Unrecoverable error while retrying test runs.') | 143 raise Exception('Unrecoverable error while retrying test runs.') |
| 141 self.OnTestsCompleted(test_runners, final_results) | 144 self.OnTestsCompleted(test_runners, final_results) |
| 142 return final_results | 145 return final_results |
| OLD | NEW |