summaryrefslogtreecommitdiffstats
path: root/testing/firefox-ui
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testing/firefox-ui/harness/MANIFEST.in2
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/__init__.py7
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/arguments/__init__.py5
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/arguments/base.py17
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py22
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/runners/__init__.py5
-rw-r--r--testing/firefox-ui/harness/firefox_ui_harness/runners/base.py28
-rw-r--r--testing/firefox-ui/harness/requirements.txt4
-rw-r--r--testing/firefox-ui/harness/setup.py52
-rw-r--r--testing/firefox-ui/mach_commands.py91
-rw-r--r--testing/firefox-ui/moz.build9
-rw-r--r--testing/firefox-ui/resources/support.html23
-rw-r--r--testing/firefox-ui/tests/functional/manifest.ini2
-rw-r--r--testing/firefox-ui/tests/functional/safebrowsing/manifest.ini7
-rw-r--r--testing/firefox-ui/tests/functional/safebrowsing/test_initial_download.py136
-rw-r--r--testing/firefox-ui/tests/functional/safebrowsing/test_notification.py132
-rw-r--r--testing/firefox-ui/tests/functional/safebrowsing/test_warning_pages.py138
-rw-r--r--testing/firefox-ui/tests/functional/security/manifest.ini1
-rw-r--r--testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py56
19 files changed, 737 insertions, 0 deletions
diff --git a/testing/firefox-ui/harness/MANIFEST.in b/testing/firefox-ui/harness/MANIFEST.in
new file mode 100644
index 0000000000..cf628b039c
--- /dev/null
+++ b/testing/firefox-ui/harness/MANIFEST.in
@@ -0,0 +1,2 @@
+exclude MANIFEST.in
+include requirements.txt
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/__init__.py b/testing/firefox-ui/harness/firefox_ui_harness/__init__.py
new file mode 100644
index 0000000000..dad49461c7
--- /dev/null
+++ b/testing/firefox-ui/harness/firefox_ui_harness/__init__.py
@@ -0,0 +1,7 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+__version__ = "1.4.0"
+
+from . import cli_functional
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/arguments/__init__.py b/testing/firefox-ui/harness/firefox_ui_harness/arguments/__init__.py
new file mode 100644
index 0000000000..c685a8c23e
--- /dev/null
+++ b/testing/firefox-ui/harness/firefox_ui_harness/arguments/__init__.py
@@ -0,0 +1,5 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from firefox_ui_harness.arguments.base import FirefoxUIArguments
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/arguments/base.py b/testing/firefox-ui/harness/firefox_ui_harness/arguments/base.py
new file mode 100644
index 0000000000..d9d1fc3246
--- /dev/null
+++ b/testing/firefox-ui/harness/firefox_ui_harness/arguments/base.py
@@ -0,0 +1,17 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness import BaseMarionetteArguments
+
+
+class FirefoxUIBaseArguments(object):
+ name = "Firefox UI Tests"
+ args = []
+
+
+class FirefoxUIArguments(BaseMarionetteArguments):
+ def __init__(self, **kwargs):
+ super(FirefoxUIArguments, self).__init__(**kwargs)
+
+ self.register_argument_container(FirefoxUIBaseArguments())
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py b/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py
new file mode 100644
index 0000000000..339a500f19
--- /dev/null
+++ b/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness.runtests import cli as mn_cli
+
+from firefox_ui_harness.arguments import FirefoxUIArguments
+from firefox_ui_harness.runners import FirefoxUITestRunner
+
+
+def cli(args=None):
+ mn_cli(
+ runner_class=FirefoxUITestRunner,
+ parser_class=FirefoxUIArguments,
+ args=args,
+ )
+
+
+if __name__ == "__main__":
+ cli()
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/runners/__init__.py b/testing/firefox-ui/harness/firefox_ui_harness/runners/__init__.py
new file mode 100644
index 0000000000..e2a7ef01f6
--- /dev/null
+++ b/testing/firefox-ui/harness/firefox_ui_harness/runners/__init__.py
@@ -0,0 +1,5 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from firefox_ui_harness.runners.base import FirefoxUITestRunner
diff --git a/testing/firefox-ui/harness/firefox_ui_harness/runners/base.py b/testing/firefox-ui/harness/firefox_ui_harness/runners/base.py
new file mode 100644
index 0000000000..41cfd86544
--- /dev/null
+++ b/testing/firefox-ui/harness/firefox_ui_harness/runners/base.py
@@ -0,0 +1,28 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+
+from marionette_harness import BaseMarionetteTestRunner, MarionetteTestCase
+
+
+class FirefoxUITestRunner(BaseMarionetteTestRunner):
+ def __init__(self, **kwargs):
+ super(FirefoxUITestRunner, self).__init__(**kwargs)
+
+ # select the appropriate GeckoInstance
+ self.app = "fxdesktop"
+
+ # low-noise log messages useful in tests
+ # TODO: should be moved to individual tests once bug 1386810
+ # is fixed
+ moz_log = ""
+ if "MOZ_LOG" in os.environ:
+ moz_log = os.environ["MOZ_LOG"]
+ if len(moz_log) > 0:
+ moz_log += ","
+ moz_log += "UrlClassifierStreamUpdater:1"
+ os.environ["MOZ_LOG"] = moz_log
+
+ self.test_handlers = [MarionetteTestCase]
diff --git a/testing/firefox-ui/harness/requirements.txt b/testing/firefox-ui/harness/requirements.txt
new file mode 100644
index 0000000000..cfebcb1be5
--- /dev/null
+++ b/testing/firefox-ui/harness/requirements.txt
@@ -0,0 +1,4 @@
+marionette-harness >= 4.0.0
+mozfile >= 1.2
+mozinfo >= 0.8
+mozinstall >= 1.12
diff --git a/testing/firefox-ui/harness/setup.py b/testing/firefox-ui/harness/setup.py
new file mode 100644
index 0000000000..3cec4b21d4
--- /dev/null
+++ b/testing/firefox-ui/harness/setup.py
@@ -0,0 +1,52 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+import os
+import re
+
+from setuptools import find_packages, setup
+
+THIS_DIR = os.path.dirname(os.path.realpath(__name__))
+
+
+def read(*parts):
+ with open(os.path.join(THIS_DIR, *parts)) as f:
+ return f.read()
+
+
+def get_version():
+ return re.findall(
+ '__version__ = "([\d\.]+)"', read("firefox_ui_harness", "__init__.py"), re.M
+ )[0]
+
+
+long_description = """Custom Marionette runner classes and entry scripts for Firefox Desktop
+specific Marionette tests.
+"""
+
+setup(
+ name="firefox-ui-harness",
+ version=get_version(),
+ description="Firefox UI Harness",
+ long_description=long_description,
+ classifiers=[
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.5",
+ "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
+ ],
+ # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+ keywords="mozilla",
+ author="DevTools",
+ author_email="dev-webdriver@mozilla.org",
+ license="MPL",
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=read("requirements.txt").splitlines(),
+ entry_points="""
+ [console_scripts]
+ firefox-ui-functional = firefox_ui_harness.cli_functional:cli
+ """,
+)
diff --git a/testing/firefox-ui/mach_commands.py b/testing/firefox-ui/mach_commands.py
new file mode 100644
index 0000000000..4c0d4a126f
--- /dev/null
+++ b/testing/firefox-ui/mach_commands.py
@@ -0,0 +1,91 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import logging
+import os
+import sys
+
+import six
+from mach.decorators import Command
+from mozbuild.base import BinaryNotFoundException
+from mozbuild.base import MachCommandConditions as conditions
+
+
+def setup_argument_parser_functional():
+ from firefox_ui_harness.arguments.base import FirefoxUIArguments
+ from mozlog.structured import commandline
+
+ parser = FirefoxUIArguments()
+ commandline.add_logging_group(parser)
+ return parser
+
+
+def run_firefox_ui_test(topsrcdir=None, **kwargs):
+ from argparse import Namespace
+
+ import firefox_ui_harness
+ from mozlog.structured import commandline
+
+ parser = setup_argument_parser_functional()
+
+ fxui_dir = os.path.join(topsrcdir, "testing", "firefox-ui")
+
+ # Set the resources path which is used to serve test data via wptserve
+ if not kwargs["server_root"]:
+ kwargs["server_root"] = os.path.join(fxui_dir, "resources")
+
+ # If called via "mach test" a dictionary of tests is passed in
+ if "test_objects" in kwargs:
+ tests = []
+ for obj in kwargs["test_objects"]:
+ tests.append(obj["file_relpath"])
+ kwargs["tests"] = tests
+ elif not kwargs.get("tests"):
+ # If no tests have been selected, set default ones
+ kwargs["tests"] = os.path.join(fxui_dir, "tests", "functional", "manifest.ini")
+
+ kwargs["logger"] = kwargs.pop("log", None)
+ if not kwargs["logger"]:
+ kwargs["logger"] = commandline.setup_logging(
+ "Firefox UI - Functional Tests", {"mach": sys.stdout}
+ )
+
+ args = Namespace()
+
+ for k, v in six.iteritems(kwargs):
+ setattr(args, k, v)
+
+ parser.verify_usage(args)
+
+ failed = firefox_ui_harness.cli_functional.cli(args=vars(args))
+
+ if failed > 0:
+ return 1
+ else:
+ return 0
+
+
+@Command(
+ "firefox-ui-functional",
+ category="testing",
+ conditions=[conditions.is_firefox],
+ description="Run the functional test suite of Firefox UI tests.",
+ parser=setup_argument_parser_functional,
+)
+def run_firefox_ui_functional(command_context, **kwargs):
+ try:
+ kwargs["binary"] = kwargs["binary"] or command_context.get_binary_path("app")
+ except BinaryNotFoundException as e:
+ command_context.log(
+ logging.ERROR,
+ "firefox-ui-functional",
+ {"error": str(e)},
+ "ERROR: {error}",
+ )
+ command_context.log(
+ logging.INFO, "firefox-ui-functional", {"help": e.help()}, "{help}"
+ )
+ return 1
+
+ return run_firefox_ui_test(topsrcdir=command_context.topsrcdir, **kwargs)
diff --git a/testing/firefox-ui/moz.build b/testing/firefox-ui/moz.build
new file mode 100644
index 0000000000..bfd7c9f009
--- /dev/null
+++ b/testing/firefox-ui/moz.build
@@ -0,0 +1,9 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+FIREFOX_UI_FUNCTIONAL_MANIFESTS += ["tests/functional/manifest.ini"]
+
+with Files("**"):
+ BUG_COMPONENT = ("Testing", "Firefox UI Tests")
+ SCHEDULES.exclusive = ["firefox-ui"]
diff --git a/testing/firefox-ui/resources/support.html b/testing/firefox-ui/resources/support.html
new file mode 100644
index 0000000000..818aa97276
--- /dev/null
+++ b/testing/firefox-ui/resources/support.html
@@ -0,0 +1,23 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <script type="text/javascript">
+ function show() {
+ var results = /\?topic=(.+)$/.exec(window.document.location);
+ var topic = decodeURIComponent(results[1].replace(/\+/g, " "));
+ var node = document.getElementById("topic");
+
+ node.textContent = topic;
+ }
+ </script>
+</head>
+
+<body onload="show()">
+ <div id="topic"></div>
+</body>
+</html>
diff --git a/testing/firefox-ui/tests/functional/manifest.ini b/testing/firefox-ui/tests/functional/manifest.ini
new file mode 100644
index 0000000000..200338addf
--- /dev/null
+++ b/testing/firefox-ui/tests/functional/manifest.ini
@@ -0,0 +1,2 @@
+[include:safebrowsing/manifest.ini]
+[include:security/manifest.ini]
diff --git a/testing/firefox-ui/tests/functional/safebrowsing/manifest.ini b/testing/firefox-ui/tests/functional/safebrowsing/manifest.ini
new file mode 100644
index 0000000000..a9d3be964f
--- /dev/null
+++ b/testing/firefox-ui/tests/functional/safebrowsing/manifest.ini
@@ -0,0 +1,7 @@
+[test_initial_download.py]
+skip-if =
+ (debug || asan || tsan) # The GAPI key isn't available in debug or sanitizer builds
+ (ccov && os == 'win') # Bug 1805893
+ (cc_type == 'clang' && os == 'win') # Bug 1565818
+[test_notification.py]
+[test_warning_pages.py]
diff --git a/testing/firefox-ui/tests/functional/safebrowsing/test_initial_download.py b/testing/firefox-ui/tests/functional/safebrowsing/test_initial_download.py
new file mode 100644
index 0000000000..ec973af674
--- /dev/null
+++ b/testing/firefox-ui/tests/functional/safebrowsing/test_initial_download.py
@@ -0,0 +1,136 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+from functools import reduce
+
+from marionette_driver import Wait
+from marionette_harness import MarionetteTestCase
+
+
+class TestSafeBrowsingInitialDownload(MarionetteTestCase):
+
+ v2_file_extensions = [
+ "vlpset",
+ "sbstore",
+ ]
+
+ v4_file_extensions = [
+ "vlpset",
+ "metadata",
+ ]
+
+ prefs_download_lists = [
+ "urlclassifier.blockedTable",
+ "urlclassifier.downloadAllowTable",
+ "urlclassifier.downloadBlockTable",
+ "urlclassifier.malwareTable",
+ "urlclassifier.phishTable",
+ "urlclassifier.trackingTable",
+ "urlclassifier.trackingWhitelistTable",
+ ]
+
+ prefs_provider_update_time = {
+ # Force an immediate download of the safebrowsing files
+ "browser.safebrowsing.provider.mozilla.nextupdatetime": 1,
+ }
+
+ prefs_safebrowsing = {
+ "browser.safebrowsing.debug": True,
+ "browser.safebrowsing.update.enabled": True,
+ }
+
+ def get_safebrowsing_files(self, is_v4):
+ files = []
+
+ if is_v4:
+ my_file_extensions = self.v4_file_extensions
+ else: # v2
+ my_file_extensions = self.v2_file_extensions
+
+ for pref_name in self.prefs_download_lists:
+ base_names = self.marionette.get_pref(pref_name).split(",")
+
+ # moztest- lists are not saved to disk
+ # pylint --py3k: W1639
+ base_names = list(
+ filter(lambda x: not x.startswith("moztest-"), base_names)
+ )
+
+ for ext in my_file_extensions:
+ files.extend(
+ [
+ "{name}.{ext}".format(name=f, ext=ext)
+ for f in base_names
+ if f and f.endswith("-proto") == is_v4
+ ]
+ )
+
+ return set(sorted(files))
+
+ def setUp(self):
+ super(TestSafeBrowsingInitialDownload, self).setUp()
+
+ self.safebrowsing_v2_files = self.get_safebrowsing_files(False)
+ if any(
+ f.startswith("goog-") or f.startswith("googpub-")
+ for f in self.safebrowsing_v2_files
+ ):
+ self.prefs_provider_update_time.update(
+ {
+ "browser.safebrowsing.provider.google.nextupdatetime": 1,
+ }
+ )
+
+ self.safebrowsing_v4_files = self.get_safebrowsing_files(True)
+ if any(
+ f.startswith("goog-") or f.startswith("googpub-")
+ for f in self.safebrowsing_v4_files
+ ):
+ self.prefs_provider_update_time.update(
+ {
+ "browser.safebrowsing.provider.google4.nextupdatetime": 1,
+ }
+ )
+
+ # Force the preferences for the new profile
+ enforce_prefs = self.prefs_safebrowsing
+ enforce_prefs.update(self.prefs_provider_update_time)
+ self.marionette.enforce_gecko_prefs(enforce_prefs)
+
+ self.safebrowsing_path = os.path.join(
+ self.marionette.instance.profile.profile, "safebrowsing"
+ )
+
+ def tearDown(self):
+ try:
+ # Restart with a fresh profile
+ self.marionette.restart(in_app=False, clean=True)
+ finally:
+ super(TestSafeBrowsingInitialDownload, self).tearDown()
+
+ def test_safe_browsing_initial_download(self):
+ def check_downloaded(_):
+ return reduce(
+ lambda state, pref: state and int(self.marionette.get_pref(pref)) != 1,
+ list(self.prefs_provider_update_time),
+ True,
+ )
+
+ try:
+ Wait(self.marionette, timeout=170).until(
+ check_downloaded,
+ message="Not all safebrowsing files have been downloaded",
+ )
+ finally:
+ files_on_disk_toplevel = os.listdir(self.safebrowsing_path)
+ for f in self.safebrowsing_v2_files:
+ self.assertIn(f, files_on_disk_toplevel)
+
+ if len(self.safebrowsing_v4_files) > 0:
+ files_on_disk_google4 = os.listdir(
+ os.path.join(self.safebrowsing_path, "google4")
+ )
+ for f in self.safebrowsing_v4_files:
+ self.assertIn(f, files_on_disk_google4)
diff --git a/testing/firefox-ui/tests/functional/safebrowsing/test_notification.py b/testing/firefox-ui/tests/functional/safebrowsing/test_notification.py
new file mode 100644
index 0000000000..4bc8d1219c
--- /dev/null
+++ b/testing/firefox-ui/tests/functional/safebrowsing/test_notification.py
@@ -0,0 +1,132 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import time
+
+from marionette_driver import By, Wait, expected
+from marionette_harness import MarionetteTestCase, WindowManagerMixin
+
+
+class TestSafeBrowsingNotificationBar(WindowManagerMixin, MarionetteTestCase):
+ def setUp(self):
+ super(TestSafeBrowsingNotificationBar, self).setUp()
+
+ self.test_data = [
+ # Unwanted software URL
+ {"unsafe_page": "https://www.itisatrap.org/firefox/unwanted.html"},
+ # Phishing URL info
+ {"unsafe_page": "https://www.itisatrap.org/firefox/its-a-trap.html"},
+ # Malware URL object
+ {"unsafe_page": "https://www.itisatrap.org/firefox/its-an-attack.html"},
+ ]
+
+ self.default_homepage = self.marionette.get_pref("browser.startup.homepage")
+
+ self.marionette.set_pref("browser.safebrowsing.phishing.enabled", True)
+ self.marionette.set_pref("browser.safebrowsing.malware.enabled", True)
+
+ # Give the browser a little time, because SafeBrowsing.jsm takes a while
+ # between start up and adding the example urls to the db.
+ # hg.mozilla.org/mozilla-central/file/46aebcd9481e/browser/base/content/browser.js#l1194
+ time.sleep(3)
+
+ # Run this test in a new tab.
+ new_tab = self.open_tab()
+ self.marionette.switch_to_window(new_tab)
+
+ def tearDown(self):
+ try:
+ self.marionette.clear_pref("browser.safebrowsing.phishing.enabled")
+ self.marionette.clear_pref("browser.safebrowsing.malware.enabled")
+
+ self.remove_permission("https://www.itisatrap.org", "safe-browsing")
+ self.close_all_tabs()
+ finally:
+ super(TestSafeBrowsingNotificationBar, self).tearDown()
+
+ def test_notification_bar(self):
+ for item in self.test_data:
+ unsafe_page = item["unsafe_page"]
+
+ # Return to the unsafe page
+ # Check "ignore warning" link then notification bar's "get me out" button
+ self.marionette.navigate(unsafe_page)
+ # Wait for the DOM to receive events for about:blocked
+ time.sleep(1)
+ self.check_ignore_warning_link(unsafe_page)
+ self.check_get_me_out_of_here_button()
+
+ # Return to the unsafe page
+ # Check "ignore warning" link then notification bar's "X" button
+ self.marionette.navigate(unsafe_page)
+ # Wait for the DOM to receive events for about:blocked
+ time.sleep(1)
+ self.check_ignore_warning_link(unsafe_page)
+ self.check_x_button()
+
+ def get_final_url(self, url):
+ self.marionette.navigate(url)
+ return self.marionette.get_url()
+
+ def remove_permission(self, host, permission):
+ with self.marionette.using_context("chrome"):
+ self.marionette.execute_script(
+ """
+ let uri = Services.io.newURI(arguments[0], null, null);
+ let principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
+ Services.perms.removeFromPrincipal(principal, arguments[1]);
+ """,
+ script_args=[host, permission],
+ )
+
+ def check_ignore_warning_link(self, unsafe_page):
+ button = self.marionette.find_element(By.ID, "seeDetailsButton")
+ button.click()
+ time.sleep(1)
+ link = self.marionette.find_element(By.ID, "ignore_warning_link")
+ link.click()
+
+ Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
+ expected.element_present(By.ID, "main-feature"),
+ message='Expected target element "#main-feature" has not been found',
+ )
+ self.assertEqual(self.marionette.get_url(), self.get_final_url(unsafe_page))
+
+ # Clean up here since the permission gets set in this function
+ self.remove_permission("https://www.itisatrap.org", "safe-browsing")
+
+ def check_get_me_out_of_here_button(self):
+ with self.marionette.using_context("chrome"):
+ notification_box = self.marionette.find_element(
+ By.CSS_SELECTOR, 'vbox.notificationbox-stack[slot="selected"]'
+ )
+ message = notification_box.find_element(
+ By.CSS_SELECTOR, "notification-message"
+ )
+ button_container = message.get_property("buttonContainer")
+ button = button_container.find_element(
+ By.CSS_SELECTOR, 'button[label="Get me out of here!"]'
+ )
+ button.click()
+
+ Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
+ lambda mn: self.default_homepage in mn.get_url(),
+ message="The default home page has not been loaded",
+ )
+
+ def check_x_button(self):
+ with self.marionette.using_context("chrome"):
+ notification_box = self.marionette.find_element(
+ By.CSS_SELECTOR, 'vbox.notificationbox-stack[slot="selected"]'
+ )
+ message = notification_box.find_element(
+ By.CSS_SELECTOR, "notification-message[value=blocked-badware-page]"
+ )
+ button = message.get_property("closeButton")
+ button.click()
+
+ Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
+ expected.element_stale(button),
+ message="The notification bar has not been closed",
+ )
diff --git a/testing/firefox-ui/tests/functional/safebrowsing/test_warning_pages.py b/testing/firefox-ui/tests/functional/safebrowsing/test_warning_pages.py
new file mode 100644
index 0000000000..1e5b3e2f56
--- /dev/null
+++ b/testing/firefox-ui/tests/functional/safebrowsing/test_warning_pages.py
@@ -0,0 +1,138 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import time
+
+from marionette_driver import By, Wait, expected
+from marionette_harness import MarionetteTestCase, WindowManagerMixin
+
+
+class TestSafeBrowsingWarningPages(WindowManagerMixin, MarionetteTestCase):
+ def setUp(self):
+ super(TestSafeBrowsingWarningPages, self).setUp()
+
+ self.urls = [
+ # Unwanted software URL
+ "https://www.itisatrap.org/firefox/unwanted.html",
+ # Phishing URL
+ "https://www.itisatrap.org/firefox/its-a-trap.html",
+ # Malware URL
+ "https://www.itisatrap.org/firefox/its-an-attack.html",
+ ]
+
+ self.default_homepage = self.marionette.get_pref("browser.startup.homepage")
+ self.support_page = self.marionette.absolute_url("support.html?topic=")
+
+ self.marionette.set_pref("app.support.baseURL", self.support_page)
+ self.marionette.set_pref("browser.safebrowsing.phishing.enabled", True)
+ self.marionette.set_pref("browser.safebrowsing.malware.enabled", True)
+
+ # Give the browser a little time, because SafeBrowsing.jsm takes a
+ # while between start up and adding the example urls to the db.
+ # hg.mozilla.org/mozilla-central/file/46aebcd9481e/browser/base/content/browser.js#l1194
+ time.sleep(3)
+
+ # Run this test in a new tab.
+ new_tab = self.open_tab()
+ self.marionette.switch_to_window(new_tab)
+
+ def tearDown(self):
+ try:
+ self.marionette.clear_pref("app.support.baseURL")
+ self.marionette.clear_pref("browser.safebrowsing.malware.enabled")
+ self.marionette.clear_pref("browser.safebrowsing.phishing.enabled")
+
+ self.remove_permission("https://www.itisatrap.org", "safe-browsing")
+ self.close_all_tabs()
+ finally:
+ super(TestSafeBrowsingWarningPages, self).tearDown()
+
+ def test_warning_pages(self):
+ for unsafe_page in self.urls:
+ # Load a test page, then test the get me out button
+ self.marionette.navigate(unsafe_page)
+ # Wait for the DOM to receive events for about:blocked
+ time.sleep(1)
+ self.check_get_me_out_of_here_button(unsafe_page)
+
+ # Load the test page again, then test the report button
+ self.marionette.navigate(unsafe_page)
+ # Wait for the DOM to receive events for about:blocked
+ time.sleep(1)
+ self.check_report_link(unsafe_page)
+
+ # Load the test page again, then test the ignore warning button
+ self.marionette.navigate(unsafe_page)
+ # Wait for the DOM to receive events for about:blocked
+ time.sleep(1)
+ self.check_ignore_warning_button(unsafe_page)
+
+ def get_final_url(self, url):
+ self.marionette.navigate(url)
+ return self.marionette.get_url()
+
+ def remove_permission(self, host, permission):
+ with self.marionette.using_context("chrome"):
+ self.marionette.execute_script(
+ """
+ let uri = Services.io.newURI(arguments[0], null, null);
+ let principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
+ Services.perms.removeFromPrincipal(principal, arguments[1]);
+ """,
+ script_args=[host, permission],
+ )
+
+ def check_get_me_out_of_here_button(self, unsafe_page):
+ button = self.marionette.find_element(By.ID, "goBackButton")
+ button.click()
+
+ Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
+ lambda mn: self.default_homepage in mn.get_url()
+ )
+
+ def check_report_link(self, unsafe_page):
+ # Get the URL of the support site for phishing and malware. This may result in a redirect.
+ with self.marionette.using_context("chrome"):
+ url = self.marionette.execute_script(
+ """
+ return Services.urlFormatter.formatURLPref("app.support.baseURL")
+ + "phishing-malware";
+ """
+ )
+
+ button = self.marionette.find_element(By.ID, "seeDetailsButton")
+ button.click()
+ link = self.marionette.find_element(By.ID, "firefox_support")
+ link.click()
+
+ # Wait for the button to become stale, whereby a longer timeout is needed
+ # here to not fail in case of slow connections.
+ Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
+ expected.element_stale(button)
+ )
+
+ # Wait for page load to be completed, so we can verify the URL even if a redirect happens.
+ # TODO: Bug 1140470: use replacement for mozmill's waitforPageLoad
+ expected_url = self.get_final_url(url)
+ Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
+ lambda mn: expected_url == mn.get_url(),
+ message="The expected URL '{}' has not been loaded".format(expected_url),
+ )
+
+ topic = self.marionette.find_element(By.ID, "topic")
+ self.assertEqual(topic.text, "phishing-malware")
+
+ def check_ignore_warning_button(self, unsafe_page):
+ button = self.marionette.find_element(By.ID, "seeDetailsButton")
+ button.click()
+ link = self.marionette.find_element(By.ID, "ignore_warning_link")
+ link.click()
+
+ Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
+ expected.element_present(By.ID, "main-feature")
+ )
+ self.assertEqual(self.marionette.get_url(), self.get_final_url(unsafe_page))
+
+ # Clean up by removing safe browsing permission for unsafe page
+ self.remove_permission("https://www.itisatrap.org", "safe-browsing")
diff --git a/testing/firefox-ui/tests/functional/security/manifest.ini b/testing/firefox-ui/tests/functional/security/manifest.ini
new file mode 100644
index 0000000000..7d95e2499f
--- /dev/null
+++ b/testing/firefox-ui/tests/functional/security/manifest.ini
@@ -0,0 +1 @@
+[test_ssl_status_after_restart.py]
diff --git a/testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py b/testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py
new file mode 100644
index 0000000000..3684433f6f
--- /dev/null
+++ b/testing/firefox-ui/tests/functional/security/test_ssl_status_after_restart.py
@@ -0,0 +1,56 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_driver import By, Wait
+from marionette_harness import MarionetteTestCase, WindowManagerMixin
+
+
+class TestSSLStatusAfterRestart(WindowManagerMixin, MarionetteTestCase):
+ def setUp(self):
+ super(TestSSLStatusAfterRestart, self).setUp()
+ self.marionette.set_context("chrome")
+
+ self.test_url = "https://www.itisatrap.org/"
+
+ # Set browser to restore previous session
+ self.marionette.set_pref("browser.startup.page", 3)
+ # Disable rcwn to make cache behavior deterministic
+ self.marionette.set_pref("network.http.rcwn.enable", False)
+
+ def tearDown(self):
+ self.marionette.clear_pref("browser.startup.page")
+ self.marionette.clear_pref("network.http.rcwn.enable")
+
+ super(TestSSLStatusAfterRestart, self).tearDown()
+
+ def test_ssl_status_after_restart(self):
+ with self.marionette.using_context("content"):
+ self.marionette.navigate(self.test_url)
+ self.verify_certificate_status(self.test_url)
+
+ self.marionette.restart(in_app=True)
+
+ self.verify_certificate_status(self.test_url)
+
+ def verify_certificate_status(self, url):
+ with self.marionette.using_context("content"):
+ Wait(self.marionette).until(
+ lambda _: self.marionette.get_url() == url,
+ message="Expected URL loaded",
+ )
+
+ identity_box = self.marionette.find_element(By.ID, "identity-box")
+ self.assertEqual(identity_box.get_attribute("pageproxystate"), "valid")
+
+ class_list = self.marionette.execute_script(
+ """
+ const names = [];
+ for (const name of arguments[0].classList) {
+ names.push(name);
+ }
+ return names;
+ """,
+ script_args=[identity_box],
+ )
+ self.assertIn("verifiedDomain", class_list)