OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 """A helper module to run Legion multi-machine tests. |
| 7 |
| 8 Example usage with 1 task machine: |
| 9 $ testing/legion/tools/legion.py run \ |
| 10 --controller-isolated out/Release/example_test_controller.isolated \ |
| 11 --dimension os Ubuntu-14.04 \ |
| 12 --task-name test-task-name \ |
| 13 --task task_machine out/Release/example_task_machine.isolated |
| 14 |
| 15 Example usage with 2 task machines with the same isolated file: |
| 16 $ testing/legion/tools/legion.py run \ |
| 17 --controller-isolated out/Release/example_test_controller.isolated \ |
| 18 --dimension os Ubuntu-14.04 \ |
| 19 --task-name test-task-name \ |
| 20 --task task_machine_1 out/Release/example_task_machine.isolated \ |
| 21 --task task_machine_2 out/Release/example_task_machine.isolated |
| 22 |
| 23 Example usage with 2 task machines with different isolated file: |
| 24 $ testing/legion/tools/legion.py run \ |
| 25 --controller-isolated out/Release/example_test_controller.isolated \ |
| 26 --dimension os Ubuntu-14.04 \ |
| 27 --task-name test-task-name \ |
| 28 --task task_machine_1 out/Release/example_task_machine_1.isolated \ |
| 29 --task task_machine_2 out/Release/example_task_machine_2.isolated |
| 30 """ |
| 31 |
| 32 import argparse |
| 33 import logging |
| 34 import os |
| 35 import subprocess |
| 36 import sys |
| 37 |
| 38 |
| 39 THIS_DIR = os.path.split(__file__)[0] |
| 40 SWARMING_DIR = os.path.join(THIS_DIR, '..', '..', '..', 'tools', |
| 41 'swarming_client') |
| 42 ISOLATE_PY = os.path.join(SWARMING_DIR, 'isolate.py') |
| 43 SWARMING_PY = os.path.join(SWARMING_DIR, 'swarming.py') |
| 44 LOGGING_LEVELS = ['DEBUG', 'INFO', 'WARNING', 'ERROR'] |
| 45 |
| 46 |
| 47 class Error(Exception): |
| 48 pass |
| 49 |
| 50 |
| 51 def GetArgs(): |
| 52 parser = argparse.ArgumentParser(description=__doc__) |
| 53 parser.add_argument('action', choices=['run', 'trigger'], |
| 54 help='The swarming action to perform.') |
| 55 parser.add_argument('-f', '--format-only', action='store_true', |
| 56 help='If true the .isolated files are archived but ' |
| 57 'swarming is not called, only the command line is built.') |
| 58 parser.add_argument('--controller-isolated', required=True, |
| 59 help='The isolated file for the test controller.') |
| 60 parser.add_argument('--isolate-server', help='Optional. The isolated server ' |
| 61 'to use.') |
| 62 parser.add_argument('--swarming-server', help='Optional. The swarming server ' |
| 63 'to use.') |
| 64 parser.add_argument('--task-name', help='Optional. The swarming task name ' |
| 65 'to use.') |
| 66 parser.add_argument('--dimension', action='append', dest='dimensions', |
| 67 nargs=2, default=[], help='Dimensions to pass to ' |
| 68 'swarming.py. This is in the form of --dimension key ' |
| 69 'value. The minimum required is --dimension os <OS>') |
| 70 parser.add_argument('--task', action='append', dest='tasks', |
| 71 nargs=2, default=[], help='List of task names used in ' |
| 72 'the test controller. This is in the form of --task name ' |
| 73 '.isolated and is passed to the controller as --name ' |
| 74 '<ISOLATED HASH>.') |
| 75 parser.add_argument('--controller-var', action='append', |
| 76 dest='controller_vars', nargs=2, default=[], |
| 77 help='Command line vars to pass to the controller. These ' |
| 78 'are in the form of --controller-var name value and are ' |
| 79 'passed to the controller as --name value.') |
| 80 parser.add_argument('-v', '--verbosity', default=0, action='count') |
| 81 return parser.parse_args() |
| 82 |
| 83 |
| 84 def RunCommand(cmd, stream_stdout=False): |
| 85 """Runs the command line and streams stdout if requested.""" |
| 86 kwargs = { |
| 87 'args': cmd, |
| 88 'stderr': subprocess.PIPE, |
| 89 } |
| 90 if not stream_stdout: |
| 91 kwargs['stdout'] = subprocess.PIPE |
| 92 |
| 93 p = subprocess.Popen(**kwargs) |
| 94 stdout, stderr = p.communicate() |
| 95 if p.returncode: |
| 96 raise Error(stderr) |
| 97 if not stream_stdout: |
| 98 logging.debug(stdout) |
| 99 return stdout |
| 100 |
| 101 |
| 102 def Archive(isolated, isolate_server=None): |
| 103 """Calls isolate.py archive with the given args.""" |
| 104 cmd = [ |
| 105 sys.executable, |
| 106 ISOLATE_PY, |
| 107 'archive', |
| 108 '--isolated', isolated, |
| 109 ] |
| 110 if isolate_server: |
| 111 cmd.extend(['--isolate-server', isolate_server]) |
| 112 print ' '.join(cmd) |
| 113 return RunCommand(cmd).split()[0] # The isolated hash |
| 114 |
| 115 |
| 116 def GetSwarmingCommandLine(args): |
| 117 """Builds and returns the command line for swarming.py run|trigger.""" |
| 118 cmd = [ |
| 119 sys.executable, |
| 120 SWARMING_PY, |
| 121 args.action, |
| 122 args.controller_isolated, |
| 123 ] |
| 124 if args.isolate_server: |
| 125 cmd.extend(['--isolate-server', args.isolate_server]) |
| 126 if args.swarming_server: |
| 127 cmd.extend(['--swarming', args.swarming_server]) |
| 128 if args.task_name: |
| 129 cmd.extend(['--task-name', args.task_name]) |
| 130 # swarming.py dimensions |
| 131 for name, value in args.dimensions: |
| 132 cmd.extend(['--dimension', name, value]) |
| 133 |
| 134 cmd.append('--') |
| 135 |
| 136 # Task name/hash values |
| 137 for name, isolated in args.tasks: |
| 138 cmd.extend(['--' + name, Archive(isolated, args.isolate_server)]) |
| 139 # Test controller args |
| 140 for name, value in args.controller_vars: |
| 141 cmd.extend(['--' + name, value]) |
| 142 print ' '.join(cmd) |
| 143 return cmd |
| 144 |
| 145 |
| 146 def main(): |
| 147 args = GetArgs() |
| 148 logging.basicConfig( |
| 149 format='%(asctime)s %(filename)s:%(lineno)s %(levelname)s] %(message)s', |
| 150 datefmt='%H:%M:%S', |
| 151 level=LOGGING_LEVELS[len(LOGGING_LEVELS)-args.verbosity-1]) |
| 152 cmd = GetSwarmingCommandLine(args) |
| 153 if not args.format_only: |
| 154 RunCommand(cmd, True) |
| 155 return 0 |
| 156 |
| 157 |
| 158 if __name__ == '__main__': |
| 159 sys.exit(main()) |
OLD | NEW |