OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium OS 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 """Runs tests on VMs in parallel.""" | 6 """Runs tests on VMs in parallel.""" |
7 | 7 |
8 import optparse | 8 import optparse |
9 import os | 9 import os |
10 import subprocess | 10 import subprocess |
11 import sys | 11 import sys |
12 import tempfile | 12 import tempfile |
13 | 13 |
14 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib')) | 14 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib')) |
15 from cros_build_lib import Die | 15 from cros_build_lib import Die |
16 from cros_build_lib import Info | 16 from cros_build_lib import Info |
17 | 17 |
18 | 18 |
19 _DEFAULT_BASE_SSH_PORT = 9222 | 19 _DEFAULT_BASE_SSH_PORT = 9222 |
20 | 20 |
21 class ParallelTestRunner(object): | 21 class ParallelTestRunner(object): |
22 """Runs tests on VMs in parallel. | 22 """Runs tests on VMs in parallel. |
23 | 23 |
24 This class is a simple wrapper around cros_run_vm_test that provides an easy | 24 This class is a simple wrapper around cros_run_vm_test that provides an easy |
25 way to spawn several test instances in parallel and aggregate the results when | 25 way to spawn several test instances in parallel and aggregate the results when |
26 the tests complete. | 26 the tests complete. Only uses emerged autotest packaged, as trying to pull |
| 27 from the caller's source tree creates races that cause tests to fail. |
27 """ | 28 """ |
28 | 29 |
29 def __init__(self, tests, base_ssh_port=_DEFAULT_BASE_SSH_PORT, board=None, | 30 def __init__(self, tests, base_ssh_port=_DEFAULT_BASE_SSH_PORT, board=None, |
30 image_path=None, order_output=False, quiet=False, | 31 image_path=None, order_output=False, quiet=False, |
31 results_dir_root=None, use_emerged=False): | 32 results_dir_root=None): |
32 """Constructs and initializes the test runner class. | 33 """Constructs and initializes the test runner class. |
33 | 34 |
34 Args: | 35 Args: |
35 tests: A list of test names (see run_remote_tests.sh). | 36 tests: A list of test names (see run_remote_tests.sh). |
36 base_ssh_port: The base SSH port. Spawned VMs listen to localhost SSH | 37 base_ssh_port: The base SSH port. Spawned VMs listen to localhost SSH |
37 ports incrementally allocated starting from the base one. | 38 ports incrementally allocated starting from the base one. |
38 board: The target board. If none, cros_run_vm_tests will use the default | 39 board: The target board. If none, cros_run_vm_tests will use the default |
39 board. | 40 board. |
40 image_path: Full path to the VM image. If none, cros_run_vm_tests will use | 41 image_path: Full path to the VM image. If none, cros_run_vm_tests will use |
41 the latest image. | 42 the latest image. |
42 order_output: If True, output of individual VMs will be piped to | 43 order_output: If True, output of individual VMs will be piped to |
43 temporary files and emitted at the end. | 44 temporary files and emitted at the end. |
44 quiet: Emits no output from the VMs. Forces --order_output to be false, | 45 quiet: Emits no output from the VMs. Forces --order_output to be false, |
45 and requires specifying --results_dir_root | 46 and requires specifying --results_dir_root |
46 results_dir_root: The results directory root. If provided, the results | 47 results_dir_root: The results directory root. If provided, the results |
47 directory root for each test will be created under it with the SSH port | 48 directory root for each test will be created under it with the SSH port |
48 appended to the test name. | 49 appended to the test name. |
49 use_emerged: Force use of emerged autotest packages. | |
50 """ | 50 """ |
51 self._tests = tests | 51 self._tests = tests |
52 self._base_ssh_port = base_ssh_port | 52 self._base_ssh_port = base_ssh_port |
53 self._board = board | 53 self._board = board |
54 self._image_path = image_path | 54 self._image_path = image_path |
55 self._order_output = order_output | 55 self._order_output = order_output |
56 self._quiet = quiet | 56 self._quiet = quiet |
57 self._results_dir_root = results_dir_root | 57 self._results_dir_root = results_dir_root |
58 self._use_emerged = use_emerged | |
59 | 58 |
60 def _SpawnTests(self): | 59 def _SpawnTests(self): |
61 """Spawns VMs and starts the test runs on them. | 60 """Spawns VMs and starts the test runs on them. |
62 | 61 |
63 Runs all tests in |self._tests|. Each test is executed on a separate VM. | 62 Runs all tests in |self._tests|. Each test is executed on a separate VM. |
64 | 63 |
65 Returns: | 64 Returns: |
66 A list of test process info objects containing the following dictionary | 65 A list of test process info objects containing the following dictionary |
67 entries: | 66 entries: |
68 'test': the test name; | 67 'test': the test name; |
69 'proc': the Popen process instance for this test run. | 68 'proc': the Popen process instance for this test run. |
70 """ | 69 """ |
71 ssh_port = self._base_ssh_port | 70 ssh_port = self._base_ssh_port |
72 spawned_tests = [] | 71 spawned_tests = [] |
73 for test in self._tests: | 72 for test in self._tests: |
74 args = [ os.path.join(os.path.dirname(__file__), 'cros_run_vm_test'), | 73 args = [ os.path.join(os.path.dirname(__file__), 'cros_run_vm_test'), |
75 '--snapshot', # The image is shared so don't modify it. | 74 '--snapshot', # The image is shared so don't modify it. |
76 '--no_graphics', | 75 '--no_graphics', |
| 76 '--use_emerged', |
77 '--ssh_port=%d' % ssh_port ] | 77 '--ssh_port=%d' % ssh_port ] |
78 if self._board: args.append('--board=%s' % self._board) | 78 if self._board: args.append('--board=%s' % self._board) |
79 if self._image_path: args.append('--image_path=%s' % self._image_path) | 79 if self._image_path: args.append('--image_path=%s' % self._image_path) |
80 results_dir = None | 80 results_dir = None |
81 if self._results_dir_root: | 81 if self._results_dir_root: |
82 results_dir = '%s/%s.%d' % (self._results_dir_root, test, ssh_port) | 82 results_dir = '%s/%s.%d' % (self._results_dir_root, test, ssh_port) |
83 args.append('--results_dir_root=%s' % results_dir) | 83 args.append('--results_dir_root=%s' % results_dir) |
84 if self._use_emerged: args.append('--use_emerged') | |
85 args.append(test) | 84 args.append(test) |
86 Info('Running %r...' % args) | 85 Info('Running %r...' % args) |
87 output = None | 86 output = None |
88 if self._quiet: | 87 if self._quiet: |
89 output = open('/dev/null', mode='w') | 88 output = open('/dev/null', mode='w') |
90 Info('Log files are in %s' % results_dir) | 89 Info('Log files are in %s' % results_dir) |
91 elif self._order_output: | 90 elif self._order_output: |
92 output = tempfile.NamedTemporaryFile(prefix='parallel_vm_test_') | 91 output = tempfile.NamedTemporaryFile(prefix='parallel_vm_test_') |
93 Info('Piping output to %s.' % output.name) | 92 Info('Piping output to %s.' % output.name) |
94 proc = subprocess.Popen(args, stdout=output, stderr=output) | 93 proc = subprocess.Popen(args, stdout=output, stderr=output) |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 parser.add_option('--order_output', action='store_true', default=False, | 148 parser.add_option('--order_output', action='store_true', default=False, |
150 help='Rather than emitting interleaved progress output ' | 149 help='Rather than emitting interleaved progress output ' |
151 'from the individual VMs, accumulate the outputs in ' | 150 'from the individual VMs, accumulate the outputs in ' |
152 'temporary files and dump them at the end.') | 151 'temporary files and dump them at the end.') |
153 parser.add_option('--quiet', action='store_true', default=False, | 152 parser.add_option('--quiet', action='store_true', default=False, |
154 help='Emits no output from the VMs. Forces --order_output' | 153 help='Emits no output from the VMs. Forces --order_output' |
155 'to be false, and requires specifying --results_dir_root') | 154 'to be false, and requires specifying --results_dir_root') |
156 parser.add_option('--results_dir_root', | 155 parser.add_option('--results_dir_root', |
157 help='Root results directory. If none specified, each test ' | 156 help='Root results directory. If none specified, each test ' |
158 'will store its results in a separate /tmp directory.') | 157 'will store its results in a separate /tmp directory.') |
159 parser.add_option('--use_emerged', action='store_true', default=False, | |
160 help='Force use of emerged autotest packages') | |
161 (options, args) = parser.parse_args() | 158 (options, args) = parser.parse_args() |
162 | 159 |
163 if not args: | 160 if not args: |
164 parser.print_help() | 161 parser.print_help() |
165 Die('no tests provided') | 162 Die('no tests provided') |
166 | 163 |
167 if options.quiet: | 164 if options.quiet: |
168 options.order_output = False | 165 options.order_output = False |
169 if not options.results_dir_root: | 166 if not options.results_dir_root: |
170 Die('--quiet requires --results_dir_root') | 167 Die('--quiet requires --results_dir_root') |
171 runner = ParallelTestRunner(args, options.base_ssh_port, options.board, | 168 runner = ParallelTestRunner(args, options.base_ssh_port, options.board, |
172 options.image_path, options.order_output, | 169 options.image_path, options.order_output, |
173 options.quiet, options.results_dir_root, | 170 options.quiet, options.results_dir_root) |
174 options.use_emerged) | |
175 runner.Run() | 171 runner.Run() |
176 | 172 |
177 | 173 |
178 if __name__ == '__main__': | 174 if __name__ == '__main__': |
179 main() | 175 main() |
OLD | NEW |