| # Copyright 2015 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from recipe_engine import recipe_api |
| |
| |
| class LegionApi(recipe_api.RecipeApi): |
| """Provides a recipes interface for the Legion framework.""" |
| |
| @property |
| def legion_path(self): |
| """Returns the path to legion.py.""" |
| return self.m.path['checkout'].join('testing', 'legion', 'tools', |
| 'legion.py') |
| |
| def create_controller(self, name, path, os, config_vars=None, |
| controller_vars=None, dimensions=None): |
| """Returns a controller config dictionary. |
| |
| Args: |
| name: The name of the controller. |
| path: The path to the .isolate or .isolated file for the controller. |
| os: The os to run the controller on. |
| config_vars: A dictionary of config vars to pass when isolating the |
| controller .isolate file. This is ignored if passing a .isolated file. |
| controller_vars: A dictionary of command line vars passed to the |
| controller. |
| dimensions: A dictionary of dimensions to pass when isolating the |
| controller .isolate file. This is ignored if passing a .isolated file. |
| """ |
| return { |
| 'name': name, |
| 'path': path, |
| 'os': os, |
| 'config_vars': config_vars or {}, |
| 'controller_vars': controller_vars or {}, |
| 'dimensions': dimensions or {}, |
| 'tasks': [] |
| } |
| |
| def add_task_to_controller(self, controller, name, path, config_vars=None): |
| """Adds a task config to a controller config. |
| |
| Args: |
| controller: A controller config returnd by create_controller. |
| name: The name of the task. This corresponds to the command line flag |
| defined in the controller code. |
| path: The path to the .isolate or .isolated file for the task. |
| config_vars: Config variables passed when isolating a task .isolate file. |
| This is ignored if passing a .isolated file. |
| """ |
| controller['tasks'].append({ |
| 'name': name, |
| 'path': path, |
| 'config_vars': config_vars or {} |
| }) |
| |
| def _archive_if_needed(self, config): |
| """Archives an isolate file if needed. |
| |
| This method is a no-op if the path is already an .isolated file. If not the |
| file is archived and the path is set to the .isolated file. |
| """ |
| for item in [config] + config['tasks']: |
| if self.m.path.splitext(item['path'])[-1] == '.isolated': |
| continue |
| isolated_path = str(item['path']) + 'd' |
| cmd = [ |
| 'archive', |
| '--isolate', item['path'], |
| '--isolated', isolated_path, |
| '--isolate-server', self.m.isolate.isolate_server, |
| ] |
| for name, value in item['config_vars'].iteritems(): |
| cmd.extend(['--config-variable', name, value]) |
| |
| self.m.python( |
| 'archive for %s' % self.m.path.split(str(item['path']))[-1], |
| self.m.swarming_client.path.join('isolate.py'), |
| cmd) |
| item['path'] = isolated_path |
| |
| def execute(self, config): |
| """Executes a Legion-based swarming test. |
| |
| config: The configuration returned by create_controller. |
| """ |
| self._archive_if_needed(config) |
| |
| cmd = [ |
| 'run', |
| '--controller-isolated', config['path'], |
| '--task-name', config['name'], |
| '--isolate-server', self.m.isolate.isolate_server, |
| '--swarming-server', self.m.chromium_swarming.swarming_server, |
| '--dimension', 'os', config['os'] |
| ] |
| |
| for name, value in config['dimensions'].iteritems(): |
| cmd.extend(['--dimension', name, value]) |
| for name, value in config['controller_vars'].iteritems(): |
| cmd.extend(['--controller-var', name, value]) |
| for task in config['tasks']: |
| cmd.extend(['--task', task['name'], task['path']]) |
| |
| step_result = self.m.python( |
| 'Running test for %s' % config['name'], |
| self.legion_path, |
| cmd, |
| stdout=self.m.raw_io.output_text()) |
| return step_result.stdout |