Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium 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 """This file allows the bots to be easily configure and run the tests.""" | 6 """This file allows the bots to be easily configure and run the tests.""" |
|
vabr (Chromium)
2015/01/27 13:09:15
Could you please add a comment like below?
Running
melandory
2015/01/27 13:25:22
Done.
| |
| 7 | 7 |
| 8 from Sheet import Sheet | |
| 9 from apiclient.discovery import build | |
| 10 from datetime import datetime | |
| 11 from gdata.gauth import OAuth2TokenFromCredentials | |
| 12 from gdata.spreadsheet.service import SpreadsheetsService | |
| 13 from oauth2client.client import SignedJwtAssertionCredentials | |
| 14 import ConfigParser | |
| 8 import argparse | 15 import argparse |
| 16 import httplib2 | |
| 17 import oauth2client.tools | |
| 9 import os | 18 import os |
| 10 import tempfile | 19 import tempfile |
| 11 | 20 |
| 12 from environment import Environment | 21 from environment import Environment |
| 13 import tests | 22 import tests |
| 14 | 23 |
| 24 _CREDENTIAL_SCOPES = "https://spreadsheets.google.com/feeds" | |
| 25 | |
| 26 # TODO(melandory): Function _authenticate belongs to separate module. | |
| 27 def _authenticate(pkey, client_email): | |
| 28 http, token = None, None | |
| 29 with open(pkey) as pkey_file: | |
| 30 private_key = pkey_file.read() | |
| 31 credentials = SignedJwtAssertionCredentials( | |
| 32 client_email, private_key, _CREDENTIAL_SCOPES) | |
| 33 http = httplib2.Http() | |
| 34 http = credentials.authorize(http) | |
| 35 build('drive', 'v2', http=http) | |
| 36 token = OAuth2TokenFromCredentials(credentials).access_token | |
| 37 return http, token | |
| 38 | |
| 39 # TODO(melandory): Functionality of _spredsheeet_for_logging belongs | |
| 40 # to websitetests, because this was we do not need to write results of run | |
|
vabr (Chromium)
2015/01/27 13:09:15
typo: was -> way
melandory
2015/01/27 13:25:22
Done.
| |
| 41 # in separate file and then read it here. | |
| 42 def _spredsheeet_for_logging(sheet_key, access_token): | |
| 43 # Connect to trix | |
| 44 service = SpreadsheetsService(additional_headers={ | |
| 45 "Authorization": "Bearer " + access_token}) | |
| 46 sheet = Sheet(service, sheet_key) | |
| 47 return sheet | |
| 48 | |
| 49 def _try_run_individual_test(websitetest, test_cmd, results_path): | |
| 50 failures = [] | |
| 51 # The tests can be flaky. This is why we try to rerun up to 3 times. | |
| 52 for x in xrange(3): | |
| 53 # TODO(rchtara): Using "pkill" is just temporary until a better, | |
| 54 # platform-independent solution is found. | |
| 55 # Using any kind of kill and process name isn't best solution. | |
| 56 # Mainly because it kills every running instace of Chrome on the machine, | |
| 57 # which is unpleasant experience, when you're running tests locally. | |
| 58 # In my opinion proper solution is to invoke chrome using subproceses and | |
| 59 # then kill only this particular instance of it. | |
| 60 os.system("pkill chrome") | |
| 61 try: | |
| 62 os.remove(results_path) | |
| 63 except Exception: | |
| 64 pass | |
| 65 # TODO(rchtara): Using "timeout is just temporary until a better, | |
| 66 # platform-independent solution is found. | |
| 67 | |
| 68 # The website test runs in two passes, each pass has an internal | |
| 69 # timeout of 200s for waiting (see |remaining_time_to_wait| and | |
| 70 # Wait() in websitetest.py). Accounting for some more time spent on | |
| 71 # the non-waiting execution, 300 seconds should be the upper bound on | |
| 72 # the runtime of one pass, thus 600 seconds for the whole test. | |
| 73 os.system("timeout 600 %s" % test_cmd) | |
|
vabr (Chromium)
2015/01/27 13:09:15
Please add:
# TODO(vabr): Use subprocess.call.
melandory
2015/01/27 13:25:22
Done.
| |
| 74 if os.path.isfile(results_path): | |
| 75 results = open(results_path, "r") | |
| 76 count = 0 # Count the number of successful tests. | |
| 77 for line in results: | |
| 78 # TODO(melandory): We do not need to send all this data to sheet. | |
| 79 failures.append(line) | |
| 80 count += line.count("successful='True'") | |
| 81 results.close() | |
| 82 # There is only two tests running for every website: the prompt and | |
| 83 # the normal test. If both of the tests were successful, the tests | |
| 84 # would be stopped for the current website. | |
| 85 if count == 2: | |
| 86 return "pass", [] | |
| 87 else: | |
| 88 pass | |
| 89 return "fail", failures | |
| 90 | |
| 91 | |
| 15 def run_tests( | 92 def run_tests( |
| 16 save_path, chrome_path, chromedriver_path, | 93 chrome_path, chromedriver_path, |
| 17 passwords_path, profile_path, *args, **kwargs): | 94 profile_path, config_path, *args, **kwargs): |
| 18 """ Runs automated tests. | 95 """ Runs automated tests. |
| 19 | 96 |
| 20 Args: | 97 Args: |
| 21 save_path: File, where results of run will be logged. | 98 save_path: File, where results of run will be logged. |
| 22 chrome_path: Location of Chrome binary. | 99 chrome_path: Location of Chrome binary. |
| 23 chromedriver_path: Location of Chrome Driver. | 100 chromedriver_path: Location of Chrome Driver. |
| 24 passwords_path: Location of file with credentials. | 101 passwords_path: Location of file with credentials. |
| 25 profile_path: Location of profile path. | 102 profile_path: Location of profile path. |
| 26 *args: Variable length argument list. | 103 *args: Variable length argument list. |
| 27 **kwargs: Arbitrary keyword arguments. | 104 **kwargs: Arbitrary keyword arguments. |
| 28 """ | 105 """ |
| 29 environment = Environment('', '', '', None, False) | 106 environment = Environment('', '', '', None, False) |
| 30 tests.Tests(environment) | 107 tests.Tests(environment) |
| 31 | 108 config = ConfigParser.ConfigParser() |
| 32 xml = open(save_path, "w") | 109 config.read(config_path) |
| 33 xml.write("<xml>") | 110 date = datetime.now().strftime('%Y-%m-%dT%H:%M:%S') |
| 34 try: | 111 try: |
| 112 _, access_token = _authenticate(config.get("credentials", "pkey"), | |
| 113 config.get("credentials", "client_email")) | |
| 114 sheet = _spredsheeet_for_logging(config.get("drive", "key"), access_token) | |
| 35 results = tempfile.NamedTemporaryFile( | 115 results = tempfile.NamedTemporaryFile( |
| 36 dir=os.path.join(tempfile.gettempdir()), delete=False) | 116 dir=os.path.join(tempfile.gettempdir()), delete=False) |
| 37 results_path = results.name | 117 results_path = results.name |
| 38 results.close() | 118 results.close() |
| 39 | 119 |
| 40 full_path = os.path.realpath(__file__) | 120 full_path = os.path.realpath(__file__) |
| 41 tests_dir = os.path.dirname(full_path) | 121 tests_dir = os.path.dirname(full_path) |
| 42 tests_path = os.path.join(tests_dir, "tests.py") | 122 tests_path = os.path.join(tests_dir, "tests.py") |
| 43 | 123 |
| 44 for websitetest in environment.websitetests: | 124 for websitetest in environment.websitetests: |
| 45 # The tests can be flaky. This is why we try to rerun up to 3 times. | 125 test_cmd = ("python %s %s --chrome-path %s " |
| 46 for x in range(0, 3): | 126 "--chromedriver-path %s" |
| 47 # TODO(rchtara): Using "pkill" is just temporary until a better, | 127 "--passwords-path %s --profile-path %s " |
| 48 # platform-independent solution is found. | 128 "--save-path %s" % |
| 49 os.system("pkill chrome") | 129 (tests_path, websitetest.name, chrome_path, |
| 50 try: | 130 chromedriver_path, |
| 51 os.remove(results_path) | 131 config.get("data_files", "passwords_path"), |
| 52 except Exception: | 132 profile_path, results_path)) |
| 53 pass | 133 status, log = _try_run_individual_test( |
| 54 # TODO(rchtara): Using "timeout is just temporary until a better, | 134 websitetest, test_cmd, results_path) |
| 55 # platform-independent solution is found. | 135 try: |
| 56 | 136 sheet.InsertRow(sheet.row_count, |
| 57 # The website test runs in two passes, each pass has an internal | 137 [websitetest.name, status, date, " | ".join(log)]) |
| 58 # timeout of 200s for waiting (see |remaining_time_to_wait| and | 138 except Exception: |
| 59 # Wait() in websitetest.py). Accounting for some more time spent on | 139 pass # TODO(melandory): Sometimes writing to spreadsheet fails. We need |
| 60 # the non-waiting execution, 300 seconds should be the upper bound on | 140 # deal with it better that just ignoring. |
| 61 # the runtime of one pass, thus 600 seconds for the whole test. | |
| 62 os.system("timeout 600 python %s %s --chrome-path %s " | |
| 63 "--chromedriver-path %s --passwords-path %s --profile-path %s " | |
| 64 "--save-path %s" % | |
| 65 (tests_path, websitetest.name, chrome_path, | |
| 66 chromedriver_path, passwords_path, | |
| 67 profile_path, results_path)) | |
| 68 if os.path.isfile(results_path): | |
| 69 results = open(results_path, "r") | |
| 70 count = 0 # Count the number of successful tests. | |
| 71 for line in results: | |
| 72 xml.write(line) | |
| 73 count += line.count("successful='True'") | |
| 74 results.close() | |
| 75 # There is only two tests running for every website: the prompt and | |
| 76 # the normal test. If both of the tests were successful, the tests | |
| 77 # would be stopped for the current website. | |
| 78 if count == 2: | |
| 79 break | |
| 80 else: | |
| 81 xml.write("<result><test name='%s' type='prompt' successful='false'>" | |
| 82 "</test><test name='%s' type='normal' successful='false'></test>" | |
| 83 "</result>" % (websitetest.name, websitetest.name)) | |
| 84 finally: | 141 finally: |
| 85 try: | 142 try: |
| 86 os.remove(results_path) | 143 os.remove(results_path) |
| 87 except Exception: | 144 except Exception: |
| 88 pass | 145 pass |
| 89 | 146 |
| 90 xml.write("</xml>") | |
| 91 xml.close() | |
| 92 | 147 |
| 93 if __name__ == "__main__": | 148 if __name__ == "__main__": |
| 94 parser = argparse.ArgumentParser( | 149 parser = argparse.ArgumentParser( |
| 95 description="Password Manager automated tests runner help.") | 150 description="Password Manager automated tests runner help.") |
| 96 parser.add_argument( | 151 parser.add_argument( |
| 97 "--chrome-path", action="store", dest="chrome_path", | 152 "--chrome-path", action="store", dest="chrome_path", |
| 98 help="Set the chrome path (required).", required=True) | 153 help="Set the chrome path (required).", required=True) |
| 99 parser.add_argument( | 154 parser.add_argument( |
| 100 "--chromedriver-path", action="store", dest="chromedriver_path", | 155 "--chromedriver-path", action="store", dest="chromedriver_path", |
| 101 help="Set the chromedriver path (required).", required=True) | 156 help="Set the chromedriver path (required).", required=True) |
| 102 parser.add_argument( | 157 parser.add_argument( |
| 158 "--config-path", action="store", dest="config_path", | |
| 159 help="File with configuration data: drive credentials, password path", | |
| 160 required=True) | |
| 161 parser.add_argument( | |
| 103 "--profile-path", action="store", dest="profile_path", | 162 "--profile-path", action="store", dest="profile_path", |
| 104 help="Set the profile path (required). You just need to choose a " | 163 help="Set the profile path (required). You just need to choose a " |
| 105 "temporary empty folder. If the folder is not empty all its content " | 164 "temporary empty folder. If the folder is not empty all its content " |
| 106 "is going to be removed.", | 165 "is going to be removed.", |
| 107 required=True) | 166 required=True) |
| 108 parser.add_argument( | |
| 109 "--passwords-path", action="store", dest="passwords_path", | |
| 110 help="Set the usernames/passwords path (required).", required=True) | |
| 111 parser.add_argument("--save-path", action="store", dest="save_path", | |
| 112 help="Write the results in a file.", required=True) | |
| 113 args = vars(parser.parse_args()) | 167 args = vars(parser.parse_args()) |
| 114 run_tests(**args) | 168 run_tests(**args) |
| OLD | NEW |