Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Unified Diff: components/test/data/autofill/automated_integration/task_flow.py

Issue 2116583004: Automated Autofill testing library + extension (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed nits, reduced preferences Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/test/data/autofill/automated_integration/task_flow.py
diff --git a/components/test/data/autofill/automated_integration/task_flow.py b/components/test/data/autofill/automated_integration/task_flow.py
new file mode 100644
index 0000000000000000000000000000000000000000..a0e7b312f2d892df99e2cae53e5a14926f737915
--- /dev/null
+++ b/components/test/data/autofill/automated_integration/task_flow.py
@@ -0,0 +1,197 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Chrome Autofill Task Flow
+
+Execute a set of autofill tasks in a fresh ChromeDriver instance that has been
+pre-loaded with some default profile.
+
+Requires:
+ - Selenium python bindings
+ http://selenium-python.readthedocs.org/
+
+ - ChromeDriver
+ https://sites.google.com/a/chromium.org/chromedriver/downloads
+ The ChromeDriver executable must be available on the search PATH.
+
+ - Chrome
+"""
+
+import abc
+from urlparse import urlparse
+import os
+import shutil
+from random import choice
+from string import ascii_lowercase
+
+from selenium import webdriver
+from selenium.common.exceptions import TimeoutException, WebDriverException
+from selenium.webdriver.chrome.options import Options
+
+
+class TaskFlow(object):
+ """Represents an executable set of Autofill Tasks.
+
+ Attributes:
+ profile: Dict of profile data that acts as the master source for
+ validating autofill behaviour.
+ debug: Whether debug output should be printed (False if not specified).
+ """
+ __metaclass__ = abc.ABCMeta
+ def __init__(self, profile, debug=False):
+ self.set_profile(profile)
+ self._debug = debug
+ self._running = False
+
+ self._tasks = self._generate_task_sequence()
+
+ def set_profile(self, profile):
+ """Validates |profile| before assigning it as the source of user data.
+
+ Args:
+ profile: Dict of profile data that acts as the master source for
+ validating autofill behaviour.
+
+ Raises:
+ ValueError: The |profile| dict provided is missing required keys
+ """
+ if not isinstance(profile, dict):
+ raise ValueError('profile must be a a valid dictionary');
+
+ self._profile = profile
+
+ def run(self, user_data_dir, chrome_binary=None):
+ """Generates and executes a sequence of chrome driver tasks.
+
+ Args:
+ user_data_dir: Path string for the writable directory in which profiles
+ should be stored.
+ chrome_binary: Path string to the Chrome binary that should be used by
+ ChromeDriver.
+
+ If None then it will use the PATH to find a binary.
+
+ Raises:
+ RuntimeError: Running the TaskFlow was attempted while it's already
+ running.
+ Exception: Any failure encountered while running the tests
+ """
+ if self._running:
+ raise RuntimeError('Cannot run TaskFlow when already running')
+
+ self._running = True
+
+ self._run_tasks(user_data_dir, chrome_binary=chrome_binary)
+
+ self._running = False
+
+ @abc.abstractmethod
+ def _generate_task_sequence(self):
+ """Generates a set of executable tasks that will be run in ChromeDriver.
+
+ Note: Subclasses must implement this method.
+
+ Raises:
+ NotImplementedError: Subclass did not implement the method
+
+ Returns:
+ A list of AutofillTask instances that are to be run in ChromeDriver.
+
+ These tasks are to be run in order.
+ """
+ raise NotImplementedError()
+
+ def _run_tasks(self, user_data_dir, chrome_binary=None):
+ """Runs the internal set of tasks in a fresh ChromeDriver instance.
+
+ Args:
+ user_data_dir: Path string for the writable directory in which profiles
+ should be stored.
+ chrome_binary: Path string to the Chrome binary that should be used by
+ ChromeDriver.
+
+ If None then it will use the PATH to find a binary.
+
+ Raises:
+ Exception: Any failure encountered while running the tests
+ """
+ driver = self._get_driver(user_data_dir, chrome_binary=chrome_binary)
+ try:
+ for task in self._tasks:
+ task.run(driver)
+ finally:
+ driver.quit()
+ shutil.rmtree(self._profile_dir_dst)
+
+ def _get_driver(self, user_data_dir, profile_name=None, chrome_binary=None,
+ chromedriver_binary='chromedriver'):
+ """Spin up a ChromeDriver instance that uses a given set of user data.
+
+ Generates a temporary profile data directory using a local set of test data.
+
+ Args:
+ user_data_dir: Path string for the writable directory in which profiles
+ should be stored.
+ profile_name: Name of the profile data directory to be created/used in
+ user_data_dir.
+
+ If None then an eight character name will be generated randomly.
+
+ This directory will be removed after the task flow completes.
+ chrome_binary: Path string to the Chrome binary that should be used by
+ ChromeDriver.
+
+ If None then it will use the PATH to find a binary.
+
+ Returns: The generated Chrome Driver instance.
+ """
+ options = Options()
+
+ if profile_name is None:
+ profile_name = ''.join(choice(ascii_lowercase) for i in range(8))
+
+ options.add_argument('--profile-directory=%s' % profile_name)
+
+ full_path = os.path.realpath(__file__)
+ path, filename = os.path.split(full_path)
+ profile_dir_src = os.path.join(path, 'testdata', 'Default')
+ self._profile_dir_dst = os.path.join(user_data_dir, profile_name)
+ self._copy_tree(profile_dir_src, self._profile_dir_dst)
+
+ if chrome_binary is not None:
+ options.binary_location = chrome_binary
+
+ options.add_argument('--user-data-dir=%s' % user_data_dir)
+ options.add_argument('--show-autofill-type-predictions')
+
+ service_args = []
+
+ driver = webdriver.Chrome(executable_path=chromedriver_binary,
+ chrome_options=options,
+ service_args=service_args)
+ driver.set_page_load_timeout(15) # seconds
+ return driver
+
+ def _copy_tree(self, src, dst):
+ """Recursively copy a directory tree.
+
+ If the destination directory does not exist then it will be created for you.
+ Doesn't overwrite newer existing files.
+
+ Args:
+ src: Path to the target source directory. It must exist.
+ dst: Path to the target destination directory. Permissions to create the
+ the directory (if necessary) and modify it's contents.
+ """
+ if not os.path.exists(dst):
+ os.makedirs(dst)
+ for item in os.listdir(src):
+ src_item = os.path.join(src, item)
+ dst_item = os.path.join(dst, item)
+ if os.path.isdir(src_item):
+ self._copy_tree(src_item, dst_item)
+ elif (not os.path.exists(dst_item) or
+ os.stat(src_item).st_mtime - os.stat(dst_item).st_mtime > 1):
+ # Copy a file if it doesn't already exist, or if existing one is older.
+ shutil.copy2(src_item, dst_item)

Powered by Google App Engine
This is Rietveld 408576698