Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320)
[chromium-blink-merge.git] / testing / legion / tools / legion.py
blob7b671335eeb86928b1a244ed740e10bd8a5f88b4
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.
6 """A helper module to run Legion multi-machine tests.
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
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
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 """
32 import argparse
33 import logging
34 import os
35 import subprocess
36 import sys
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']
47 class Error(Exception):
48 pass
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()
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,
90 if not stream_stdout:
91 kwargs['stdout'] = subprocess.PIPE
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
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,
110 if isolate_server:
111 cmd.extend(['--isolate-server', isolate_server])
112 print ' '.join(cmd)
113 return RunCommand(cmd).split()[0] # The isolated hash
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,
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])
134 cmd.append('--')
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
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
158 if __name__ == '__main__':
159 sys.exit(main())