Index: build/android/pylib/host_driven/test_runner.py |
diff --git a/build/android/pylib/host_driven/python_test_caller.py b/build/android/pylib/host_driven/test_runner.py |
similarity index 23% |
rename from build/android/pylib/host_driven/python_test_caller.py |
rename to build/android/pylib/host_driven/test_runner.py |
index fc53d7725f9bb8291eab00accd67fa128e8168d1..620c4655ae73f94cefdcb5dbc224324c418906c7 100644 |
--- a/build/android/pylib/host_driven/python_test_caller.py |
+++ b/build/android/pylib/host_driven/test_runner.py |
@@ -2,8 +2,7 @@ |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
-"""Helper module for calling python-based tests.""" |
- |
+"""Runs host-driven tests on a particular device.""" |
import logging |
import sys |
@@ -11,14 +10,17 @@ import time |
import traceback |
from pylib.base import base_test_result |
+from pylib.base import base_test_runner |
from pylib.instrumentation import test_result |
+import test_case |
+ |
-class PythonExceptionTestResult(test_result.InstrumentationTestResult): |
- """Helper class for creating a test result from python exception.""" |
+class HostDrivenExceptionTestResult(test_result.InstrumentationTestResult): |
+ """Test result corresponding to a python exception in a host-driven test.""" |
def __init__(self, test_name, start_date_ms, exc_info): |
- """Constructs an PythonExceptionTestResult object. |
+ """Constructs a HostDrivenExceptionTestResult object. |
Args: |
test_name: name of the test which raised an exception. |
@@ -31,85 +33,103 @@ class PythonExceptionTestResult(test_result.InstrumentationTestResult): |
log_msg = 'Exception:\n' + trace_info |
duration_ms = (int(time.time()) * 1000) - start_date_ms |
- super(PythonExceptionTestResult, self).__init__( |
- 'PythonWrapper#' + test_name, |
+ super(HostDrivenExceptionTestResult, self).__init__( |
+ test_name, |
base_test_result.ResultType.FAIL, |
start_date_ms, |
duration_ms, |
log=str(exc_type) + ' ' + log_msg) |
-def CallPythonTest(test, options): |
- """Invokes a test function and translates Python exceptions into test results. |
+class HostDrivenTestRunner(base_test_runner.BaseTestRunner): |
+ """Orchestrates running a set of host-driven tests. |
+ |
+ Any Python exceptions in the tests are caught and translated into a failed |
+ result, rather than being re-raised on the main thread. |
+ """ |
- This method invokes SetUp()/TearDown() on the test. It is intended to be |
- resilient to exceptions in SetUp(), the test itself, and TearDown(). Any |
- Python exception means the test is marked as failed, and the test result will |
- contain information about the exception. |
+ #override |
+ def __init__(self, device, shard_index, tool, build_type, push_deps, |
+ cleanup_test_files): |
+ """Creates a new HostDrivenTestRunner. |
- If SetUp() raises an exception, the test is not run. |
+ Args: |
+ device: Attached android device. |
+ shard_index: Shard index. |
+ tool: Name of the Valgrind tool. |
+ build_type: 'Release' or 'Debug'. |
+ push_deps: If True, push all dependencies to the device. |
+ cleanup_test_files: Whether or not to cleanup test files on device. |
+ """ |
- If TearDown() raises an exception, the test is treated as a failure. However, |
- if the test itself raised an exception beforehand, that stack trace will take |
- precedence whether or not TearDown() also raised an exception. |
+ super(HostDrivenTestRunner, self).__init__(device, tool, build_type, |
+ push_deps, cleanup_test_files) |
- shard_index is not applicable in single-device scenarios, when test execution |
- is serial rather than parallel. Tests can use this to bring up servers with |
- unique port numbers, for example. See also python_test_sharder. |
+ # The shard index affords the ability to create unique port numbers (e.g. |
+ # DEFAULT_PORT + shard_index) if the test so wishes. |
+ self.shard_index = shard_index |
- Args: |
- test: an object which is ostensibly a subclass of PythonTestBase. |
- options: Options to use for setting up tests. |
+ #override |
+ def RunTest(self, test): |
+ """Sets up and runs a test case. |
- Returns: |
- A TestRunResults object which contains any results produced by the test or, |
- in the case of a Python exception, the Python exception info. |
- """ |
+ Args: |
+ test: An object which is ostensibly a subclass of HostDrivenTestCase. |
- start_date_ms = int(time.time()) * 1000 |
- failed = False |
- |
- try: |
- test.SetUp(options) |
- except Exception: |
- failed = True |
- logging.exception( |
- 'Caught exception while trying to run SetUp() for test: ' + |
- test.qualified_name) |
- # Tests whose SetUp() method has failed are likely to fail, or at least |
- # yield invalid results. |
- exc_info = sys.exc_info() |
- results = base_test_result.TestRunResults() |
- results.AddResult(PythonExceptionTestResult( |
- test.qualified_name, start_date_ms, exc_info)) |
- return results |
- |
- try: |
- results = test.Run() |
- except Exception: |
- # Setting this lets TearDown() avoid stomping on our stack trace from Run() |
- # should TearDown() also raise an exception. |
- failed = True |
- logging.exception('Caught exception while trying to run test: ' + |
- test.qualified_name) |
- exc_info = sys.exc_info() |
- results = base_test_result.TestRunResults() |
- results.AddResult(PythonExceptionTestResult( |
- test.qualified_name, start_date_ms, exc_info)) |
- |
- try: |
- test.TearDown() |
- except Exception: |
- logging.exception( |
- 'Caught exception while trying run TearDown() for test: ' + |
- test.qualified_name) |
- if not failed: |
- # Don't stomp the error during the test if TearDown blows up. This is a |
- # trade-off: if the test fails, this will mask any problem with TearDown |
- # until the test is fixed. |
+ Returns: |
+ A TestRunResults object which contains the result produced by the test |
+ and, in the case of a failure, the test that should be retried. |
+ """ |
+ |
+ assert isinstance(test, test_case.HostDrivenTestCase) |
+ |
+ start_date_ms = int(time.time()) * 1000 |
+ exception_raised = False |
+ |
+ try: |
+ test.SetUp(self.device, self.shard_index, self.build_type, |
+ self._push_deps, self._cleanup_test_files) |
+ except Exception: |
+ logging.exception( |
+ 'Caught exception while trying to run SetUp() for test: ' + |
+ test.tagged_name) |
+ # Tests whose SetUp() method has failed are likely to fail, or at least |
+ # yield invalid results. |
exc_info = sys.exc_info() |
results = base_test_result.TestRunResults() |
- results.AddResult(PythonExceptionTestResult( |
- test.qualified_name, start_date_ms, exc_info)) |
- |
- return results |
+ results.AddResult(HostDrivenExceptionTestResult( |
+ test.tagged_name, start_date_ms, exc_info)) |
+ return results, test |
+ |
+ try: |
+ results = test.Run() |
+ except Exception: |
+ # Setting this lets TearDown() avoid stomping on our stack trace from |
+ # Run() should TearDown() also raise an exception. |
+ exception_raised = True |
+ logging.exception('Caught exception while trying to run test: ' + |
+ test.tagged_name) |
+ exc_info = sys.exc_info() |
+ results = base_test_result.TestRunResults() |
+ results.AddResult(HostDrivenExceptionTestResult( |
+ test.tagged_name, start_date_ms, exc_info)) |
+ |
+ try: |
+ test.TearDown() |
+ except Exception: |
+ logging.exception( |
+ 'Caught exception while trying run TearDown() for test: ' + |
+ test.tagged_name) |
+ if not exception_raised: |
+ # Don't stomp the error during the test if TearDown blows up. This is a |
+ # trade-off: if the test fails, this will mask any problem with TearDown |
+ # until the test is fixed. |
+ exc_info = sys.exc_info() |
+ results = base_test_result.TestRunResults() |
+ results.AddResult(HostDrivenExceptionTestResult( |
+ test.tagged_name, start_date_ms, exc_info)) |
+ |
+ if not results.DidRunPass(): |
+ return results, test |
+ else: |
+ return results, None |