зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1223028: Exhaust server-originated commands
The Python client does not currently exhaust all the command requests originating from the server as pointed out by :bhsu in https://bugzilla.mozilla.org/show_bug.cgi?id=1211503#c12. This prevents making multiple calls to runEmulatorCmd and runEmulatorShell inside executeScript/executeJSScript/executeAsyncScript. This failure makes marionette-webapi fail. We loop through all the commands originating from the server until we get sent back a response. r=dburns --HG-- extra : commitid : 8oBRRddi4TJ extra : rebase_source : 98b10ccaba525acd391bf614a91aec1b8f7daf4e
This commit is contained in:
Родитель
4d78a9aa16
Коммит
942d6c9426
|
@ -12,30 +12,27 @@ class TestEmulatorContent(MarionetteTestCase):
|
|||
@skip_if_desktop
|
||||
def test_emulator_cmd(self):
|
||||
self.marionette.set_script_timeout(10000)
|
||||
expected = ["<build>",
|
||||
"OK"]
|
||||
result = self.marionette.execute_async_script("""
|
||||
runEmulatorCmd("avd name", marionetteScriptFinished)
|
||||
""");
|
||||
self.assertEqual(result, expected)
|
||||
expected = ["<build>", "OK"]
|
||||
res = self.marionette.execute_async_script(
|
||||
"runEmulatorCmd('avd name', marionetteScriptFinished)");
|
||||
self.assertEqual(res, expected)
|
||||
|
||||
@skip_if_desktop
|
||||
def test_emulator_shell(self):
|
||||
self.marionette.set_script_timeout(10000)
|
||||
expected = ["Hello World!"]
|
||||
result = self.marionette.execute_async_script("""
|
||||
runEmulatorShell(["echo", "Hello World!"], marionetteScriptFinished)
|
||||
""");
|
||||
self.assertEqual(result, expected)
|
||||
res = self.marionette.execute_async_script(
|
||||
"runEmulatorShell(['echo', 'Hello World!'], marionetteScriptFinished)")
|
||||
self.assertEqual(res, expected)
|
||||
|
||||
@skip_if_desktop
|
||||
def test_emulator_order(self):
|
||||
self.marionette.set_script_timeout(10000)
|
||||
self.assertRaises(MarionetteException,
|
||||
self.marionette.execute_async_script,
|
||||
"""runEmulatorCmd("gsm status", function(result) {});
|
||||
marionetteScriptFinished(true);
|
||||
""");
|
||||
with self.assertRaises(MarionetteException):
|
||||
self.marionette.execute_async_script("""
|
||||
runEmulatorCmd("gsm status", function(res) {});
|
||||
marionetteScriptFinished(true);
|
||||
""")
|
||||
|
||||
|
||||
class TestEmulatorChrome(TestEmulatorContent):
|
||||
|
@ -132,6 +129,24 @@ class TestEmulatorCallbacks(MarionetteTestCase):
|
|||
with self.assertRaisesRegexp(JavascriptException, "TypeError"):
|
||||
self.marionette.execute_async_script("runEmulatorCmd()")
|
||||
|
||||
def test_multiple_callbacks(self):
|
||||
res = self.marionette.execute_async_script("""
|
||||
runEmulatorCmd("what");
|
||||
runEmulatorCmd("ho");
|
||||
marionetteScriptFinished("Frobisher");
|
||||
""")
|
||||
self.assertEqual("Frobisher", res)
|
||||
|
||||
# This should work, but requires work on emulator callbacks:
|
||||
"""
|
||||
def test_multiple_nested_callbacks(self):
|
||||
res = self.marionette.execute_async_script('''
|
||||
runEmulatorCmd("what", function(res) {
|
||||
runEmulatorCmd("ho", marionetteScriptFinished);
|
||||
});''')
|
||||
self.assertEqual("cmd response", res)
|
||||
"""
|
||||
|
||||
|
||||
def escape(word):
|
||||
return "'%s'" % word
|
||||
|
|
|
@ -671,6 +671,27 @@ class Marionette(object):
|
|||
|
||||
@do_crash_check
|
||||
def _send_message(self, name, params=None, key=None):
|
||||
"""Send a blocking message to the server.
|
||||
|
||||
Marionette provides an asynchronous, non-blocking interface and
|
||||
this attempts to paper over this by providing a synchronous API
|
||||
to the user.
|
||||
|
||||
In particular, the Python client can be instructed to carry out
|
||||
a sequence of instructions on the connected emulator. For this
|
||||
reason, if ``execute_script``, ``execute_js_script``, or
|
||||
``execute_async_script`` is called, it will loop until all
|
||||
commands requested from the server have been exhausted, and we
|
||||
receive our expected response.
|
||||
|
||||
:param name: Requested command key.
|
||||
:param params: Optional dictionary of key/value arguments.
|
||||
:param key: Optional key to extract from response.
|
||||
|
||||
:returns: Full response from the server, or if `key` is given,
|
||||
the value of said key in the response.
|
||||
"""
|
||||
|
||||
if not self.session_id and name != "newSession":
|
||||
raise errors.MarionetteException("Please start a session")
|
||||
|
||||
|
@ -692,13 +713,16 @@ class Marionette(object):
|
|||
returncode = self.instance.runner.wait(timeout=self.DEFAULT_STARTUP_TIMEOUT)
|
||||
raise IOError("process died with returncode %s" % returncode)
|
||||
raise
|
||||
|
||||
except socket.timeout:
|
||||
self.session = None
|
||||
self.window = None
|
||||
self.client.close()
|
||||
raise errors.TimeoutException("Connection timed out")
|
||||
|
||||
if isinstance(msg, transport.Command):
|
||||
# support execution of commands on the client,
|
||||
# loop until we receive our expected response
|
||||
while isinstance(msg, transport.Command):
|
||||
if msg.name == "runEmulatorCmd":
|
||||
self.emulator_callback_id = msg.params.get("id")
|
||||
msg = self._emulator_cmd(msg.params["emulator_cmd"])
|
||||
|
|
|
@ -114,7 +114,7 @@ ContentSender.prototype.send = function(name, args) {
|
|||
let rmFn = msg => {
|
||||
if (this.curId !== msg.json.command_id) {
|
||||
logger.warn("Skipping out-of-sync response from listener: " +
|
||||
`Expected response to \`${name}' with ID ${this.curId}, ` +
|
||||
`Expected response to ${name} with ID ${this.curId}, ` +
|
||||
"but got: " + msg.name + msg.json.toSource());
|
||||
return;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче