test_push.py revision ef1a5c0de1a2cfb039574f9d011d256114bda99a
17e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi#!/usr/bin/python
27e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi#
37e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
47e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi# Use of this source code is governed by a BSD-style license that can be
57e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi# found in the LICENSE file.
67e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
77e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi"""Tool to validate code in prod branch before pushing to lab.
87e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
97e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiThe script runs push_to_prod suite to verify code in prod branch is ready to be
107e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shipushed. Link to design document:
117e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shihttps://docs.google.com/a/google.com/document/d/1JMz0xS3fZRSHMpFkkKAL_rxsdbNZomhHbC3B8L71uuI/edit
127e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
137e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiTo verify if prod branch can be pushed to lab, run following command in
147e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shichromeos-autotest.cbf server:
1552d9f1ff5cadba2828e64288afb5491122e3078dMichael Liang/usr/local/autotest/site_utils/test_push.py -e someone@company.com
167e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
177e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiThe script uses latest stumpy canary build as test build by default.
187e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
197e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi"""
207e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
217e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiimport argparse
227e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiimport getpass
23ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shiimport multiprocessing
247e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiimport os
257e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiimport re
267e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiimport subprocess
277e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiimport sys
28ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shiimport time
29ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shiimport traceback
307e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiimport urllib2
317e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
327e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiimport common
33a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shitry:
34a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    from autotest_lib.frontend import setup_django_environment
35a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    from autotest_lib.frontend.afe import models
36a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shiexcept ImportError:
37a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    # Unittest may not have Django database configured and will fail to import.
38a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    pass
395fa602cbd7787ff604758f03b71da19b66263ca1Dan Shifrom autotest_lib.client.common_lib import global_config
407e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shifrom autotest_lib.server import site_utils
4147d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shifrom autotest_lib.server.cros import provision
427e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shifrom autotest_lib.server.cros.dynamic_suite import frontend_wrappers
437e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shifrom autotest_lib.server.cros.dynamic_suite import reporting
44a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shifrom autotest_lib.server.hosts import cros_host
455fa602cbd7787ff604758f03b71da19b66263ca1Dan Shifrom autotest_lib.site_utils import gmail_lib
4647d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shifrom autotest_lib.site_utils.suite_scheduler import constants
477e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
487e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiCONFIG = global_config.global_config
497e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
507e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiMAIL_FROM = 'chromeos-test@google.com'
515ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan ShiDEVSERVERS = CONFIG.get_config_value('CROS', 'dev_server', type=list,
525ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi                                     default=[])
535ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan ShiBUILD_REGEX = '^R[\d]+-[\d]+\.[\d]+\.[\d]+$'
547e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiRUN_SUITE_COMMAND = 'run_suite.py'
557e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiPUSH_TO_PROD_SUITE = 'push_to_prod'
568f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob JuelichDUMMY_SUITE = 'dummy'
577e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiAU_SUITE = 'paygen_au_canary'
587e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
596dddf60ffaf30337e17d393eb797f67f2419f02bFang DengSUITE_JOB_START_INFO_REGEX = ('^.*Created suite job:.*'
606dddf60ffaf30337e17d393eb797f67f2419f02bFang Deng                              'tab_id=view_job&object_id=(\d+)$')
617e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
627e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi# Dictionary of test results keyed by test name regular expression.
637e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiEXPECTED_TEST_RESULTS = {'^SERVER_JOB$':                 'GOOD',
647e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         # This is related to dummy_Fail/control.dependency.
657e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Fail.dependency$':       'TEST_NA',
66dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi                         'login_LoginSuccess.*':         'GOOD',
677e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'platform_InstallTestImage_SERVER_JOB$': 'GOOD',
6847d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi                         'provision_AutoUpdate.double':  'GOOD',
697e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Pass.*':                 'GOOD',
707e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Fail.Fail$':             'FAIL',
717e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Fail.RetryFail$':        'FAIL',
727e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Fail.RetrySuccess':      'GOOD',
737e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Fail.Error$':            'ERROR',
747e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Fail.Warn$':             'WARN',
757e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Fail.NAError$':          'TEST_NA',
767e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         'dummy_Fail.Crash$':            'GOOD',
777e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                         }
787e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
798f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob JuelichEXPECTED_TEST_RESULTS_DUMMY = {'^SERVER_JOB$':       'GOOD',
808f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                               'dummy_Pass.*':       'GOOD',
818f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                               'dummy_Fail.Fail':    'FAIL',
828f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                               'dummy_Fail.Warn':    'WARN',
838f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                               'dummy_Fail.Crash':   'GOOD',
848f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                               'dummy_Fail.Error':   'ERROR',
858f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                               'dummy_Fail.NAError': 'TEST_NA',}
868f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich
877e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiEXPECTED_TEST_RESULTS_AU = {'SERVER_JOB$':                        'GOOD',
887e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi         'autoupdate_EndToEndTest.paygen_au_canary_test_delta.*': 'GOOD',
897e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi         'autoupdate_EndToEndTest.paygen_au_canary_test_full.*':  'GOOD',
907e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi         }
917e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
927e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi# Anchor for the auto-filed bug for dummy_Fail tests.
937e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiBUG_ANCHOR = 'TestFailure(push_to_prod,dummy_Fail.Fail,always fail)'
947e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
957e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiURL_HOST = CONFIG.get_config_value('SERVER', 'hostname', type=str)
967e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan ShiURL_PATTERN = CONFIG.get_config_value('CROS', 'log_url_pattern', type=str)
977e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
98dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi# Some test could be missing from the test results for various reasons. Add
99dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi# such test in this list and explain the reason.
100dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan ShiIGNORE_MISSING_TESTS = [
101dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi    # For latest build, npo_test_delta does not exist.
102dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi    'autoupdate_EndToEndTest.npo_test_delta.*',
103dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi    # For trybot build, nmo_test_delta does not exist.
104dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi    'autoupdate_EndToEndTest.nmo_test_delta.*',
105dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi    # Older build does not have login_LoginSuccess test in push_to_prod suite.
106dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi    # TODO(dshi): Remove following lines after R41 is stable.
107dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi    'login_LoginSuccess']
108dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi
1097e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi# Save all run_suite command output.
1107e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shirun_suite_output = []
1117e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1127e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiclass TestPushException(Exception):
1137e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """Exception to be raised when the test to push to prod failed."""
1147e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    pass
1157e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1165ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi
1175ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shidef get_default_build(devserver=None, board='stumpy'):
1185ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    """Get the default build to be used for test.
1195ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi
1205ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    @param devserver: devserver used to look for latest staged build. If value
1215ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi                      is None, all devservers in config will be tried.
1225ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    @param board: Name of board to be tested, default is stumpy.
1235ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    @return: Build to be tested, e.g., stumpy-release/R36-5881.0.0
1245ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    """
1255ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    LATEST_BUILD_URL_PATTERN = '%s/latestbuild?target=%s-release'
1265ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    build = None
1275ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    if not devserver:
1285ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi        for server in DEVSERVERS:
129ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi            url = LATEST_BUILD_URL_PATTERN % (server, board)
130ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi            build = urllib2.urlopen(url).read()
131ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi            if build and re.match(BUILD_REGEX, build):
132ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                return '%s-release/%s' % (board, build)
1335ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi
1345ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    # If no devserver has any build staged for the given board, use the stable
1355ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    # build in config.
1365ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    build = CONFIG.get_config_value('CROS', 'stable_cros_version')
1375ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi    return '%s-release/%s' % (board, build)
1385ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi
1395ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi
1407e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shidef parse_arguments():
1417e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """Parse arguments for test_push tool.
1427e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1437e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @return: Parsed arguments.
1447e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1457e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """
1467e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    parser = argparse.ArgumentParser()
1477e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    parser.add_argument('-b', '--board', dest='board', default='stumpy',
1487e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                        help='Default is stumpy.')
1498f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    parser.add_argument('-sb', '--shard_board', dest='shard_board',
1508f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                        default='quawks',
1518f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                        help='Default is quawks.')
1527e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    parser.add_argument('-i', '--build', dest='build', default=None,
1537e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                        help='Default is the latest canary build of given '
1547e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                             'board. Must be a canary build, otherwise AU test '
1557e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                             'will fail.')
1568f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    parser.add_argument('-si', '--shard_build', dest='shard_build', default=None,
1578f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                        help='Default is the latest canary build of given '
1588f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                             'board. Must be a canary build, otherwise AU test '
1598f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                             'will fail.')
1607e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    parser.add_argument('-p', '--pool', dest='pool', default='bvt')
1617e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    parser.add_argument('-u', '--num', dest='num', type=int, default=3,
1627e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                        help='Run on at most NUM machines.')
1637e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    parser.add_argument('-f', '--file_bugs', dest='file_bugs', default='True',
1647e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                        help='File bugs on test failures. Must pass "True" or '
1657e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                             '"False" if used.')
1667e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    parser.add_argument('-e', '--email', dest='email', default=None,
1677e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                        help='Email address for the notification to be sent to '
1687e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                             'after the script finished running.')
1697e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    parser.add_argument('-d', '--devserver', dest='devserver',
1705ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi                        default=None,
1717e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                        help='devserver to find what\'s the latest build.')
1727e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1737e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    arguments = parser.parse_args(sys.argv[1:])
1747e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1757e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    # Get latest canary build as default build.
1767e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if not arguments.build:
1775ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi        arguments.build = get_default_build(arguments.devserver,
1785ba5d2e1433f180e2eaeac5721547e6f61ab30a7Dan Shi                                            arguments.board)
1798f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    if not arguments.shard_build:
1808f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich        arguments.shard_build = get_default_build(arguments.devserver,
1818f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich                                                  arguments.shard_board)
1827e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1837e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    return arguments
1847e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1857e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1868f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelichdef do_run_suite(suite_name, arguments, use_shard=False):
1877e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """Call run_suite to run a suite job, and return the suite job id.
1887e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1897e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    The script waits the suite job to finish before returning the suite job id.
1907e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    Also it will echo the run_suite output to stdout.
1917e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1927e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @param suite_name: Name of a suite, e.g., dummy.
1937e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @param arguments: Arguments for run_suite command.
1948f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    @param use_shard: If true, suite is scheduled for shard board.
1958f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich
1967e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @return: Suite job ID.
1977e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
1987e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """
1998f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    if not use_shard:
2008f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich        board = arguments.board
2018f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich        build = arguments.build
2028f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    else:
2038f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich        board = arguments.shard_board
2048f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich        build = arguments.shard_build
2058f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich
20647d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi    # Remove cros-version label to force provision.
20747d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi    afe = frontend_wrappers.RetryingAFE(timeout_min=0.1, delay_sec=10)
20847d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi    hosts = afe.get_hosts(label=constants.Labels.BOARD_PREFIX+board)
20947d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi    for host in hosts:
21047d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi        for label in [l for l in host.labels
21147d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi                      if l.startswith(provision.CROS_VERSION_PREFIX)]:
21247d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi            afe.run('host_remove_labels', id=host.id, labels=[label])
21347d3288e3ad2feba6c866ec369f2cfa8abb9346aDan Shi
214ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    current_dir = os.path.dirname(os.path.realpath(__file__))
215ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    cmd = [os.path.join(current_dir, RUN_SUITE_COMMAND),
2167e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi           '-s', suite_name,
2178f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich           '-b', board,
2188f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich           '-i', build,
2197e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi           '-p', arguments.pool,
2207e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi           '-u', str(arguments.num),
2217e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi           '-f', arguments.file_bugs]
2227e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2237e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    suite_job_id = None
2247e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2257e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
2267e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                            stderr=subprocess.STDOUT)
2277e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2287e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    while True:
2297e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        line = proc.stdout.readline()
2307e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2317e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        # Break when run_suite process completed.
2327e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        if not line and proc.poll() != None:
2337e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi            break
2347e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        print line.rstrip()
2357e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        run_suite_output.append(line.rstrip())
2367e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2377e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        if not suite_job_id:
2387e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi            m = re.match(SUITE_JOB_START_INFO_REGEX, line)
2397e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi            if m and m.group(1):
2407e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                suite_job_id = int(m.group(1))
2417e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2427e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if not suite_job_id:
2437e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        raise TestPushException('Failed to retrieve suite job ID.')
244a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi
245a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    print 'Suite job %s is completed.' % suite_job_id
2467e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    return suite_job_id
2477e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2487e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
249a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shidef check_dut_image(build, suite_job_id):
250a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    """Confirm all DUTs used for the suite are imaged to expected build.
251a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi
252a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    @param build: Expected build to be imaged.
253a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    @param suite_job_id: job ID of the suite job.
254a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    @raise TestPushException: If a DUT does not have expected build imaged.
255a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    """
256a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    print 'Checking image installed in DUTs...'
257a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    job_ids = [job.id for job in
258a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi               models.Job.objects.filter(parent_job_id=suite_job_id)]
259a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    hqes = [models.HostQueueEntry.objects.filter(job_id=job_id)[0]
260a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi            for job_id in job_ids]
261a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    hostnames = set([hqe.host.hostname for hqe in hqes])
262a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    for hostname in hostnames:
263a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi        host = cros_host.CrosHost(hostname)
264a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi        found_build = host.get_build()
265a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi        if found_build != build:
266a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi            raise TestPushException('DUT is not imaged properly. Host %s has '
267a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi                                    'build %s, while build %s is expected.' %
268a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi                                    (hostname, found_build, build))
269a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi
270a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi
2718f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelichdef test_suite(suite_name, expected_results, arguments, use_shard=False):
2727e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """Call run_suite to start a suite job and verify results.
2737e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2747e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @param suite_name: Name of a suite, e.g., dummy
2757e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @param expected_results: A dictionary of test name to test result.
2767e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @param arguments: Arguments for run_suite command.
2778f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    @param use_shard: If true, suite is scheduled for shard board.
2787e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """
2798f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    suite_job_id = do_run_suite(suite_name, arguments, use_shard)
2807e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
281a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    # Confirm all DUTs used for the suite are imaged to expected build.
2828f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    # hqe.host_id for jobs running in shard is not synced back to master db,
2838f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    # therefore, skip verifying dut build for jobs running in shard.
2848f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich    if suite_name != AU_SUITE and not use_shard:
285a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi        check_dut_image(arguments.build, suite_job_id)
286a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi
2877e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    # Find all tests and their status
288a8da7602ee0113004ef1b7213eab5599e3236ae7Dan Shi    print 'Comparing test results...'
2897e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    TKO = frontend_wrappers.RetryingTKO(timeout_min=0.1, delay_sec=10)
2907e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    test_views = site_utils.get_test_views_from_tko(suite_job_id, TKO)
2917e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2927e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    mismatch_errors = []
2937e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    extra_test_errors = []
2947e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
2957e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    found_keys = set()
2967e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    for test_name,test_status in test_views.items():
2977e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        print "%s%s" % (test_name.ljust(30), test_status)
2987e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        test_found = False
2997e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        for key,val in expected_results.items():
3007e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi            if re.search(key, test_name):
3017e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                test_found = True
3027e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                found_keys.add(key)
3037e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                # TODO(dshi): result for this test is ignored until servo is
3047e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                # added to a host accessible by cbf server (crbug.com/277109).
3057e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                if key == 'platform_InstallTestImage_SERVER_JOB$':
3067e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                    continue
3077e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                if val != test_status:
3087e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                    error = ('%s Expected: [%s], Actual: [%s]' %
3097e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                             (test_name, val, test_status))
3107e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                    mismatch_errors.append(error)
3117e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        if not test_found:
3127e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi            extra_test_errors.append(test_name)
3137e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3147e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    missing_test_errors = set(expected_results.keys()) - found_keys
315dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi    for exception in IGNORE_MISSING_TESTS:
316dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi        try:
317dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi            missing_test_errors.remove(exception)
318dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi        except KeyError:
319dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi            pass
320dc9eb17ac97d5407a2ebce0510fe0311b3f18bfcDan Shi
3217e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    summary = []
3227e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if mismatch_errors:
3237e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.append(('Results of %d test(s) do not match expected '
3247e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                        'values:') % len(mismatch_errors))
3257e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.extend(mismatch_errors)
3267e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.append('\n')
3277e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3287e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if extra_test_errors:
3297e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.append('%d test(s) are not expected to be run:' %
3307e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                       len(extra_test_errors))
3317e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.extend(extra_test_errors)
3327e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.append('\n')
3337e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3347e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if missing_test_errors:
3357e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.append('%d test(s) are missing from the results:' %
3367e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                       len(missing_test_errors))
3377e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.extend(missing_test_errors)
3387e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.append('\n')
3397e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3407e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    # Test link to log can be loaded.
3417e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    job_name = '%s-%s' % (suite_job_id, getpass.getuser())
3427e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    log_link = URL_PATTERN % (URL_HOST, job_name)
3437e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    try:
3447e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        urllib2.urlopen(log_link).read()
3457e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    except urllib2.URLError:
3467e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        summary.append('Failed to load page for link to log: %s.' % log_link)
3477e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3487e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if summary:
3497e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        raise TestPushException('\n'.join(summary))
3507e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3517e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
352ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shidef test_suite_wrapper(queue, suite_name, expected_results, arguments,
353ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                       use_shard=False):
354ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    """Wrapper to call test_suite. Handle exception and pipe it to parent
355ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    process.
356ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
357ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    @param queue: Queue to save exception to be accessed by parent process.
358ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    @param suite_name: Name of a suite, e.g., dummy
359ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    @param expected_results: A dictionary of test name to test result.
360ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    @param arguments: Arguments for run_suite command.
361ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    @param use_shard: If true, suite is scheduled for shard board.
362ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    """
363ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    try:
364ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        test_suite(suite_name, expected_results, arguments, use_shard)
365ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    except:
366ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        # Store the whole exc_info leads to a PicklingError.
367ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        except_type, except_value, tb = sys.exc_info()
368ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        queue.put((except_type, except_value, traceback.extract_tb(tb)))
369ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
370ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
3717e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shidef close_bug():
3727e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """Close all existing bugs filed for dummy_Fail.
3737e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3747e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @return: A list of issue ids to be used in check_bug_filed_and_deduped.
3757e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """
3767e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    old_issue_ids = []
3777e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    reporter = reporting.Reporter()
3787e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    while True:
3797e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        issue = reporter.find_issue_by_marker(BUG_ANCHOR)
3807e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        if not issue:
3817e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi            return old_issue_ids
3827e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        if issue.id in old_issue_ids:
3837e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi            raise TestPushException('Failed to close issue %d' % issue.id)
3847e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        old_issue_ids.append(issue.id)
3857e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        reporter.modify_bug_report(issue.id,
3867e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                                   comment='Issue closed by test_push script.',
3877e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                                   label_update='',
3887e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                                   status='WontFix')
3897e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3907e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3917e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shidef check_bug_filed_and_deduped(old_issue_ids):
3927e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """Confirm bug related to dummy_Fail was filed and deduped.
3937e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
3947e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @param old_issue_ids: A list of issue ids that was closed earlier. id of the
3957e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        new issue must be not in this list.
3967e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    @raise TestPushException: If auto bug file failed to create a new issue or
3977e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        dedupe multiple failures.
3987e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """
3997e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    reporter = reporting.Reporter()
4007e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    issue = reporter.find_issue_by_marker(BUG_ANCHOR)
4017e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if not issue:
4027e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        raise TestPushException('Auto bug file failed. Unable to locate bug '
4037e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                                'with marker %s' % BUG_ANCHOR)
4047e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if old_issue_ids and issue.id in old_issue_ids:
4057e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        raise TestPushException('Auto bug file failed to create a new issue. '
4067e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                                'id of the old issue found is %d.' % issue.id)
4077e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if not ('%s2' % reporter.AUTOFILED_COUNT) in issue.labels:
4087e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        raise TestPushException(('Auto bug file failed to dedupe for issue %d '
4097e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                                 'with labels of %s.') %
4107e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                                (issue.id, issue.labels))
4117e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    # Close the bug, and do the search again, which should return None.
4127e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    reporter.modify_bug_report(issue.id,
4137e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                               comment='Issue closed by test_push script.',
4147e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                               label_update='',
4157e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                               status='WontFix')
4167e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    second_issue = reporter.find_issue_by_marker(BUG_ANCHOR)
4177e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if second_issue:
4187e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        ids = '%d, %d' % (issue.id, second_issue.id)
4197e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        raise TestPushException(('Auto bug file failed. Multiple issues (%s) '
4207e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi                                 'filed with marker %s') % (ids, BUG_ANCHOR))
4217e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    print 'Issue %d was filed and deduped successfully.' % issue.id
4227e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
4237e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
424ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shidef check_queue(queue):
425ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    """Check the queue for any exception being raised.
426ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
427ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    @param queue: Queue used to store exception for parent process to access.
428ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    @raise: Any exception found in the queue.
429ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    """
430ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    if queue.empty():
431ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        return
432ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    exc_info = queue.get()
433ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    # Raise the exception with original backtrace.
434ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    print 'Original stack trace of the exception:\n%s' % exc_info[2]
435ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi    raise exc_info[0](exc_info[1])
436ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
437ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
4387e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shidef main():
4397e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    """Entry point for test_push script."""
4407e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    arguments = parse_arguments()
4417e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
4427e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    try:
4437e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        # Close existing bugs. New bug should be filed in dummy_Fail test.
4447e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        old_issue_ids = close_bug()
4457e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
446ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        queue = multiprocessing.Queue()
447ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
448ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        push_to_prod_suite = multiprocessing.Process(
449ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                target=test_suite_wrapper,
450ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                args=(queue, PUSH_TO_PROD_SUITE, EXPECTED_TEST_RESULTS,
451ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                      arguments))
452ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        push_to_prod_suite.start()
4538f14391ed7dbbb0c8081d8e9a0ba60b7fa09ff4fJakob Juelich
4547e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        # TODO(dshi): Remove following line after crbug.com/267644 is fixed.
4557e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        # Also, merge EXPECTED_TEST_RESULTS_AU to EXPECTED_TEST_RESULTS
456ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        au_suite = multiprocessing.Process(
457ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                target=test_suite_wrapper,
458ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                args=(queue, AU_SUITE, EXPECTED_TEST_RESULTS_AU,
459ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                      arguments))
460ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        au_suite.start()
461ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
462ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        shard_suite = multiprocessing.Process(
463ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                target=test_suite_wrapper,
464ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                args=(queue, DUMMY_SUITE, EXPECTED_TEST_RESULTS_DUMMY,
465ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                      arguments, True))
466ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        shard_suite.start()
467ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
468ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        bug_filing_checked = False
469ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        while (push_to_prod_suite.is_alive() or au_suite.is_alive() or
470ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi               shard_suite.is_alive()):
471ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi            check_queue(queue)
472ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi            # Check bug filing results to fail early if bug filing failed.
473ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi            if not bug_filing_checked and not push_to_prod_suite.is_alive():
474ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                check_bug_filed_and_deduped(old_issue_ids)
475ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi                bug_filing_checked = True
476ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi            time.sleep(5)
477ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
478ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        check_queue(queue)
479ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi
480ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        push_to_prod_suite.join()
481ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        au_suite.join()
482ef1a5c0de1a2cfb039574f9d011d256114bda99aDan Shi        shard_suite.join()
4837e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    except Exception as e:
4847e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        print 'Test for pushing to prod failed:\n'
4857e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        print str(e)
4867e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        # Send out email about the test failure.
4877e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        if arguments.email:
4885fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi            gmail_lib.send_email(
4895fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi                    arguments.email,
4905fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi                    'Test for pushing to prod failed. Do NOT push!',
4915fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi                    ('Errors occurred during the test:\n\n%s\n\n' % str(e) +
4925fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi                     'run_suite output:\n\n%s' % '\n'.join(run_suite_output)))
4937e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi        raise
4947e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
4957e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    message = ('\nAll tests are completed successfully, prod branch is ready to'
4967e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi               ' be pushed.')
4977e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    print message
4987e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    # Send out email about test completed successfully.
4997e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    if arguments.email:
5005fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi        gmail_lib.send_email(
5015fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi                arguments.email,
5025fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi                'Test for pushing to prod completed successfully',
5035fa602cbd7787ff604758f03b71da19b66263ca1Dan Shi                message)
5047e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
5057e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi
5067e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shiif __name__ == '__main__':
5077e04fa8cf1f07512f52870cf4bffd9f8b0801088Dan Shi    sys.exit(main())
508