blob: 03fc60bebd015913a3a71d80101eb7801713b20e [file] [log] [blame]
Dan Shi7e04fa82013-07-25 15:08:48 -07001#!/usr/bin/python
2#
3# Copyright (c) 2013 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 to validate code in prod branch before pushing to lab.
8
9The script runs push_to_prod suite to verify code in prod branch is ready to be
10pushed. Link to design document:
11https://docs.google.com/a/google.com/document/d/1JMz0xS3fZRSHMpFkkKAL_rxsdbNZomhHbC3B8L71uuI/edit
12
13To verify if prod branch can be pushed to lab, run following command in
14chromeos-autotest.cbf server:
Michael Liang52d9f1f2014-06-17 15:01:24 -070015/usr/local/autotest/site_utils/test_push.py -e someone@company.com
Dan Shi7e04fa82013-07-25 15:08:48 -070016
Dan Shi8df9c002016-03-08 15:37:39 -080017The script uses latest gandof canary build as test build by default.
Dan Shi7e04fa82013-07-25 15:08:48 -070018
19"""
20
21import argparse
22import getpass
Dan Shief1a5c02015-04-07 17:37:09 -070023import multiprocessing
Dan Shi7e04fa82013-07-25 15:08:48 -070024import os
25import re
26import subprocess
27import sys
Dan Shief1a5c02015-04-07 17:37:09 -070028import time
29import traceback
Dan Shi7e04fa82013-07-25 15:08:48 -070030import urllib2
31
32import common
Dan Shia8da7602014-05-09 15:18:15 -070033try:
34 from autotest_lib.frontend import setup_django_environment
35 from autotest_lib.frontend.afe import models
36except ImportError:
37 # Unittest may not have Django database configured and will fail to import.
38 pass
Dan Shi5fa602c2015-03-26 17:54:13 -070039from autotest_lib.client.common_lib import global_config
Dan Shi7e04fa82013-07-25 15:08:48 -070040from autotest_lib.server import site_utils
Dan Shi47d32882014-12-22 16:25:05 -080041from autotest_lib.server.cros import provision
Dan Shi7e04fa82013-07-25 15:08:48 -070042from autotest_lib.server.cros.dynamic_suite import frontend_wrappers
Kevin Cheng6e4c2642015-12-11 09:45:57 -080043from autotest_lib.server.hosts import factory
Dan Shi5fa602c2015-03-26 17:54:13 -070044from autotest_lib.site_utils import gmail_lib
Dan Shi47d32882014-12-22 16:25:05 -080045from autotest_lib.site_utils.suite_scheduler import constants
Dan Shi7e04fa82013-07-25 15:08:48 -070046
47CONFIG = global_config.global_config
48
Dan Shiefd403e2016-02-03 11:37:02 -080049AFE = frontend_wrappers.RetryingAFE(timeout_min=0.5, delay_sec=2)
50
Dan Shi7e04fa82013-07-25 15:08:48 -070051MAIL_FROM = 'chromeos-test@google.com'
Dan Shi5ba5d2e2014-05-09 13:47:00 -070052DEVSERVERS = CONFIG.get_config_value('CROS', 'dev_server', type=list,
53 default=[])
54BUILD_REGEX = '^R[\d]+-[\d]+\.[\d]+\.[\d]+$'
Dan Shi7e04fa82013-07-25 15:08:48 -070055RUN_SUITE_COMMAND = 'run_suite.py'
56PUSH_TO_PROD_SUITE = 'push_to_prod'
Jakob Juelich8f143912014-10-10 14:08:05 -070057DUMMY_SUITE = 'dummy'
Dan Shi7e04fa82013-07-25 15:08:48 -070058AU_SUITE = 'paygen_au_canary'
59
Fang Deng6dddf602014-04-17 17:01:47 -070060SUITE_JOB_START_INFO_REGEX = ('^.*Created suite job:.*'
61 'tab_id=view_job&object_id=(\d+)$')
Dan Shi7e04fa82013-07-25 15:08:48 -070062
63# Dictionary of test results keyed by test name regular expression.
64EXPECTED_TEST_RESULTS = {'^SERVER_JOB$': 'GOOD',
65 # This is related to dummy_Fail/control.dependency.
66 'dummy_Fail.dependency$': 'TEST_NA',
Dan Shidc9eb172014-12-09 16:05:02 -080067 'login_LoginSuccess.*': 'GOOD',
Dan Shi7e04fa82013-07-25 15:08:48 -070068 'platform_InstallTestImage_SERVER_JOB$': 'GOOD',
Dan Shi47d32882014-12-22 16:25:05 -080069 'provision_AutoUpdate.double': 'GOOD',
Dan Shi7e04fa82013-07-25 15:08:48 -070070 'dummy_Pass.*': 'GOOD',
71 'dummy_Fail.Fail$': 'FAIL',
72 'dummy_Fail.RetryFail$': 'FAIL',
73 'dummy_Fail.RetrySuccess': 'GOOD',
74 'dummy_Fail.Error$': 'ERROR',
75 'dummy_Fail.Warn$': 'WARN',
76 'dummy_Fail.NAError$': 'TEST_NA',
77 'dummy_Fail.Crash$': 'GOOD',
78 }
79
Jakob Juelich8f143912014-10-10 14:08:05 -070080EXPECTED_TEST_RESULTS_DUMMY = {'^SERVER_JOB$': 'GOOD',
81 'dummy_Pass.*': 'GOOD',
82 'dummy_Fail.Fail': 'FAIL',
83 'dummy_Fail.Warn': 'WARN',
84 'dummy_Fail.Crash': 'GOOD',
85 'dummy_Fail.Error': 'ERROR',
86 'dummy_Fail.NAError': 'TEST_NA',}
87
Dan Shi7e04fa82013-07-25 15:08:48 -070088EXPECTED_TEST_RESULTS_AU = {'SERVER_JOB$': 'GOOD',
Dan Shi15e6d722015-09-29 14:20:47 -070089 'autoupdate_EndToEndTest.paygen_au_canary_delta.*': 'GOOD',
90 'autoupdate_EndToEndTest.paygen_au_canary_full.*': 'GOOD',
Dan Shi7e04fa82013-07-25 15:08:48 -070091 }
92
Dan Shi7e04fa82013-07-25 15:08:48 -070093URL_HOST = CONFIG.get_config_value('SERVER', 'hostname', type=str)
94URL_PATTERN = CONFIG.get_config_value('CROS', 'log_url_pattern', type=str)
95
Dan Shidc9eb172014-12-09 16:05:02 -080096# Some test could be missing from the test results for various reasons. Add
97# such test in this list and explain the reason.
98IGNORE_MISSING_TESTS = [
99 # For latest build, npo_test_delta does not exist.
100 'autoupdate_EndToEndTest.npo_test_delta.*',
101 # For trybot build, nmo_test_delta does not exist.
102 'autoupdate_EndToEndTest.nmo_test_delta.*',
103 # Older build does not have login_LoginSuccess test in push_to_prod suite.
104 # TODO(dshi): Remove following lines after R41 is stable.
105 'login_LoginSuccess']
106
Dan Shi7e04fa82013-07-25 15:08:48 -0700107# Save all run_suite command output.
108run_suite_output = []
109
110class TestPushException(Exception):
111 """Exception to be raised when the test to push to prod failed."""
112 pass
113
Dan Shi5ba5d2e2014-05-09 13:47:00 -0700114
Kevin Cheng6e4c2642015-12-11 09:45:57 -0800115def powerwash_dut(hostname):
116 """Powerwash the dut with the given hostname.
117
118 @param hostname: hostname of the dut.
119 """
120 host = factory.create_host(hostname)
121 host.run('echo "fast safe" > '
122 '/mnt/stateful_partition/factory_install_reset')
123 host.run('reboot')
124 host.close()
125
126
Dan Shi8df9c002016-03-08 15:37:39 -0800127def get_default_build(devserver=None, board='gandof'):
Dan Shi5ba5d2e2014-05-09 13:47:00 -0700128 """Get the default build to be used for test.
129
130 @param devserver: devserver used to look for latest staged build. If value
131 is None, all devservers in config will be tried.
Dan Shi8df9c002016-03-08 15:37:39 -0800132 @param board: Name of board to be tested, default is gandof.
133 @return: Build to be tested, e.g., gandof-release/R36-5881.0.0
Dan Shi5ba5d2e2014-05-09 13:47:00 -0700134 """
135 LATEST_BUILD_URL_PATTERN = '%s/latestbuild?target=%s-release'
136 build = None
137 if not devserver:
138 for server in DEVSERVERS:
Dan Shief1a5c02015-04-07 17:37:09 -0700139 url = LATEST_BUILD_URL_PATTERN % (server, board)
140 build = urllib2.urlopen(url).read()
141 if build and re.match(BUILD_REGEX, build):
142 return '%s-release/%s' % (board, build)
Dan Shi5ba5d2e2014-05-09 13:47:00 -0700143
144 # If no devserver has any build staged for the given board, use the stable
145 # build in config.
146 build = CONFIG.get_config_value('CROS', 'stable_cros_version')
147 return '%s-release/%s' % (board, build)
148
149
Dan Shi7e04fa82013-07-25 15:08:48 -0700150def parse_arguments():
151 """Parse arguments for test_push tool.
152
153 @return: Parsed arguments.
154
155 """
156 parser = argparse.ArgumentParser()
Dan Shi8df9c002016-03-08 15:37:39 -0800157 parser.add_argument('-b', '--board', dest='board', default='gandof',
158 help='Default is gandof.')
Jakob Juelich8f143912014-10-10 14:08:05 -0700159 parser.add_argument('-sb', '--shard_board', dest='shard_board',
160 default='quawks',
161 help='Default is quawks.')
Dan Shi7e04fa82013-07-25 15:08:48 -0700162 parser.add_argument('-i', '--build', dest='build', default=None,
163 help='Default is the latest canary build of given '
164 'board. Must be a canary build, otherwise AU test '
Don Garrett10c73612016-06-01 12:42:18 -0700165 'will fail. (ex: gandolf-release/R53-8397.0.0)')
Jakob Juelich8f143912014-10-10 14:08:05 -0700166 parser.add_argument('-si', '--shard_build', dest='shard_build', default=None,
167 help='Default is the latest canary build of given '
168 'board. Must be a canary build, otherwise AU test '
169 'will fail.')
Dan Shi7e04fa82013-07-25 15:08:48 -0700170 parser.add_argument('-p', '--pool', dest='pool', default='bvt')
171 parser.add_argument('-u', '--num', dest='num', type=int, default=3,
172 help='Run on at most NUM machines.')
173 parser.add_argument('-f', '--file_bugs', dest='file_bugs', default='True',
174 help='File bugs on test failures. Must pass "True" or '
175 '"False" if used.')
176 parser.add_argument('-e', '--email', dest='email', default=None,
177 help='Email address for the notification to be sent to '
178 'after the script finished running.')
179 parser.add_argument('-d', '--devserver', dest='devserver',
Dan Shi5ba5d2e2014-05-09 13:47:00 -0700180 default=None,
Dan Shi7e04fa82013-07-25 15:08:48 -0700181 help='devserver to find what\'s the latest build.')
Shuqian Zhaod4864772015-08-06 09:46:22 -0700182 parser.add_argument('-t', '--timeout_min', dest='timeout_min', type=int,
183 default=24,
184 help='Time in mins to wait before abort the jobs we '
185 'are waiting on. Only for the asynchronous suites '
186 'triggered by create_and_return flag.')
Dan Shi7e04fa82013-07-25 15:08:48 -0700187
188 arguments = parser.parse_args(sys.argv[1:])
189
190 # Get latest canary build as default build.
191 if not arguments.build:
Dan Shi5ba5d2e2014-05-09 13:47:00 -0700192 arguments.build = get_default_build(arguments.devserver,
193 arguments.board)
Jakob Juelich8f143912014-10-10 14:08:05 -0700194 if not arguments.shard_build:
195 arguments.shard_build = get_default_build(arguments.devserver,
196 arguments.shard_board)
Dan Shi7e04fa82013-07-25 15:08:48 -0700197
198 return arguments
199
200
Shuqian Zhaod4864772015-08-06 09:46:22 -0700201def do_run_suite(suite_name, arguments, use_shard=False,
202 create_and_return=False):
Dan Shi7e04fa82013-07-25 15:08:48 -0700203 """Call run_suite to run a suite job, and return the suite job id.
204
205 The script waits the suite job to finish before returning the suite job id.
206 Also it will echo the run_suite output to stdout.
207
208 @param suite_name: Name of a suite, e.g., dummy.
209 @param arguments: Arguments for run_suite command.
Jakob Juelich8f143912014-10-10 14:08:05 -0700210 @param use_shard: If true, suite is scheduled for shard board.
Shuqian Zhaod4864772015-08-06 09:46:22 -0700211 @param create_and_return: If True, run_suite just creates the suite, print
212 the job id, then finish immediately.
Jakob Juelich8f143912014-10-10 14:08:05 -0700213
Dan Shi7e04fa82013-07-25 15:08:48 -0700214 @return: Suite job ID.
215
216 """
Jakob Juelich8f143912014-10-10 14:08:05 -0700217 if not use_shard:
218 board = arguments.board
219 build = arguments.build
220 else:
221 board = arguments.shard_board
222 build = arguments.shard_build
223
Dan Shi47d32882014-12-22 16:25:05 -0800224 # Remove cros-version label to force provision.
Dan Shiefd403e2016-02-03 11:37:02 -0800225 hosts = AFE.get_hosts(label=constants.Labels.BOARD_PREFIX+board)
Dan Shi47d32882014-12-22 16:25:05 -0800226 for host in hosts:
227 for label in [l for l in host.labels
228 if l.startswith(provision.CROS_VERSION_PREFIX)]:
Dan Shiefd403e2016-02-03 11:37:02 -0800229 AFE.run('host_remove_labels', id=host.id, labels=[label])
Dan Shi47d32882014-12-22 16:25:05 -0800230
Kevin Cheng6e4c2642015-12-11 09:45:57 -0800231 if use_shard and not create_and_return:
232 # Let's verify the repair flow and powerwash the duts. We can
233 # assume they're all cros hosts (valid assumption?) so powerwash
234 # will work.
235 try:
236 powerwash_dut(host.hostname)
237 except Exception as e:
238 raise TestPushException('Failed to powerwash dut %s. Make '
239 'sure the dut is working first. '
240 'Error: %s' % (host.hostname, e))
Dan Shiefd403e2016-02-03 11:37:02 -0800241 AFE.reverify_hosts(hostnames=[host.hostname])
Kevin Cheng6e4c2642015-12-11 09:45:57 -0800242
Dan Shief1a5c02015-04-07 17:37:09 -0700243 current_dir = os.path.dirname(os.path.realpath(__file__))
244 cmd = [os.path.join(current_dir, RUN_SUITE_COMMAND),
Dan Shi7e04fa82013-07-25 15:08:48 -0700245 '-s', suite_name,
Jakob Juelich8f143912014-10-10 14:08:05 -0700246 '-b', board,
247 '-i', build,
Dan Shi7e04fa82013-07-25 15:08:48 -0700248 '-p', arguments.pool,
249 '-u', str(arguments.num),
250 '-f', arguments.file_bugs]
Shuqian Zhaod4864772015-08-06 09:46:22 -0700251 if create_and_return:
252 cmd += ['-c']
Dan Shi7e04fa82013-07-25 15:08:48 -0700253
254 suite_job_id = None
Dan Shi7e04fa82013-07-25 15:08:48 -0700255
256 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
257 stderr=subprocess.STDOUT)
258
259 while True:
260 line = proc.stdout.readline()
261
262 # Break when run_suite process completed.
263 if not line and proc.poll() != None:
264 break
265 print line.rstrip()
266 run_suite_output.append(line.rstrip())
267
268 if not suite_job_id:
269 m = re.match(SUITE_JOB_START_INFO_REGEX, line)
270 if m and m.group(1):
271 suite_job_id = int(m.group(1))
272
273 if not suite_job_id:
274 raise TestPushException('Failed to retrieve suite job ID.')
Dan Shia8da7602014-05-09 15:18:15 -0700275
Shuqian Zhaod4864772015-08-06 09:46:22 -0700276 # If create_and_return specified, wait for the suite to finish.
277 if create_and_return:
278 end = time.time() + arguments.timeout_min * 60
Dan Shiefd403e2016-02-03 11:37:02 -0800279 while not AFE.get_jobs(id=suite_job_id, finished=True):
Shuqian Zhaod4864772015-08-06 09:46:22 -0700280 if time.time() < end:
281 time.sleep(10)
282 else:
Dan Shiefd403e2016-02-03 11:37:02 -0800283 AFE.run('abort_host_queue_entries', job=suite_job_id)
Shuqian Zhaod4864772015-08-06 09:46:22 -0700284 raise TestPushException(
285 'Asynchronous suite triggered by create_and_return '
286 'flag has timed out after %d mins. Aborting it.' %
287 arguments.timeout_min)
288
Dan Shia8da7602014-05-09 15:18:15 -0700289 print 'Suite job %s is completed.' % suite_job_id
Dan Shi7e04fa82013-07-25 15:08:48 -0700290 return suite_job_id
291
292
Dan Shia8da7602014-05-09 15:18:15 -0700293def check_dut_image(build, suite_job_id):
294 """Confirm all DUTs used for the suite are imaged to expected build.
295
296 @param build: Expected build to be imaged.
297 @param suite_job_id: job ID of the suite job.
298 @raise TestPushException: If a DUT does not have expected build imaged.
299 """
300 print 'Checking image installed in DUTs...'
301 job_ids = [job.id for job in
302 models.Job.objects.filter(parent_job_id=suite_job_id)]
303 hqes = [models.HostQueueEntry.objects.filter(job_id=job_id)[0]
304 for job_id in job_ids]
305 hostnames = set([hqe.host.hostname for hqe in hqes])
306 for hostname in hostnames:
Dan Shiefd403e2016-02-03 11:37:02 -0800307 found_build = site_utils.get_build_from_afe(hostname, AFE)
Dan Shia8da7602014-05-09 15:18:15 -0700308 if found_build != build:
309 raise TestPushException('DUT is not imaged properly. Host %s has '
310 'build %s, while build %s is expected.' %
311 (hostname, found_build, build))
312
313
Shuqian Zhaod4864772015-08-06 09:46:22 -0700314def test_suite(suite_name, expected_results, arguments, use_shard=False,
315 create_and_return=False):
Dan Shi7e04fa82013-07-25 15:08:48 -0700316 """Call run_suite to start a suite job and verify results.
317
318 @param suite_name: Name of a suite, e.g., dummy
319 @param expected_results: A dictionary of test name to test result.
320 @param arguments: Arguments for run_suite command.
Jakob Juelich8f143912014-10-10 14:08:05 -0700321 @param use_shard: If true, suite is scheduled for shard board.
Shuqian Zhaod4864772015-08-06 09:46:22 -0700322 @param create_and_return: If True, run_suite just creates the suite, print
323 the job id, then finish immediately.
Dan Shi7e04fa82013-07-25 15:08:48 -0700324 """
Shuqian Zhaod4864772015-08-06 09:46:22 -0700325 suite_job_id = do_run_suite(suite_name, arguments, use_shard,
326 create_and_return)
Dan Shi7e04fa82013-07-25 15:08:48 -0700327
Dan Shia8da7602014-05-09 15:18:15 -0700328 # Confirm all DUTs used for the suite are imaged to expected build.
Jakob Juelich8f143912014-10-10 14:08:05 -0700329 # hqe.host_id for jobs running in shard is not synced back to master db,
330 # therefore, skip verifying dut build for jobs running in shard.
331 if suite_name != AU_SUITE and not use_shard:
Dan Shia8da7602014-05-09 15:18:15 -0700332 check_dut_image(arguments.build, suite_job_id)
333
Dan Shi7e04fa82013-07-25 15:08:48 -0700334 # Find all tests and their status
Dan Shia8da7602014-05-09 15:18:15 -0700335 print 'Comparing test results...'
Dan Shi7e04fa82013-07-25 15:08:48 -0700336 TKO = frontend_wrappers.RetryingTKO(timeout_min=0.1, delay_sec=10)
337 test_views = site_utils.get_test_views_from_tko(suite_job_id, TKO)
338
339 mismatch_errors = []
340 extra_test_errors = []
341
342 found_keys = set()
343 for test_name,test_status in test_views.items():
344 print "%s%s" % (test_name.ljust(30), test_status)
345 test_found = False
346 for key,val in expected_results.items():
347 if re.search(key, test_name):
348 test_found = True
349 found_keys.add(key)
350 # TODO(dshi): result for this test is ignored until servo is
351 # added to a host accessible by cbf server (crbug.com/277109).
352 if key == 'platform_InstallTestImage_SERVER_JOB$':
353 continue
Dan Shi7e04fa82013-07-25 15:08:48 -0700354 if val != test_status:
355 error = ('%s Expected: [%s], Actual: [%s]' %
356 (test_name, val, test_status))
357 mismatch_errors.append(error)
358 if not test_found:
359 extra_test_errors.append(test_name)
360
361 missing_test_errors = set(expected_results.keys()) - found_keys
Dan Shidc9eb172014-12-09 16:05:02 -0800362 for exception in IGNORE_MISSING_TESTS:
363 try:
364 missing_test_errors.remove(exception)
365 except KeyError:
366 pass
367
Dan Shi7e04fa82013-07-25 15:08:48 -0700368 summary = []
369 if mismatch_errors:
370 summary.append(('Results of %d test(s) do not match expected '
371 'values:') % len(mismatch_errors))
372 summary.extend(mismatch_errors)
373 summary.append('\n')
374
375 if extra_test_errors:
376 summary.append('%d test(s) are not expected to be run:' %
377 len(extra_test_errors))
378 summary.extend(extra_test_errors)
379 summary.append('\n')
380
381 if missing_test_errors:
382 summary.append('%d test(s) are missing from the results:' %
383 len(missing_test_errors))
384 summary.extend(missing_test_errors)
385 summary.append('\n')
386
387 # Test link to log can be loaded.
388 job_name = '%s-%s' % (suite_job_id, getpass.getuser())
389 log_link = URL_PATTERN % (URL_HOST, job_name)
390 try:
391 urllib2.urlopen(log_link).read()
392 except urllib2.URLError:
393 summary.append('Failed to load page for link to log: %s.' % log_link)
394
395 if summary:
396 raise TestPushException('\n'.join(summary))
397
398
Dan Shief1a5c02015-04-07 17:37:09 -0700399def test_suite_wrapper(queue, suite_name, expected_results, arguments,
Shuqian Zhaod4864772015-08-06 09:46:22 -0700400 use_shard=False, create_and_return=False):
Dan Shief1a5c02015-04-07 17:37:09 -0700401 """Wrapper to call test_suite. Handle exception and pipe it to parent
402 process.
403
404 @param queue: Queue to save exception to be accessed by parent process.
405 @param suite_name: Name of a suite, e.g., dummy
406 @param expected_results: A dictionary of test name to test result.
407 @param arguments: Arguments for run_suite command.
408 @param use_shard: If true, suite is scheduled for shard board.
Shuqian Zhaod4864772015-08-06 09:46:22 -0700409 @param create_and_return: If True, run_suite just creates the suite, print
410 the job id, then finish immediately.
Dan Shief1a5c02015-04-07 17:37:09 -0700411 """
412 try:
Shuqian Zhaod4864772015-08-06 09:46:22 -0700413 test_suite(suite_name, expected_results, arguments, use_shard,
414 create_and_return)
Dan Shief1a5c02015-04-07 17:37:09 -0700415 except:
416 # Store the whole exc_info leads to a PicklingError.
417 except_type, except_value, tb = sys.exc_info()
418 queue.put((except_type, except_value, traceback.extract_tb(tb)))
419
420
Dan Shief1a5c02015-04-07 17:37:09 -0700421def check_queue(queue):
422 """Check the queue for any exception being raised.
423
424 @param queue: Queue used to store exception for parent process to access.
425 @raise: Any exception found in the queue.
426 """
427 if queue.empty():
428 return
429 exc_info = queue.get()
430 # Raise the exception with original backtrace.
431 print 'Original stack trace of the exception:\n%s' % exc_info[2]
432 raise exc_info[0](exc_info[1])
433
434
Dan Shi7e04fa82013-07-25 15:08:48 -0700435def main():
436 """Entry point for test_push script."""
437 arguments = parse_arguments()
438
439 try:
Dan Shief1a5c02015-04-07 17:37:09 -0700440 queue = multiprocessing.Queue()
441
442 push_to_prod_suite = multiprocessing.Process(
443 target=test_suite_wrapper,
444 args=(queue, PUSH_TO_PROD_SUITE, EXPECTED_TEST_RESULTS,
445 arguments))
446 push_to_prod_suite.start()
Jakob Juelich8f143912014-10-10 14:08:05 -0700447
Dan Shi7e04fa82013-07-25 15:08:48 -0700448 # TODO(dshi): Remove following line after crbug.com/267644 is fixed.
449 # Also, merge EXPECTED_TEST_RESULTS_AU to EXPECTED_TEST_RESULTS
Dan Shief1a5c02015-04-07 17:37:09 -0700450 au_suite = multiprocessing.Process(
451 target=test_suite_wrapper,
452 args=(queue, AU_SUITE, EXPECTED_TEST_RESULTS_AU,
453 arguments))
454 au_suite.start()
455
456 shard_suite = multiprocessing.Process(
457 target=test_suite_wrapper,
458 args=(queue, DUMMY_SUITE, EXPECTED_TEST_RESULTS_DUMMY,
459 arguments, True))
460 shard_suite.start()
461
Shuqian Zhaod4864772015-08-06 09:46:22 -0700462 # suite test with --create_and_return flag
463 asynchronous_suite = multiprocessing.Process(
464 target=test_suite_wrapper,
465 args=(queue, DUMMY_SUITE, EXPECTED_TEST_RESULTS_DUMMY,
466 arguments, True, True))
467 asynchronous_suite.start()
468
Dan Shief1a5c02015-04-07 17:37:09 -0700469 while (push_to_prod_suite.is_alive() or au_suite.is_alive() or
Shuqian Zhaod4864772015-08-06 09:46:22 -0700470 shard_suite.is_alive() or asynchronous_suite.is_alive()):
Dan Shief1a5c02015-04-07 17:37:09 -0700471 check_queue(queue)
Dan Shief1a5c02015-04-07 17:37:09 -0700472 time.sleep(5)
473
474 check_queue(queue)
475
476 push_to_prod_suite.join()
477 au_suite.join()
478 shard_suite.join()
Shuqian Zhaod4864772015-08-06 09:46:22 -0700479 asynchronous_suite.join()
Dan Shi7e04fa82013-07-25 15:08:48 -0700480 except Exception as e:
481 print 'Test for pushing to prod failed:\n'
482 print str(e)
483 # Send out email about the test failure.
484 if arguments.email:
Dan Shi5fa602c2015-03-26 17:54:13 -0700485 gmail_lib.send_email(
486 arguments.email,
487 'Test for pushing to prod failed. Do NOT push!',
488 ('Errors occurred during the test:\n\n%s\n\n' % str(e) +
489 'run_suite output:\n\n%s' % '\n'.join(run_suite_output)))
Dan Shi7e04fa82013-07-25 15:08:48 -0700490 raise
491
492 message = ('\nAll tests are completed successfully, prod branch is ready to'
493 ' be pushed.')
494 print message
495 # Send out email about test completed successfully.
496 if arguments.email:
Dan Shi5fa602c2015-03-26 17:54:13 -0700497 gmail_lib.send_email(
498 arguments.email,
499 'Test for pushing to prod completed successfully',
500 message)
Dan Shi7e04fa82013-07-25 15:08:48 -0700501
502
503if __name__ == '__main__':
504 sys.exit(main())