toolkit/mozapps/extensions/test/xpinstall/head.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 const RELATIVE_DIR = "toolkit/mozapps/extensions/test/xpinstall/";
michael@0 2
michael@0 3 const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR;
michael@0 4 const TESTROOT2 = "http://example.org/browser/" + RELATIVE_DIR;
michael@0 5 const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
michael@0 6 const PROMPT_URL = "chrome://global/content/commonDialog.xul";
michael@0 7 const ADDONS_URL = "chrome://mozapps/content/extensions/extensions.xul";
michael@0 8 const PREF_LOGGING_ENABLED = "extensions.logging.enabled";
michael@0 9 const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
michael@0 10 const CHROME_NAME = "mochikit";
michael@0 11
michael@0 12 function getChromeRoot(path) {
michael@0 13 if (path === undefined) {
michael@0 14 return "chrome://" + CHROME_NAME + "/content/browser/" + RELATIVE_DIR
michael@0 15 }
michael@0 16 return getRootDirectory(path);
michael@0 17 }
michael@0 18
michael@0 19 function extractChromeRoot(path) {
michael@0 20 var chromeRootPath = getChromeRoot(path);
michael@0 21 var jar = getJar(chromeRootPath);
michael@0 22 if (jar) {
michael@0 23 var tmpdir = extractJarToTmp(jar);
michael@0 24 return "file://" + tmpdir.path + "/";
michael@0 25 }
michael@0 26 return chromeRootPath;
michael@0 27 }
michael@0 28
michael@0 29 /**
michael@0 30 * This is a test harness designed to handle responding to UI during the process
michael@0 31 * of installing an XPI. A test can set callbacks to hear about specific parts
michael@0 32 * of the sequence.
michael@0 33 * Before use setup must be called and finish must be called afterwards.
michael@0 34 */
michael@0 35 var Harness = {
michael@0 36 // If set then the callback is called when an install is attempted and
michael@0 37 // software installation is disabled.
michael@0 38 installDisabledCallback: null,
michael@0 39 // If set then the callback is called when an install is attempted and
michael@0 40 // then canceled.
michael@0 41 installCancelledCallback: null,
michael@0 42 // If set then the callback will be called when an install is blocked by the
michael@0 43 // whitelist. The callback should return true to continue with the install
michael@0 44 // anyway.
michael@0 45 installBlockedCallback: null,
michael@0 46 // If set will be called in the event of authentication being needed to get
michael@0 47 // the xpi. Should return a 2 element array of username and password, or
michael@0 48 // null to not authenticate.
michael@0 49 authenticationCallback: null,
michael@0 50 // If set this will be called to allow checking the contents of the xpinstall
michael@0 51 // confirmation dialog. The callback should return true to continue the install.
michael@0 52 installConfirmCallback: null,
michael@0 53 // If set will be called when downloading of an item has begun.
michael@0 54 downloadStartedCallback: null,
michael@0 55 // If set will be called during the download of an item.
michael@0 56 downloadProgressCallback: null,
michael@0 57 // If set will be called when an xpi fails to download.
michael@0 58 downloadFailedCallback: null,
michael@0 59 // If set will be called when an xpi download is cancelled.
michael@0 60 downloadCancelledCallback: null,
michael@0 61 // If set will be called when downloading of an item has ended.
michael@0 62 downloadEndedCallback: null,
michael@0 63 // If set will be called when installation by the extension manager of an xpi
michael@0 64 // item starts
michael@0 65 installStartedCallback: null,
michael@0 66 // If set will be called when an xpi fails to install.
michael@0 67 installFailedCallback: null,
michael@0 68 // If set will be called when each xpi item to be installed completes
michael@0 69 // installation.
michael@0 70 installEndedCallback: null,
michael@0 71 // If set will be called when all triggered items are installed or the install
michael@0 72 // is canceled.
michael@0 73 installsCompletedCallback: null,
michael@0 74
michael@0 75 pendingCount: null,
michael@0 76 installCount: null,
michael@0 77 runningInstalls: null,
michael@0 78
michael@0 79 waitingForFinish: false,
michael@0 80
michael@0 81 // Setup and tear down functions
michael@0 82 setup: function() {
michael@0 83 if (!this.waitingForFinish) {
michael@0 84 waitForExplicitFinish();
michael@0 85 this.waitingForFinish = true;
michael@0 86
michael@0 87 Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
michael@0 88 Services.obs.addObserver(this, "addon-install-started", false);
michael@0 89 Services.obs.addObserver(this, "addon-install-disabled", false);
michael@0 90 Services.obs.addObserver(this, "addon-install-blocked", false);
michael@0 91 Services.obs.addObserver(this, "addon-install-failed", false);
michael@0 92 Services.obs.addObserver(this, "addon-install-complete", false);
michael@0 93
michael@0 94 AddonManager.addInstallListener(this);
michael@0 95
michael@0 96 Services.wm.addListener(this);
michael@0 97
michael@0 98 var self = this;
michael@0 99 registerCleanupFunction(function() {
michael@0 100 Services.prefs.clearUserPref(PREF_LOGGING_ENABLED);
michael@0 101 Services.obs.removeObserver(self, "addon-install-started");
michael@0 102 Services.obs.removeObserver(self, "addon-install-disabled");
michael@0 103 Services.obs.removeObserver(self, "addon-install-blocked");
michael@0 104 Services.obs.removeObserver(self, "addon-install-failed");
michael@0 105 Services.obs.removeObserver(self, "addon-install-complete");
michael@0 106
michael@0 107 AddonManager.removeInstallListener(self);
michael@0 108
michael@0 109 Services.wm.removeListener(self);
michael@0 110
michael@0 111 AddonManager.getAllInstalls(function(aInstalls) {
michael@0 112 is(aInstalls.length, 0, "Should be no active installs at the end of the test");
michael@0 113 aInstalls.forEach(function(aInstall) {
michael@0 114 info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state);
michael@0 115 aInstall.cancel();
michael@0 116 });
michael@0 117 });
michael@0 118 });
michael@0 119 }
michael@0 120
michael@0 121 this.installCount = 0;
michael@0 122 this.pendingCount = 0;
michael@0 123 this.runningInstalls = [];
michael@0 124 },
michael@0 125
michael@0 126 finish: function() {
michael@0 127 finish();
michael@0 128 },
michael@0 129
michael@0 130 endTest: function() {
michael@0 131 // Defer the final notification to allow things like the InstallTrigger
michael@0 132 // callback to complete
michael@0 133 var self = this;
michael@0 134 executeSoon(function() {
michael@0 135 let callback = self.installsCompletedCallback;
michael@0 136 let count = self.installCount;
michael@0 137
michael@0 138 is(self.runningInstalls.length, 0, "Should be no running installs left");
michael@0 139 self.runningInstalls.forEach(function(aInstall) {
michael@0 140 info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state);
michael@0 141 });
michael@0 142
michael@0 143 self.installBlockedCallback = null;
michael@0 144 self.authenticationCallback = null;
michael@0 145 self.installConfirmCallback = null;
michael@0 146 self.downloadStartedCallback = null;
michael@0 147 self.downloadProgressCallback = null;
michael@0 148 self.downloadCancelledCallback = null;
michael@0 149 self.downloadFailedCallback = null;
michael@0 150 self.downloadEndedCallback = null;
michael@0 151 self.installStartedCallback = null;
michael@0 152 self.installFailedCallback = null;
michael@0 153 self.installEndedCallback = null;
michael@0 154 self.installsCompletedCallback = null;
michael@0 155 self.runningInstalls = null;
michael@0 156
michael@0 157 if (callback)
michael@0 158 callback(count);
michael@0 159 });
michael@0 160 },
michael@0 161
michael@0 162 // Window open handling
michael@0 163 windowReady: function(window) {
michael@0 164 if (window.document.location.href == XPINSTALL_URL) {
michael@0 165 if (this.installBlockedCallback)
michael@0 166 ok(false, "Should have been blocked by the whitelist");
michael@0 167 this.pendingCount = window.document.getElementById("itemList").childNodes.length;
michael@0 168
michael@0 169 // If there is a confirm callback then its return status determines whether
michael@0 170 // to install the items or not. If not the test is over.
michael@0 171 if (this.installConfirmCallback && !this.installConfirmCallback(window)) {
michael@0 172 window.document.documentElement.cancelDialog();
michael@0 173 }
michael@0 174 else {
michael@0 175 // Initially the accept button is disabled on a countdown timer
michael@0 176 var button = window.document.documentElement.getButton("accept");
michael@0 177 button.disabled = false;
michael@0 178 window.document.documentElement.acceptDialog();
michael@0 179 }
michael@0 180 }
michael@0 181 else if (window.document.location.href == PROMPT_URL) {
michael@0 182 var promptType = window.args.promptType;
michael@0 183 switch (promptType) {
michael@0 184 case "alert":
michael@0 185 case "alertCheck":
michael@0 186 case "confirmCheck":
michael@0 187 case "confirm":
michael@0 188 case "confirmEx":
michael@0 189 window.document.documentElement.acceptDialog();
michael@0 190 break;
michael@0 191 case "promptUserAndPass":
michael@0 192 // This is a login dialog, hopefully an authentication prompt
michael@0 193 // for the xpi.
michael@0 194 if (this.authenticationCallback) {
michael@0 195 var auth = this.authenticationCallback();
michael@0 196 if (auth && auth.length == 2) {
michael@0 197 window.document.getElementById("loginTextbox").value = auth[0];
michael@0 198 window.document.getElementById("password1Textbox").value = auth[1];
michael@0 199 window.document.documentElement.acceptDialog();
michael@0 200 }
michael@0 201 else {
michael@0 202 window.document.documentElement.cancelDialog();
michael@0 203 }
michael@0 204 }
michael@0 205 else {
michael@0 206 window.document.documentElement.cancelDialog();
michael@0 207 }
michael@0 208 break;
michael@0 209 default:
michael@0 210 ok(false, "prompt type " + promptType + " not handled in test.");
michael@0 211 break;
michael@0 212 }
michael@0 213 }
michael@0 214 },
michael@0 215
michael@0 216 // Install blocked handling
michael@0 217
michael@0 218 installDisabled: function(installInfo) {
michael@0 219 ok(!!this.installDisabledCallback, "Installation shouldn't have been disabled");
michael@0 220 if (this.installDisabledCallback)
michael@0 221 this.installDisabledCallback(installInfo);
michael@0 222 this.expectingCancelled = true;
michael@0 223 installInfo.installs.forEach(function(install) {
michael@0 224 install.cancel();
michael@0 225 });
michael@0 226 this.expectingCancelled = false;
michael@0 227 this.endTest();
michael@0 228 },
michael@0 229
michael@0 230 installCancelled: function(installInfo) {
michael@0 231 if (this.expectingCancelled)
michael@0 232 return;
michael@0 233
michael@0 234 ok(!!this.installCancelledCallback, "Installation shouldn't have been cancelled");
michael@0 235 if (this.installCancelledCallback)
michael@0 236 this.installCancelledCallback(installInfo);
michael@0 237 this.endTest();
michael@0 238 },
michael@0 239
michael@0 240 installBlocked: function(installInfo) {
michael@0 241 ok(!!this.installBlockedCallback, "Shouldn't have been blocked by the whitelist");
michael@0 242 if (this.installBlockedCallback && this.installBlockedCallback(installInfo)) {
michael@0 243 this.installBlockedCallback = null;
michael@0 244 installInfo.install();
michael@0 245 }
michael@0 246 else {
michael@0 247 this.expectingCancelled = true;
michael@0 248 installInfo.installs.forEach(function(install) {
michael@0 249 install.cancel();
michael@0 250 });
michael@0 251 this.expectingCancelled = false;
michael@0 252 this.endTest();
michael@0 253 }
michael@0 254 },
michael@0 255
michael@0 256 // nsIWindowMediatorListener
michael@0 257
michael@0 258 onWindowTitleChange: function(window, title) {
michael@0 259 },
michael@0 260
michael@0 261 onOpenWindow: function(window) {
michael@0 262 var domwindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
michael@0 263 .getInterface(Components.interfaces.nsIDOMWindow);
michael@0 264 var self = this;
michael@0 265 waitForFocus(function() {
michael@0 266 self.windowReady(domwindow);
michael@0 267 }, domwindow);
michael@0 268 },
michael@0 269
michael@0 270 onCloseWindow: function(window) {
michael@0 271 },
michael@0 272
michael@0 273 // Addon Install Listener
michael@0 274
michael@0 275 onNewInstall: function(install) {
michael@0 276 this.runningInstalls.push(install);
michael@0 277 },
michael@0 278
michael@0 279 onDownloadStarted: function(install) {
michael@0 280 this.pendingCount++;
michael@0 281 if (this.downloadStartedCallback)
michael@0 282 this.downloadStartedCallback(install);
michael@0 283 },
michael@0 284
michael@0 285 onDownloadProgress: function(install) {
michael@0 286 if (this.downloadProgressCallback)
michael@0 287 this.downloadProgressCallback(install);
michael@0 288 },
michael@0 289
michael@0 290 onDownloadEnded: function(install) {
michael@0 291 if (this.downloadEndedCallback)
michael@0 292 this.downloadEndedCallback(install);
michael@0 293 },
michael@0 294
michael@0 295 onDownloadCancelled: function(install) {
michael@0 296 isnot(this.runningInstalls.indexOf(install), -1,
michael@0 297 "Should only see cancelations for started installs");
michael@0 298 this.runningInstalls.splice(this.runningInstalls.indexOf(install), 1);
michael@0 299
michael@0 300 if (this.downloadCancelledCallback)
michael@0 301 this.downloadCancelledCallback(install);
michael@0 302 this.checkTestEnded();
michael@0 303 },
michael@0 304
michael@0 305 onDownloadFailed: function(install) {
michael@0 306 if (this.downloadFailedCallback)
michael@0 307 this.downloadFailedCallback(install);
michael@0 308 this.checkTestEnded();
michael@0 309 },
michael@0 310
michael@0 311 onInstallStarted: function(install) {
michael@0 312 if (this.installStartedCallback)
michael@0 313 this.installStartedCallback(install);
michael@0 314 },
michael@0 315
michael@0 316 onInstallEnded: function(install, addon) {
michael@0 317 if (this.installEndedCallback)
michael@0 318 this.installEndedCallback(install, addon);
michael@0 319 this.installCount++;
michael@0 320 this.checkTestEnded();
michael@0 321 },
michael@0 322
michael@0 323 onInstallFailed: function(install) {
michael@0 324 if (this.installFailedCallback)
michael@0 325 this.installFailedCallback(install);
michael@0 326 this.checkTestEnded();
michael@0 327 },
michael@0 328
michael@0 329 checkTestEnded: function() {
michael@0 330 if (--this.pendingCount == 0)
michael@0 331 this.endTest();
michael@0 332 },
michael@0 333
michael@0 334 // nsIObserver
michael@0 335
michael@0 336 observe: function(subject, topic, data) {
michael@0 337 var installInfo = subject.QueryInterface(Components.interfaces.amIWebInstallInfo);
michael@0 338 switch (topic) {
michael@0 339 case "addon-install-started":
michael@0 340 is(this.runningInstalls.length, installInfo.installs.length,
michael@0 341 "Should have seen the expected number of installs started");
michael@0 342 break;
michael@0 343 case "addon-install-disabled":
michael@0 344 this.installDisabled(installInfo);
michael@0 345 break;
michael@0 346 case "addon-install-cancelled":
michael@0 347 this.installCancelled(installInfo);
michael@0 348 break;
michael@0 349 case "addon-install-blocked":
michael@0 350 this.installBlocked(installInfo);
michael@0 351 break;
michael@0 352 case "addon-install-failed":
michael@0 353 installInfo.installs.forEach(function(aInstall) {
michael@0 354 isnot(this.runningInstalls.indexOf(aInstall), -1,
michael@0 355 "Should only see failures for started installs");
michael@0 356
michael@0 357 ok(aInstall.error != 0 || aInstall.addon.appDisabled,
michael@0 358 "Failed installs should have an error or be appDisabled");
michael@0 359
michael@0 360 this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1);
michael@0 361 }, this);
michael@0 362 break;
michael@0 363 case "addon-install-complete":
michael@0 364 installInfo.installs.forEach(function(aInstall) {
michael@0 365 isnot(this.runningInstalls.indexOf(aInstall), -1,
michael@0 366 "Should only see completed events for started installs");
michael@0 367
michael@0 368 is(aInstall.error, 0, "Completed installs should have no error");
michael@0 369 ok(!aInstall.appDisabled, "Completed installs should not be appDisabled");
michael@0 370
michael@0 371 // Complete installs are either in the INSTALLED or CANCELLED state
michael@0 372 // since the test may cancel installs the moment they complete.
michael@0 373 ok(aInstall.state == AddonManager.STATE_INSTALLED ||
michael@0 374 aInstall.state == AddonManager.STATE_CANCELLED,
michael@0 375 "Completed installs should be in the right state");
michael@0 376
michael@0 377 this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1);
michael@0 378 }, this);
michael@0 379 break;
michael@0 380 }
michael@0 381 },
michael@0 382
michael@0 383 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
michael@0 384 Ci.nsIWindowMediatorListener,
michael@0 385 Ci.nsISupports])
michael@0 386 }

mercurial