Commit c503f651 authored by melandory's avatar melandory Committed by Commit bot

[Password manager tests] Write to spreadsheets.

Writes results of running tests to trix instead of local file.

R=vabr@chromium.org
BUG=435249

Review URL: https://codereview.chromium.org/873333002

Cr-Commit-Position: refs/heads/master@{#313508}
parent 6b4a28b7
...@@ -3,18 +3,125 @@ ...@@ -3,18 +3,125 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # 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 argparse
import httplib2
import oauth2client.tools
import os import os
import tempfile import tempfile
from environment import Environment from environment import Environment
import tests 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( def run_tests(
save_path, chrome_path, chromedriver_path, chrome_path, chromedriver_path,
passwords_path, profile_path, *args, **kwargs): profile_path, config_path, *args, **kwargs):
""" Runs automated tests. """ Runs automated tests.
Args: Args:
...@@ -28,10 +135,13 @@ def run_tests( ...@@ -28,10 +135,13 @@ def run_tests(
""" """
environment = Environment('', '', '', None, False) environment = Environment('', '', '', None, False)
tests.Tests(environment) tests.Tests(environment)
config = ConfigParser.ConfigParser()
xml = open(save_path, "w") config.read(config_path)
xml.write("<xml>") date = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
try: 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( results = tempfile.NamedTemporaryFile(
dir=os.path.join(tempfile.gettempdir()), delete=False) dir=os.path.join(tempfile.gettempdir()), delete=False)
results_path = results.name results_path = results.name
...@@ -42,53 +152,28 @@ def run_tests( ...@@ -42,53 +152,28 @@ def run_tests(
tests_path = os.path.join(tests_dir, "tests.py") tests_path = os.path.join(tests_dir, "tests.py")
for websitetest in environment.websitetests: for websitetest in environment.websitetests:
# The tests can be flaky. This is why we try to rerun up to 3 times. test_cmd = ("python %s %s --chrome-path %s "
for x in range(0, 3): "--chromedriver-path %s"
# TODO(rchtara): Using "pkill" is just temporary until a better, "--passwords-path %s --profile-path %s "
# platform-independent solution is found. "--save-path %s" %
os.system("pkill chrome") (tests_path, websitetest.name, chrome_path,
try: chromedriver_path,
os.remove(results_path) config.get("data_files", "passwords_path"),
except Exception: profile_path, results_path))
pass status, log = _try_run_individual_test(
# TODO(rchtara): Using "timeout is just temporary until a better, websitetest, test_cmd, results_path)
# platform-independent solution is found. try:
sheet.InsertRow(sheet.row_count,
# The website test runs in two passes, each pass has an internal [websitetest.name, status, date, " | ".join(log)])
# timeout of 200s for waiting (see |remaining_time_to_wait| and except Exception:
# Wait() in websitetest.py). Accounting for some more time spent on pass # TODO(melandory): Sometimes writing to spreadsheet fails. We need
# the non-waiting execution, 300 seconds should be the upper bound on # deal with it better that just ignoring.
# 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))
finally: finally:
try: try:
os.remove(results_path) os.remove(results_path)
except Exception: except Exception:
pass pass
xml.write("</xml>")
xml.close()
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
...@@ -99,16 +184,15 @@ if __name__ == "__main__": ...@@ -99,16 +184,15 @@ if __name__ == "__main__":
parser.add_argument( parser.add_argument(
"--chromedriver-path", action="store", dest="chromedriver_path", "--chromedriver-path", action="store", dest="chromedriver_path",
help="Set the chromedriver path (required).", required=True) 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( parser.add_argument(
"--profile-path", action="store", dest="profile_path", "--profile-path", action="store", dest="profile_path",
help="Set the profile path (required). You just need to choose a " help="Set the profile path (required). You just need to choose a "
"temporary empty folder. If the folder is not empty all its content " "temporary empty folder. If the folder is not empty all its content "
"is going to be removed.", "is going to be removed.",
required=True) 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()) args = vars(parser.parse_args())
run_tests(**args) run_tests(**args)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment