blob: 7ca0cce0ba3b40658dbde6a9413748a5e634ef47 [file] [log] [blame]
Henrique Nakashima14cfed592021-11-10 19:35:071#!/usr/bin/env python3
Scott Graham58655152017-09-22 22:41:012
Avi Drissmandfd880852022-09-15 20:11:093# Copyright 2017 The Chromium Authors
Scott Graham58655152017-09-22 22:41:014# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
Elly Fong-Jones23e2b712019-09-06 18:14:587"""Runs a gtest-based test on Swarming, optionally many times, collecting the
8output of the runs into a directory. Useful for flake checking, and faster than
9using trybots by avoiding repeated bot_update, compile, archive, etc. and
10allowing greater parallelism.
Scott Graham58655152017-09-22 22:41:0111
12To use, run in a new shell (it blocks until all Swarming jobs complete):
13
Elly Fong-Jones23e2b712019-09-06 18:14:5814 tools/run-swarmed.py out/rel base_unittests
Scott Graham58655152017-09-22 22:41:0115
16The logs of the runs will be stored in results/ (or specify a results directory
17with --results=some_dir). You can then do something like `grep -L SUCCESS
18results/*` to find the tests that failed or otherwise process the log files.
Elly Fong-Jones23e2b712019-09-06 18:14:5819
20See //docs/workflow/debugging-with-swarming.md for more details.
Scott Graham58655152017-09-22 22:41:0121"""
22
Henrique Nakashima14cfed592021-11-10 19:35:0723
Raul Tambre66e754d2019-09-25 12:03:4424
Scott Graham58655152017-09-22 22:41:0125import argparse
Takuto Ikuta85e93c12020-02-05 22:27:2426import hashlib
27import json
Andrew Grieve5d0a0f82020-03-20 17:26:5928import multiprocessing.dummy
Scott Graham58655152017-09-22 22:41:0129import os
30import shutil
31import subprocess
32import sys
Henrique Nakashima14cfed592021-11-10 19:35:0733import traceback
Scott Grahama3f95772017-10-10 19:37:3934
Ben Pastenefbc2cf32021-09-29 01:29:4835CHROMIUM_ROOT = os.path.join(os.path.dirname(__file__), os.pardir)
36BUILD_DIR = os.path.join(CHROMIUM_ROOT, 'build')
37
38if BUILD_DIR not in sys.path:
39 sys.path.insert(0, BUILD_DIR)
40import gn_helpers
Scott Grahama3f95772017-10-10 19:37:3941
42INTERNAL_ERROR_EXIT_CODE = -1000
43
Jeffrey Cohenf128b51c2020-04-24 18:23:0744DEFAULT_ANDROID_DEVICE_TYPE = "walleye"
45
Scott Grahama3f95772017-10-10 19:37:3946
47def _Spawn(args):
48 """Triggers a swarming job. The arguments passed are:
49 - The index of the job;
50 - The command line arguments object;
Junji Watanabe927cbe8f2021-01-12 21:04:2651 - The digest of test files.
Scott Grahama3f95772017-10-10 19:37:3952
53 The return value is passed to a collect-style map() and consists of:
54 - The index of the job;
55 - The json file created by triggering and used to collect results;
56 - The command line arguments object.
57 """
Henrique Nakashima14cfed592021-11-10 19:35:0758 try:
59 return _DoSpawn(args)
60 except Exception as e:
61 traceback.print_exc()
62 return None
63
64
65def _DoSpawn(args):
Junji Watanabe927cbe8f2021-01-12 21:04:2666 index, args, cas_digest, swarming_command = args
Ben Pastenefbc2cf32021-09-29 01:29:4867 runner_args = []
Scott Grahama3f95772017-10-10 19:37:3968 json_file = os.path.join(args.results, '%d.json' % index)
Takuto Ikuta85e93c12020-02-05 22:27:2469 trigger_args = [
70 'tools/luci-go/swarming',
71 'trigger',
72 '-S',
Will Yeagera399b982024-03-21 19:30:5873 f'https://{args.swarming_instance}.appspot.com',
Junji Watanabe927cbe8f2021-01-12 21:04:2674 '-digest',
75 cas_digest,
Takuto Ikuta85e93c12020-02-05 22:27:2476 '-dump-json',
77 json_file,
Takuto Ikuta85e93c12020-02-05 22:27:2478 '-tag=purpose:user-debug-run-swarmed',
Max Ihlenfeldtd77fbd22024-08-06 16:28:5379 # 30 is try level. So use the same here.
80 '-priority',
81 '30',
Nico Weberb161b5632018-02-27 14:31:4482 ]
83 if args.target_os == 'fuchsia':
84 trigger_args += [
Takuto Ikuta85e93c12020-02-05 22:27:2485 '-d',
86 'kvm=1',
Ben Pastene9721f0c3892020-06-15 18:50:0087 ]
kylechar97370f302023-02-01 21:32:0988 if args.gpu is None:
89 trigger_args += [
90 '-d',
91 'gpu=none',
92 ]
Ben Pastenefbc2cf32021-09-29 01:29:4893 elif args.target_os == 'android':
94 if args.arch == 'x86':
95 # No x86 Android devices are available in swarming. So assume we want to
96 # run on emulators when building for x86 on Android.
97 args.swarming_os = 'Linux'
98 args.pool = 'chromium.tests.avd'
Haiyang Pan56581b32024-07-03 20:46:4099 # android_28_google_apis_x86 == Android P emulator.
100 # See //tools/android/avd/proto/ for other options.
Ben Pastenefbc2cf32021-09-29 01:29:48101 runner_args.append(
Haiyang Pan56581b32024-07-03 20:46:40102 '--avd-config=../../tools/android/avd/proto/android_28_google_apis_x86.textpb'
103 )
Ben Pastenefbc2cf32021-09-29 01:29:48104 elif args.device_type is None and args.device_os is None:
105 # The aliases for device type are stored here:
106 # luci/appengine/swarming/ui2/modules/alias.js
107 # for example 'blueline' = 'Pixel 3'
108 trigger_args += ['-d', 'device_type=' + DEFAULT_ANDROID_DEVICE_TYPE]
Victor Hugo Vianna Silvab1a40ce2023-07-25 02:05:19109 elif args.target_os == 'ios':
Will Yeagera399b982024-03-21 19:30:58110 runner_args.append(f'--xcode-build-version={args.ios_xcode_build_version}')
Victor Hugo Vianna Silvab1a40ce2023-07-25 02:05:19111 runner_args.append('--xctest')
Will Yeagera399b982024-03-21 19:30:58112 runner_args.append('--out-dir=${ISOLATED_OUTDIR}')
113
114 if args.ios_sim_version and args.ios_sim_platform:
115 # simulator test runner and trigger args
Will Yeagera399b982024-03-21 19:30:58116 runner_args.append(f'--version={args.ios_sim_version}')
117 runner_args.extend(['--platform', args.ios_sim_platform])
118
119 version_with_underscore = args.ios_sim_version.replace('.', '_')
120 trigger_args.extend([
121 '-named-cache', f'runtime_ios_{version_with_underscore}'
122 f'=Runtime-ios-{args.ios_sim_version}'
123 ])
124 elif args.ios_device:
Will Yeager330009ca2024-04-16 15:30:20125 # device trigger args
Will Yeagera399b982024-03-21 19:30:58126 trigger_args.extend(['-d', f'device={args.ios_device}'])
127 trigger_args.extend(['-d', 'device_status=available'])
128 else:
129 raise Exception('Either both of --ios-sim-version and --ios-sim-platform '
130 'or --ios-device is required')
131
Will Yeagera399b982024-03-21 19:30:58132 trigger_args.extend(
133 ['-named-cache', f'xcode_ios_{args.ios_xcode_build_version}=Xcode.app'])
134 trigger_args.extend(
135 ['-cipd-package', '.:infra/tools/mac_toolchain/${platform}=latest'])
Victor Hugo Vianna Silvab1a40ce2023-07-25 02:05:19136
Haiyang Pana05cb2e2024-04-17 20:27:26137 if args.service_account:
138 account = args.service_account
139 elif args.swarming_instance == 'chromium-swarm':
140 account = '[email protected]'
141 elif args.swarming_instance == 'chrome-swarming':
142 account = '[email protected]'
143 trigger_args.extend(['-service-account', account])
144
Victor Hugo Vianna Silvab1a40ce2023-07-25 02:05:19145 if args.arch != 'detect':
Ben Pastene9721f0c3892020-06-15 18:50:00146 trigger_args += [
Takuto Ikuta85e93c12020-02-05 22:27:24147 '-d',
148 'cpu=' + args.arch,
Nico Weberb161b5632018-02-27 14:31:44149 ]
Jeffrey Cohenf128b51c2020-04-24 18:23:07150
Jeffrey Cohenf128b51c2020-04-24 18:23:07151 if args.device_type:
152 trigger_args += ['-d', 'device_type=' + args.device_type]
153
154 if args.device_os:
Takuto Ikuta85e93c12020-02-05 22:27:24155 trigger_args += ['-d', 'device_os=' + args.device_os]
Jeffrey Cohenf128b51c2020-04-24 18:23:07156
kylechar97370f302023-02-01 21:32:09157 if args.gpu:
158 trigger_args += ['-d', 'gpu=' + args.gpu]
159
Andrew Grieve5d0a0f82020-03-20 17:26:59160 if not args.no_test_flags:
161 # These flags are recognized by our test runners, but do not work
162 # when running custom scripts.
John Budorick2fb152e22020-06-23 04:44:54163 runner_args += [
Andrew Grieve37370d02022-06-03 19:27:59164 '--test-launcher-summary-output=${ISOLATED_OUTDIR}/output.json'
Andrew Grieve5d0a0f82020-03-20 17:26:59165 ]
Andrew Grieve37370d02022-06-03 19:27:59166 if 'junit' not in args.target_name:
167 runner_args += ['--system-log-file=${ISOLATED_OUTDIR}/system_log']
Peter Collingbourne426ef6f2019-02-15 04:13:45168 if args.gtest_filter:
John Budorick2fb152e22020-06-23 04:44:54169 runner_args.append('--gtest_filter=' + args.gtest_filter)
Cammie Smith Barnes773a75642020-09-08 20:17:44170 if args.gtest_repeat:
171 runner_args.append('--gtest_repeat=' + args.gtest_repeat)
ckitagawa3251d622021-03-09 15:10:30172 if args.test_launcher_shard_index and args.test_launcher_total_shards:
173 runner_args.append('--test-launcher-shard-index=' +
174 args.test_launcher_shard_index)
175 runner_args.append('--test-launcher-total-shards=' +
176 args.test_launcher_total_shards)
Nico Weberb161b5632018-02-27 14:31:44177 elif args.target_os == 'fuchsia':
Scott Graham682f1b42017-10-18 23:35:13178 filter_file = \
Elly Fong-Jones23e2b712019-09-06 18:14:58179 'testing/buildbot/filters/fuchsia.' + args.target_name + '.filter'
Scott Graham682f1b42017-10-18 23:35:13180 if os.path.isfile(filter_file):
John Budorick2fb152e22020-06-23 04:44:54181 runner_args.append('--test-launcher-filter-file=../../' + filter_file)
182
Henrique Nakashima14cfed592021-11-10 19:35:07183 runner_args.extend(args.runner_args)
184
Ben Pastenefbc2cf32021-09-29 01:29:48185 trigger_args.extend(['-d', 'os=' + args.swarming_os])
186 trigger_args.extend(['-d', 'pool=' + args.pool])
Takuto Ikutab2c765b92020-12-07 23:06:22187 trigger_args.extend(['--relative-cwd', args.out_dir, '--'])
Dirk Prankea7e791a2020-10-26 22:18:52188 trigger_args.extend(swarming_command)
189 trigger_args.extend(runner_args)
John Budorick2fb152e22020-06-23 04:44:54190
Scott Grahama3f95772017-10-10 19:37:39191 with open(os.devnull, 'w') as nul:
192 subprocess.check_call(trigger_args, stdout=nul)
193 return (index, json_file, args)
194
195
196def _Collect(spawn_result):
Henrique Nakashima14cfed592021-11-10 19:35:07197 if spawn_result is None:
198 return 1
199
Scott Grahama3f95772017-10-10 19:37:39200 index, json_file, args = spawn_result
Takuto Ikuta85e93c12020-02-05 22:27:24201 with open(json_file) as f:
202 task_json = json.load(f)
203 task_ids = [task['task_id'] for task in task_json['tasks']]
Andrew Grievea8dedf132020-03-20 16:13:53204
205 for t in task_ids:
Will Yeagera399b982024-03-21 19:30:58206 print('Task {}: https://{}.appspot.com/task?id={}'.format(
207 index, args.swarming_instance, t))
208 p = subprocess.Popen([
209 'tools/luci-go/swarming',
210 'collect',
211 '-S',
212 f'https://{args.swarming_instance}.appspot.com',
213 '--task-output-stdout=console',
214 ] + task_ids,
215 stdout=subprocess.PIPE,
216 stderr=subprocess.STDOUT)
Scott Grahama3f95772017-10-10 19:37:39217 stdout = p.communicate()[0]
218 if p.returncode != 0 and len(stdout) < 2**10 and 'Internal error!' in stdout:
219 exit_code = INTERNAL_ERROR_EXIT_CODE
220 file_suffix = '.INTERNAL_ERROR'
221 else:
222 exit_code = p.returncode
223 file_suffix = '' if exit_code == 0 else '.FAILED'
224 filename = '%d%s.stdout.txt' % (index, file_suffix)
Henrique Nakashima14cfed592021-11-10 19:35:07225 with open(os.path.join(args.results, filename), 'wb') as f:
Scott Grahama3f95772017-10-10 19:37:39226 f.write(stdout)
227 return exit_code
Scott Graham58655152017-09-22 22:41:01228
229
230def main():
231 parser = argparse.ArgumentParser()
Will Yeagera399b982024-03-21 19:30:58232 parser.add_argument(
233 '--swarming-instance',
234 choices=['chromium-swarm', 'chrome-swarming'],
235 default='chromium-swarm',
236 help='The swarming instance where the task(s) will be run.')
Elly Fong-Jones23e2b712019-09-06 18:14:58237 parser.add_argument('--swarming-os', help='OS specifier for Swarming.')
Nico Weberb161b5632018-02-27 14:31:44238 parser.add_argument('--target-os', default='detect', help='gn target_os')
Wez1fcb2d122018-01-18 02:34:30239 parser.add_argument('--arch', '-a', default='detect',
240 help='CPU architecture of the test binary.')
Dan McArdleab00ef82020-12-30 05:40:55241 parser.add_argument('--build',
242 dest='build',
243 action='store_true',
244 help='Build before isolating.')
245 parser.add_argument('--no-build',
246 dest='build',
247 action='store_false',
248 help='Do not build, just isolate (default).')
Andrew Grieve5d0a0f82020-03-20 17:26:59249 parser.add_argument('--isolate-map-file', '-i',
250 help='path to isolate map file if not using default')
Scott Graham58655152017-09-22 22:41:01251 parser.add_argument('--copies', '-n', type=int, default=1,
252 help='Number of copies to spawn.')
Jeffrey Cohenf128b51c2020-04-24 18:23:07253 parser.add_argument(
254 '--device-os', help='Run tests on the given version of Android.')
kylechar97370f302023-02-01 21:32:09255 parser.add_argument('--device-type',
256 help='device_type specifier for Swarming'
257 ' from https://chromium-swarm.appspot.com/botlist .')
258 parser.add_argument('--gpu',
259 help='gpu specifier for Swarming'
260 ' from https://chromium-swarm.appspot.com/botlist .')
Ben Pastene6ca322c2020-06-12 01:34:26261 parser.add_argument('--pool',
262 default='chromium.tests',
263 help='Use the given swarming pool.')
Scott Graham58655152017-09-22 22:41:01264 parser.add_argument('--results', '-r', default='results',
265 help='Directory in which to store results.')
Henrique Nakashima14cfed592021-11-10 19:35:07266 parser.add_argument(
267 '--gtest_filter',
268 help='Deprecated. Pass as test runner arg instead, like \'-- '
269 '--gtest_filter="*#testFoo"\'')
Wei-Yin Chen (陳威尹)3f33a022020-06-10 01:17:32270 parser.add_argument(
Cammie Smith Barnes773a75642020-09-08 20:17:44271 '--gtest_repeat',
Henrique Nakashima14cfed592021-11-10 19:35:07272 help='Deprecated. Pass as test runner arg instead, like \'-- '
273 '--gtest_repeat=99\'')
ckitagawa3251d622021-03-09 15:10:30274 parser.add_argument(
275 '--test-launcher-shard-index',
276 help='Shard index to run. Use with --test-launcher-total-shards.')
277 parser.add_argument('--test-launcher-total-shards',
278 help='Number of shards to split the test into. Use with'
279 ' --test-launcher-shard-index.')
Andrew Grieve5d0a0f82020-03-20 17:26:59280 parser.add_argument('--no-test-flags', action='store_true',
281 help='Do not add --test-launcher-summary-output and '
282 '--system-log-file flags to the comment.')
Elly Fong-Jones23e2b712019-09-06 18:14:58283 parser.add_argument('out_dir', type=str, help='Build directory.')
284 parser.add_argument('target_name', type=str, help='Name of target to run.')
Will Yeagera399b982024-03-21 19:30:58285 parser.add_argument(
286 '--service-account',
Haiyang Pana05cb2e2024-04-17 20:27:26287 help='Optional service account that the swarming task will be run using. '
288 'Default value will be set based on the "--swarming-instance".')
289 # ios only args
Will Yeagera399b982024-03-21 19:30:58290 parser.add_argument('--ios-xcode-build-version',
291 help='The version of xcode that will be used for all '
292 'xcodebuild CLI commands')
293 parser.add_argument('--ios-sim-version',
294 help='iOS simulator version, ex. 17.2')
295 parser.add_argument('--ios-sim-platform',
296 help='iOS simulator platform, ex. iPhone 14')
297 parser.add_argument('--ios-device',
298 help='iOS physical device type, ex. iPhone12,1')
Henrique Nakashima14cfed592021-11-10 19:35:07299 parser.add_argument(
300 'runner_args',
301 nargs='*',
302 type=str,
303 help='Arguments to pass to the test runner, e.g. gtest_filter and '
304 'gtest_repeat.')
Ben Pastene11d8b7662025-02-27 20:00:49305 parser.add_argument('--force',
306 action='store_true',
307 help='Bypasses deprecation notice.')
Scott Graham682f1b42017-10-18 23:35:13308
Henrique Nakashima14cfed592021-11-10 19:35:07309 args = parser.parse_intermixed_args()
Scott Graham58655152017-09-22 22:41:01310
Ben Pastene11d8b7662025-02-27 20:00:49311 # TODO(crbug.com/386167803): Remove this script after this deprecation notice
312 # has been live for a few months.
313 if not args.force:
314 print(
315 'This script is deprecated in favor of the UTR. For more info, see '
316 'https://chromium.googlesource.com/chromium/src/+/main/tools/utr/README.md. '
317 'To skip this warning, re-run this script with "--force". Note that '
318 'this script will be deleted sometime in 2025.',
319 file=sys.stderr)
320 return 1
321
Ben Pastenefbc2cf32021-09-29 01:29:48322 with open(os.path.join(args.out_dir, 'args.gn')) as f:
323 gn_args = gn_helpers.FromGNArgs(f.read())
324
Nico Weberb161b5632018-02-27 14:31:44325 if args.target_os == 'detect':
Nico Weberb161b5632018-02-27 14:31:44326 if 'target_os' in gn_args:
327 args.target_os = gn_args['target_os'].strip('"')
328 else:
Takuto Ikutaed87b352022-02-04 11:52:56329 args.target_os = {
330 'darwin': 'mac',
331 'linux': 'linux',
332 'win32': 'win'
333 }[sys.platform]
Nico Weberb161b5632018-02-27 14:31:44334
Elly Fong-Jones23e2b712019-09-06 18:14:58335 if args.swarming_os is None:
336 args.swarming_os = {
Will Yeagera399b982024-03-21 19:30:58337 'mac': 'Mac',
338 'ios': 'Mac',
339 'win': 'Windows',
340 'linux': 'Linux',
341 'android': 'Android',
342 'fuchsia': 'Linux'
Elly Fong-Jones23e2b712019-09-06 18:14:58343 }[args.target_os]
344
Nico Weber9a7c2472020-02-06 15:27:33345 if args.target_os == 'win' and args.target_name.endswith('.exe'):
346 # The machinery expects not to have a '.exe' suffix.
347 args.target_name = os.path.splitext(args.target_name)[0]
348
Wez1fcb2d122018-01-18 02:34:30349 # Determine the CPU architecture of the test binary, if not specified.
Ben Pastenefbc2cf32021-09-29 01:29:48350 if args.arch == 'detect':
Victor Hugo Vianna Silvab1a40ce2023-07-25 02:05:19351 if args.target_os == 'ios':
352 print('iOS must specify --arch. Probably arm64 or x86-64.')
353 return 1
Ben Pastenefbc2cf32021-09-29 01:29:48354 if args.target_os not in ('android', 'mac', 'win'):
355 executable_info = subprocess.check_output(
Takuto Ikutaed87b352022-02-04 11:52:56356 ['file', os.path.join(args.out_dir, args.target_name)], text=True)
Ben Pastenefbc2cf32021-09-29 01:29:48357 if 'ARM aarch64' in executable_info:
358 args.arch = 'arm64',
359 else:
360 args.arch = 'x86-64'
361 elif args.target_os == 'android':
362 args.arch = gn_args.get('target_cpu', 'detect')
Wez1fcb2d122018-01-18 02:34:30363
Bruce Dawson66f8265c2023-02-21 19:16:05364 mb_cmd = [sys.executable, 'tools/mb/mb.py', 'isolate']
Nico Weber9a7c2472020-02-06 15:27:33365 if not args.build:
366 mb_cmd.append('--no-build')
Andrew Grieve5d0a0f82020-03-20 17:26:59367 if args.isolate_map_file:
368 mb_cmd += ['--isolate-map-file', args.isolate_map_file]
Nico Weber9a7c2472020-02-06 15:27:33369 mb_cmd += ['//' + args.out_dir, args.target_name]
Henrique Nakashima513e1772021-11-10 21:23:13370 subprocess.check_call(mb_cmd, shell=os.name == 'nt')
Scott Graham58655152017-09-22 22:41:01371
Raul Tambre66e754d2019-09-25 12:03:44372 print('If you get authentication errors, follow:')
373 print(
Takuto Ikuta11aac052021-06-08 20:47:04374 ' https://chromium.googlesource.com/chromium/src/+/HEAD/docs/workflow/debugging-with-swarming.md#authenticating'
Raul Tambre66e754d2019-09-25 12:03:44375 )
Scott Graham58655152017-09-22 22:41:01376
Raul Tambre66e754d2019-09-25 12:03:44377 print('Uploading to isolate server, this can take a while...')
Junji Watanabe927cbe8f2021-01-12 21:04:26378 isolate = os.path.join(args.out_dir, args.target_name + '.isolate')
Junji Watanabee32793152021-01-15 00:13:56379 archive_json = os.path.join(args.out_dir, args.target_name + '.archive.json')
Takuto Ikuta85e93c12020-02-05 22:27:24380 subprocess.check_output([
Will Yeagera399b982024-03-21 19:30:58381 'tools/luci-go/isolate', 'archive', '-cas-instance',
382 args.swarming_instance, '-isolate', isolate, '-dump-json', archive_json
Takuto Ikuta85e93c12020-02-05 22:27:24383 ])
Junji Watanabee32793152021-01-15 00:13:56384 with open(archive_json) as f:
Junji Watanabe927cbe8f2021-01-12 21:04:26385 cas_digest = json.load(f).get(args.target_name)
Scott Graham58655152017-09-22 22:41:01386
Bruce Dawson66f8265c2023-02-21 19:16:05387 mb_cmd = [
388 sys.executable, 'tools/mb/mb.py', 'get-swarming-command', '--as-list'
389 ]
Dirk Prankea7e791a2020-10-26 22:18:52390 if not args.build:
391 mb_cmd.append('--no-build')
392 if args.isolate_map_file:
393 mb_cmd += ['--isolate-map-file', args.isolate_map_file]
394 mb_cmd += ['//' + args.out_dir, args.target_name]
Henrique Nakashima513e1772021-11-10 21:23:13395 mb_output = subprocess.check_output(mb_cmd, shell=os.name == 'nt')
Henrique Nakashima14cfed592021-11-10 19:35:07396 swarming_cmd = json.loads(mb_output)
Dirk Prankea7e791a2020-10-26 22:18:52397
Scott Graham58655152017-09-22 22:41:01398 if os.path.isdir(args.results):
399 shutil.rmtree(args.results)
400 os.makedirs(args.results)
401
Scott Grahama3f95772017-10-10 19:37:39402 try:
Raul Tambre66e754d2019-09-25 12:03:44403 print('Triggering %d tasks...' % args.copies)
Andrew Grieve5d0a0f82020-03-20 17:26:59404 # Use dummy since threadpools give better exception messages
405 # than process pools do, and threads work fine for what we're doing.
406 pool = multiprocessing.dummy.Pool()
Henrique Nakashima14cfed592021-11-10 19:35:07407 spawn_args = [(i, args, cas_digest, swarming_cmd)
408 for i in range(args.copies)]
Scott Grahama3f95772017-10-10 19:37:39409 spawn_results = pool.imap_unordered(_Spawn, spawn_args)
Scott Graham58655152017-09-22 22:41:01410
Scott Grahama3f95772017-10-10 19:37:39411 exit_codes = []
412 collect_results = pool.imap_unordered(_Collect, spawn_results)
413 for result in collect_results:
414 exit_codes.append(result)
415 successes = sum(1 for x in exit_codes if x == 0)
416 errors = sum(1 for x in exit_codes if x == INTERNAL_ERROR_EXIT_CODE)
417 failures = len(exit_codes) - successes - errors
418 clear_to_eol = '\033[K'
Raul Tambre66e754d2019-09-25 12:03:44419 print(
420 '\r[%d/%d] collected: '
421 '%d successes, %d failures, %d bot errors...%s' %
422 (len(exit_codes), args.copies, successes, failures, errors,
423 clear_to_eol),
424 end=' ')
Scott Grahama3f95772017-10-10 19:37:39425 sys.stdout.flush()
426
Raul Tambre66e754d2019-09-25 12:03:44427 print()
428 print('Results logs collected into', os.path.abspath(args.results) + '.')
Scott Grahama3f95772017-10-10 19:37:39429 finally:
430 pool.close()
431 pool.join()
Scott Graham58655152017-09-22 22:41:01432 return 0
433
434
435if __name__ == '__main__':
436 sys.exit(main())