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 |