Bug 909129 - fix Marionette imported scripts leak, add clearImportedScripts call, r=dburns

This commit is contained in:
Malini Das 2013-09-27 11:27:28 -04:00
parent 203d1cece9
commit e0680e60ae
4 changed files with 194 additions and 4 deletions

View File

@ -1186,6 +1186,14 @@ class Marionette(object):
js = f.read()
return self._send_message('importScript', 'ok', script=js)
def clear_imported_scripts(self):
'''
Clears all imported scripts in this context, ie: calling clear_imported_scripts in chrome
context will clear only scripts you imported in chrome, and will leave the scripts
you imported in content context.
'''
return self._send_message('clearImportedScripts', 'ok')
def add_cookie(self, cookie):
"""
Adds a cookie to your current session.

View File

@ -5,14 +5,125 @@
import os
from marionette_test import MarionetteTestCase
from errors import JavascriptException
class TestImportScript(MarionetteTestCase):
def setUp(self):
MarionetteTestCase.setUp(self)
self.marionette.set_script_timeout(3000)
def clear_other_context(self):
self.marionette.set_context("chrome")
self.marionette.clear_imported_scripts()
self.marionette.set_context("content")
def check_file_exists(self):
self.marionette.set_context("chrome")
exists = self.marionette.execute_async_script("""
Components.utils.import("resource://gre/modules/FileUtils.jsm");
let checkTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
let f = function() {
if (FileUtils == undefined) {
checkTimer.initWithCallback(f, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return;
}
let importedScripts = FileUtils.getFile('TmpD', ['marionetteContentScripts']);
marionetteScriptFinished(importedScripts.exists());
};
checkTimer.initWithCallback(f, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
""")
self.marionette.set_context("content")
return exists
def get_file_size(self):
self.marionette.set_context("chrome")
size = self.marionette.execute_async_script("""
Components.utils.import("resource://gre/modules/FileUtils.jsm");
let checkTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
let f = function() {
if (FileUtils == undefined) {
checkTimer.initWithCallback(f, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return;
}
let importedScripts = FileUtils.getFile('TmpD', ['marionetteContentScripts']);
marionetteScriptFinished(importedScripts.fileSize);
};
checkTimer.initWithCallback(f, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
""")
self.marionette.set_context("content")
return size
def test_import_script(self):
js = os.path.abspath(os.path.join(__file__, os.path.pardir, "importscript.js"))
self.marionette.import_script(js)
self.assertEqual("i'm a test function!", self.marionette.execute_script("return testFunc();"))
self.assertEqual("i'm a test function!", self.marionette.execute_async_script("marionetteScriptFinished(testFunc());"))
def test_import_script_twice(self):
js = os.path.abspath(os.path.join(__file__, os.path.pardir, "importscript.js"))
self.marionette.import_script(js)
self.assertEqual("i'm a test function!", self.marionette.execute_script("return testFunc();"))
self.assertEqual("i'm a test function!", self.marionette.execute_async_script("marionetteScriptFinished(testFunc());"))
self.assertTrue(self.check_file_exists())
file_size = self.get_file_size()
self.assertNotEqual(file_size, None)
self.marionette.import_script(js)
file_size = self.get_file_size()
self.assertEqual(file_size, self.get_file_size())
self.assertEqual("i'm a test function!", self.marionette.execute_script("return testFunc();"))
self.assertEqual("i'm a test function!", self.marionette.execute_async_script("marionetteScriptFinished(testFunc());"))
def test_import_two_scripts_twice(self):
js = os.path.abspath(os.path.join(__file__, os.path.pardir, "importscript.js"))
self.marionette.import_script(js)
self.assertEqual("i'm a test function!", self.marionette.execute_script("return testFunc();"))
self.assertEqual("i'm a test function!", self.marionette.execute_async_script("marionetteScriptFinished(testFunc());"))
self.assertTrue(self.check_file_exists())
file_size = self.get_file_size()
self.assertNotEqual(file_size, None)
self.marionette.import_script(js)
# same script should not append to file
self.assertEqual(file_size, self.get_file_size())
self.assertEqual("i'm a test function!", self.marionette.execute_script("return testFunc();"))
self.assertEqual("i'm a test function!", self.marionette.execute_async_script("marionetteScriptFinished(testFunc());"))
js = os.path.abspath(os.path.join(__file__, os.path.pardir, "importanotherscript.js"))
self.marionette.import_script(js)
new_size = self.get_file_size()
# new script should append to file
self.assertNotEqual(file_size, new_size)
file_size = new_size
self.assertEqual("i'm yet another test function!",
self.marionette.execute_script("return testAnotherFunc();"))
self.assertEqual("i'm yet another test function!",
self.marionette.execute_async_script("marionetteScriptFinished(testAnotherFunc());"))
self.marionette.import_script(js)
# same script should not append to file
self.assertEqual(file_size, self.get_file_size())
def test_import_script_and_clear(self):
js = os.path.abspath(os.path.join(__file__, os.path.pardir, "importscript.js"))
self.marionette.import_script(js)
self.assertEqual("i'm a test function!", self.marionette.execute_script("return testFunc();"))
self.assertEqual("i'm a test function!", self.marionette.execute_async_script("marionetteScriptFinished(testFunc());"))
self.marionette.clear_imported_scripts()
self.assertFalse(self.check_file_exists())
self.assertRaises(JavascriptException, self.marionette.execute_script, "return testFunc();")
self.assertRaises(JavascriptException, self.marionette.execute_async_script, "marionetteScriptFinished(testFunc());")
def test_import_script_and_clear_in_chrome(self):
js = os.path.abspath(os.path.join(__file__, os.path.pardir, "importscript.js"))
self.marionette.import_script(js)
self.assertTrue(self.check_file_exists())
file_size = self.get_file_size()
self.assertEqual("i'm a test function!", self.marionette.execute_script("return testFunc();"))
self.assertEqual("i'm a test function!", self.marionette.execute_async_script("marionetteScriptFinished(testFunc());"))
self.clear_other_context()
# clearing other context's script file should not affect ours
self.assertTrue(self.check_file_exists())
self.assertEqual(file_size, self.get_file_size())
self.assertEqual("i'm a test function!", self.marionette.execute_script("return testFunc();"))
self.assertEqual("i'm a test function!", self.marionette.execute_async_script("marionetteScriptFinished(testFunc());"))
def test_importing_another_script_and_check_they_append(self):
firstjs = os.path.abspath(
os.path.join(__file__, os.path.pardir, "importscript.js"))
@ -31,4 +142,41 @@ class TestImportScript(MarionetteTestCase):
class TestImportScriptChrome(TestImportScript):
def setUp(self):
MarionetteTestCase.setUp(self)
self.marionette.set_script_timeout(30000)
self.marionette.set_context("chrome")
def clear_other_context(self):
self.marionette.set_context("content")
self.marionette.clear_imported_scripts()
self.marionette.set_context("chrome")
def check_file_exists(self):
return self.marionette.execute_async_script("""
Components.utils.import("resource://gre/modules/FileUtils.jsm");
let checkTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
let f = function() {
if (FileUtils == undefined) {
checkTimer.initWithCallback(f, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return;
}
let importedScripts = FileUtils.getFile('TmpD', ['marionetteChromeScripts']);
marionetteScriptFinished(importedScripts.exists());
};
checkTimer.initWithCallback(f, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
""")
def get_file_size(self):
return self.marionette.execute_async_script("""
Components.utils.import("resource://gre/modules/FileUtils.jsm");
let checkTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
let f = function() {
if (FileUtils == undefined) {
checkTimer.initWithCallback(f, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return;
}
let importedScripts = FileUtils.getFile('TmpD', ['marionetteChromeScripts']);
marionetteScriptFinished(importedScripts.fileSize);
};
checkTimer.initWithCallback(f, 100, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
""")

View File

@ -96,7 +96,7 @@ function registerSelf() {
if (register[0]) {
listenerId = register[0].id;
importedScripts = FileUtils.File(register[0].importedScripts);
importedScripts = FileUtils.getFile('TmpD', ['marionetteContentScripts']);
startListeners();
}
}

View File

@ -134,7 +134,8 @@ function MarionetteServerConnection(aPrefix, aTransport, aServer)
this.command_id = null;
this.mainFrame = null; //topmost chrome frame
this.curFrame = null; // chrome iframe that currently has focus
this.importedScripts = FileUtils.getFile('TmpD', ['marionettescriptchrome']);
this.importedScripts = FileUtils.getFile('TmpD', ['marionetteChromeScripts']);
this.importedScriptHashes = {"chrome" : [], "content": []};
this.currentFrameElement = null;
this.testName = null;
this.mozBrowserClose = null;
@ -1991,7 +1992,8 @@ MarionetteServerConnection.prototype = {
this.mainFrame.focus();
}
try {
this.importedScripts.remove(false);
FileUtils.getDir('TmpD', ['marionetteChromeScripts']).remove(true);
FileUtils.getDir('TmpD', ['marionetteContentScripts']).remove(true);
}
catch (e) {
}
@ -2054,6 +2056,23 @@ MarionetteServerConnection.prototype = {
importScript: function MDA_importScript(aRequest) {
let command_id = this.command_id = this.getCommandId();
let converter =
Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let result = {};
let data = converter.convertToByteArray(aRequest.script, result);
let ch = Components.classes["@mozilla.org/security/hash;1"]
.createInstance(Components.interfaces.nsICryptoHash);
ch.init(ch.MD5);
ch.update(data, data.length);
let hash = ch.finish(true);
if (this.importedScriptHashes[this.context].indexOf(hash) > -1) {
//we have already imported this script
this.sendOk(command_id);
return;
}
this.importedScriptHashes[this.context].push(hash);
if (this.context == "chrome") {
let file;
if (this.importedScripts.exists()) {
@ -2079,6 +2098,21 @@ MarionetteServerConnection.prototype = {
}
},
clearImportedScripts: function MDA_clearImportedScripts(aRequest) {
let command_id = this.command_id = this.getCommandId();
let file;
if (this.context == "chrome") {
file = FileUtils.getFile('TmpD', ['marionetteChromeScripts']);
}
else {
file = FileUtils.getFile('TmpD', ['marionetteContentScripts']);
}
if (file.exists()) {
file.remove(true);
}
this.sendOk(command_id);
},
/**
* Takes a screenshot of a DOM node. If there is no node given a screenshot
* of the window will be taken.
@ -2196,7 +2230,6 @@ MarionetteServerConnection.prototype = {
listenerWindow);
}
this.curBrowser.elementManager.seenItems[reg.id] = Cu.getWeakReference(listenerWindow);
reg.importedScripts = this.importedScripts.path;
if (nullPrevious && (this.curBrowser.curFrameId != null)) {
if (!this.sendAsync("newSession",
{ B2G: (appName == "B2G") },
@ -2261,6 +2294,7 @@ MarionetteServerConnection.prototype.requestTypes = {
"deleteSession": MarionetteServerConnection.prototype.deleteSession,
"emulatorCmdResult": MarionetteServerConnection.prototype.emulatorCmdResult,
"importScript": MarionetteServerConnection.prototype.importScript,
"clearImportedScripts": MarionetteServerConnection.prototype.clearImportedScripts,
"getAppCacheStatus": MarionetteServerConnection.prototype.getAppCacheStatus,
"closeWindow": MarionetteServerConnection.prototype.closeWindow,
"setTestName": MarionetteServerConnection.prototype.setTestName,