Index: components/test/data/password_manager/automated_tests/run_tests.py |
diff --git a/components/test/data/password_manager/automated_tests/run_tests.py b/components/test/data/password_manager/automated_tests/run_tests.py |
index 1e8bc2adbfd990eb24034f4d7a32f4cf380fe338..0fea5077e7a40acf50a0af84ef748193647fc525 100644 |
--- a/components/test/data/password_manager/automated_tests/run_tests.py |
+++ b/components/test/data/password_manager/automated_tests/run_tests.py |
@@ -3,18 +3,125 @@ |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
-"""This file allows the bots to be easily configure and run the tests.""" |
+"""This file allows the bots to be easily configure and run the tests. |
+Running this script requires passing --config-path with a path to a config file |
+of the following structure: |
+ [credentials] |
+ pkey=full_path |
+ client_email=email_assigned_by_google_dev_console |
+ [drive] |
+ key=sheet_key_from_sheet_url |
+ [data_files] |
+ passwords_path=full_path_to_the_file_with_passwords |
+""" |
+from Sheet import Sheet |
+from apiclient.discovery import build |
+from datetime import datetime |
+from gdata.gauth import OAuth2TokenFromCredentials |
+from gdata.spreadsheet.service import SpreadsheetsService |
+from oauth2client.client import SignedJwtAssertionCredentials |
+import ConfigParser |
import argparse |
+import httplib2 |
+import oauth2client.tools |
import os |
import tempfile |
from environment import Environment |
import tests |
+_CREDENTIAL_SCOPES = "https://spreadsheets.google.com/feeds" |
+ |
+# TODO(melandory): Function _authenticate belongs to separate module. |
+def _authenticate(pkey, client_email): |
+""" Authenticates user. |
+ |
+ Args: |
+ pkey: Full path to file with private key generated by Google |
+ Developer Console. |
+ client_email: Email address corresponding to private key and also |
+ generated by Google Developer Console. |
+""" |
+ http, token = None, None |
+ with open(pkey) as pkey_file: |
+ private_key = pkey_file.read() |
+ credentials = SignedJwtAssertionCredentials( |
+ client_email, private_key, _CREDENTIAL_SCOPES) |
+ http = httplib2.Http() |
+ http = credentials.authorize(http) |
+ build('drive', 'v2', http=http) |
+ token = OAuth2TokenFromCredentials(credentials).access_token |
+ return http, token |
+ |
+# TODO(melandory): Functionality of _spredsheeet_for_logging belongs |
+# to websitetests, because this way we do not need to write results of run |
+# in separate file and then read it here. |
+def _spredsheeet_for_logging(sheet_key, access_token): |
+ """ Connects to document where result of test run will be logged. |
+ Args: |
+ sheet_key: Key of sheet in Trix. Can be found in sheet's URL. |
+ access_token: Access token of an account which should have edit rights. |
+ """ |
+ # Connect to trix |
+ service = SpreadsheetsService(additional_headers={ |
+ "Authorization": "Bearer " + access_token}) |
+ sheet = Sheet(service, sheet_key) |
+ return sheet |
+ |
+def _try_run_individual_test(test_cmd, results_path): |
+ """ Runs individual test and logs results to trix. |
+ |
+ Args: |
+ test_cmd: String contains command which runs test. |
+ results_path: Full path to file where results of test run will be logged. |
+ """ |
+ failures = [] |
+ # The tests can be flaky. This is why we try to rerun up to 3 times. |
+ for x in xrange(3): |
+ # TODO(rchtara): Using "pkill" is just temporary until a better, |
+ # platform-independent solution is found. |
+ # Using any kind of kill and process name isn't best solution. |
+ # Mainly because it kills every running instace of Chrome on the machine, |
+ # which is unpleasant experience, when you're running tests locally. |
+ # In my opinion proper solution is to invoke chrome using subproceses and |
+ # then kill only this particular instance of it. |
+ os.system("pkill chrome") |
+ try: |
+ os.remove(results_path) |
+ except Exception: |
+ pass |
+ # TODO(rchtara): Using "timeout is just temporary until a better, |
+ # platform-independent solution is found. |
+ |
+ # The website test runs in two passes, each pass has an internal |
+ # timeout of 200s for waiting (see |remaining_time_to_wait| and |
+ # Wait() in websitetest.py). Accounting for some more time spent on |
+ # the non-waiting execution, 300 seconds should be the upper bound on |
+ # the runtime of one pass, thus 600 seconds for the whole test. |
+ # TODO(vabr): Use subprocess.call. |
+ os.system("timeout 600 %s" % test_cmd) |
+ if os.path.isfile(results_path): |
+ results = open(results_path, "r") |
+ count = 0 # Count the number of successful tests. |
+ for line in results: |
+ # TODO(melandory): We do not need to send all this data to sheet. |
+ failures.append(line) |
+ count += line.count("successful='True'") |
+ results.close() |
+ # There is only two tests running for every website: the prompt and |
+ # the normal test. If both of the tests were successful, the tests |
+ # would be stopped for the current website. |
+ if count == 2: |
+ return "pass", [] |
+ else: |
+ pass |
+ return "fail", failures |
+ |
+ |
def run_tests( |
- save_path, chrome_path, chromedriver_path, |
- passwords_path, profile_path, *args, **kwargs): |
+ chrome_path, chromedriver_path, |
+ profile_path, config_path, *args, **kwargs): |
""" Runs automated tests. |
Args: |
@@ -28,10 +135,13 @@ def run_tests( |
""" |
environment = Environment('', '', '', None, False) |
tests.Tests(environment) |
- |
- xml = open(save_path, "w") |
- xml.write("<xml>") |
+ config = ConfigParser.ConfigParser() |
+ config.read(config_path) |
+ date = datetime.now().strftime('%Y-%m-%dT%H:%M:%S') |
try: |
+ _, access_token = _authenticate(config.get("credentials", "pkey"), |
+ config.get("credentials", "client_email")) |
+ sheet = _spredsheeet_for_logging(config.get("drive", "key"), access_token) |
results = tempfile.NamedTemporaryFile( |
dir=os.path.join(tempfile.gettempdir()), delete=False) |
results_path = results.name |
@@ -42,53 +152,28 @@ def run_tests( |
tests_path = os.path.join(tests_dir, "tests.py") |
for websitetest in environment.websitetests: |
- # The tests can be flaky. This is why we try to rerun up to 3 times. |
- for x in range(0, 3): |
- # TODO(rchtara): Using "pkill" is just temporary until a better, |
- # platform-independent solution is found. |
- os.system("pkill chrome") |
- try: |
- os.remove(results_path) |
- except Exception: |
- pass |
- # TODO(rchtara): Using "timeout is just temporary until a better, |
- # platform-independent solution is found. |
- |
- # The website test runs in two passes, each pass has an internal |
- # timeout of 200s for waiting (see |remaining_time_to_wait| and |
- # Wait() in websitetest.py). Accounting for some more time spent on |
- # the non-waiting execution, 300 seconds should be the upper bound on |
- # the runtime of one pass, thus 600 seconds for the whole test. |
- os.system("timeout 600 python %s %s --chrome-path %s " |
- "--chromedriver-path %s --passwords-path %s --profile-path %s " |
- "--save-path %s" % |
- (tests_path, websitetest.name, chrome_path, |
- chromedriver_path, passwords_path, |
- profile_path, results_path)) |
- if os.path.isfile(results_path): |
- results = open(results_path, "r") |
- count = 0 # Count the number of successful tests. |
- for line in results: |
- xml.write(line) |
- count += line.count("successful='True'") |
- results.close() |
- # There is only two tests running for every website: the prompt and |
- # the normal test. If both of the tests were successful, the tests |
- # would be stopped for the current website. |
- if count == 2: |
- break |
- else: |
- xml.write("<result><test name='%s' type='prompt' successful='false'>" |
- "</test><test name='%s' type='normal' successful='false'></test>" |
- "</result>" % (websitetest.name, websitetest.name)) |
+ test_cmd = ("python %s %s --chrome-path %s " |
+ "--chromedriver-path %s" |
+ "--passwords-path %s --profile-path %s " |
+ "--save-path %s" % |
+ (tests_path, websitetest.name, chrome_path, |
+ chromedriver_path, |
+ config.get("data_files", "passwords_path"), |
+ profile_path, results_path)) |
+ status, log = _try_run_individual_test( |
+ websitetest, test_cmd, results_path) |
+ try: |
+ sheet.InsertRow(sheet.row_count, |
+ [websitetest.name, status, date, " | ".join(log)]) |
+ except Exception: |
+ pass # TODO(melandory): Sometimes writing to spreadsheet fails. We need |
+ # deal with it better that just ignoring. |
finally: |
try: |
os.remove(results_path) |
except Exception: |
pass |
- xml.write("</xml>") |
- xml.close() |
if __name__ == "__main__": |
parser = argparse.ArgumentParser( |
@@ -100,15 +185,14 @@ if __name__ == "__main__": |
"--chromedriver-path", action="store", dest="chromedriver_path", |
help="Set the chromedriver path (required).", required=True) |
parser.add_argument( |
+ "--config-path", action="store", dest="config_path", |
+ help="File with configuration data: drive credentials, password path", |
+ required=True) |
+ parser.add_argument( |
"--profile-path", action="store", dest="profile_path", |
help="Set the profile path (required). You just need to choose a " |
"temporary empty folder. If the folder is not empty all its content " |
"is going to be removed.", |
required=True) |
- parser.add_argument( |
- "--passwords-path", action="store", dest="passwords_path", |
- help="Set the usernames/passwords path (required).", required=True) |
- parser.add_argument("--save-path", action="store", dest="save_path", |
- help="Write the results in a file.", required=True) |
args = vars(parser.parse_args()) |
run_tests(**args) |