diff --git a/testing/marionette/client/marionette/__init__.py b/testing/marionette/client/marionette/__init__.py index fd39434f0f9e..1894eb274cfe 100644 --- a/testing/marionette/client/marionette/__init__.py +++ b/testing/marionette/client/marionette/__init__.py @@ -18,6 +18,7 @@ from runner import ( MarionetteTestResult, MarionetteTextTestRunner, MemoryEnduranceTestCaseMixin, + MozHttpd, OptionParser, TestManifest, TestResult, diff --git a/testing/marionette/client/marionette/runner/__init__.py b/testing/marionette/client/marionette/runner/__init__.py index 7458855bf1a5..c0ba0a7d487a 100644 --- a/testing/marionette/client/marionette/runner/__init__.py +++ b/testing/marionette/client/marionette/runner/__init__.py @@ -5,7 +5,7 @@ from base import ( B2GTestResultMixin, BaseMarionetteOptions, BaseMarionetteTestRunner, Marionette, MarionetteTest, MarionetteTestResult, MarionetteTextTestRunner, - OptionParser, TestManifest, TestResult, TestResultCollection + MozHttpd, OptionParser, TestManifest, TestResult, TestResultCollection ) from mixins import ( B2GTestCaseMixin, B2GTestResultMixin, EnduranceOptionsMixin, diff --git a/testing/marionette/client/marionette/runner/base.py b/testing/marionette/client/marionette/runner/base.py index 55c2ea6fef3e..9690104967f5 100644 --- a/testing/marionette/client/marionette/runner/base.py +++ b/testing/marionette/client/marionette/runner/base.py @@ -14,20 +14,18 @@ import sys import time import traceback import unittest -import warnings import xml.dom.minidom as dom from manifestparser import TestManifest from manifestparser.filters import tags from marionette_driver.marionette import Marionette from mixins.b2g import B2GTestResultMixin, get_b2g_pid, get_dm +from mozhttpd import MozHttpd from mozlog.structured.structuredlog import get_default_logger from moztest.adapters.unit import StructuredTestRunner, StructuredTestResult from moztest.results import TestResultCollection, TestResult, relevant_line import mozversion -import httpd - here = os.path.abspath(os.path.dirname(__file__)) @@ -640,6 +638,24 @@ class BaseMarionetteTestRunner(object): self.skipped = 0 self.failures = [] + def start_httpd(self, need_external_ip): + if self.server_root is None or os.path.isdir(self.server_root): + host = '127.0.0.1' + if need_external_ip: + host = moznetwork.get_ip() + docroot = self.server_root or os.path.join(os.path.dirname(here), 'www') + if not os.path.isdir(docroot): + raise Exception('Server root %s is not a valid path' % docroot) + self.httpd = MozHttpd(host=host, + port=0, + docroot=docroot) + self.httpd.start() + self.marionette.baseurl = 'http://%s:%d/' % (host, self.httpd.httpd.server_port) + self.logger.info('running webserver on %s' % self.marionette.baseurl) + else: + self.marionette.baseurl = self.server_root + self.logger.info('using content from %s' % self.marionette.baseurl) + def _build_kwargs(self): kwargs = { 'device_serial': self.device_serial, @@ -765,8 +781,6 @@ setReq.onerror = function() { if not self.httpd: self.logger.info("starting httpd") self.start_httpd(need_external_ip) - self.marionette.baseurl = self.httpd.get_url() - self.logger.info("running httpd on %s" % self.marionette.baseurl) for test in tests: self.add_test(test) @@ -847,20 +861,6 @@ setReq.onerror = function() { self.logger.suite_end() - def start_httpd(self, need_external_ip): - warnings.warn("start_httpd has been deprecated in favour of create_httpd", - DeprecationWarning) - self.httpd = self.create_httpd(need_external_ip) - - def create_httpd(self, need_external_ip): - host = "127.0.0.1" - if need_external_ip: - host = moznetwork.get_ip() - root = self.server_root or os.path.join(os.path.dirname(here), "www") - rv = httpd.FixtureServer(root, host=host) - rv.start() - return rv - def add_test(self, test, expected='pass', test_container=None): filepath = os.path.abspath(test) diff --git a/testing/marionette/client/marionette/runner/httpd.py b/testing/marionette/client/marionette/runner/httpd.py deleted file mode 100644 index 1c787c9e22cb..000000000000 --- a/testing/marionette/client/marionette/runner/httpd.py +++ /dev/null @@ -1,61 +0,0 @@ -# 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 mozhttpd import MozHttpd - - -class FixtureServer(object): - - def __init__(self, root, host="127.0.0.1", port=0): - if not os.path.isdir(root): - raise Exception("Server root is not a valid path: %s" % root) - self.root = root - self.host = host - self.port = port - self._server = None - - def start(self, block=False): - if self.alive: - return - self._server = MozHttpd(host=self.host, port=self.port, docroot=self.root, urlhandlers=[ - {"method": "POST", "path": "/file_upload", "function": upload_handler}]) - self._server.start(block=block) - self.port = self._server.httpd.server_port - self.base_url = self.get_url() - - def stop(self): - if not self.alive: - return - self._server.stop() - self._server = None - - @property - def alive(self): - return self._server is not None - - def get_url(self, path="/"): - if not self.alive: - raise "Server not started" - return self._server.get_url(path) - - @property - def urlhandlers(self): - return self._server.urlhandlers - - -def upload_handler(query, postdata=None): - return (200, {}, query.headers.getheader("Content-Type")) - - -if __name__ == "__main__": - here = os.path.abspath(os.path.dirname(__file__)) - root = os.path.join(os.path.dirname(here), "www") - httpd = FixtureServer(root, port=2829) - print "Started fixture server on http://%s:%d/" % (httpd.host, httpd.port) - try: - httpd.start(True) - except KeyboardInterrupt: - pass diff --git a/testing/marionette/client/marionette/tests/unit/test_file_upload.py b/testing/marionette/client/marionette/tests/unit/test_file_upload.py deleted file mode 100644 index 8d1201470b88..000000000000 --- a/testing/marionette/client/marionette/tests/unit/test_file_upload.py +++ /dev/null @@ -1,135 +0,0 @@ -# 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 contextlib -import urllib - -from tempfile import NamedTemporaryFile as tempfile - -from marionette import MarionetteTestCase, skip -from marionette_driver import By, errors, expected -from marionette_driver.wait import Wait - - -single = "data:text/html,%s" % urllib.quote("") -multiple = "data:text/html,%s" % urllib.quote("") -upload = lambda url: "data:text/html,%s" % urllib.quote(""" -
- - -
""" % url) - - -class TestFileUpload(MarionetteTestCase): - - def test_sets_one_file(self): - self.marionette.navigate(single) - input = self.input - - exp = None - with tempfile() as f: - input.send_keys(f.name) - exp = [f.name] - - files = self.get_files(input) - self.assertEqual(len(files), 1) - self.assertFilesEqual(files, exp) - - def test_sets_multiple_files(self): - self.marionette.navigate(multiple) - input = self.input - - exp = None - with contextlib.nested(tempfile(), tempfile()) as (a, b): - input.send_keys(a.name) - input.send_keys(b.name) - exp = [a.name, b.name] - - files = self.get_files(input) - self.assertEqual(len(files), 2) - self.assertFilesEqual(files, exp) - - def test_sets_multiple_indentical_files(self): - self.marionette.navigate(multiple) - input = self.input - - exp = [] - with tempfile() as f: - input.send_keys(f.name) - input.send_keys(f.name) - exp = f.name - - files = self.get_files(input) - self.assertEqual(len(files), 2) - self.assertFilesEqual(files, exp) - - def test_clear_file(self): - self.marionette.navigate(single) - input = self.input - - with tempfile() as f: - input.send_keys(f.name) - - self.assertEqual(len(self.get_files(input)), 1) - input.clear() - self.assertEqual(len(self.get_files(input)), 0) - - def test_clear_files(self): - self.marionette.navigate(multiple) - input = self.input - - with contextlib.nested(tempfile(), tempfile()) as (a, b): - input.send_keys(a.name) - input.send_keys(b.name) - - self.assertEqual(len(self.get_files(input)), 2) - input.clear() - self.assertEqual(len(self.get_files(input)), 0) - - def test_illegal_file(self): - self.marionette.navigate(single) - with self.assertRaisesRegexp(errors.MarionetteException, "File not found"): - self.input.send_keys("rochefort") - - def test_upload(self): - self.marionette.navigate( - upload(self.marionette.absolute_url("file_upload"))) - - with tempfile() as f: - f.write("camembert") - f.flush() - self.input.send_keys(f.name) - self.submit.click() - - self.assertIn("multipart/form-data", self.body.text) - - def find_inputs(self): - return self.marionette.find_elements("tag name", "input") - - @property - def input(self): - return self.find_inputs()[0] - - @property - def submit(self): - return self.find_inputs()[1] - - @property - def body(self): - return Wait(self.marionette).until( - expected.element_present(By.TAG_NAME, "body")) - - def get_files(self, el): - # This is horribly complex because (1) Marionette doesn't serialise arrays properly, - # and (2) accessing File.name in the content JS throws a permissions - # error. - fl = self.marionette.execute_script( - "return arguments[0].files", script_args=[el]) - return [f["name"] for f in [v for k, v in fl.iteritems() if k.isdigit()]] - - def assertFilesEqual(self, act, exp): - # File array returned from browser doesn't contain full path names, - # this cuts off the path of the expected files. - filenames = [f.rsplit("/", 0)[-1] for f in act] - self.assertListEqual(filenames, act) diff --git a/testing/marionette/client/marionette/tests/unit/unit-tests.ini b/testing/marionette/client/marionette/tests/unit/unit-tests.ini index 2e539e9f66d0..5ad6d7f47024 100644 --- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini +++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini @@ -154,6 +154,3 @@ b2g = false b2g = false [test_teardown_context_preserved.py] b2g = false -[test_file_upload.py] -b2g = false -skip-if = os == "win" # http://bugs.python.org/issue14574 diff --git a/testing/marionette/driver.js b/testing/marionette/driver.js index fa0bc8631766..7551fa07b628 100644 --- a/testing/marionette/driver.js +++ b/testing/marionette/driver.js @@ -884,9 +884,8 @@ GeckoDriver.prototype.executeScriptInSandbox = function( directInject, async, timeout) { - if (directInject && async && (timeout == null || timeout == 0)) { + if (directInject && async && (timeout == null || timeout == 0)) throw new TimeoutError("Please set a timeout"); - } if (this.importedScripts.exists()) { let stream = Cc["@mozilla.org/network/file-input-stream;1"] @@ -2308,10 +2307,6 @@ GeckoDriver.prototype.getElementRect = function(cmd, resp) { GeckoDriver.prototype.sendKeysToElement = function(cmd, resp) { let {id, value} = cmd.parameters; - if (!value) { - throw new IllegalArgumentError(`Expected character sequence: ${value}`); - } - switch (this.context) { case Context.CHROME: let win = this.getCurrentWindow(); @@ -2327,36 +2322,7 @@ GeckoDriver.prototype.sendKeysToElement = function(cmd, resp) { break; case Context.CONTENT: - let err; - let listener = function(msg) { - this.mm.removeMessageListener("Marionette:setElementValue", listener); - - let val = msg.data.value; - let el = msg.objects.element; - let win = this.getCurrentWindow(); - - if (el.type == "file") { - Cu.importGlobalProperties(["File"]); - let fs = Array.prototype.slice.call(el.files); - let file; - try { - file = new File(val); - } catch (e) { - err = new IllegalArgumentError(`File not found: ${val}`); - } - fs.push(file); - el.mozSetFileArray(fs); - } else { - el.value = val; - } - }.bind(this); - - this.mm.addMessageListener("Marionette:setElementValue", listener); yield this.listener.sendKeysToElement({id: id, value: value}); - this.mm.removeMessageListener("Marionette:setElementValue", listener); - if (err) { - throw err; - } break; } }; diff --git a/testing/marionette/error.js b/testing/marionette/error.js index 9f664fa37260..db5edcaaf236 100644 --- a/testing/marionette/error.js +++ b/testing/marionette/error.js @@ -10,7 +10,6 @@ const errors = [ "ElementNotVisibleError", "FrameSendFailureError", "FrameSendNotInitializedError", - "IllegalArgumentError", "InvalidElementStateError", "JavaScriptError", "NoAlertOpenError", @@ -160,14 +159,6 @@ this.FrameSendNotInitializedError = function(frame) { }; FrameSendNotInitializedError.prototype = Object.create(WebDriverError.prototype); -this.IllegalArgumentError = function(msg) { - WebDriverError.call(this, msg); - this.name = "IllegalArgumentError"; - this.status = "illegal argument"; - this.code = 13; // unknown error -}; -IllegalArgumentError.prototype = Object.create(WebDriverError.prototype); - this.InvalidElementStateError = function(msg) { WebDriverError.call(this, msg); this.name = "InvalidElementStateError"; @@ -309,7 +300,6 @@ const errorObjs = [ this.ElementNotVisibleError, this.FrameSendFailureError, this.FrameSendNotInitializedError, - this.IllegalArgumentError, this.InvalidElementStateError, this.JavaScriptError, this.NoAlertOpenError, diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js index 33822d5cd4db..c10b3d9e2e3d 100644 --- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -35,10 +35,9 @@ let isB2G = false; let marionetteTestName; let winUtil = content.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); -let listenerId = null; // unique ID of this listener + .getInterface(Ci.nsIDOMWindowUtils); +let listenerId = null; //unique ID of this listener let curFrame = content; -let isRemoteBrowser = () => curFrame.contentWindow !== null; let previousFrame = null; let elementManager = new ElementManager([]); let accessibility = new Accessibility(); @@ -1549,39 +1548,11 @@ function isElementSelected(msg) { */ function sendKeysToElement(msg) { let command_id = msg.json.command_id; - let val = msg.json.value; let el = elementManager.getKnownElement(msg.json.id, curFrame); - if (el.type == "file") { - let p = val.join(""); + let keysToSend = msg.json.value; - // for some reason using mozSetFileArray doesn't work with e10s - // enabled (probably a bug), but a workaround is to elevate the element's - // privileges with SpecialPowers - // - // this extra branch can be removed when the e10s bug 1149998 is fixed - if (isRemoteBrowser()) { - let fs = Array.prototype.slice.call(el.files); - let file; - try { - file = new File(p); - } catch (e) { - let err = new IllegalArgumentError(`File not found: ${val}`); - sendError(err.message, err.code, err.stack, command_id); - return; - } - fs.push(file); - - let wel = new SpecialPowers(utils.window).wrap(el); - wel.mozSetFileArray(fs); - } else { - sendSyncMessage("Marionette:setElementValue", {value: p}, {element: el}); - } - - sendOk(command_id); - } else { - utils.sendKeysToElement(curFrame, el, val, sendOk, sendError, command_id); - } + utils.sendKeysToElement(curFrame, el, keysToSend, sendOk, sendError, command_id); } /** @@ -1611,13 +1582,10 @@ function clearElement(msg) { let command_id = msg.json.command_id; try { let el = elementManager.getKnownElement(msg.json.id, curFrame); - if (el.type == "file") { - el.value = null; - } else { - utils.clearElement(el); - } + utils.clearElement(el); sendOk(command_id); - } catch (e) { + } + catch (e) { sendError(e.message, e.code, e.stack, command_id); } }