def __init__(self, *args, **kwargs): """Initialize the test case and create a ping server.""" super(TelemetryTestCase, self).__init__(*args, **kwargs) self.ping_server = PingServer( self.testvars["server_root"], self.testvars["server_url"] )
def fixture_ping_server(): """Run a ping server on localhost on a free port assigned by the OS""" server = PingServer(SERVER_ROOT, "http://localhost:0") server.start() yield server server.stop()
class TelemetryTestCase(WindowManagerMixin, MarionetteTestCase): def __init__(self, *args, **kwargs): """Initialize the test case and create a ping server.""" super(TelemetryTestCase, self).__init__(*args, **kwargs) self.ping_server = PingServer(self.testvars["server_root"], self.testvars["server_url"]) def setUp(self, *args, **kwargs): """Set up the test case and start the ping server.""" super(TelemetryTestCase, self).setUp(*args, **kwargs) # Store IDs of addons installed via self.install_addon() self.addon_ids = [] with self.marionette.using_context(self.marionette.CONTEXT_CONTENT): self.marionette.navigate("about:about") self.ping_server.start() def disable_telemetry(self): """Disable the Firefox Data Collection and Use in the current browser.""" self.marionette.instance.profile.set_persistent_preferences( {"datareporting.healthreport.uploadEnabled": False}) self.marionette.set_pref("datareporting.healthreport.uploadEnabled", False) def enable_telemetry(self): """Enable the Firefox Data Collection and Use in the current browser.""" self.marionette.instance.profile.set_persistent_preferences( {"datareporting.healthreport.uploadEnabled": True}) self.marionette.set_pref("datareporting.healthreport.uploadEnabled", True) @contextlib.contextmanager def new_tab(self): """Perform operations in a new tab and then close the new tab.""" with self.marionette.using_context(self.marionette.CONTEXT_CHROME): start_tab = self.marionette.current_window_handle new_tab = self.open_tab(focus=True) self.marionette.switch_to_window(new_tab) yield self.marionette.close() self.marionette.switch_to_window(start_tab) def search(self, text): """Perform a search via the browser's URL bar.""" # Reload newtab to prevent urlbar from not accepting correct input with self.marionette.using_context(self.marionette.CONTEXT_CONTENT): self.marionette.navigate("about:newtab") with self.marionette.using_context(self.marionette.CONTEXT_CHROME): self.marionette.execute_script("gURLBar.select();") urlbar = self.marionette.find_element(By.ID, "urlbar-input") urlbar.send_keys(keys.Keys.DELETE) urlbar.send_keys(text + keys.Keys.ENTER) # This script checks that the search terms used for searching # appear in the URL when the page loads. script = """\ let location = document.location.toString() function validate(term){ return location.includes(term) } return arguments[0].every(validate) """ # Wait for search page to load with self.marionette.using_context(self.marionette.CONTEXT_CONTENT): Wait(self.marionette, 30, 0.5).until( lambda driver: driver.execute_script( script, script_args=[text.split()]), message="Search terms not found, maybe the page didn't load?", ) def search_in_new_tab(self, text): """Open a new tab and perform a search via the browser's URL bar, then close the new tab.""" with self.new_tab(): self.search(text) def assertIsValidUUID(self, value): """Check if the given UUID is valid.""" self.assertIsNotNone(value) self.assertNotEqual(value, "") # Check for client ID that is used when Telemetry upload is disabled self.assertNotEqual(value, CANARY_CLIENT_ID, msg="UUID is CANARY CLIENT ID") self.assertIsNotNone( re.match(UUID_PATTERN, value), msg="UUID does not match regular expression", ) def wait_for_pings(self, action_func, ping_filter, count, ping_server=None): """Call the given action and wait for pings to come in and return the `count` number of pings, that match the given filter. """ if ping_server is None: ping_server = self.ping_server # Keep track of the current number of pings current_num_pings = len(ping_server.pings) # New list to store new pings that satisfy the filter filtered_pings = [] def wait_func(*args, **kwargs): # Ignore existing pings in ping_server.pings new_pings = ping_server.pings[current_num_pings:] # Filter pings to make sure we wait for the correct ping type filtered_pings[:] = [p for p in new_pings if ping_filter(p)] return len(filtered_pings) >= count self.logger.info("wait_for_pings running action '{action}'.".format( action=action_func.__name__)) # Call given action and wait for a ping action_func() try: Wait(self.marionette, 60).until(wait_func) except Exception as e: self.fail("Error waiting for ping: {}".format(e)) return filtered_pings[:count] def wait_for_ping(self, action_func, ping_filter, ping_server=None): """Call wait_for_pings() with the given action_func and ping_filter and return the first result. """ [ping] = self.wait_for_pings(action_func, ping_filter, 1, ping_server=ping_server) return ping def restart_browser(self): """Restarts browser while maintaining the same profile.""" return self.marionette.restart(clean=False, in_app=True) def start_browser(self): """Start the browser.""" return self.marionette.start_session() def quit_browser(self): """Quit the browser.""" return self.marionette.quit(in_app=True) def install_addon(self): """Install a minimal addon.""" addon_name = "helloworld" self._install_addon(addon_name) def install_dynamic_addon(self): """Install a dynamic probe addon. Source Code: https://github.com/mozilla-extensions/dynamic-probe-telemetry-extension """ addon_name = "dynamic_addon/dynamic-probe-telemetry-extension-signed.xpi" self._install_addon(addon_name, temp=False) def _install_addon(self, addon_name, temp=True): """Logic to install addon and add its ID to self.addons.ids""" resources_dir = os.path.join(os.path.dirname(__file__), "resources") addon_path = os.path.abspath(os.path.join(resources_dir, addon_name)) try: # Ensure the Environment has init'd so the installed addon # triggers an "environment-change" ping. script = """\ let [resolve] = arguments; Cu.import("resource://gre/modules/TelemetryEnvironment.jsm"); TelemetryEnvironment.onInitialized().then(resolve); """ with self.marionette.using_context(self.marionette.CONTEXT_CHROME): self.marionette.execute_async_script(textwrap.dedent(script)) addons = Addons(self.marionette) addon_id = addons.install(addon_path, temp=temp) except MarionetteException as e: self.fail("{} - Error installing addon: {} - ".format(e.cause, e)) else: self.addon_ids.append(addon_id) def set_persistent_profile_preferences(self, preferences): """Wrapper for setting persistent preferences on a user profile""" return self.marionette.instance.profile.set_persistent_preferences( preferences) def set_preferences(self, preferences): """Wrapper for setting persistent preferences on a user profile""" return self.marionette.set_prefs(preferences) @property def client_id(self): """Return the ID of the current client.""" with self.marionette.using_context(self.marionette.CONTEXT_CHROME): return self.marionette.execute_script( 'Cu.import("resource://gre/modules/ClientID.jsm");' "return ClientID.getCachedClientID();") @property def subsession_id(self): """Return the ID of the current subsession.""" with self.marionette.using_context(self.marionette.CONTEXT_CHROME): ping_data = self.marionette.execute_script( 'Cu.import("resource://gre/modules/TelemetryController.jsm");' "return TelemetryController.getCurrentPingData(true);") return ping_data[u"payload"][u"info"][u"subsessionId"] def tearDown(self, *args, **kwargs): """Stop the ping server and tear down the testcase.""" super(TelemetryTestCase, self).tearDown() self.ping_server.stop() self.marionette.quit(clean=True)