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,49 +3,89 @@ ...@@ -3,49 +3,89 @@
# 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
def run_tests( _CREDENTIAL_SCOPES = "https://spreadsheets.google.com/feeds"
save_path, chrome_path, chromedriver_path,
passwords_path, profile_path, *args, **kwargs): # TODO(melandory): Function _authenticate belongs to separate module.
""" Runs automated tests. def _authenticate(pkey, client_email):
""" Authenticates user.
Args: Args:
save_path: File, where results of run will be logged. pkey: Full path to file with private key generated by Google
chrome_path: Location of Chrome binary. Developer Console.
chromedriver_path: Location of Chrome Driver. client_email: Email address corresponding to private key and also
passwords_path: Location of file with credentials. generated by Google Developer Console.
profile_path: Location of profile path. """
*args: Variable length argument list. http, token = None, None
**kwargs: Arbitrary keyword arguments. with open(pkey) as pkey_file:
""" private_key = pkey_file.read()
environment = Environment('', '', '', None, False) credentials = SignedJwtAssertionCredentials(
tests.Tests(environment) 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
xml = open(save_path, "w") # TODO(melandory): Functionality of _spredsheeet_for_logging belongs
xml.write("<xml>") # to websitetests, because this way we do not need to write results of run
try: # in separate file and then read it here.
results = tempfile.NamedTemporaryFile( def _spredsheeet_for_logging(sheet_key, access_token):
dir=os.path.join(tempfile.gettempdir()), delete=False) """ Connects to document where result of test run will be logged.
results_path = results.name Args:
results.close() 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
full_path = os.path.realpath(__file__) def _try_run_individual_test(test_cmd, results_path):
tests_dir = os.path.dirname(full_path) """ Runs individual test and logs results to trix.
tests_path = os.path.join(tests_dir, "tests.py")
for websitetest in environment.websitetests: 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. # The tests can be flaky. This is why we try to rerun up to 3 times.
for x in range(0, 3): for x in xrange(3):
# TODO(rchtara): Using "pkill" is just temporary until a better, # TODO(rchtara): Using "pkill" is just temporary until a better,
# platform-independent solution is found. # 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") os.system("pkill chrome")
try: try:
os.remove(results_path) os.remove(results_path)
...@@ -59,36 +99,81 @@ def run_tests( ...@@ -59,36 +99,81 @@ def run_tests(
# Wait() in websitetest.py). Accounting for some more time spent on # Wait() in websitetest.py). Accounting for some more time spent on
# the non-waiting execution, 300 seconds should be the upper bound 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. # the runtime of one pass, thus 600 seconds for the whole test.
os.system("timeout 600 python %s %s --chrome-path %s " # TODO(vabr): Use subprocess.call.
"--chromedriver-path %s --passwords-path %s --profile-path %s " os.system("timeout 600 %s" % test_cmd)
"--save-path %s" %
(tests_path, websitetest.name, chrome_path,
chromedriver_path, passwords_path,
profile_path, results_path))
if os.path.isfile(results_path): if os.path.isfile(results_path):
results = open(results_path, "r") results = open(results_path, "r")
count = 0 # Count the number of successful tests. count = 0 # Count the number of successful tests.
for line in results: for line in results:
xml.write(line) # TODO(melandory): We do not need to send all this data to sheet.
failures.append(line)
count += line.count("successful='True'") count += line.count("successful='True'")
results.close() results.close()
# There is only two tests running for every website: the prompt and # There is only two tests running for every website: the prompt and
# the normal test. If both of the tests were successful, the tests # the normal test. If both of the tests were successful, the tests
# would be stopped for the current website. # would be stopped for the current website.
if count == 2: if count == 2:
break return "pass", []
else: else:
xml.write("<result><test name='%s' type='prompt' successful='false'>" pass
"</test><test name='%s' type='normal' successful='false'></test>" return "fail", failures
"</result>" % (websitetest.name, websitetest.name))
def run_tests(
chrome_path, chromedriver_path,
profile_path, config_path, *args, **kwargs):
""" Runs automated tests.
Args:
save_path: File, where results of run will be logged.
chrome_path: Location of Chrome binary.
chromedriver_path: Location of Chrome Driver.
passwords_path: Location of file with credentials.
profile_path: Location of profile path.
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
"""
environment = Environment('', '', '', None, False)
tests.Tests(environment)
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
results.close()
full_path = os.path.realpath(__file__)
tests_dir = os.path.dirname(full_path)
tests_path = os.path.join(tests_dir, "tests.py")
for websitetest in environment.websitetests:
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: 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