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.

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

mercurial