Chris Masone | 24b80f1 | 2012-02-14 14:18:01 -0800 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # |
| 3 | # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | |
| 7 | """Tool for running suites of tests and waiting for completion. |
| 8 | |
| 9 | The desired test suite will be scheduled with autotest, and then |
| 10 | this tool will block until the job is complete, printing a summary |
| 11 | at the end. Error conditions result in exceptions. |
| 12 | |
| 13 | This is intended for use only with Chrome OS test suits that leverage the |
| 14 | dynamic suite infrastructure in server/cros/dynamic_suite.py. |
| 15 | """ |
| 16 | |
| 17 | import optparse, time, sys |
| 18 | import common |
Chris Masone | 8ac6671 | 2012-02-15 14:21:02 -0800 | [diff] [blame] | 19 | from autotest_lib.server.cros import frontend_wrappers |
Chris Masone | 24b80f1 | 2012-02-14 14:18:01 -0800 | [diff] [blame] | 20 | |
| 21 | def parse_options(): |
| 22 | usage = "usage: %prog [options] control_file" |
| 23 | parser = optparse.OptionParser(usage=usage) |
| 24 | parser.add_option("-b", "--board", dest="board") |
| 25 | parser.add_option("-i", "--build", dest="build") |
Scott Zawalski | 6565017 | 2012-02-16 11:48:26 -0500 | [diff] [blame^] | 26 | parser.add_option("-p", "--pool", dest="pool", default=None) |
Chris Masone | 24b80f1 | 2012-02-14 14:18:01 -0800 | [diff] [blame] | 27 | parser.add_option("-s", "--suite_name", dest="name") |
Chris Masone | 8ac6671 | 2012-02-15 14:21:02 -0800 | [diff] [blame] | 28 | parser.add_option("-t", "--timeout_min", dest="timeout_min", default=30) |
| 29 | parser.add_option("-d", "--delay_sec", dest="delay_sec", default=10) |
Chris Masone | 24b80f1 | 2012-02-14 14:18:01 -0800 | [diff] [blame] | 30 | options, args = parser.parse_args() |
| 31 | return parser, options, args |
| 32 | |
| 33 | |
| 34 | def get_pretty_status(status): |
| 35 | if status == 'GOOD': |
| 36 | return '[ PASSED ]' |
| 37 | return '[ FAILED ]' |
| 38 | |
| 39 | |
| 40 | def status_is_relevant(status): |
| 41 | """ |
| 42 | Indicates whether the status of a given test is meaningful or not. |
| 43 | |
| 44 | @param status: frontend.TestStatus object to look at. |
| 45 | @return True if this is a test result worth looking at further. |
| 46 | """ |
| 47 | return not (status['test_name'].startswith('SERVER_JOB') or |
| 48 | status['test_name'].startswith('CLIENT_JOB')) |
| 49 | |
| 50 | |
| 51 | def main(): |
| 52 | parser, options, args = parse_options() |
| 53 | if args or not options.build or not options.board or not options.name: |
| 54 | parser.print_help() |
| 55 | return |
Chris Masone | 8ac6671 | 2012-02-15 14:21:02 -0800 | [diff] [blame] | 56 | afe = frontend_wrappers.RetryingAFE(timeout_min=options.timeout_min, |
| 57 | delay_sec=options.delay_sec) |
Chris Masone | 24b80f1 | 2012-02-14 14:18:01 -0800 | [diff] [blame] | 58 | job_id = afe.run('create_suite_job', |
| 59 | suite_name=options.name, |
| 60 | board=options.board, |
Scott Zawalski | 6565017 | 2012-02-16 11:48:26 -0500 | [diff] [blame^] | 61 | build=options.build, |
| 62 | pool=options.pool) |
Chris Masone | 8ac6671 | 2012-02-15 14:21:02 -0800 | [diff] [blame] | 63 | TKO = frontend_wrappers.RetryingTKO(timeout_min=options.timeout_min, |
| 64 | delay_sec=options.delay_sec) |
Chris Masone | 24b80f1 | 2012-02-14 14:18:01 -0800 | [diff] [blame] | 65 | # Return code that will be sent back to autotest_rpc_server.py |
| 66 | code = 0 |
| 67 | while True: |
| 68 | if not afe.get_jobs(id=job_id, finished=True): |
| 69 | time.sleep(1) |
| 70 | continue |
| 71 | views = filter(status_is_relevant, |
| 72 | TKO.run('get_test_views', afe_job_id=job_id)) |
| 73 | width = len(max(map(lambda x: x['test_name'], views), key=len)) + 3 |
| 74 | for entry in views: |
| 75 | test_entry = entry['test_name'].ljust(width) |
| 76 | print "%s%s" % (test_entry, get_pretty_status(entry['status'])) |
| 77 | if entry['status'] != 'GOOD': |
| 78 | print "%s %s: %s" % (test_entry, |
| 79 | entry['status'], |
| 80 | entry['reason']) |
| 81 | code = 1 |
| 82 | break |
| 83 | return code |
| 84 | |
| 85 | if __name__ == "__main__": |
| 86 | sys.exit(main()) |