author | Philipp von Weitershausen <philipp@weitershausen.de> |
Fri, 18 May 2012 13:30:43 -0700 | |
changeset 94360 | 9dab33fa5ff4aecbc36dfd6c09027fee897cf05e |
parent 94359 | 921706236f86b85e1df48757963ddc87a98d0cb9 |
child 94417 | 642d1a36702f7fb3f34dd3a4220adf6a5a257fa9 |
child 94422 | b292b2847b7f1de280c57384a2426dd0e25455b3 |
push id | 22711 |
push user | pweitershausen@mozilla.com |
push date | Fri, 18 May 2012 20:31:04 +0000 |
treeherder | mozilla-central@9dab33fa5ff4 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jgriffin |
bugs | 754216 |
milestone | 15.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -164,21 +164,37 @@ class Marionette(object): self.window = None self.client.close() if self.emulator: port = self.emulator.restart(self.local_port) if port is not None: self.port = self.client.port = port raise TimeoutException(message='socket.timeout', status=21, stacktrace=None) + # Process any emulator commands that are sent from a script + # while it's executing. + while response.get("emulator_cmd"): + response = self._handle_emulator_cmd(response) + if (response_key == 'ok' and response.get('ok') == True) or response_key in response: return response[response_key] else: self._handle_error(response) + def _handle_emulator_cmd(self, response): + cmd = response.get("emulator_cmd") + if not cmd or not self.emulator: + raise MarionetteException(message="No emulator in this test to run " + "command against.") + cmd = cmd.encode("ascii") + result = self.emulator._run_telnet(cmd) + return self.client.send({"type": "emulatorCmdResult", + "id": response.get("id"), + "result": result}) + def _handle_error(self, response): if 'error' in response and isinstance(response['error'], dict): status = response['error'].get('status', 500) message = response['error'].get('message') stacktrace = response['error'].get('stacktrace') # status numbers come from # http://code.google.com/p/selenium/wiki/JsonWireProtocol#Response_Status_Codes if status == 7:
--- a/testing/marionette/client/marionette/marionette_test.py +++ b/testing/marionette/client/marionette/marionette_test.py @@ -146,16 +146,20 @@ class MarionetteJSTestCase(CommonTestCas else: js += line context = self.context_re.search(js) if context: context = context.group(3) self.marionette.set_context(context) + if context != "chrome": + page = self.marionette.absolute_url("empty.html") + self.marionette.navigate(page) + timeout = self.timeout_re.search(js) if timeout: timeout = timeout.group(3) self.marionette.set_script_timeout(timeout) launch_app = self.launch_re.search(js) if launch_app: launch_app = launch_app.group(3)
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/marionette/tests/unit/test_emulator.py @@ -0,0 +1,20 @@ +from marionette_test import MarionetteTestCase +from errors import JavascriptException, MarionetteException + +class TestEmulatorContent(MarionetteTestCase): + + def test_emulator_cmd(self): + self.marionette.set_script_timeout(10000) + expected = ["gsm voice state: home", + "gsm data state: home", + "OK"] + result = self.marionette.execute_async_script(""" + runEmulatorCmd("gsm status", marionetteScriptFinished) + """); + self.assertEqual(result, expected) + +class TestEmulatorChrome(TestEmulatorContent): + + def setUp(self): + super(TestEmulatorChrome, self).setUp() + self.marionette.set_context("chrome")
--- a/testing/marionette/client/marionette/tests/unit/test_simpletest_pass.js +++ b/testing/marionette/client/marionette/tests/unit/test_simpletest_pass.js @@ -2,10 +2,13 @@ * 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/. */ MARIONETTE_TIMEOUT = 1000; is(2, 2, "test for is()"); isnot(2, 3, "test for isnot()"); ok(2 == 2, "test for ok()"); + +is(window.location.pathname.slice(-10), "empty.html"); + setTimeout(finish, 100);
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini +++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini @@ -5,16 +5,17 @@ b2g = false [test_getattr.py] b2g = false [test_elementState.py] b2g = false [test_text.py] b2g = false [test_log.py] +[test_emulator.py] [test_execute_async_script.py] [test_execute_script.py] [test_simpletest_fail.js] [test_findelement.py] b2g = false [test_navigation.py] b2g = false
new file mode 100644 --- /dev/null +++ b/testing/marionette/client/marionette/www/empty.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> +<head> +<title>Marionette Test</title> +</head> +<body> +</body> +</html>
--- a/testing/marionette/client/marionette/www/test.html +++ b/testing/marionette/client/marionette/www/test.html @@ -1,9 +1,9 @@ -<!doctype html> +<!DOCTYPE html> <html> <head> <title>Marionette Test</title> </head> <body> <h1 id="testh1">Test Page</h1> <script type="text/javascript"> window.ready = true;
--- a/testing/marionette/marionette-actors.js +++ b/testing/marionette/marionette-actors.js @@ -126,16 +126,17 @@ function MarionetteDriverActor(aConnecti //register all message listeners this.messageManager.addMessageListener("Marionette:ok", this); this.messageManager.addMessageListener("Marionette:done", this); this.messageManager.addMessageListener("Marionette:error", this); this.messageManager.addMessageListener("Marionette:log", this); this.messageManager.addMessageListener("Marionette:testLog", this); this.messageManager.addMessageListener("Marionette:register", this); this.messageManager.addMessageListener("Marionette:goUrl", this); + this.messageManager.addMessageListener("Marionette:runEmulatorCmd", this); } MarionetteDriverActor.prototype = { //name of the actor actorPrefix: "marionette", /** @@ -160,18 +161,23 @@ MarionetteDriverActor.prototype = { * @param object msg * Response to send back to client * @param string command_id * Unique identifier assigned to the client's request. * Used to distinguish the asynchronous responses. */ sendToClient: function MDA_sendToClient(msg, command_id) { logger.info("sendToClient: " + JSON.stringify(msg) + ", " + command_id + ", " + this.command_id); - if (command_id == undefined || command_id == this.command_id) { - this.conn.send(msg); + if (this.command_id != null && + command_id != null && + this.command_id != command_id) { + return; + } + this.conn.send(msg); + if (command_id != null) { this.command_id = null; } }, /** * Send a value to client * * @param object value @@ -501,17 +507,17 @@ MarionetteDriverActor.prototype = { if (this.context == "content") { this.sendAsync("executeScript", {value: aRequest.value, args: aRequest.args, newSandbox:aRequest.newSandbox}); return; } let curWindow = this.getCurrentWindow(); - let marionette = new Marionette(false, curWindow, "chrome", this.marionetteLog); + let marionette = new Marionette(this, curWindow, "chrome", this.marionetteLog); let _chromeSandbox = this.createExecuteSandbox(curWindow, marionette, aRequest.args); if (!_chromeSandbox) return; try { _chromeSandbox.finish = function chromeSandbox_finish() { return marionette.generate_results(); }; @@ -608,17 +614,17 @@ MarionetteDriverActor.prototype = { id: this.command_id, newSandbox: aRequest.newSandbox}); return; } let curWindow = this.getCurrentWindow(); let original_onerror = curWindow.onerror; let that = this; - let marionette = new Marionette(true, curWindow, "chrome", this.marionetteLog); + let marionette = new Marionette(this, curWindow, "chrome", this.marionetteLog); marionette.command_id = this.command_id; function chromeAsyncReturnFunc(value, status) { if (value == undefined) value = null; if (that.command_id == marionette.command_id) { if (that.timer != null) { that.timer.cancel(); @@ -1176,19 +1182,51 @@ MarionetteDriverActor.prototype = { this.sendOk(); this.messageManager.removeMessageListener("Marionette:ok", this); this.messageManager.removeMessageListener("Marionette:done", this); this.messageManager.removeMessageListener("Marionette:error", this); this.messageManager.removeMessageListener("Marionette:log", this); this.messageManager.removeMessageListener("Marionette:testLog", this); this.messageManager.removeMessageListener("Marionette:register", this); this.messageManager.removeMessageListener("Marionette:goUrl", this); + this.messageManager.removeMessageListener("Marionette:runEmulatorCmd", this); this.curBrowser = null; }, + _emu_cb_id: 0, + _emu_cbs: null, + runEmulatorCmd: function runEmulatorCmd(cmd, callback) { + if (typeof callback != "function") { + throw "Need to provide callback function!"; + } + if (!this._emu_cbs) { + this._emu_cbs = {}; + } + this._emu_cbs[this._emu_cb_id] = callback; + this.sendToClient({emulator_cmd: cmd, id: this._emu_cb_id}); + this._emu_cb_id += 1; + }, + + emulatorCmdResult: function emulatorCmdResult(message) { + if (this.context != "chrome") { + this.sendAsync("emulatorCmdResult", message); + return; + } + + let cb = this._emu_cbs[message.id]; + delete this._emu_cbs[message.id]; + try { + cb(message.result); + } + catch(e) { + this.sendError(e.message, e.num, e.stack); + return; + } + }, + /** * Receives all messages from content messageManager */ receiveMessage: function MDA_receiveMessage(message) { switch (message.name) { case "DOMContentLoaded": this.sendOk(); this.messageManager.removeMessageListener("DOMContentLoaded", this, true); @@ -1205,16 +1243,19 @@ MarionetteDriverActor.prototype = { case "Marionette:log": //log server-side messages logger.info(message.json.message); break; case "Marionette:testLog": //log messages from tests this.marionetteLog.addLogs(message.json.value); break; + case "Marionette:runEmulatorCmd": + this.sendToClient(message.json); + break; case "Marionette:register": // This code processes the content listener's registration information // and either accepts the listener, or ignores it let nullPrevious = (this.curBrowser.curFrameId == null); let curWin = this.getCurrentWindow(); let frameObject = curWin.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowUtils).getOuterWindowWithId(message.json.value); let reg = this.curBrowser.register(message.json.value, message.json.href); if (reg) { @@ -1264,17 +1305,18 @@ MarionetteDriverActor.prototype.requestT "getUrl": MarionetteDriverActor.prototype.getUrl, "goBack": MarionetteDriverActor.prototype.goBack, "goForward": MarionetteDriverActor.prototype.goForward, "refresh": MarionetteDriverActor.prototype.refresh, "getWindow": MarionetteDriverActor.prototype.getWindow, "getWindows": MarionetteDriverActor.prototype.getWindows, "switchToFrame": MarionetteDriverActor.prototype.switchToFrame, "switchToWindow": MarionetteDriverActor.prototype.switchToWindow, - "deleteSession": MarionetteDriverActor.prototype.deleteSession + "deleteSession": MarionetteDriverActor.prototype.deleteSession, + "emulatorCmdResult": MarionetteDriverActor.prototype.emulatorCmdResult }; /** * Creates a BrowserObj. BrowserObjs handle interactions with the * browser, according to the current environment (desktop, b2g, etc.) * * @param nsIDOMWindow win * The window whose browser needs to be accessed
--- a/testing/marionette/marionette-listener.js +++ b/testing/marionette/marionette-listener.js @@ -96,16 +96,17 @@ function startListeners() { addMessageListenerId("Marionette:isElementDisplayed", isElementDisplayed); addMessageListenerId("Marionette:isElementEnabled", isElementEnabled); addMessageListenerId("Marionette:isElementSelected", isElementSelected); addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement); addMessageListenerId("Marionette:clearElement", clearElement); addMessageListenerId("Marionette:switchToFrame", switchToFrame); addMessageListenerId("Marionette:deleteSession", deleteSession); addMessageListenerId("Marionette:sleepSession", sleepSession); + addMessageListenerId("Marionette:emulatorCmdResult", emulatorCmdResult); } /** * Called when we start a new session. It registers the * current environment, and resets all values */ function newSession(msg) { isB2G = msg.json.B2G; @@ -153,16 +154,17 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:isElementDisplayed", isElementDisplayed); removeMessageListenerId("Marionette:isElementEnabled", isElementEnabled); removeMessageListenerId("Marionette:isElementSelected", isElementSelected); removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement); removeMessageListenerId("Marionette:clearElement", clearElement); removeMessageListenerId("Marionette:switchToFrame", switchToFrame); removeMessageListenerId("Marionette:deleteSession", deleteSession); removeMessageListenerId("Marionette:sleepSession", sleepSession); + removeMessageListenerId("Marionette:emulatorCmdResult", emulatorCmdResult); this.elementManager.reset(); } /* * Helper methods */ /** @@ -232,17 +234,17 @@ function createExecuteContentSandbox(aWi let sandbox = new Cu.Sandbox(aWindow); sandbox.global = sandbox; sandbox.window = aWindow; sandbox.document = sandbox.window.document; sandbox.navigator = sandbox.window.navigator; sandbox.__proto__ = sandbox.window; sandbox.testUtils = utils; - let marionette = new Marionette(false, aWindow, "content", marionetteLogObj); + let marionette = new Marionette(this, aWindow, "content", marionetteLogObj); sandbox.marionette = marionette; marionette.exports.forEach(function(fn) { sandbox[fn] = marionette[fn].bind(marionette); }); sandbox.SpecialPowers = new SpecialPowers(aWindow); sandbox.asyncComplete = function sandbox_asyncComplete(value, status) { @@ -683,10 +685,34 @@ function switchToFrame(msg) { } curWindow = curWindow.frames[foundFrame]; curWindow.focus(); sendOk(); sandbox = null; } +let _emu_cb_id = 0; +let _emu_cbs = {}; +function runEmulatorCmd(cmd, callback) { + if (typeof callback != "function") { + throw "Need to provide callback function!"; + } + _emu_cbs[_emu_cb_id] = callback; + sendAsyncMessage("Marionette:runEmulatorCmd", {emulator_cmd: cmd, id: _emu_cb_id}); + _emu_cb_id += 1; +} + +function emulatorCmdResult(msg) { + let message = msg.json; + let cb = _emu_cbs[message.id]; + delete _emu_cbs[message.id]; + try { + cb(message.result); + } + catch(e) { + sendError(e.message, e.num, e.stack); + return; + } +} + //call register self when we get loaded registerSelf();
--- a/testing/marionette/marionette-simpletest.js +++ b/testing/marionette/marionette-simpletest.js @@ -1,26 +1,27 @@ /* 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/. */ /* * The Marionette object, passed to the script context. */ -function Marionette(is_async, window, context, logObj) { - this.is_async = is_async; +function Marionette(scope, window, context, logObj) { + this.scope = scope; this.window = window; this.tests = []; this.logObj = logObj; this.context = context; this.timeout = 0; } Marionette.prototype = { - exports: ['ok', 'is', 'isnot', 'log', 'getLogs', 'generate_results', 'waitFor'], + exports: ['ok', 'is', 'isnot', 'log', 'getLogs', 'generate_results', 'waitFor', + 'runEmulatorCmd'], ok: function Marionette__ok(condition, name, diag) { let test = {'result': !!condition, 'name': name, 'diag': diag}; this.logResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL"); this.tests.push(test); }, is: function Marionette__is(a, b, name) { @@ -129,10 +130,15 @@ Marionette.prototype = { if (Date.now() - timeout > this.timeout) { dump("waitFor timeout: " + test.toString() + "\n"); // the script will timeout here, so no need to raise a separate // timeout exception return; } this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, timeout); }, + + runEmulatorCmd: function runEmulatorCmd(cmd, callback) { + this.scope.runEmulatorCmd(cmd, callback); + }, + };