| Index: testing/legion/tools/legion.py
|
| diff --git a/testing/legion/tools/legion.py b/testing/legion/tools/legion.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..7b671335eeb86928b1a244ed740e10bd8a5f88b4
|
| --- /dev/null
|
| +++ b/testing/legion/tools/legion.py
|
| @@ -0,0 +1,159 @@
|
| +#!/usr/bin/env python
|
| +# 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.
|
| +
|
| +"""A helper module to run Legion multi-machine tests.
|
| +
|
| +Example usage with 1 task machine:
|
| +$ testing/legion/tools/legion.py run \
|
| + --controller-isolated out/Release/example_test_controller.isolated \
|
| + --dimension os Ubuntu-14.04 \
|
| + --task-name test-task-name \
|
| + --task task_machine out/Release/example_task_machine.isolated
|
| +
|
| +Example usage with 2 task machines with the same isolated file:
|
| +$ testing/legion/tools/legion.py run \
|
| + --controller-isolated out/Release/example_test_controller.isolated \
|
| + --dimension os Ubuntu-14.04 \
|
| + --task-name test-task-name \
|
| + --task task_machine_1 out/Release/example_task_machine.isolated \
|
| + --task task_machine_2 out/Release/example_task_machine.isolated
|
| +
|
| +Example usage with 2 task machines with different isolated file:
|
| +$ testing/legion/tools/legion.py run \
|
| + --controller-isolated out/Release/example_test_controller.isolated \
|
| + --dimension os Ubuntu-14.04 \
|
| + --task-name test-task-name \
|
| + --task task_machine_1 out/Release/example_task_machine_1.isolated \
|
| + --task task_machine_2 out/Release/example_task_machine_2.isolated
|
| +"""
|
| +
|
| +import argparse
|
| +import logging
|
| +import os
|
| +import subprocess
|
| +import sys
|
| +
|
| +
|
| +THIS_DIR = os.path.split(__file__)[0]
|
| +SWARMING_DIR = os.path.join(THIS_DIR, '..', '..', '..', 'tools',
|
| + 'swarming_client')
|
| +ISOLATE_PY = os.path.join(SWARMING_DIR, 'isolate.py')
|
| +SWARMING_PY = os.path.join(SWARMING_DIR, 'swarming.py')
|
| +LOGGING_LEVELS = ['DEBUG', 'INFO', 'WARNING', 'ERROR']
|
| +
|
| +
|
| +class Error(Exception):
|
| + pass
|
| +
|
| +
|
| +def GetArgs():
|
| + parser = argparse.ArgumentParser(description=__doc__)
|
| + parser.add_argument('action', choices=['run', 'trigger'],
|
| + help='The swarming action to perform.')
|
| + parser.add_argument('-f', '--format-only', action='store_true',
|
| + help='If true the .isolated files are archived but '
|
| + 'swarming is not called, only the command line is built.')
|
| + parser.add_argument('--controller-isolated', required=True,
|
| + help='The isolated file for the test controller.')
|
| + parser.add_argument('--isolate-server', help='Optional. The isolated server '
|
| + 'to use.')
|
| + parser.add_argument('--swarming-server', help='Optional. The swarming server '
|
| + 'to use.')
|
| + parser.add_argument('--task-name', help='Optional. The swarming task name '
|
| + 'to use.')
|
| + parser.add_argument('--dimension', action='append', dest='dimensions',
|
| + nargs=2, default=[], help='Dimensions to pass to '
|
| + 'swarming.py. This is in the form of --dimension key '
|
| + 'value. The minimum required is --dimension os <OS>')
|
| + parser.add_argument('--task', action='append', dest='tasks',
|
| + nargs=2, default=[], help='List of task names used in '
|
| + 'the test controller. This is in the form of --task name '
|
| + '.isolated and is passed to the controller as --name '
|
| + '<ISOLATED HASH>.')
|
| + parser.add_argument('--controller-var', action='append',
|
| + dest='controller_vars', nargs=2, default=[],
|
| + help='Command line vars to pass to the controller. These '
|
| + 'are in the form of --controller-var name value and are '
|
| + 'passed to the controller as --name value.')
|
| + parser.add_argument('-v', '--verbosity', default=0, action='count')
|
| + return parser.parse_args()
|
| +
|
| +
|
| +def RunCommand(cmd, stream_stdout=False):
|
| + """Runs the command line and streams stdout if requested."""
|
| + kwargs = {
|
| + 'args': cmd,
|
| + 'stderr': subprocess.PIPE,
|
| + }
|
| + if not stream_stdout:
|
| + kwargs['stdout'] = subprocess.PIPE
|
| +
|
| + p = subprocess.Popen(**kwargs)
|
| + stdout, stderr = p.communicate()
|
| + if p.returncode:
|
| + raise Error(stderr)
|
| + if not stream_stdout:
|
| + logging.debug(stdout)
|
| + return stdout
|
| +
|
| +
|
| +def Archive(isolated, isolate_server=None):
|
| + """Calls isolate.py archive with the given args."""
|
| + cmd = [
|
| + sys.executable,
|
| + ISOLATE_PY,
|
| + 'archive',
|
| + '--isolated', isolated,
|
| + ]
|
| + if isolate_server:
|
| + cmd.extend(['--isolate-server', isolate_server])
|
| + print ' '.join(cmd)
|
| + return RunCommand(cmd).split()[0] # The isolated hash
|
| +
|
| +
|
| +def GetSwarmingCommandLine(args):
|
| + """Builds and returns the command line for swarming.py run|trigger."""
|
| + cmd = [
|
| + sys.executable,
|
| + SWARMING_PY,
|
| + args.action,
|
| + args.controller_isolated,
|
| + ]
|
| + if args.isolate_server:
|
| + cmd.extend(['--isolate-server', args.isolate_server])
|
| + if args.swarming_server:
|
| + cmd.extend(['--swarming', args.swarming_server])
|
| + if args.task_name:
|
| + cmd.extend(['--task-name', args.task_name])
|
| + # swarming.py dimensions
|
| + for name, value in args.dimensions:
|
| + cmd.extend(['--dimension', name, value])
|
| +
|
| + cmd.append('--')
|
| +
|
| + # Task name/hash values
|
| + for name, isolated in args.tasks:
|
| + cmd.extend(['--' + name, Archive(isolated, args.isolate_server)])
|
| + # Test controller args
|
| + for name, value in args.controller_vars:
|
| + cmd.extend(['--' + name, value])
|
| + print ' '.join(cmd)
|
| + return cmd
|
| +
|
| +
|
| +def main():
|
| + args = GetArgs()
|
| + logging.basicConfig(
|
| + format='%(asctime)s %(filename)s:%(lineno)s %(levelname)s] %(message)s',
|
| + datefmt='%H:%M:%S',
|
| + level=LOGGING_LEVELS[len(LOGGING_LEVELS)-args.verbosity-1])
|
| + cmd = GetSwarmingCommandLine(args)
|
| + if not args.format_only:
|
| + RunCommand(cmd, True)
|
| + return 0
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + sys.exit(main())
|
|
|