OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Shards a given test suite and runs the shards in parallel. | 6 """Shards a given test suite and runs the shards in parallel. |
7 | 7 |
8 ShardingSupervisor is called to process the command line options and creates | 8 ShardingSupervisor is called to process the command line options and creates |
9 the specified number of worker threads. These threads then run each shard of | 9 the specified number of worker threads. These threads then run each shard of |
10 the test in a separate process and report on the results. When all the shards | 10 the test in a separate process and report on the results. When all the shards |
11 have been completed, the supervisor reprints any lines indicating a test | 11 have been completed, the supervisor reprints any lines indicating a test |
12 failure for convenience. If only one shard is to be run, a single subprocess | 12 failure for convenience. If only one shard is to be run, a single subprocess |
13 is started for that shard and the output is identical to gtest's output. | 13 is started for that shard and the output is identical to gtest's output. |
14 """ | 14 """ |
15 | 15 |
16 | 16 |
17 from cStringIO import StringIO | 17 from cStringIO import StringIO |
18 import optparse | 18 import optparse |
19 import os | 19 import os |
20 import pty | 20 import pty |
21 import Queue | 21 import Queue |
| 22 import random |
22 import re | 23 import re |
23 import subprocess | 24 import subprocess |
24 import sys | 25 import sys |
25 import threading | 26 import threading |
26 | 27 |
27 | 28 |
28 SS_USAGE = "Usage: python %prog [options] path/to/test [gtest_args]" | 29 SS_USAGE = "Usage: python %prog [options] path/to/test [gtest_args]" |
29 SS_DEFAULT_NUM_CORES = 4 | 30 SS_DEFAULT_NUM_CORES = 4 |
30 SS_DEFAULT_SHARDS_PER_CORE = 5 # num_shards = cores * SHARDS_PER_CORE | 31 SS_DEFAULT_SHARDS_PER_CORE = 5 # num_shards = cores * SHARDS_PER_CORE |
31 SS_DEFAULT_RUNS_PER_CORE = 1 # num_workers = cores * RUNS_PER_CORE | 32 SS_DEFAULT_RUNS_PER_CORE = 1 # num_workers = cores * RUNS_PER_CORE |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 " specified") | 286 " specified") |
286 parser.add_option( | 287 parser.add_option( |
287 "--no-color", action="store_false", dest="color", | 288 "--no-color", action="store_false", dest="color", |
288 help="disable color output") | 289 help="disable color output") |
289 parser.add_option( | 290 parser.add_option( |
290 "-s", "--runshard", type="int", help="single shard index to run") | 291 "-s", "--runshard", type="int", help="single shard index to run") |
291 parser.add_option( | 292 parser.add_option( |
292 "--reorder", action="store_true", | 293 "--reorder", action="store_true", |
293 help="ensure that all output from an earlier shard is printed before" | 294 help="ensure that all output from an earlier shard is printed before" |
294 " output from a later shard") | 295 " output from a later shard") |
| 296 parser.add_option("--random-seed", action="store_true", |
| 297 help="shuffle the tests with a random seed value") |
295 parser.disable_interspersed_args() | 298 parser.disable_interspersed_args() |
296 (options, args) = parser.parse_args() | 299 (options, args) = parser.parse_args() |
297 | 300 |
298 if not args: | 301 if not args: |
299 parser.error("You must specify a path to test!") | 302 parser.error("You must specify a path to test!") |
300 if not os.path.exists(args[0]): | 303 if not os.path.exists(args[0]): |
301 parser.error("%s does not exist!" % args[0]) | 304 parser.error("%s does not exist!" % args[0]) |
302 | 305 |
303 num_cores = DetectNumCores() | 306 num_cores = DetectNumCores() |
304 | 307 |
305 if options.shards_per_core < 1: | 308 if options.shards_per_core < 1: |
306 parser.error("You must have at least 1 shard per core!") | 309 parser.error("You must have at least 1 shard per core!") |
307 num_shards = num_cores * options.shards_per_core | 310 num_shards = num_cores * options.shards_per_core |
308 | 311 |
309 if options.runs_per_core < 1: | 312 if options.runs_per_core < 1: |
310 parser.error("You must have at least 1 run per core!") | 313 parser.error("You must have at least 1 run per core!") |
311 num_runs = num_cores * options.runs_per_core | 314 num_runs = num_cores * options.runs_per_core |
312 | 315 |
313 gtest_args = ["--gtest_color=%s" % { | 316 gtest_args = ["--gtest_color=%s" % { |
314 True: "yes", False: "no"}[options.color]] + args[1:] | 317 True: "yes", False: "no"}[options.color]] + args[1:] |
315 | 318 |
| 319 if options.random_seed: |
| 320 seed = random.randint(1, 99999) |
| 321 gtest_args.extend(["--gtest_shuffle", "--gtest_random_seed=%i" % seed]) |
| 322 |
316 if options.runshard != None: | 323 if options.runshard != None: |
317 # run a single shard and exit | 324 # run a single shard and exit |
318 if (options.runshard < 0 or options.runshard >= num_shards): | 325 if (options.runshard < 0 or options.runshard >= num_shards): |
319 parser.error("Invalid shard number given parameters!") | 326 parser.error("Invalid shard number given parameters!") |
320 shard = RunShard( | 327 shard = RunShard( |
321 args[0], num_shards, options.runshard, gtest_args, None, None) | 328 args[0], num_shards, options.runshard, gtest_args, None, None) |
322 shard.communicate() | 329 shard.communicate() |
323 return shard.poll() | 330 return shard.poll() |
324 | 331 |
325 # shard and run the whole test | 332 # shard and run the whole test |
326 ss = ShardingSupervisor(args[0], num_shards, num_runs, options.color, | 333 ss = ShardingSupervisor(args[0], num_shards, num_runs, options.color, |
327 options.reorder, gtest_args) | 334 options.reorder, gtest_args) |
328 return ss.ShardTest() | 335 return ss.ShardTest() |
329 | 336 |
330 | 337 |
331 if __name__ == "__main__": | 338 if __name__ == "__main__": |
332 sys.exit(main()) | 339 sys.exit(main()) |
333 | 340 |
OLD | NEW |