Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | * http://creativecommons.org/publicdomain/zero/1.0/ |
michael@0 | 3 | */ |
michael@0 | 4 | |
michael@0 | 5 | Components.utils.import("resource://gre/modules/NetUtil.jsm"); |
michael@0 | 6 | |
michael@0 | 7 | let tmp = {}; |
michael@0 | 8 | Components.utils.import("resource://gre/modules/AddonManager.jsm", tmp); |
michael@0 | 9 | Components.utils.import("resource://gre/modules/Log.jsm", tmp); |
michael@0 | 10 | let AddonManager = tmp.AddonManager; |
michael@0 | 11 | let AddonManagerPrivate = tmp.AddonManagerPrivate; |
michael@0 | 12 | let Log = tmp.Log; |
michael@0 | 13 | |
michael@0 | 14 | var pathParts = gTestPath.split("/"); |
michael@0 | 15 | // Drop the test filename |
michael@0 | 16 | pathParts.splice(pathParts.length - 1, pathParts.length); |
michael@0 | 17 | |
michael@0 | 18 | var gTestInWindow = /-window$/.test(pathParts[pathParts.length - 1]); |
michael@0 | 19 | |
michael@0 | 20 | // Drop the UI type |
michael@0 | 21 | if (gTestInWindow) { |
michael@0 | 22 | pathParts.splice(pathParts.length - 1, pathParts.length); |
michael@0 | 23 | } |
michael@0 | 24 | |
michael@0 | 25 | const RELATIVE_DIR = pathParts.slice(4).join("/") + "/"; |
michael@0 | 26 | |
michael@0 | 27 | const TESTROOT = "http://example.com/" + RELATIVE_DIR; |
michael@0 | 28 | const TESTROOT2 = "http://example.org/" + RELATIVE_DIR; |
michael@0 | 29 | const CHROMEROOT = pathParts.join("/") + "/"; |
michael@0 | 30 | const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; |
michael@0 | 31 | const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; |
michael@0 | 32 | const PREF_XPI_ENABLED = "xpinstall.enabled"; |
michael@0 | 33 | const PREF_UPDATEURL = "extensions.update.url"; |
michael@0 | 34 | const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled"; |
michael@0 | 35 | |
michael@0 | 36 | const MANAGER_URI = "about:addons"; |
michael@0 | 37 | const INSTALL_URI = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; |
michael@0 | 38 | const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; |
michael@0 | 39 | const PREF_SEARCH_MAXRESULTS = "extensions.getAddons.maxResults"; |
michael@0 | 40 | const PREF_STRICT_COMPAT = "extensions.strictCompatibility"; |
michael@0 | 41 | |
michael@0 | 42 | var PREF_CHECK_COMPATIBILITY; |
michael@0 | 43 | (function() { |
michael@0 | 44 | var channel = "default"; |
michael@0 | 45 | try { |
michael@0 | 46 | channel = Services.prefs.getCharPref("app.update.channel"); |
michael@0 | 47 | } catch (e) { } |
michael@0 | 48 | if (channel != "aurora" && |
michael@0 | 49 | channel != "beta" && |
michael@0 | 50 | channel != "release") { |
michael@0 | 51 | var version = "nightly"; |
michael@0 | 52 | } else { |
michael@0 | 53 | version = Services.appinfo.version.replace(/^([^\.]+\.[0-9]+[a-z]*).*/gi, "$1"); |
michael@0 | 54 | } |
michael@0 | 55 | PREF_CHECK_COMPATIBILITY = "extensions.checkCompatibility." + version; |
michael@0 | 56 | })(); |
michael@0 | 57 | |
michael@0 | 58 | var gPendingTests = []; |
michael@0 | 59 | var gTestsRun = 0; |
michael@0 | 60 | var gTestStart = null; |
michael@0 | 61 | |
michael@0 | 62 | var gUseInContentUI = !gTestInWindow && ("switchToTabHavingURI" in window); |
michael@0 | 63 | |
michael@0 | 64 | var gRestorePrefs = [{name: PREF_LOGGING_ENABLED}, |
michael@0 | 65 | {name: "extensions.webservice.discoverURL"}, |
michael@0 | 66 | {name: "extensions.update.url"}, |
michael@0 | 67 | {name: "extensions.update.background.url"}, |
michael@0 | 68 | {name: "extensions.update.enabled"}, |
michael@0 | 69 | {name: "extensions.update.autoUpdateDefault"}, |
michael@0 | 70 | {name: "extensions.getAddons.get.url"}, |
michael@0 | 71 | {name: "extensions.getAddons.getWithPerformance.url"}, |
michael@0 | 72 | {name: "extensions.getAddons.search.browseURL"}, |
michael@0 | 73 | {name: "extensions.getAddons.search.url"}, |
michael@0 | 74 | {name: "extensions.getAddons.cache.enabled"}, |
michael@0 | 75 | {name: "devtools.chrome.enabled"}, |
michael@0 | 76 | {name: "devtools.debugger.remote-enabled"}, |
michael@0 | 77 | {name: PREF_SEARCH_MAXRESULTS}, |
michael@0 | 78 | {name: PREF_STRICT_COMPAT}, |
michael@0 | 79 | {name: PREF_CHECK_COMPATIBILITY}]; |
michael@0 | 80 | |
michael@0 | 81 | for (let pref of gRestorePrefs) { |
michael@0 | 82 | if (!Services.prefs.prefHasUserValue(pref.name)) { |
michael@0 | 83 | pref.type = "clear"; |
michael@0 | 84 | continue; |
michael@0 | 85 | } |
michael@0 | 86 | pref.type = Services.prefs.getPrefType(pref.name); |
michael@0 | 87 | if (pref.type == Services.prefs.PREF_BOOL) |
michael@0 | 88 | pref.value = Services.prefs.getBoolPref(pref.name); |
michael@0 | 89 | else if (pref.type == Services.prefs.PREF_INT) |
michael@0 | 90 | pref.value = Services.prefs.getIntPref(pref.name); |
michael@0 | 91 | else if (pref.type == Services.prefs.PREF_STRING) |
michael@0 | 92 | pref.value = Services.prefs.getCharPref(pref.name); |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | // Turn logging on for all tests |
michael@0 | 96 | Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true); |
michael@0 | 97 | |
michael@0 | 98 | // Helper to register test failures and close windows if any are left open |
michael@0 | 99 | function checkOpenWindows(aWindowID) { |
michael@0 | 100 | let windows = Services.wm.getEnumerator(aWindowID); |
michael@0 | 101 | let found = false; |
michael@0 | 102 | while (windows.hasMoreElements()) { |
michael@0 | 103 | let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow); |
michael@0 | 104 | if (!win.closed) { |
michael@0 | 105 | found = true; |
michael@0 | 106 | win.close(); |
michael@0 | 107 | } |
michael@0 | 108 | } |
michael@0 | 109 | if (found) |
michael@0 | 110 | ok(false, "Found unexpected " + aWindowID + " window still open"); |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | registerCleanupFunction(function() { |
michael@0 | 114 | // Restore prefs |
michael@0 | 115 | for (let pref of gRestorePrefs) { |
michael@0 | 116 | if (pref.type == "clear") |
michael@0 | 117 | Services.prefs.clearUserPref(pref.name); |
michael@0 | 118 | else if (pref.type == Services.prefs.PREF_BOOL) |
michael@0 | 119 | Services.prefs.setBoolPref(pref.name, pref.value); |
michael@0 | 120 | else if (pref.type == Services.prefs.PREF_INT) |
michael@0 | 121 | Services.prefs.setIntPref(pref.name, pref.value); |
michael@0 | 122 | else if (pref.type == Services.prefs.PREF_STRING) |
michael@0 | 123 | Services.prefs.setCharPref(pref.name, pref.value); |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | // Throw an error if the add-ons manager window is open anywhere |
michael@0 | 127 | checkOpenWindows("Addons:Manager"); |
michael@0 | 128 | checkOpenWindows("Addons:Compatibility"); |
michael@0 | 129 | checkOpenWindows("Addons:Install"); |
michael@0 | 130 | |
michael@0 | 131 | return new Promise((resolve, reject) => AddonManager.getAllInstalls(resolve)) |
michael@0 | 132 | .then(aInstalls => { |
michael@0 | 133 | for (let install of aInstalls) { |
michael@0 | 134 | if (install instanceof MockInstall) |
michael@0 | 135 | continue; |
michael@0 | 136 | |
michael@0 | 137 | ok(false, "Should not have seen an install of " + install.sourceURI.spec + " in state " + install.state); |
michael@0 | 138 | install.cancel(); |
michael@0 | 139 | } |
michael@0 | 140 | }); |
michael@0 | 141 | }); |
michael@0 | 142 | |
michael@0 | 143 | function log_exceptions(aCallback, ...aArgs) { |
michael@0 | 144 | try { |
michael@0 | 145 | return aCallback.apply(null, aArgs); |
michael@0 | 146 | } |
michael@0 | 147 | catch (e) { |
michael@0 | 148 | info("Exception thrown: " + e); |
michael@0 | 149 | throw e; |
michael@0 | 150 | } |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | function log_callback(aPromise, aCallback) { |
michael@0 | 154 | aPromise.then(aCallback) |
michael@0 | 155 | .then(null, e => info("Exception thrown: " + e)); |
michael@0 | 156 | return aPromise; |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | function add_test(test) { |
michael@0 | 160 | gPendingTests.push(test); |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | function run_next_test() { |
michael@0 | 164 | if (gTestsRun > 0) |
michael@0 | 165 | info("Test " + gTestsRun + " took " + (Date.now() - gTestStart) + "ms"); |
michael@0 | 166 | |
michael@0 | 167 | if (gPendingTests.length == 0) { |
michael@0 | 168 | end_test(); |
michael@0 | 169 | return; |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | gTestsRun++; |
michael@0 | 173 | var test = gPendingTests.shift(); |
michael@0 | 174 | if (test.name) |
michael@0 | 175 | info("Running test " + gTestsRun + " (" + test.name + ")"); |
michael@0 | 176 | else |
michael@0 | 177 | info("Running test " + gTestsRun); |
michael@0 | 178 | |
michael@0 | 179 | gTestStart = Date.now(); |
michael@0 | 180 | log_exceptions(test); |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | function get_addon_file_url(aFilename) { |
michael@0 | 184 | try { |
michael@0 | 185 | var cr = Cc["@mozilla.org/chrome/chrome-registry;1"]. |
michael@0 | 186 | getService(Ci.nsIChromeRegistry); |
michael@0 | 187 | var fileurl = cr.convertChromeURL(makeURI(CHROMEROOT + "addons/" + aFilename)); |
michael@0 | 188 | return fileurl.QueryInterface(Ci.nsIFileURL); |
michael@0 | 189 | } catch(ex) { |
michael@0 | 190 | var jar = getJar(CHROMEROOT + "addons/" + aFilename); |
michael@0 | 191 | var tmpDir = extractJarToTmp(jar); |
michael@0 | 192 | tmpDir.append(aFilename); |
michael@0 | 193 | |
michael@0 | 194 | return Services.io.newFileURI(tmpDir).QueryInterface(Ci.nsIFileURL); |
michael@0 | 195 | } |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | function get_test_items_in_list(aManager) { |
michael@0 | 199 | var tests = "@tests.mozilla.org"; |
michael@0 | 200 | |
michael@0 | 201 | let view = aManager.document.getElementById("view-port").selectedPanel; |
michael@0 | 202 | let listid = view.id == "search-view" ? "search-list" : "addon-list"; |
michael@0 | 203 | let item = aManager.document.getElementById(listid).firstChild; |
michael@0 | 204 | let items = []; |
michael@0 | 205 | |
michael@0 | 206 | while (item) { |
michael@0 | 207 | if (item.localName != "richlistitem") { |
michael@0 | 208 | item = item.nextSibling; |
michael@0 | 209 | continue; |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - tests.length) == tests) |
michael@0 | 213 | items.push(item); |
michael@0 | 214 | item = item.nextSibling; |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | return items; |
michael@0 | 218 | } |
michael@0 | 219 | |
michael@0 | 220 | function check_all_in_list(aManager, aIds, aIgnoreExtras) { |
michael@0 | 221 | var doc = aManager.document; |
michael@0 | 222 | var view = doc.getElementById("view-port").selectedPanel; |
michael@0 | 223 | var listid = view.id == "search-view" ? "search-list" : "addon-list"; |
michael@0 | 224 | var list = doc.getElementById(listid); |
michael@0 | 225 | |
michael@0 | 226 | var inlist = []; |
michael@0 | 227 | var node = list.firstChild; |
michael@0 | 228 | while (node) { |
michael@0 | 229 | if (node.value) |
michael@0 | 230 | inlist.push(node.value); |
michael@0 | 231 | node = node.nextSibling; |
michael@0 | 232 | } |
michael@0 | 233 | |
michael@0 | 234 | for (let id of aIds) { |
michael@0 | 235 | if (inlist.indexOf(id) == -1) |
michael@0 | 236 | ok(false, "Should find " + id + " in the list"); |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | if (aIgnoreExtras) |
michael@0 | 240 | return; |
michael@0 | 241 | |
michael@0 | 242 | for (let inlistItem of inlist) { |
michael@0 | 243 | if (aIds.indexOf(inlistItem) == -1) |
michael@0 | 244 | ok(false, "Shouldn't have seen " + inlistItem + " in the list"); |
michael@0 | 245 | } |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | function get_addon_element(aManager, aId) { |
michael@0 | 249 | var doc = aManager.document; |
michael@0 | 250 | var view = doc.getElementById("view-port").selectedPanel; |
michael@0 | 251 | var listid = "addon-list"; |
michael@0 | 252 | if (view.id == "search-view") |
michael@0 | 253 | listid = "search-list"; |
michael@0 | 254 | else if (view.id == "updates-view") |
michael@0 | 255 | listid = "updates-list"; |
michael@0 | 256 | var list = doc.getElementById(listid); |
michael@0 | 257 | |
michael@0 | 258 | var node = list.firstChild; |
michael@0 | 259 | while (node) { |
michael@0 | 260 | if (node.value == aId) |
michael@0 | 261 | return node; |
michael@0 | 262 | node = node.nextSibling; |
michael@0 | 263 | } |
michael@0 | 264 | return null; |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | function wait_for_view_load(aManagerWindow, aCallback, aForceWait, aLongerTimeout) { |
michael@0 | 268 | requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); |
michael@0 | 269 | |
michael@0 | 270 | if (!aForceWait && !aManagerWindow.gViewController.isLoading) { |
michael@0 | 271 | log_exceptions(aCallback, aManagerWindow); |
michael@0 | 272 | return; |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | aManagerWindow.document.addEventListener("ViewChanged", function() { |
michael@0 | 276 | aManagerWindow.document.removeEventListener("ViewChanged", arguments.callee, false); |
michael@0 | 277 | log_exceptions(aCallback, aManagerWindow); |
michael@0 | 278 | }, false); |
michael@0 | 279 | } |
michael@0 | 280 | |
michael@0 | 281 | function wait_for_manager_load(aManagerWindow, aCallback) { |
michael@0 | 282 | if (!aManagerWindow.gIsInitializing) { |
michael@0 | 283 | log_exceptions(aCallback, aManagerWindow); |
michael@0 | 284 | return; |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | info("Waiting for initialization"); |
michael@0 | 288 | aManagerWindow.document.addEventListener("Initialized", function() { |
michael@0 | 289 | aManagerWindow.document.removeEventListener("Initialized", arguments.callee, false); |
michael@0 | 290 | log_exceptions(aCallback, aManagerWindow); |
michael@0 | 291 | }, false); |
michael@0 | 292 | } |
michael@0 | 293 | |
michael@0 | 294 | function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) { |
michael@0 | 295 | let p = new Promise((resolve, reject) => { |
michael@0 | 296 | |
michael@0 | 297 | function setup_manager(aManagerWindow) { |
michael@0 | 298 | if (aLoadCallback) |
michael@0 | 299 | log_exceptions(aLoadCallback, aManagerWindow); |
michael@0 | 300 | |
michael@0 | 301 | if (aView) |
michael@0 | 302 | aManagerWindow.loadView(aView); |
michael@0 | 303 | |
michael@0 | 304 | ok(aManagerWindow != null, "Should have an add-ons manager window"); |
michael@0 | 305 | is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI"); |
michael@0 | 306 | |
michael@0 | 307 | waitForFocus(function() { |
michael@0 | 308 | info("window has focus, waiting for manager load"); |
michael@0 | 309 | wait_for_manager_load(aManagerWindow, function() { |
michael@0 | 310 | info("Manager waiting for view load"); |
michael@0 | 311 | wait_for_view_load(aManagerWindow, function() { |
michael@0 | 312 | resolve(aManagerWindow); |
michael@0 | 313 | }, null, aLongerTimeout); |
michael@0 | 314 | }); |
michael@0 | 315 | }, aManagerWindow); |
michael@0 | 316 | } |
michael@0 | 317 | |
michael@0 | 318 | if (gUseInContentUI) { |
michael@0 | 319 | info("Loading manager window in tab"); |
michael@0 | 320 | Services.obs.addObserver(function (aSubject, aTopic, aData) { |
michael@0 | 321 | Services.obs.removeObserver(arguments.callee, aTopic); |
michael@0 | 322 | if (aSubject.location.href != MANAGER_URI) { |
michael@0 | 323 | info("Ignoring load event for " + aSubject.location.href); |
michael@0 | 324 | return; |
michael@0 | 325 | } |
michael@0 | 326 | setup_manager(aSubject); |
michael@0 | 327 | }, "EM-loaded", false); |
michael@0 | 328 | |
michael@0 | 329 | gBrowser.selectedTab = gBrowser.addTab(); |
michael@0 | 330 | switchToTabHavingURI(MANAGER_URI, true); |
michael@0 | 331 | } else { |
michael@0 | 332 | info("Loading manager window in dialog"); |
michael@0 | 333 | Services.obs.addObserver(function (aSubject, aTopic, aData) { |
michael@0 | 334 | Services.obs.removeObserver(arguments.callee, aTopic); |
michael@0 | 335 | setup_manager(aSubject); |
michael@0 | 336 | }, "EM-loaded", false); |
michael@0 | 337 | |
michael@0 | 338 | openDialog(MANAGER_URI); |
michael@0 | 339 | } |
michael@0 | 340 | }); |
michael@0 | 341 | |
michael@0 | 342 | // The promise resolves with the manager window, so it is passed to the callback |
michael@0 | 343 | return log_callback(p, aCallback); |
michael@0 | 344 | } |
michael@0 | 345 | |
michael@0 | 346 | function close_manager(aManagerWindow, aCallback, aLongerTimeout) { |
michael@0 | 347 | let p = new Promise((resolve, reject) => { |
michael@0 | 348 | requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); |
michael@0 | 349 | |
michael@0 | 350 | ok(aManagerWindow != null, "Should have an add-ons manager window to close"); |
michael@0 | 351 | is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI"); |
michael@0 | 352 | |
michael@0 | 353 | aManagerWindow.addEventListener("unload", function() { |
michael@0 | 354 | try { |
michael@0 | 355 | dump("Manager window unload handler"); |
michael@0 | 356 | this.removeEventListener("unload", arguments.callee, false); |
michael@0 | 357 | resolve(); |
michael@0 | 358 | } catch(e) { |
michael@0 | 359 | reject(e); |
michael@0 | 360 | } |
michael@0 | 361 | }, false); |
michael@0 | 362 | }); |
michael@0 | 363 | |
michael@0 | 364 | info("Telling manager window to close"); |
michael@0 | 365 | aManagerWindow.close(); |
michael@0 | 366 | info("Manager window close() call returned"); |
michael@0 | 367 | |
michael@0 | 368 | return log_callback(p, aCallback); |
michael@0 | 369 | } |
michael@0 | 370 | |
michael@0 | 371 | function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) { |
michael@0 | 372 | if (!aManagerWindow) { |
michael@0 | 373 | return open_manager(aView, aCallback, aLoadCallback); |
michael@0 | 374 | } |
michael@0 | 375 | |
michael@0 | 376 | return close_manager(aManagerWindow) |
michael@0 | 377 | .then(() => open_manager(aView, aCallback, aLoadCallback)); |
michael@0 | 378 | } |
michael@0 | 379 | |
michael@0 | 380 | function wait_for_window_open(aCallback) { |
michael@0 | 381 | Services.wm.addListener({ |
michael@0 | 382 | onOpenWindow: function(aWindow) { |
michael@0 | 383 | Services.wm.removeListener(this); |
michael@0 | 384 | |
michael@0 | 385 | let domwindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) |
michael@0 | 386 | .getInterface(Ci.nsIDOMWindow); |
michael@0 | 387 | domwindow.addEventListener("load", function() { |
michael@0 | 388 | domwindow.removeEventListener("load", arguments.callee, false); |
michael@0 | 389 | executeSoon(function() { |
michael@0 | 390 | aCallback(domwindow); |
michael@0 | 391 | }); |
michael@0 | 392 | }, false); |
michael@0 | 393 | }, |
michael@0 | 394 | |
michael@0 | 395 | onCloseWindow: function(aWindow) { |
michael@0 | 396 | }, |
michael@0 | 397 | |
michael@0 | 398 | onWindowTitleChange: function(aWindow, aTitle) { |
michael@0 | 399 | } |
michael@0 | 400 | }); |
michael@0 | 401 | } |
michael@0 | 402 | |
michael@0 | 403 | function get_string(aName, ...aArgs) { |
michael@0 | 404 | var bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/extensions.properties"); |
michael@0 | 405 | if (aArgs.length == 0) |
michael@0 | 406 | return bundle.GetStringFromName(aName); |
michael@0 | 407 | return bundle.formatStringFromName(aName, aArgs, aArgs.length); |
michael@0 | 408 | } |
michael@0 | 409 | |
michael@0 | 410 | function formatDate(aDate) { |
michael@0 | 411 | return Cc["@mozilla.org/intl/scriptabledateformat;1"] |
michael@0 | 412 | .getService(Ci.nsIScriptableDateFormat) |
michael@0 | 413 | .FormatDate("", |
michael@0 | 414 | Ci.nsIScriptableDateFormat.dateFormatLong, |
michael@0 | 415 | aDate.getFullYear(), |
michael@0 | 416 | aDate.getMonth() + 1, |
michael@0 | 417 | aDate.getDate() |
michael@0 | 418 | ); |
michael@0 | 419 | } |
michael@0 | 420 | |
michael@0 | 421 | function is_hidden(aElement) { |
michael@0 | 422 | var style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, ""); |
michael@0 | 423 | if (style.display == "none") |
michael@0 | 424 | return true; |
michael@0 | 425 | if (style.visibility != "visible") |
michael@0 | 426 | return true; |
michael@0 | 427 | |
michael@0 | 428 | // Hiding a parent element will hide all its children |
michael@0 | 429 | if (aElement.parentNode != aElement.ownerDocument) |
michael@0 | 430 | return is_hidden(aElement.parentNode); |
michael@0 | 431 | |
michael@0 | 432 | return false; |
michael@0 | 433 | } |
michael@0 | 434 | |
michael@0 | 435 | function is_element_visible(aElement, aMsg) { |
michael@0 | 436 | isnot(aElement, null, "Element should not be null, when checking visibility"); |
michael@0 | 437 | ok(!is_hidden(aElement), aMsg); |
michael@0 | 438 | } |
michael@0 | 439 | |
michael@0 | 440 | function is_element_hidden(aElement, aMsg) { |
michael@0 | 441 | isnot(aElement, null, "Element should not be null, when checking visibility"); |
michael@0 | 442 | ok(is_hidden(aElement), aMsg); |
michael@0 | 443 | } |
michael@0 | 444 | |
michael@0 | 445 | /** |
michael@0 | 446 | * Install an add-on and call a callback when complete. |
michael@0 | 447 | * |
michael@0 | 448 | * The callback will receive the Addon for the installed add-on. |
michael@0 | 449 | */ |
michael@0 | 450 | function install_addon(path, cb, pathPrefix=TESTROOT) { |
michael@0 | 451 | let p = new Promise((resolve, reject) => { |
michael@0 | 452 | AddonManager.getInstallForURL(pathPrefix + path, (install) => { |
michael@0 | 453 | install.addListener({ |
michael@0 | 454 | onInstallEnded: () => resolve(install.addon), |
michael@0 | 455 | }); |
michael@0 | 456 | |
michael@0 | 457 | install.install(); |
michael@0 | 458 | }, "application/x-xpinstall"); |
michael@0 | 459 | }); |
michael@0 | 460 | |
michael@0 | 461 | return log_callback(p, cb); |
michael@0 | 462 | } |
michael@0 | 463 | |
michael@0 | 464 | function CategoryUtilities(aManagerWindow) { |
michael@0 | 465 | this.window = aManagerWindow; |
michael@0 | 466 | |
michael@0 | 467 | var self = this; |
michael@0 | 468 | this.window.addEventListener("unload", function() { |
michael@0 | 469 | self.window.removeEventListener("unload", arguments.callee, false); |
michael@0 | 470 | self.window = null; |
michael@0 | 471 | }, false); |
michael@0 | 472 | } |
michael@0 | 473 | |
michael@0 | 474 | CategoryUtilities.prototype = { |
michael@0 | 475 | window: null, |
michael@0 | 476 | |
michael@0 | 477 | get selectedCategory() { |
michael@0 | 478 | isnot(this.window, null, "Should not get selected category when manager window is not loaded"); |
michael@0 | 479 | var selectedItem = this.window.document.getElementById("categories").selectedItem; |
michael@0 | 480 | isnot(selectedItem, null, "A category should be selected"); |
michael@0 | 481 | var view = this.window.gViewController.parseViewId(selectedItem.value); |
michael@0 | 482 | return (view.type == "list") ? view.param : view.type; |
michael@0 | 483 | }, |
michael@0 | 484 | |
michael@0 | 485 | get: function(aCategoryType, aAllowMissing) { |
michael@0 | 486 | isnot(this.window, null, "Should not get category when manager window is not loaded"); |
michael@0 | 487 | var categories = this.window.document.getElementById("categories"); |
michael@0 | 488 | |
michael@0 | 489 | var viewId = "addons://list/" + aCategoryType; |
michael@0 | 490 | var items = categories.getElementsByAttribute("value", viewId); |
michael@0 | 491 | if (items.length) |
michael@0 | 492 | return items[0]; |
michael@0 | 493 | |
michael@0 | 494 | viewId = "addons://" + aCategoryType + "/"; |
michael@0 | 495 | items = categories.getElementsByAttribute("value", viewId); |
michael@0 | 496 | if (items.length) |
michael@0 | 497 | return items[0]; |
michael@0 | 498 | |
michael@0 | 499 | if (!aAllowMissing) |
michael@0 | 500 | ok(false, "Should have found a category with type " + aCategoryType); |
michael@0 | 501 | return null; |
michael@0 | 502 | }, |
michael@0 | 503 | |
michael@0 | 504 | getViewId: function(aCategoryType) { |
michael@0 | 505 | isnot(this.window, null, "Should not get view id when manager window is not loaded"); |
michael@0 | 506 | return this.get(aCategoryType).value; |
michael@0 | 507 | }, |
michael@0 | 508 | |
michael@0 | 509 | isVisible: function(aCategory) { |
michael@0 | 510 | isnot(this.window, null, "Should not check visible state when manager window is not loaded"); |
michael@0 | 511 | if (aCategory.hasAttribute("disabled") && |
michael@0 | 512 | aCategory.getAttribute("disabled") == "true") |
michael@0 | 513 | return false; |
michael@0 | 514 | |
michael@0 | 515 | return !is_hidden(aCategory); |
michael@0 | 516 | }, |
michael@0 | 517 | |
michael@0 | 518 | isTypeVisible: function(aCategoryType) { |
michael@0 | 519 | return this.isVisible(this.get(aCategoryType)); |
michael@0 | 520 | }, |
michael@0 | 521 | |
michael@0 | 522 | open: function(aCategory, aCallback) { |
michael@0 | 523 | |
michael@0 | 524 | isnot(this.window, null, "Should not open category when manager window is not loaded"); |
michael@0 | 525 | ok(this.isVisible(aCategory), "Category should be visible if attempting to open it"); |
michael@0 | 526 | |
michael@0 | 527 | EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window); |
michael@0 | 528 | let p = new Promise((resolve, reject) => wait_for_view_load(this.window, resolve)); |
michael@0 | 529 | |
michael@0 | 530 | return log_callback(p, aCallback); |
michael@0 | 531 | }, |
michael@0 | 532 | |
michael@0 | 533 | openType: function(aCategoryType, aCallback) { |
michael@0 | 534 | return this.open(this.get(aCategoryType), aCallback); |
michael@0 | 535 | } |
michael@0 | 536 | } |
michael@0 | 537 | |
michael@0 | 538 | function CertOverrideListener(host, bits) { |
michael@0 | 539 | this.host = host; |
michael@0 | 540 | this.bits = bits; |
michael@0 | 541 | } |
michael@0 | 542 | |
michael@0 | 543 | CertOverrideListener.prototype = { |
michael@0 | 544 | host: null, |
michael@0 | 545 | bits: null, |
michael@0 | 546 | |
michael@0 | 547 | getInterface: function (aIID) { |
michael@0 | 548 | return this.QueryInterface(aIID); |
michael@0 | 549 | }, |
michael@0 | 550 | |
michael@0 | 551 | QueryInterface: function(aIID) { |
michael@0 | 552 | if (aIID.equals(Ci.nsIBadCertListener2) || |
michael@0 | 553 | aIID.equals(Ci.nsIInterfaceRequestor) || |
michael@0 | 554 | aIID.equals(Ci.nsISupports)) |
michael@0 | 555 | return this; |
michael@0 | 556 | |
michael@0 | 557 | throw Components.Exception("No interface", Components.results.NS_ERROR_NO_INTERFACE); |
michael@0 | 558 | }, |
michael@0 | 559 | |
michael@0 | 560 | notifyCertProblem: function (socketInfo, sslStatus, targetHost) { |
michael@0 | 561 | var cert = sslStatus.QueryInterface(Components.interfaces.nsISSLStatus) |
michael@0 | 562 | .serverCert; |
michael@0 | 563 | var cos = Cc["@mozilla.org/security/certoverride;1"]. |
michael@0 | 564 | getService(Ci.nsICertOverrideService); |
michael@0 | 565 | cos.rememberValidityOverride(this.host, -1, cert, this.bits, false); |
michael@0 | 566 | return true; |
michael@0 | 567 | } |
michael@0 | 568 | } |
michael@0 | 569 | |
michael@0 | 570 | // Add overrides for the bad certificates |
michael@0 | 571 | function addCertOverride(host, bits) { |
michael@0 | 572 | var req = new XMLHttpRequest(); |
michael@0 | 573 | try { |
michael@0 | 574 | req.open("GET", "https://" + host + "/", false); |
michael@0 | 575 | req.channel.notificationCallbacks = new CertOverrideListener(host, bits); |
michael@0 | 576 | req.send(null); |
michael@0 | 577 | } |
michael@0 | 578 | catch (e) { |
michael@0 | 579 | // This request will fail since the SSL server is not trusted yet |
michael@0 | 580 | } |
michael@0 | 581 | } |
michael@0 | 582 | |
michael@0 | 583 | /***** Mock Provider *****/ |
michael@0 | 584 | |
michael@0 | 585 | function MockProvider(aUseAsyncCallbacks, aTypes) { |
michael@0 | 586 | this.addons = []; |
michael@0 | 587 | this.installs = []; |
michael@0 | 588 | this.callbackTimers = []; |
michael@0 | 589 | this.timerLocations = new Map(); |
michael@0 | 590 | this.useAsyncCallbacks = (aUseAsyncCallbacks === undefined) ? true : aUseAsyncCallbacks; |
michael@0 | 591 | this.types = (aTypes === undefined) ? [{ |
michael@0 | 592 | id: "extension", |
michael@0 | 593 | name: "Extensions", |
michael@0 | 594 | uiPriority: 4000, |
michael@0 | 595 | flags: AddonManager.TYPE_UI_VIEW_LIST |
michael@0 | 596 | }] : aTypes; |
michael@0 | 597 | |
michael@0 | 598 | var self = this; |
michael@0 | 599 | registerCleanupFunction(function() { |
michael@0 | 600 | if (self.started) |
michael@0 | 601 | self.unregister(); |
michael@0 | 602 | }); |
michael@0 | 603 | |
michael@0 | 604 | this.register(); |
michael@0 | 605 | } |
michael@0 | 606 | |
michael@0 | 607 | MockProvider.prototype = { |
michael@0 | 608 | addons: null, |
michael@0 | 609 | installs: null, |
michael@0 | 610 | started: null, |
michael@0 | 611 | apiDelay: 10, |
michael@0 | 612 | callbackTimers: null, |
michael@0 | 613 | timerLocations: null, |
michael@0 | 614 | useAsyncCallbacks: null, |
michael@0 | 615 | types: null, |
michael@0 | 616 | |
michael@0 | 617 | /***** Utility functions *****/ |
michael@0 | 618 | |
michael@0 | 619 | /** |
michael@0 | 620 | * Register this provider with the AddonManager |
michael@0 | 621 | */ |
michael@0 | 622 | register: function MP_register() { |
michael@0 | 623 | AddonManagerPrivate.registerProvider(this, this.types); |
michael@0 | 624 | }, |
michael@0 | 625 | |
michael@0 | 626 | /** |
michael@0 | 627 | * Unregister this provider with the AddonManager |
michael@0 | 628 | */ |
michael@0 | 629 | unregister: function MP_unregister() { |
michael@0 | 630 | AddonManagerPrivate.unregisterProvider(this); |
michael@0 | 631 | }, |
michael@0 | 632 | |
michael@0 | 633 | /** |
michael@0 | 634 | * Adds an add-on to the list of add-ons that this provider exposes to the |
michael@0 | 635 | * AddonManager, dispatching appropriate events in the process. |
michael@0 | 636 | * |
michael@0 | 637 | * @param aAddon |
michael@0 | 638 | * The add-on to add |
michael@0 | 639 | */ |
michael@0 | 640 | addAddon: function MP_addAddon(aAddon) { |
michael@0 | 641 | var oldAddons = this.addons.filter(function(aOldAddon) aOldAddon.id == aAddon.id); |
michael@0 | 642 | var oldAddon = oldAddons.length > 0 ? oldAddons[0] : null; |
michael@0 | 643 | |
michael@0 | 644 | this.addons = this.addons.filter(function(aOldAddon) aOldAddon.id != aAddon.id); |
michael@0 | 645 | |
michael@0 | 646 | this.addons.push(aAddon); |
michael@0 | 647 | aAddon._provider = this; |
michael@0 | 648 | |
michael@0 | 649 | if (!this.started) |
michael@0 | 650 | return; |
michael@0 | 651 | |
michael@0 | 652 | let requiresRestart = (aAddon.operationsRequiringRestart & |
michael@0 | 653 | AddonManager.OP_NEEDS_RESTART_INSTALL) != 0; |
michael@0 | 654 | AddonManagerPrivate.callInstallListeners("onExternalInstall", null, aAddon, |
michael@0 | 655 | oldAddon, requiresRestart) |
michael@0 | 656 | }, |
michael@0 | 657 | |
michael@0 | 658 | /** |
michael@0 | 659 | * Removes an add-on from the list of add-ons that this provider exposes to |
michael@0 | 660 | * the AddonManager, dispatching the onUninstalled event in the process. |
michael@0 | 661 | * |
michael@0 | 662 | * @param aAddon |
michael@0 | 663 | * The add-on to add |
michael@0 | 664 | */ |
michael@0 | 665 | removeAddon: function MP_removeAddon(aAddon) { |
michael@0 | 666 | var pos = this.addons.indexOf(aAddon); |
michael@0 | 667 | if (pos == -1) { |
michael@0 | 668 | ok(false, "Tried to remove an add-on that wasn't registered with the mock provider"); |
michael@0 | 669 | return; |
michael@0 | 670 | } |
michael@0 | 671 | |
michael@0 | 672 | this.addons.splice(pos, 1); |
michael@0 | 673 | |
michael@0 | 674 | if (!this.started) |
michael@0 | 675 | return; |
michael@0 | 676 | |
michael@0 | 677 | AddonManagerPrivate.callAddonListeners("onUninstalled", aAddon); |
michael@0 | 678 | }, |
michael@0 | 679 | |
michael@0 | 680 | /** |
michael@0 | 681 | * Adds an add-on install to the list of installs that this provider exposes |
michael@0 | 682 | * to the AddonManager, dispatching appropriate events in the process. |
michael@0 | 683 | * |
michael@0 | 684 | * @param aInstall |
michael@0 | 685 | * The add-on install to add |
michael@0 | 686 | */ |
michael@0 | 687 | addInstall: function MP_addInstall(aInstall) { |
michael@0 | 688 | this.installs.push(aInstall); |
michael@0 | 689 | aInstall._provider = this; |
michael@0 | 690 | |
michael@0 | 691 | if (!this.started) |
michael@0 | 692 | return; |
michael@0 | 693 | |
michael@0 | 694 | aInstall.callListeners("onNewInstall"); |
michael@0 | 695 | }, |
michael@0 | 696 | |
michael@0 | 697 | removeInstall: function MP_removeInstall(aInstall) { |
michael@0 | 698 | var pos = this.installs.indexOf(aInstall); |
michael@0 | 699 | if (pos == -1) { |
michael@0 | 700 | ok(false, "Tried to remove an install that wasn't registered with the mock provider"); |
michael@0 | 701 | return; |
michael@0 | 702 | } |
michael@0 | 703 | |
michael@0 | 704 | this.installs.splice(pos, 1); |
michael@0 | 705 | }, |
michael@0 | 706 | |
michael@0 | 707 | /** |
michael@0 | 708 | * Creates a set of mock add-on objects and adds them to the list of add-ons |
michael@0 | 709 | * managed by this provider. |
michael@0 | 710 | * |
michael@0 | 711 | * @param aAddonProperties |
michael@0 | 712 | * An array of objects containing properties describing the add-ons |
michael@0 | 713 | * @return Array of the new MockAddons |
michael@0 | 714 | */ |
michael@0 | 715 | createAddons: function MP_createAddons(aAddonProperties) { |
michael@0 | 716 | var newAddons = []; |
michael@0 | 717 | for (let addonProp of aAddonProperties) { |
michael@0 | 718 | let addon = new MockAddon(addonProp.id); |
michael@0 | 719 | for (let prop in addonProp) { |
michael@0 | 720 | if (prop == "id") |
michael@0 | 721 | continue; |
michael@0 | 722 | if (prop == "applyBackgroundUpdates") { |
michael@0 | 723 | addon._applyBackgroundUpdates = addonProp[prop]; |
michael@0 | 724 | continue; |
michael@0 | 725 | } |
michael@0 | 726 | if (prop == "appDisabled") { |
michael@0 | 727 | addon._appDisabled = addonProp[prop]; |
michael@0 | 728 | continue; |
michael@0 | 729 | } |
michael@0 | 730 | addon[prop] = addonProp[prop]; |
michael@0 | 731 | } |
michael@0 | 732 | if (!addon.optionsType && !!addon.optionsURL) |
michael@0 | 733 | addon.optionsType = AddonManager.OPTIONS_TYPE_DIALOG; |
michael@0 | 734 | |
michael@0 | 735 | // Make sure the active state matches the passed in properties |
michael@0 | 736 | addon.isActive = addon.shouldBeActive; |
michael@0 | 737 | |
michael@0 | 738 | this.addAddon(addon); |
michael@0 | 739 | newAddons.push(addon); |
michael@0 | 740 | } |
michael@0 | 741 | |
michael@0 | 742 | return newAddons; |
michael@0 | 743 | }, |
michael@0 | 744 | |
michael@0 | 745 | /** |
michael@0 | 746 | * Creates a set of mock add-on install objects and adds them to the list |
michael@0 | 747 | * of installs managed by this provider. |
michael@0 | 748 | * |
michael@0 | 749 | * @param aInstallProperties |
michael@0 | 750 | * An array of objects containing properties describing the installs |
michael@0 | 751 | * @return Array of the new MockInstalls |
michael@0 | 752 | */ |
michael@0 | 753 | createInstalls: function MP_createInstalls(aInstallProperties) { |
michael@0 | 754 | var newInstalls = []; |
michael@0 | 755 | for (let installProp of aInstallProperties) { |
michael@0 | 756 | let install = new MockInstall(installProp.name || null, |
michael@0 | 757 | installProp.type || null, |
michael@0 | 758 | null); |
michael@0 | 759 | for (let prop in installProp) { |
michael@0 | 760 | switch (prop) { |
michael@0 | 761 | case "name": |
michael@0 | 762 | case "type": |
michael@0 | 763 | break; |
michael@0 | 764 | case "sourceURI": |
michael@0 | 765 | install[prop] = NetUtil.newURI(installProp[prop]); |
michael@0 | 766 | break; |
michael@0 | 767 | default: |
michael@0 | 768 | install[prop] = installProp[prop]; |
michael@0 | 769 | } |
michael@0 | 770 | } |
michael@0 | 771 | this.addInstall(install); |
michael@0 | 772 | newInstalls.push(install); |
michael@0 | 773 | } |
michael@0 | 774 | |
michael@0 | 775 | return newInstalls; |
michael@0 | 776 | }, |
michael@0 | 777 | |
michael@0 | 778 | /***** AddonProvider implementation *****/ |
michael@0 | 779 | |
michael@0 | 780 | /** |
michael@0 | 781 | * Called to initialize the provider. |
michael@0 | 782 | */ |
michael@0 | 783 | startup: function MP_startup() { |
michael@0 | 784 | this.started = true; |
michael@0 | 785 | }, |
michael@0 | 786 | |
michael@0 | 787 | /** |
michael@0 | 788 | * Called when the provider should shutdown. |
michael@0 | 789 | */ |
michael@0 | 790 | shutdown: function MP_shutdown() { |
michael@0 | 791 | if (this.callbackTimers.length) { |
michael@0 | 792 | info("MockProvider: pending callbacks at shutdown(): calling immediately"); |
michael@0 | 793 | } |
michael@0 | 794 | while (this.callbackTimers.length > 0) { |
michael@0 | 795 | // When we notify the callback timer, it removes itself from our array |
michael@0 | 796 | let timer = this.callbackTimers[0]; |
michael@0 | 797 | try { |
michael@0 | 798 | let setAt = this.timerLocations.get(timer); |
michael@0 | 799 | info("Notifying timer set at " + (setAt || "unknown location")); |
michael@0 | 800 | timer.callback.notify(timer); |
michael@0 | 801 | timer.cancel(); |
michael@0 | 802 | } catch(e) { |
michael@0 | 803 | info("Timer notify failed: " + e); |
michael@0 | 804 | } |
michael@0 | 805 | } |
michael@0 | 806 | this.callbackTimers = []; |
michael@0 | 807 | this.timerLocations = null; |
michael@0 | 808 | |
michael@0 | 809 | this.started = false; |
michael@0 | 810 | }, |
michael@0 | 811 | |
michael@0 | 812 | /** |
michael@0 | 813 | * Called to get an Addon with a particular ID. |
michael@0 | 814 | * |
michael@0 | 815 | * @param aId |
michael@0 | 816 | * The ID of the add-on to retrieve |
michael@0 | 817 | * @param aCallback |
michael@0 | 818 | * A callback to pass the Addon to |
michael@0 | 819 | */ |
michael@0 | 820 | getAddonByID: function MP_getAddon(aId, aCallback) { |
michael@0 | 821 | for (let addon of this.addons) { |
michael@0 | 822 | if (addon.id == aId) { |
michael@0 | 823 | this._delayCallback(aCallback, addon); |
michael@0 | 824 | return; |
michael@0 | 825 | } |
michael@0 | 826 | } |
michael@0 | 827 | |
michael@0 | 828 | aCallback(null); |
michael@0 | 829 | }, |
michael@0 | 830 | |
michael@0 | 831 | /** |
michael@0 | 832 | * Called to get Addons of a particular type. |
michael@0 | 833 | * |
michael@0 | 834 | * @param aTypes |
michael@0 | 835 | * An array of types to fetch. Can be null to get all types. |
michael@0 | 836 | * @param callback |
michael@0 | 837 | * A callback to pass an array of Addons to |
michael@0 | 838 | */ |
michael@0 | 839 | getAddonsByTypes: function MP_getAddonsByTypes(aTypes, aCallback) { |
michael@0 | 840 | var addons = this.addons.filter(function(aAddon) { |
michael@0 | 841 | if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) |
michael@0 | 842 | return false; |
michael@0 | 843 | return true; |
michael@0 | 844 | }); |
michael@0 | 845 | this._delayCallback(aCallback, addons); |
michael@0 | 846 | }, |
michael@0 | 847 | |
michael@0 | 848 | /** |
michael@0 | 849 | * Called to get Addons that have pending operations. |
michael@0 | 850 | * |
michael@0 | 851 | * @param aTypes |
michael@0 | 852 | * An array of types to fetch. Can be null to get all types |
michael@0 | 853 | * @param aCallback |
michael@0 | 854 | * A callback to pass an array of Addons to |
michael@0 | 855 | */ |
michael@0 | 856 | getAddonsWithOperationsByTypes: function MP_getAddonsWithOperationsByTypes(aTypes, aCallback) { |
michael@0 | 857 | var addons = this.addons.filter(function(aAddon) { |
michael@0 | 858 | if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) |
michael@0 | 859 | return false; |
michael@0 | 860 | return aAddon.pendingOperations != 0; |
michael@0 | 861 | }); |
michael@0 | 862 | this._delayCallback(aCallback, addons); |
michael@0 | 863 | }, |
michael@0 | 864 | |
michael@0 | 865 | /** |
michael@0 | 866 | * Called to get the current AddonInstalls, optionally restricting by type. |
michael@0 | 867 | * |
michael@0 | 868 | * @param aTypes |
michael@0 | 869 | * An array of types or null to get all types |
michael@0 | 870 | * @param aCallback |
michael@0 | 871 | * A callback to pass the array of AddonInstalls to |
michael@0 | 872 | */ |
michael@0 | 873 | getInstallsByTypes: function MP_getInstallsByTypes(aTypes, aCallback) { |
michael@0 | 874 | var installs = this.installs.filter(function(aInstall) { |
michael@0 | 875 | // Appear to have actually removed cancelled installs from the provider |
michael@0 | 876 | if (aInstall.state == AddonManager.STATE_CANCELLED) |
michael@0 | 877 | return false; |
michael@0 | 878 | |
michael@0 | 879 | if (aTypes && aTypes.length > 0 && aTypes.indexOf(aInstall.type) == -1) |
michael@0 | 880 | return false; |
michael@0 | 881 | |
michael@0 | 882 | return true; |
michael@0 | 883 | }); |
michael@0 | 884 | this._delayCallback(aCallback, installs); |
michael@0 | 885 | }, |
michael@0 | 886 | |
michael@0 | 887 | /** |
michael@0 | 888 | * Called when a new add-on has been enabled when only one add-on of that type |
michael@0 | 889 | * can be enabled. |
michael@0 | 890 | * |
michael@0 | 891 | * @param aId |
michael@0 | 892 | * The ID of the newly enabled add-on |
michael@0 | 893 | * @param aType |
michael@0 | 894 | * The type of the newly enabled add-on |
michael@0 | 895 | * @param aPendingRestart |
michael@0 | 896 | * true if the newly enabled add-on will only become enabled after a |
michael@0 | 897 | * restart |
michael@0 | 898 | */ |
michael@0 | 899 | addonChanged: function MP_addonChanged(aId, aType, aPendingRestart) { |
michael@0 | 900 | // Not implemented |
michael@0 | 901 | }, |
michael@0 | 902 | |
michael@0 | 903 | /** |
michael@0 | 904 | * Update the appDisabled property for all add-ons. |
michael@0 | 905 | */ |
michael@0 | 906 | updateAddonAppDisabledStates: function MP_updateAddonAppDisabledStates() { |
michael@0 | 907 | // Not needed |
michael@0 | 908 | }, |
michael@0 | 909 | |
michael@0 | 910 | /** |
michael@0 | 911 | * Called to get an AddonInstall to download and install an add-on from a URL. |
michael@0 | 912 | * |
michael@0 | 913 | * @param aUrl |
michael@0 | 914 | * The URL to be installed |
michael@0 | 915 | * @param aHash |
michael@0 | 916 | * A hash for the install |
michael@0 | 917 | * @param aName |
michael@0 | 918 | * A name for the install |
michael@0 | 919 | * @param aIconURL |
michael@0 | 920 | * An icon URL for the install |
michael@0 | 921 | * @param aVersion |
michael@0 | 922 | * A version for the install |
michael@0 | 923 | * @param aLoadGroup |
michael@0 | 924 | * An nsILoadGroup to associate requests with |
michael@0 | 925 | * @param aCallback |
michael@0 | 926 | * A callback to pass the AddonInstall to |
michael@0 | 927 | */ |
michael@0 | 928 | getInstallForURL: function MP_getInstallForURL(aUrl, aHash, aName, aIconURL, |
michael@0 | 929 | aVersion, aLoadGroup, aCallback) { |
michael@0 | 930 | // Not yet implemented |
michael@0 | 931 | }, |
michael@0 | 932 | |
michael@0 | 933 | /** |
michael@0 | 934 | * Called to get an AddonInstall to install an add-on from a local file. |
michael@0 | 935 | * |
michael@0 | 936 | * @param aFile |
michael@0 | 937 | * The file to be installed |
michael@0 | 938 | * @param aCallback |
michael@0 | 939 | * A callback to pass the AddonInstall to |
michael@0 | 940 | */ |
michael@0 | 941 | getInstallForFile: function MP_getInstallForFile(aFile, aCallback) { |
michael@0 | 942 | // Not yet implemented |
michael@0 | 943 | }, |
michael@0 | 944 | |
michael@0 | 945 | /** |
michael@0 | 946 | * Called to test whether installing add-ons is enabled. |
michael@0 | 947 | * |
michael@0 | 948 | * @return true if installing is enabled |
michael@0 | 949 | */ |
michael@0 | 950 | isInstallEnabled: function MP_isInstallEnabled() { |
michael@0 | 951 | return false; |
michael@0 | 952 | }, |
michael@0 | 953 | |
michael@0 | 954 | /** |
michael@0 | 955 | * Called to test whether this provider supports installing a particular |
michael@0 | 956 | * mimetype. |
michael@0 | 957 | * |
michael@0 | 958 | * @param aMimetype |
michael@0 | 959 | * The mimetype to check for |
michael@0 | 960 | * @return true if the mimetype is supported |
michael@0 | 961 | */ |
michael@0 | 962 | supportsMimetype: function MP_supportsMimetype(aMimetype) { |
michael@0 | 963 | return false; |
michael@0 | 964 | }, |
michael@0 | 965 | |
michael@0 | 966 | /** |
michael@0 | 967 | * Called to test whether installing add-ons from a URI is allowed. |
michael@0 | 968 | * |
michael@0 | 969 | * @param aUri |
michael@0 | 970 | * The URI being installed from |
michael@0 | 971 | * @return true if installing is allowed |
michael@0 | 972 | */ |
michael@0 | 973 | isInstallAllowed: function MP_isInstallAllowed(aUri) { |
michael@0 | 974 | return false; |
michael@0 | 975 | }, |
michael@0 | 976 | |
michael@0 | 977 | |
michael@0 | 978 | /***** Internal functions *****/ |
michael@0 | 979 | |
michael@0 | 980 | /** |
michael@0 | 981 | * Delay calling a callback to fake a time-consuming async operation. |
michael@0 | 982 | * The delay is specified by the apiDelay property, in milliseconds. |
michael@0 | 983 | * Parameters to send to the callback should be specified as arguments after |
michael@0 | 984 | * the aCallback argument. |
michael@0 | 985 | * |
michael@0 | 986 | * @param aCallback Callback to eventually call |
michael@0 | 987 | */ |
michael@0 | 988 | _delayCallback: function MP_delayCallback(aCallback, ...aArgs) { |
michael@0 | 989 | if (!this.useAsyncCallbacks) { |
michael@0 | 990 | aCallback(...aArgs); |
michael@0 | 991 | return; |
michael@0 | 992 | } |
michael@0 | 993 | |
michael@0 | 994 | let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |
michael@0 | 995 | // Need to keep a reference to the timer, so it doesn't get GC'ed |
michael@0 | 996 | this.callbackTimers.push(timer); |
michael@0 | 997 | // Capture a stack trace where the timer was set |
michael@0 | 998 | // needs the 'new Error' hack until bug 1007656 |
michael@0 | 999 | this.timerLocations.set(timer, Log.stackTrace(new Error("dummy"))); |
michael@0 | 1000 | timer.initWithCallback(() => { |
michael@0 | 1001 | let idx = this.callbackTimers.indexOf(timer); |
michael@0 | 1002 | if (idx == -1) { |
michael@0 | 1003 | dump("MockProvider._delayCallback lost track of timer set at " |
michael@0 | 1004 | + (this.timerLocations.get(timer) || "unknown location") + "\n"); |
michael@0 | 1005 | } else { |
michael@0 | 1006 | this.callbackTimers.splice(idx, 1); |
michael@0 | 1007 | } |
michael@0 | 1008 | this.timerLocations.delete(timer); |
michael@0 | 1009 | aCallback(...aArgs); |
michael@0 | 1010 | }, this.apiDelay, timer.TYPE_ONE_SHOT); |
michael@0 | 1011 | } |
michael@0 | 1012 | }; |
michael@0 | 1013 | |
michael@0 | 1014 | /***** Mock Addon object for the Mock Provider *****/ |
michael@0 | 1015 | |
michael@0 | 1016 | function MockAddon(aId, aName, aType, aOperationsRequiringRestart) { |
michael@0 | 1017 | // Only set required attributes. |
michael@0 | 1018 | this.id = aId || ""; |
michael@0 | 1019 | this.name = aName || ""; |
michael@0 | 1020 | this.type = aType || "extension"; |
michael@0 | 1021 | this.version = ""; |
michael@0 | 1022 | this.isCompatible = true; |
michael@0 | 1023 | this.isDebuggable = false; |
michael@0 | 1024 | this.providesUpdatesSecurely = true; |
michael@0 | 1025 | this.blocklistState = 0; |
michael@0 | 1026 | this._appDisabled = false; |
michael@0 | 1027 | this._userDisabled = false; |
michael@0 | 1028 | this._applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE; |
michael@0 | 1029 | this.scope = AddonManager.SCOPE_PROFILE; |
michael@0 | 1030 | this.isActive = true; |
michael@0 | 1031 | this.creator = ""; |
michael@0 | 1032 | this.pendingOperations = 0; |
michael@0 | 1033 | this._permissions = AddonManager.PERM_CAN_UNINSTALL | |
michael@0 | 1034 | AddonManager.PERM_CAN_ENABLE | |
michael@0 | 1035 | AddonManager.PERM_CAN_DISABLE | |
michael@0 | 1036 | AddonManager.PERM_CAN_UPGRADE; |
michael@0 | 1037 | this.operationsRequiringRestart = aOperationsRequiringRestart || |
michael@0 | 1038 | (AddonManager.OP_NEEDS_RESTART_INSTALL | |
michael@0 | 1039 | AddonManager.OP_NEEDS_RESTART_UNINSTALL | |
michael@0 | 1040 | AddonManager.OP_NEEDS_RESTART_ENABLE | |
michael@0 | 1041 | AddonManager.OP_NEEDS_RESTART_DISABLE); |
michael@0 | 1042 | } |
michael@0 | 1043 | |
michael@0 | 1044 | MockAddon.prototype = { |
michael@0 | 1045 | get shouldBeActive() { |
michael@0 | 1046 | return !this.appDisabled && !this._userDisabled; |
michael@0 | 1047 | }, |
michael@0 | 1048 | |
michael@0 | 1049 | get appDisabled() { |
michael@0 | 1050 | return this._appDisabled; |
michael@0 | 1051 | }, |
michael@0 | 1052 | |
michael@0 | 1053 | set appDisabled(val) { |
michael@0 | 1054 | if (val == this._appDisabled) |
michael@0 | 1055 | return val; |
michael@0 | 1056 | |
michael@0 | 1057 | AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["appDisabled"]); |
michael@0 | 1058 | |
michael@0 | 1059 | var currentActive = this.shouldBeActive; |
michael@0 | 1060 | this._appDisabled = val; |
michael@0 | 1061 | var newActive = this.shouldBeActive; |
michael@0 | 1062 | this._updateActiveState(currentActive, newActive); |
michael@0 | 1063 | |
michael@0 | 1064 | return val; |
michael@0 | 1065 | }, |
michael@0 | 1066 | |
michael@0 | 1067 | get userDisabled() { |
michael@0 | 1068 | return this._userDisabled; |
michael@0 | 1069 | }, |
michael@0 | 1070 | |
michael@0 | 1071 | set userDisabled(val) { |
michael@0 | 1072 | if (val == this._userDisabled) |
michael@0 | 1073 | return val; |
michael@0 | 1074 | |
michael@0 | 1075 | var currentActive = this.shouldBeActive; |
michael@0 | 1076 | this._userDisabled = val; |
michael@0 | 1077 | var newActive = this.shouldBeActive; |
michael@0 | 1078 | this._updateActiveState(currentActive, newActive); |
michael@0 | 1079 | |
michael@0 | 1080 | return val; |
michael@0 | 1081 | }, |
michael@0 | 1082 | |
michael@0 | 1083 | get permissions() { |
michael@0 | 1084 | let permissions = this._permissions; |
michael@0 | 1085 | if (this.appDisabled || !this._userDisabled) |
michael@0 | 1086 | permissions &= ~AddonManager.PERM_CAN_ENABLE; |
michael@0 | 1087 | if (this.appDisabled || this._userDisabled) |
michael@0 | 1088 | permissions &= ~AddonManager.PERM_CAN_DISABLE; |
michael@0 | 1089 | return permissions; |
michael@0 | 1090 | }, |
michael@0 | 1091 | |
michael@0 | 1092 | set permissions(val) { |
michael@0 | 1093 | return this._permissions = val; |
michael@0 | 1094 | }, |
michael@0 | 1095 | |
michael@0 | 1096 | get applyBackgroundUpdates() { |
michael@0 | 1097 | return this._applyBackgroundUpdates; |
michael@0 | 1098 | }, |
michael@0 | 1099 | |
michael@0 | 1100 | set applyBackgroundUpdates(val) { |
michael@0 | 1101 | if (val != AddonManager.AUTOUPDATE_DEFAULT && |
michael@0 | 1102 | val != AddonManager.AUTOUPDATE_DISABLE && |
michael@0 | 1103 | val != AddonManager.AUTOUPDATE_ENABLE) { |
michael@0 | 1104 | ok(false, "addon.applyBackgroundUpdates set to an invalid value: " + val); |
michael@0 | 1105 | } |
michael@0 | 1106 | this._applyBackgroundUpdates = val; |
michael@0 | 1107 | AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["applyBackgroundUpdates"]); |
michael@0 | 1108 | }, |
michael@0 | 1109 | |
michael@0 | 1110 | isCompatibleWith: function(aAppVersion, aPlatformVersion) { |
michael@0 | 1111 | return true; |
michael@0 | 1112 | }, |
michael@0 | 1113 | |
michael@0 | 1114 | findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) { |
michael@0 | 1115 | // Tests can implement this if they need to |
michael@0 | 1116 | }, |
michael@0 | 1117 | |
michael@0 | 1118 | uninstall: function() { |
michael@0 | 1119 | if (this.pendingOperations & AddonManager.PENDING_UNINSTALL) |
michael@0 | 1120 | throw Components.Exception("Add-on is already pending uninstall"); |
michael@0 | 1121 | |
michael@0 | 1122 | var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL); |
michael@0 | 1123 | this.pendingOperations |= AddonManager.PENDING_UNINSTALL; |
michael@0 | 1124 | AddonManagerPrivate.callAddonListeners("onUninstalling", this, needsRestart); |
michael@0 | 1125 | if (!needsRestart) { |
michael@0 | 1126 | this.pendingOperations -= AddonManager.PENDING_UNINSTALL; |
michael@0 | 1127 | this._provider.removeAddon(this); |
michael@0 | 1128 | } |
michael@0 | 1129 | }, |
michael@0 | 1130 | |
michael@0 | 1131 | cancelUninstall: function() { |
michael@0 | 1132 | if (!(this.pendingOperations & AddonManager.PENDING_UNINSTALL)) |
michael@0 | 1133 | throw Components.Exception("Add-on is not pending uninstall"); |
michael@0 | 1134 | |
michael@0 | 1135 | this.pendingOperations -= AddonManager.PENDING_UNINSTALL; |
michael@0 | 1136 | AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); |
michael@0 | 1137 | }, |
michael@0 | 1138 | |
michael@0 | 1139 | _updateActiveState: function(currentActive, newActive) { |
michael@0 | 1140 | if (currentActive == newActive) |
michael@0 | 1141 | return; |
michael@0 | 1142 | |
michael@0 | 1143 | if (newActive == this.isActive) { |
michael@0 | 1144 | this.pendingOperations -= (newActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE); |
michael@0 | 1145 | AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); |
michael@0 | 1146 | } |
michael@0 | 1147 | else if (newActive) { |
michael@0 | 1148 | var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE); |
michael@0 | 1149 | this.pendingOperations |= AddonManager.PENDING_ENABLE; |
michael@0 | 1150 | AddonManagerPrivate.callAddonListeners("onEnabling", this, needsRestart); |
michael@0 | 1151 | if (!needsRestart) { |
michael@0 | 1152 | this.isActive = newActive; |
michael@0 | 1153 | this.pendingOperations -= AddonManager.PENDING_ENABLE; |
michael@0 | 1154 | AddonManagerPrivate.callAddonListeners("onEnabled", this); |
michael@0 | 1155 | } |
michael@0 | 1156 | } |
michael@0 | 1157 | else { |
michael@0 | 1158 | var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE); |
michael@0 | 1159 | this.pendingOperations |= AddonManager.PENDING_DISABLE; |
michael@0 | 1160 | AddonManagerPrivate.callAddonListeners("onDisabling", this, needsRestart); |
michael@0 | 1161 | if (!needsRestart) { |
michael@0 | 1162 | this.isActive = newActive; |
michael@0 | 1163 | this.pendingOperations -= AddonManager.PENDING_DISABLE; |
michael@0 | 1164 | AddonManagerPrivate.callAddonListeners("onDisabled", this); |
michael@0 | 1165 | } |
michael@0 | 1166 | } |
michael@0 | 1167 | } |
michael@0 | 1168 | }; |
michael@0 | 1169 | |
michael@0 | 1170 | /***** Mock AddonInstall object for the Mock Provider *****/ |
michael@0 | 1171 | |
michael@0 | 1172 | function MockInstall(aName, aType, aAddonToInstall) { |
michael@0 | 1173 | this.name = aName || ""; |
michael@0 | 1174 | // Don't expose type until download completed |
michael@0 | 1175 | this._type = aType || "extension"; |
michael@0 | 1176 | this.type = null; |
michael@0 | 1177 | this.version = "1.0"; |
michael@0 | 1178 | this.iconURL = ""; |
michael@0 | 1179 | this.infoURL = ""; |
michael@0 | 1180 | this.state = AddonManager.STATE_AVAILABLE; |
michael@0 | 1181 | this.error = 0; |
michael@0 | 1182 | this.sourceURI = null; |
michael@0 | 1183 | this.file = null; |
michael@0 | 1184 | this.progress = 0; |
michael@0 | 1185 | this.maxProgress = -1; |
michael@0 | 1186 | this.certificate = null; |
michael@0 | 1187 | this.certName = ""; |
michael@0 | 1188 | this.existingAddon = null; |
michael@0 | 1189 | this.addon = null; |
michael@0 | 1190 | this._addonToInstall = aAddonToInstall; |
michael@0 | 1191 | this.listeners = []; |
michael@0 | 1192 | |
michael@0 | 1193 | // Another type of install listener for tests that want to check the results |
michael@0 | 1194 | // of code run from standard install listeners |
michael@0 | 1195 | this.testListeners = []; |
michael@0 | 1196 | } |
michael@0 | 1197 | |
michael@0 | 1198 | MockInstall.prototype = { |
michael@0 | 1199 | install: function() { |
michael@0 | 1200 | switch (this.state) { |
michael@0 | 1201 | case AddonManager.STATE_AVAILABLE: |
michael@0 | 1202 | this.state = AddonManager.STATE_DOWNLOADING; |
michael@0 | 1203 | if (!this.callListeners("onDownloadStarted")) { |
michael@0 | 1204 | this.state = AddonManager.STATE_CANCELLED; |
michael@0 | 1205 | this.callListeners("onDownloadCancelled"); |
michael@0 | 1206 | return; |
michael@0 | 1207 | } |
michael@0 | 1208 | |
michael@0 | 1209 | this.type = this._type; |
michael@0 | 1210 | |
michael@0 | 1211 | // Adding addon to MockProvider to be implemented when needed |
michael@0 | 1212 | if (this._addonToInstall) |
michael@0 | 1213 | this.addon = this._addonToInstall; |
michael@0 | 1214 | else { |
michael@0 | 1215 | this.addon = new MockAddon("", this.name, this.type); |
michael@0 | 1216 | this.addon.version = this.version; |
michael@0 | 1217 | this.addon.pendingOperations = AddonManager.PENDING_INSTALL; |
michael@0 | 1218 | } |
michael@0 | 1219 | this.addon.install = this; |
michael@0 | 1220 | if (this.existingAddon) { |
michael@0 | 1221 | if (!this.addon.id) |
michael@0 | 1222 | this.addon.id = this.existingAddon.id; |
michael@0 | 1223 | this.existingAddon.pendingUpgrade = this.addon; |
michael@0 | 1224 | this.existingAddon.pendingOperations |= AddonManager.PENDING_UPGRADE; |
michael@0 | 1225 | } |
michael@0 | 1226 | |
michael@0 | 1227 | this.state = AddonManager.STATE_DOWNLOADED; |
michael@0 | 1228 | this.callListeners("onDownloadEnded"); |
michael@0 | 1229 | |
michael@0 | 1230 | case AddonManager.STATE_DOWNLOADED: |
michael@0 | 1231 | this.state = AddonManager.STATE_INSTALLING; |
michael@0 | 1232 | if (!this.callListeners("onInstallStarted")) { |
michael@0 | 1233 | this.state = AddonManager.STATE_CANCELLED; |
michael@0 | 1234 | this.callListeners("onInstallCancelled"); |
michael@0 | 1235 | return; |
michael@0 | 1236 | } |
michael@0 | 1237 | |
michael@0 | 1238 | AddonManagerPrivate.callAddonListeners("onInstalling", this.addon); |
michael@0 | 1239 | |
michael@0 | 1240 | this.state = AddonManager.STATE_INSTALLED; |
michael@0 | 1241 | this.callListeners("onInstallEnded"); |
michael@0 | 1242 | break; |
michael@0 | 1243 | case AddonManager.STATE_DOWNLOADING: |
michael@0 | 1244 | case AddonManager.STATE_CHECKING: |
michael@0 | 1245 | case AddonManger.STATE_INSTALLING: |
michael@0 | 1246 | // Installation is already running |
michael@0 | 1247 | return; |
michael@0 | 1248 | default: |
michael@0 | 1249 | ok(false, "Cannot start installing when state = " + this.state); |
michael@0 | 1250 | } |
michael@0 | 1251 | }, |
michael@0 | 1252 | |
michael@0 | 1253 | cancel: function() { |
michael@0 | 1254 | switch (this.state) { |
michael@0 | 1255 | case AddonManager.STATE_AVAILABLE: |
michael@0 | 1256 | this.state = AddonManager.STATE_CANCELLED; |
michael@0 | 1257 | break; |
michael@0 | 1258 | case AddonManager.STATE_INSTALLED: |
michael@0 | 1259 | this.state = AddonManager.STATE_CANCELLED; |
michael@0 | 1260 | this._provider.removeInstall(this); |
michael@0 | 1261 | this.callListeners("onInstallCancelled"); |
michael@0 | 1262 | break; |
michael@0 | 1263 | default: |
michael@0 | 1264 | // Handling cancelling when downloading to be implemented when needed |
michael@0 | 1265 | ok(false, "Cannot cancel when state = " + this.state); |
michael@0 | 1266 | } |
michael@0 | 1267 | }, |
michael@0 | 1268 | |
michael@0 | 1269 | |
michael@0 | 1270 | addListener: function(aListener) { |
michael@0 | 1271 | if (!this.listeners.some(function(i) i == aListener)) |
michael@0 | 1272 | this.listeners.push(aListener); |
michael@0 | 1273 | }, |
michael@0 | 1274 | |
michael@0 | 1275 | removeListener: function(aListener) { |
michael@0 | 1276 | this.listeners = this.listeners.filter(function(i) i != aListener); |
michael@0 | 1277 | }, |
michael@0 | 1278 | |
michael@0 | 1279 | addTestListener: function(aListener) { |
michael@0 | 1280 | if (!this.testListeners.some(function(i) i == aListener)) |
michael@0 | 1281 | this.testListeners.push(aListener); |
michael@0 | 1282 | }, |
michael@0 | 1283 | |
michael@0 | 1284 | removeTestListener: function(aListener) { |
michael@0 | 1285 | this.testListeners = this.testListeners.filter(function(i) i != aListener); |
michael@0 | 1286 | }, |
michael@0 | 1287 | |
michael@0 | 1288 | callListeners: function(aMethod) { |
michael@0 | 1289 | var result = AddonManagerPrivate.callInstallListeners(aMethod, this.listeners, |
michael@0 | 1290 | this, this.addon); |
michael@0 | 1291 | |
michael@0 | 1292 | // Call test listeners after standard listeners to remove race condition |
michael@0 | 1293 | // between standard and test listeners |
michael@0 | 1294 | for (let listener of this.testListeners) { |
michael@0 | 1295 | try { |
michael@0 | 1296 | if (aMethod in listener) |
michael@0 | 1297 | if (listener[aMethod].call(listener, this, this.addon) === false) |
michael@0 | 1298 | result = false; |
michael@0 | 1299 | } |
michael@0 | 1300 | catch (e) { |
michael@0 | 1301 | ok(false, "Test listener threw exception: " + e); |
michael@0 | 1302 | } |
michael@0 | 1303 | } |
michael@0 | 1304 | |
michael@0 | 1305 | return result; |
michael@0 | 1306 | } |
michael@0 | 1307 | }; |
michael@0 | 1308 | |
michael@0 | 1309 | function waitForCondition(condition, nextTest, errorMsg) { |
michael@0 | 1310 | let tries = 0; |
michael@0 | 1311 | let interval = setInterval(function() { |
michael@0 | 1312 | if (tries >= 30) { |
michael@0 | 1313 | ok(false, errorMsg); |
michael@0 | 1314 | moveOn(); |
michael@0 | 1315 | } |
michael@0 | 1316 | var conditionPassed; |
michael@0 | 1317 | try { |
michael@0 | 1318 | conditionPassed = condition(); |
michael@0 | 1319 | } catch (e) { |
michael@0 | 1320 | ok(false, e + "\n" + e.stack); |
michael@0 | 1321 | conditionPassed = false; |
michael@0 | 1322 | } |
michael@0 | 1323 | if (conditionPassed) { |
michael@0 | 1324 | moveOn(); |
michael@0 | 1325 | } |
michael@0 | 1326 | tries++; |
michael@0 | 1327 | }, 100); |
michael@0 | 1328 | let moveOn = function() { clearInterval(interval); nextTest(); }; |
michael@0 | 1329 | } |
michael@0 | 1330 | |
michael@0 | 1331 | function getTestPluginTag() { |
michael@0 | 1332 | let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); |
michael@0 | 1333 | let tags = ph.getPluginTags(); |
michael@0 | 1334 | |
michael@0 | 1335 | // Find the test plugin |
michael@0 | 1336 | for (let i = 0; i < tags.length; i++) { |
michael@0 | 1337 | if (tags[i].name == "Test Plug-in") |
michael@0 | 1338 | return tags[i]; |
michael@0 | 1339 | } |
michael@0 | 1340 | ok(false, "Unable to find plugin"); |
michael@0 | 1341 | return null; |
michael@0 | 1342 | } |