Index: scripts/slave/recipe_modules/chromium_tests/steps.py |
diff --git a/scripts/slave/recipe_modules/chromium_tests/steps.py b/scripts/slave/recipe_modules/chromium_tests/steps.py |
index 58d9fdcf87cc5c46110723b8aaf2bf822f91ed4b..9d93d2ba848160a89bca259219d473d807d124d0 100644 |
--- a/scripts/slave/recipe_modules/chromium_tests/steps.py |
+++ b/scripts/slave/recipe_modules/chromium_tests/steps.py |
@@ -814,6 +814,117 @@ class AMPInstrumentationTest(AMPTest): |
isolate_file_path=isolate_file_path).run(api, suffix) |
+class IsolatedScriptTest(Test): |
+ def __init__(self, name, args=None, target_name=None, **runtest_kwargs): |
+ """Constructs an instance of IsolatedScriptTest. |
+ |
+ An IsolatedScriptTest knows how to invoke an isolate which obeys a certain |
+ contract. The isolate's main target must be a wrapper script which must |
+ interpret certain command line arguments as follows: |
+ |
+ --isolated-script-test-output [FILENAME] |
+ |
+ The wrapper script must write the simplified json output that the recipes |
+ consume (similar to GTestTest and ScriptTest) into |FILENAME|. |
+ |
+ The contract may be expanded later to support functionality like sharding |
+ and retries of specific failed tests. Currently the examples of such wrapper |
+ scripts live in src/testing/scripts/ in the Chromium workspace. |
+ |
+ Args: |
+ name: Displayed name of the test. May be modified by suffixes. |
+ args: Arguments to be passed to the test. |
+ target_name: Actual name of the test. Defaults to name. |
+ runtest_kwargs: Additional keyword args forwarded to the runtest. |
+ """ |
+ super(IsolatedScriptTest, self).__init__() |
+ self._name = name |
+ self._args = args or [] |
+ self._target_name = target_name |
+ self._runtest_kwargs = runtest_kwargs |
+ |
+ @property |
+ def name(self): |
+ return self._name |
+ |
+ @property |
+ def target_name(self): |
+ return self._target_name or self._name |
+ |
+ @property |
+ def isolate_target(self): |
+ return self.target_name |
+ |
+ @property |
+ def uses_swarming(self): |
+ return True |
+ |
+ def compile_targets(self, _): |
+ return [self.target_name] |
+ |
+ # TODO(nednguyen, kbr): figure out what to do with Android. |
+ # (crbug.com/533480) |
+ def run(self, api, suffix): |
+ # Copy the list because run can be invoked multiple times and we modify |
+ # the local copy. |
+ args = self._args[:] |
+ |
+ kwargs = {} |
+ # TODO(nednguyen, kbr): define contract with the wrapper script to rerun |
+ # a subset of the tests. (crbug.com/533481) |
+ json_results_file = api.json.output() |
+ step_test_data = lambda: api.json.test_api.output( |
+ {'valid': True, 'failures': []}) |
+ kwargs['name'] = self._step_name(suffix) |
+ kwargs['args'] = args |
+ kwargs['args'].extend( |
+ ['--isolated-script-test-output', json_results_file]) |
+ kwargs['step_test_data'] = step_test_data |
+ kwargs['xvfb'] = True |
+ kwargs['test_type'] = self.name |
+ kwargs.update(self._runtest_kwargs) |
+ |
+ try: |
+ # TODO(nednguyen, kbr): |
+ # Replace runtest usage here with a better alternative. |
+ # (crbug.com/533479) |
+ # Figure out whether we need to get revision and webkit_revision, and |
+ # if so, where to get them from. (crbug.com/533141) |
+ api.isolate.runtest(self.target_name, None, None, **kwargs) |
+ finally: |
+ self._test_runs[suffix] = api.step.active_result |
+ if self.has_valid_results(api, suffix): |
+ self._test_runs[suffix].presentation.step_text += ( |
+ api.test_utils.format_step_text([ |
+ ['failures:', self.failures(api, suffix)] |
+ ])) |
+ |
+ return self._test_runs[suffix] |
+ |
+ def has_valid_results(self, api, suffix): |
+ try: |
+ # Make sure the JSON includes all necessary data. |
+ self.failures(api, suffix) |
+ |
+ return self._test_runs[suffix].json.output['valid'] |
+ except Exception: # pragma: no cover |
+ return False |
+ |
+ def failures(self, api, suffix): |
+ return self._test_runs[suffix].json.output['failures'] |
+ |
+ |
+def generate_isolated_script(api, mastername, buildername, test_spec, |
+ enable_swarming=False, |
+ scripts_compile_targets=None): |
+ for spec in test_spec.get(buildername, {}).get( |
+ 'isolated_scripts', []): |
+ yield IsolatedScriptTest( |
+ str(spec['name']), |
+ args=spec.get('args', []), |
+ target_name=spec['isolate_name']) |
+ |
+ |
class GTestTest(Test): |
def __init__(self, name, args=None, target_name=None, enable_swarming=False, |
swarming_shards=1, swarming_dimensions=None, swarming_tags=None, |