mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 751783 - Allow sandbox reuse between execute_script calls, r=jgriffin, r=mdas, DONTBUILD because NPOTB,
This commit is contained in:
parent
f008076292
commit
3025c86b7f
@ -313,7 +313,7 @@ class Marionette(object):
|
||||
|
||||
return unwrapped
|
||||
|
||||
def execute_js_script(self, script, script_args=None, timeout=True):
|
||||
def execute_js_script(self, script, script_args=None, timeout=True, new_sandbox=True):
|
||||
if script_args is None:
|
||||
script_args = []
|
||||
args = self.wrapArguments(script_args)
|
||||
@ -321,21 +321,30 @@ class Marionette(object):
|
||||
'value',
|
||||
value=script,
|
||||
args=args,
|
||||
timeout=timeout)
|
||||
timeout=timeout,
|
||||
newSandbox=new_sandbox)
|
||||
return self.unwrapValue(response)
|
||||
|
||||
def execute_script(self, script, script_args=None):
|
||||
def execute_script(self, script, script_args=None, new_sandbox=True):
|
||||
if script_args is None:
|
||||
script_args = []
|
||||
args = self.wrapArguments(script_args)
|
||||
response = self._send_message('executeScript', 'value', value=script, args=args)
|
||||
response = self._send_message('executeScript',
|
||||
'value',
|
||||
value=script,
|
||||
args=args,
|
||||
newSandbox=new_sandbox)
|
||||
return self.unwrapValue(response)
|
||||
|
||||
def execute_async_script(self, script, script_args=None):
|
||||
def execute_async_script(self, script, script_args=None, new_sandbox=True):
|
||||
if script_args is None:
|
||||
script_args = []
|
||||
args = self.wrapArguments(script_args)
|
||||
response = self._send_message('executeAsyncScript', 'value', value=script, args=args)
|
||||
response = self._send_message('executeAsyncScript',
|
||||
'value',
|
||||
value=script,
|
||||
args=args,
|
||||
newSandbox=new_sandbox)
|
||||
return self.unwrapValue(response)
|
||||
|
||||
def find_element(self, method, target, id=None):
|
||||
|
@ -71,11 +71,11 @@ class TestExecuteAsyncContent(MarionetteTestCase):
|
||||
def test_same_context(self):
|
||||
var1 = 'testing'
|
||||
self.assertEqual(self.marionette.execute_script("""
|
||||
window.wrappedJSObject._testvar = '%s';
|
||||
return window.wrappedJSObject._testvar;
|
||||
this.testvar = '%s';
|
||||
return this.testvar;
|
||||
""" % var1), var1)
|
||||
self.assertEqual(self.marionette.execute_async_script(
|
||||
"marionetteScriptFinished(window.wrappedJSObject._testvar);"), var1)
|
||||
"marionetteScriptFinished(this.testvar);", new_sandbox=False), var1)
|
||||
|
||||
def test_execute_no_return(self):
|
||||
self.assertEqual(self.marionette.execute_async_script("marionetteScriptFinished()"), None)
|
||||
@ -102,6 +102,19 @@ var c = Components.classes;
|
||||
marionetteScriptFinished(1);
|
||||
""")
|
||||
|
||||
def test_sandbox_reuse(self):
|
||||
# Sandboxes between `execute_script()` invocations are shared.
|
||||
self.marionette.execute_async_script("this.foobar = [23, 42];"
|
||||
"marionetteScriptFinished();")
|
||||
self.assertEqual(self.marionette.execute_async_script(
|
||||
"marionetteScriptFinished(this.foobar);", new_sandbox=False), [23, 42])
|
||||
|
||||
self.marionette.execute_async_script("global.barfoo = [42, 23];"
|
||||
"marionetteScriptFinished();")
|
||||
self.assertEqual(self.marionette.execute_async_script(
|
||||
"marionetteScriptFinished(global.barfoo);", new_sandbox=False), [42, 23])
|
||||
|
||||
|
||||
class TestExecuteAsyncChrome(TestExecuteAsyncContent):
|
||||
def setUp(self):
|
||||
super(TestExecuteAsyncChrome, self).setUp()
|
||||
@ -119,3 +132,6 @@ var c = Components.classes;
|
||||
marionetteScriptFinished(1);
|
||||
"""))
|
||||
|
||||
def test_sandbox_reuse(self):
|
||||
pass
|
||||
|
||||
|
@ -64,6 +64,13 @@ class TestExecuteContent(MarionetteTestCase):
|
||||
self.assertEqual(self.marionette.execute_script("return {'foo': [1, 'a', 2]};"),
|
||||
{'foo': [1, 'a', 2]})
|
||||
|
||||
def test_sandbox_reuse(self):
|
||||
# Sandboxes between `execute_script()` invocations are shared.
|
||||
self.marionette.execute_script("this.foobar = [23, 42];")
|
||||
self.assertEqual(self.marionette.execute_script("return this.foobar;", new_sandbox=False), [23, 42])
|
||||
|
||||
self.marionette.execute_script("global.barfoo = [42, 23];")
|
||||
self.assertEqual(self.marionette.execute_script("return global.barfoo;", new_sandbox=False), [42, 23])
|
||||
|
||||
class TestExecuteChrome(TestExecuteContent):
|
||||
def setUp(self):
|
||||
@ -73,3 +80,5 @@ class TestExecuteChrome(TestExecuteContent):
|
||||
def test_execute_permission(self):
|
||||
self.assertEqual(1, self.marionette.execute_script("var c = Components.classes;return 1;"))
|
||||
|
||||
def test_sandbox_reuse(self):
|
||||
pass
|
||||
|
@ -472,8 +472,16 @@ MarionetteDriverActor.prototype = {
|
||||
* function body
|
||||
*/
|
||||
execute: function MDA_execute(aRequest, directInject) {
|
||||
logger.info("newSandbox: " + aRequest.newSandbox);
|
||||
if (aRequest.newSandbox == undefined) {
|
||||
//if client does not send a value in newSandbox,
|
||||
//then they expect the same behaviour as webdriver
|
||||
aRequest.newSandbox = true;
|
||||
}
|
||||
if (this.context == "content") {
|
||||
this.sendAsync("executeScript", {value: aRequest.value, args: aRequest.args});
|
||||
this.sendAsync("executeScript", {value: aRequest.value,
|
||||
args: aRequest.args,
|
||||
newSandbox:aRequest.newSandbox});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -533,6 +541,11 @@ MarionetteDriverActor.prototype = {
|
||||
*/
|
||||
executeJSScript: function MDA_executeJSScript(aRequest) {
|
||||
//all pure JS scripts will need to call Marionette.finish() to complete the test.
|
||||
if (aRequest.newSandbox == undefined) {
|
||||
//if client does not send a value in newSandbox,
|
||||
//then they expect the same behaviour as webdriver
|
||||
aRequest.newSandbox = true;
|
||||
}
|
||||
if (this.context == "chrome") {
|
||||
if (aRequest.timeout) {
|
||||
this.executeWithCallback(aRequest, aRequest.timeout);
|
||||
@ -562,12 +575,18 @@ MarionetteDriverActor.prototype = {
|
||||
* function body
|
||||
*/
|
||||
executeWithCallback: function MDA_executeWithCallback(aRequest, directInject) {
|
||||
if (aRequest.newSandbox == undefined) {
|
||||
//if client does not send a value in newSandbox,
|
||||
//then they expect the same behaviour as webdriver
|
||||
aRequest.newSandbox = true;
|
||||
}
|
||||
this.command_id = this.uuidGen.generateUUID().toString();
|
||||
|
||||
if (this.context == "content") {
|
||||
this.sendAsync("executeAsyncScript", {value: aRequest.value,
|
||||
args: aRequest.args,
|
||||
id: this.command_id});
|
||||
id: this.command_id,
|
||||
newSandbox: aRequest.newSandbox});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,15 @@ let activeFrame = null;
|
||||
let curWindow = content;
|
||||
let elementManager = new ElementManager([]);
|
||||
|
||||
// The sandbox we execute test scripts in. Gets lazily created in
|
||||
// createExecuteContentSandbox().
|
||||
let sandbox;
|
||||
|
||||
// Flag to indicate whether an async script is currently running or not.
|
||||
let asyncTestRunning = false;
|
||||
let asyncTestCommandId;
|
||||
let asyncTestTimeoutId;
|
||||
|
||||
/**
|
||||
* Called when listener is first started up.
|
||||
* The listener sends its unique window ID and its current URI to the actor.
|
||||
@ -178,6 +187,7 @@ function sendError(message, status, trace, command_id) {
|
||||
* Clear test values after completion of test
|
||||
*/
|
||||
function resetValues() {
|
||||
sandbox = null;
|
||||
marionetteTimeout = null;
|
||||
curWin = content;
|
||||
}
|
||||
@ -197,28 +207,54 @@ function errUnload() {
|
||||
/**
|
||||
* Returns a content sandbox that can be used by the execute_foo functions.
|
||||
*/
|
||||
function createExecuteContentSandbox(aWindow, marionette, args) {
|
||||
try {
|
||||
args = elementManager.convertWrappedArguments(args, aWindow);
|
||||
}
|
||||
catch(e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
return;
|
||||
}
|
||||
|
||||
function createExecuteContentSandbox(aWindow) {
|
||||
let sandbox = new Cu.Sandbox(aWindow);
|
||||
sandbox.global = sandbox;
|
||||
sandbox.window = aWindow;
|
||||
sandbox.document = sandbox.window.document;
|
||||
sandbox.navigator = sandbox.window.navigator;
|
||||
sandbox.__namedArgs = elementManager.applyNamedArgs(args);
|
||||
sandbox.__marionetteParams = args;
|
||||
sandbox.__proto__ = sandbox.window;
|
||||
sandbox.testUtils = utils;
|
||||
|
||||
let marionette = new Marionette(false, aWindow, "content", marionetteLogObj);
|
||||
sandbox.marionette = marionette;
|
||||
marionette.exports.forEach(function(fn) {
|
||||
sandbox[fn] = marionette[fn].bind(marionette);
|
||||
});
|
||||
|
||||
sandbox.asyncComplete = function sandbox_asyncComplete(value, status) {
|
||||
curWindow.removeEventListener("unload", errUnload, false);
|
||||
|
||||
/* clear all timeouts potentially generated by the script*/
|
||||
for (let i = 0; i <= asyncTestTimeoutId; i++) {
|
||||
curWindow.clearTimeout(i);
|
||||
}
|
||||
|
||||
sendSyncMessage("Marionette:testLog",
|
||||
{value: elementManager.wrapValue(marionetteLogObj.getLogs())});
|
||||
marionetteLogObj.clearLogs();
|
||||
if (status == 0){
|
||||
sendResponse({value: elementManager.wrapValue(value), status: status}, asyncTestCommandId);
|
||||
}
|
||||
else {
|
||||
sendError(value, status, null, asyncTestCommandId);
|
||||
}
|
||||
|
||||
asyncTestRunning = false;
|
||||
asyncTestTimeoutId = undefined;
|
||||
asyncTestCommandId = undefined;
|
||||
};
|
||||
sandbox.finish = function sandbox_finish() {
|
||||
if (asyncTestRunning) {
|
||||
sandbox.asyncComplete(marionette.generate_results(), 0);
|
||||
} else {
|
||||
return marionette.generate_results();
|
||||
}
|
||||
};
|
||||
sandbox.marionetteScriptFinished = function sandbox_marionetteScriptFinished(value) {
|
||||
return sandbox.asyncComplete(value, 0);
|
||||
};
|
||||
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
@ -228,15 +264,14 @@ function createExecuteContentSandbox(aWindow, marionette, args) {
|
||||
*/
|
||||
function executeScript(msg, directInject) {
|
||||
let script = msg.json.value;
|
||||
let marionette = new Marionette(false, curWindow, "content", marionetteLogObj);
|
||||
|
||||
let sandbox = createExecuteContentSandbox(curWindow, marionette, msg.json.args);
|
||||
if (!sandbox)
|
||||
if (msg.json.newSandbox || !sandbox) {
|
||||
sandbox = createExecuteContentSandbox(curWindow);
|
||||
if (!sandbox) {
|
||||
sendError("Could not create sandbox!");
|
||||
return;
|
||||
|
||||
sandbox.finish = function sandbox_finish() {
|
||||
return marionette.generate_results();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (directInject) {
|
||||
@ -251,6 +286,15 @@ function executeScript(msg, directInject) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
sandbox.__marionetteParams = elementManager.convertWrappedArguments(
|
||||
msg.json.args, curWindow);
|
||||
}
|
||||
catch(e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
return;
|
||||
}
|
||||
|
||||
let scriptSrc = "let __marionetteFunc = function(){" + script + "};" +
|
||||
"__marionetteFunc.apply(null, __marionetteParams);";
|
||||
let res = Cu.evalInSandbox(scriptSrc, sandbox, "1.8");
|
||||
@ -302,39 +346,29 @@ function executeJSScript(msg) {
|
||||
function executeWithCallback(msg, timeout) {
|
||||
curWindow.addEventListener("unload", errUnload, false);
|
||||
let script = msg.json.value;
|
||||
let command_id = msg.json.id;
|
||||
asyncTestCommandId = msg.json.id;
|
||||
|
||||
// Error code 28 is scriptTimeout, but spec says execute_async should return 21 (Timeout),
|
||||
// see http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/execute_async.
|
||||
// However Selenium code returns 28, see
|
||||
// http://code.google.com/p/selenium/source/browse/trunk/javascript/firefox-driver/js/evaluate.js.
|
||||
// We'll stay compatible with the Selenium code.
|
||||
let timeoutId = curWindow.setTimeout(function() {
|
||||
contentAsyncReturnFunc('timed out', 28);
|
||||
asyncTestTimeoutId = curWindow.setTimeout(function() {
|
||||
sandbox.asyncComplete('timed out', 28);
|
||||
}, marionetteTimeout);
|
||||
curWindow.addEventListener('error', function win__onerror(evt) {
|
||||
curWindow.removeEventListener('error', win__onerror, true);
|
||||
contentAsyncReturnFunc(evt, 17);
|
||||
sandbox.asyncComplete(evt, 17);
|
||||
return true;
|
||||
}, true);
|
||||
|
||||
function contentAsyncReturnFunc(value, status) {
|
||||
curWindow.removeEventListener("unload", errUnload, false);
|
||||
|
||||
/* clear all timeouts potentially generated by the script*/
|
||||
for(let i=0; i<=timeoutId; i++) {
|
||||
curWindow.clearTimeout(i);
|
||||
if (msg.json.newSandbox || !sandbox) {
|
||||
sandbox = createExecuteContentSandbox(curWindow);
|
||||
if (!sandbox) {
|
||||
sendError("Could not create sandbox!");
|
||||
return;
|
||||
}
|
||||
|
||||
sendSyncMessage("Marionette:testLog", {value: elementManager.wrapValue(marionetteLogObj.getLogs())});
|
||||
marionetteLogObj.clearLogs();
|
||||
if (status == 0){
|
||||
sendResponse({value: elementManager.wrapValue(value), status: status}, command_id);
|
||||
}
|
||||
else {
|
||||
sendError(value, status, null, command_id);
|
||||
}
|
||||
};
|
||||
|
||||
let scriptSrc;
|
||||
if (timeout) {
|
||||
@ -344,24 +378,22 @@ function executeWithCallback(msg, timeout) {
|
||||
scriptSrc = script;
|
||||
}
|
||||
else {
|
||||
scriptSrc = "let marionetteScriptFinished = function(value) { return asyncComplete(value,0);};" +
|
||||
"__marionetteParams.push(marionetteScriptFinished);" +
|
||||
try {
|
||||
sandbox.__marionetteParams = elementManager.convertWrappedArguments(
|
||||
msg.json.args, curWindow);
|
||||
}
|
||||
catch(e) {
|
||||
sendError(e.message, e.num, e.stack);
|
||||
return;
|
||||
}
|
||||
|
||||
scriptSrc = "__marionetteParams.push(marionetteScriptFinished);" +
|
||||
"let __marionetteFunc = function() { " + script + "};" +
|
||||
"__marionetteFunc.apply(null, __marionetteParams); ";
|
||||
}
|
||||
|
||||
let marionette = new Marionette(true, curWindow, "content", marionetteLogObj);
|
||||
|
||||
let sandbox = createExecuteContentSandbox(curWindow, marionette, msg.json.args);
|
||||
if (!sandbox)
|
||||
return;
|
||||
|
||||
sandbox.asyncComplete = contentAsyncReturnFunc;
|
||||
sandbox.finish = function sandbox_finish() {
|
||||
contentAsyncReturnFunc(marionette.generate_results(), 0);
|
||||
};
|
||||
|
||||
try {
|
||||
asyncTestRunning = true;
|
||||
Cu.evalInSandbox(scriptSrc, sandbox, "1.8");
|
||||
} catch (e) {
|
||||
// 17 = JavascriptException
|
||||
@ -621,13 +653,15 @@ function switchToFrame(msg) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (foundFrame != null) {
|
||||
if (foundFrame == null) {
|
||||
sendError("Unable to locate frame: " + msg.json.value, 8, null);
|
||||
return;
|
||||
}
|
||||
curWindow = curWindow.frames[foundFrame];
|
||||
curWindow.focus();
|
||||
sendOk();
|
||||
} else {
|
||||
sendError("Unable to locate frame: " + msg.json.value, 8, null);
|
||||
}
|
||||
|
||||
sandbox = null;
|
||||
}
|
||||
|
||||
//call register self when we get loaded
|
||||
|
@ -11,10 +11,11 @@ function Marionette(is_async, window, context, logObj) {
|
||||
this.tests = [];
|
||||
this.logObj = logObj;
|
||||
this.context = context;
|
||||
this.exports = ['ok', 'is', 'isnot', 'log', 'getLogs', 'generate_results', 'waitFor'];
|
||||
}
|
||||
|
||||
Marionette.prototype = {
|
||||
exports: ['ok', 'is', 'isnot', 'log', 'getLogs', 'generate_results', 'waitFor'],
|
||||
|
||||
ok: function Marionette__ok(condition, name, diag) {
|
||||
let test = {'result': !!condition, 'name': name, 'diag': diag};
|
||||
this.logResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
|
||||
@ -62,6 +63,8 @@ Marionette.prototype = {
|
||||
'diag': this.tests[i].diag});
|
||||
}
|
||||
}
|
||||
// Reset state in case this object is reused for more tests.
|
||||
this.tests = [];
|
||||
return {"passed": passed, "failed": failed, "failures": failures};
|
||||
},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user