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
39 THIS_DIR
= os
.path
.split(__file__
)[0]
40 SWARMING_DIR
= os
.path
.join(THIS_DIR
, '..', '..', '..', 'tools',
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):
51 class ArgumentError(Error
):
56 parser
= argparse
.ArgumentParser(description
=__doc__
)
57 parser
.add_argument('action', choices
=['run', 'trigger'],
58 help='The swarming action to perform.')
59 parser
.add_argument('-f', '--format-only', action
='store_true',
60 help='If true the .isolated files are archived but '
61 'swarming is not called, only the command line is built.')
62 parser
.add_argument('--controller-isolated', required
=True,
63 help='The isolated file for the test controller.')
64 parser
.add_argument('--isolate-server', help='Optional. The isolated server '
65 'to use.', default
=os
.environ
.get('ISOLATE_SERVER', ''))
66 parser
.add_argument('--swarming-server', help='Optional. The swarming server '
67 'to use.', default
=os
.environ
.get('SWARMING_SERVER', ''))
68 parser
.add_argument('--task-name', help='Optional. The swarming task name '
70 parser
.add_argument('--dimension', action
='append', dest
='dimensions',
71 nargs
=2, default
=[], help='Dimensions to pass to '
72 'swarming.py. This is in the form of --dimension key '
73 'value. The minimum required is --dimension os <OS>')
74 parser
.add_argument('--task', action
='append', dest
='tasks',
75 nargs
=2, default
=[], help='List of task names used in '
76 'the test controller. This is in the form of --task name '
77 '.isolated and is passed to the controller as --name '
79 parser
.add_argument('--controller-var', action
='append',
80 dest
='controller_vars', nargs
=2, default
=[],
81 help='Command line vars to pass to the controller. These '
82 'are in the form of --controller-var name value and are '
83 'passed to the controller as --name value.')
84 parser
.add_argument('-v', '--verbosity', default
=0, action
='count')
85 return parser
.parse_args()
88 def RunCommand(cmd
, stream_stdout
=False):
89 """Runs the command line and streams stdout if requested."""
92 'stderr': subprocess
.PIPE
,
95 kwargs
['stdout'] = subprocess
.PIPE
97 p
= subprocess
.Popen(**kwargs
)
98 stdout
, stderr
= p
.communicate()
101 if not stream_stdout
:
102 logging
.debug(stdout
)
106 def Archive(isolated
, isolate_server
):
107 """Calls isolate.py archive with the given args."""
112 '--isolated', isolated
,
114 cmd
.extend(['--isolate-server', isolate_server
])
116 return RunCommand(cmd
).split()[0] # The isolated hash
119 def GetSwarmingCommandLine(args
):
120 """Builds and returns the command line for swarming.py run|trigger."""
125 args
.controller_isolated
,
127 cmd
.extend(['--isolate-server', args
.isolate_server
])
128 cmd
.extend(['--swarming', args
.swarming_server
])
130 cmd
.extend(['--task-name', args
.task_name
])
131 # swarming.py dimensions
132 for name
, value
in args
.dimensions
:
133 cmd
.extend(['--dimension', name
, value
])
137 cmd
.extend(['--swarming-server', args
.swarming_server
])
138 cmd
.extend(['--isolate-server', args
.isolate_server
])
139 # Specify the output dir
140 cmd
.extend(['--output-dir', '${ISOLATED_OUTDIR}'])
141 # Task name/hash values
142 for name
, isolated
in args
.tasks
:
143 cmd
.extend(['--' + name
, Archive(isolated
, args
.isolate_server
)])
144 # Test controller args
145 for name
, value
in args
.controller_vars
:
146 cmd
.extend(['--' + name
, value
])
153 if not args
.swarming_server
:
154 raise ArgumentError('Missing required argument: --swarming-server')
155 if not args
.isolate_server
:
156 raise ArgumentError('Missing required argument: --isolate-server')
158 format
='%(asctime)s %(filename)s:%(lineno)s %(levelname)s] %(message)s',
160 level
=LOGGING_LEVELS
[len(LOGGING_LEVELS
)-args
.verbosity
-1])
161 cmd
= GetSwarmingCommandLine(args
)
162 if not args
.format_only
:
163 RunCommand(cmd
, True)
167 if __name__
== '__main__':