blob: fab12658f1976cc5409c5bfb17f8e9a2542a143d [file] [log] [blame]
Chris Masone24b80f12012-02-14 14:18:01 -08001#!/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
9The desired test suite will be scheduled with autotest, and then
10this tool will block until the job is complete, printing a summary
11at the end. Error conditions result in exceptions.
12
13This is intended for use only with Chrome OS test suits that leverage the
14dynamic suite infrastructure in server/cros/dynamic_suite.py.
15"""
16
17import optparse, time, sys
18import common
Chris Masone8ac66712012-02-15 14:21:02 -080019from autotest_lib.server.cros import frontend_wrappers
Chris Masone24b80f12012-02-14 14:18:01 -080020
21def 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 Zawalski65650172012-02-16 11:48:26 -050026 parser.add_option("-p", "--pool", dest="pool", default=None)
Chris Masone24b80f12012-02-14 14:18:01 -080027 parser.add_option("-s", "--suite_name", dest="name")
Chris Masone8ac66712012-02-15 14:21:02 -080028 parser.add_option("-t", "--timeout_min", dest="timeout_min", default=30)
29 parser.add_option("-d", "--delay_sec", dest="delay_sec", default=10)
Chris Masone24b80f12012-02-14 14:18:01 -080030 options, args = parser.parse_args()
31 return parser, options, args
32
33
34def get_pretty_status(status):
35 if status == 'GOOD':
36 return '[ PASSED ]'
37 return '[ FAILED ]'
38
39
40def 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
51def 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 Masone8ac66712012-02-15 14:21:02 -080056 afe = frontend_wrappers.RetryingAFE(timeout_min=options.timeout_min,
57 delay_sec=options.delay_sec)
Chris Masone24b80f12012-02-14 14:18:01 -080058 job_id = afe.run('create_suite_job',
59 suite_name=options.name,
60 board=options.board,
Scott Zawalski65650172012-02-16 11:48:26 -050061 build=options.build,
62 pool=options.pool)
Chris Masone8ac66712012-02-15 14:21:02 -080063 TKO = frontend_wrappers.RetryingTKO(timeout_min=options.timeout_min,
64 delay_sec=options.delay_sec)
Chris Masone24b80f12012-02-14 14:18:01 -080065 # 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
85if __name__ == "__main__":
86 sys.exit(main())