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.
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 }