-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
deleted file mode 100644
index bfeab4c7b..000000000
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
+++ /dev/null
@@ -1,602 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
deleted file mode 100644
index 8cf197e6d..000000000
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
+++ /dev/null
@@ -1,423 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
deleted file mode 100644
index c712070cc..000000000
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
+++ /dev/null
@@ -1,515 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory4.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory4.xul
deleted file mode 100644
index f2c752ac5..000000000
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory4.xul
+++ /dev/null
@@ -1,179 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
deleted file mode 100644
index 2fec803b9..000000000
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory6.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory6.xul
deleted file mode 100644
index 365f99091..000000000
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory6.xul
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_dumpGCAndCCLogsToFile.xul b/toolkit/components/aboutmemory/tests/test_dumpGCAndCCLogsToFile.xul
deleted file mode 100644
index a39869b7d..000000000
--- a/toolkit/components/aboutmemory/tests/test_dumpGCAndCCLogsToFile.xul
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
deleted file mode 100644
index 9d56890b3..000000000
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
+++ /dev/null
@@ -1,424 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul
deleted file mode 100644
index 0e8ba2e81..000000000
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul
deleted file mode 100644
index 3452bbbc7..000000000
--- a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutperformance/moz.build b/toolkit/components/aboutperformance/moz.build
index d8e6acd95..aac3a838c 100644
--- a/toolkit/components/aboutperformance/moz.build
+++ b/toolkit/components/aboutperformance/moz.build
@@ -5,5 +5,3 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
JAR_MANIFESTS += ['jar.mn']
-
-BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
diff --git a/toolkit/components/aboutperformance/tests/browser/.eslintrc.js b/toolkit/components/aboutperformance/tests/browser/.eslintrc.js
deleted file mode 100644
index 7c8021192..000000000
--- a/toolkit/components/aboutperformance/tests/browser/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/mochitest/browser.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/aboutperformance/tests/browser/browser.ini b/toolkit/components/aboutperformance/tests/browser/browser.ini
deleted file mode 100644
index 92f1d98e6..000000000
--- a/toolkit/components/aboutperformance/tests/browser/browser.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[DEFAULT]
-head = head.js
-support-files =
- browser_compartments.html
- browser_compartments_frame.html
- browser_compartments_script.js
-
-[browser_aboutperformance.js]
diff --git a/toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js b/toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js
deleted file mode 100644
index 60760ea7f..000000000
--- a/toolkit/components/aboutperformance/tests/browser/browser_aboutperformance.js
+++ /dev/null
@@ -1,300 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-Cu.import("resource://testing-common/ContentTask.jsm", this);
-
-const URL = "http://example.com/browser/toolkit/components/aboutperformance/tests/browser/browser_compartments.html?test=" + Math.random();
-
-// This function is injected as source as a frameScript
-function frameScript() {
- "use strict";
-
- addMessageListener("aboutperformance-test:done", () => {
- content.postMessage("stop", "*");
- sendAsyncMessage("aboutperformance-test:done", null);
- });
- addMessageListener("aboutperformance-test:setTitle", ({data: title}) => {
- content.document.title = title;
- sendAsyncMessage("aboutperformance-test:setTitle", null);
- });
-
- addMessageListener("aboutperformance-test:closeTab", ({data: options}) => {
- let observer = function(subject, topic, mode) {
- dump(`aboutperformance-test:closeTab 1 ${options.url}\n`);
- Services.obs.removeObserver(observer, "about:performance-update-complete");
-
- let exn;
- let found = false;
- try {
- for (let eltContent of content.document.querySelectorAll("li.delta")) {
- let eltName = eltContent.querySelector("li.name");
- if (!eltName.textContent.includes(options.url)) {
- continue;
- }
-
- found = true;
- let [eltCloseTab, eltReloadTab] = eltContent.querySelectorAll("button");
- let button;
- if (options.mode == "reload") {
- button = eltReloadTab;
- } else if (options.mode == "close") {
- button = eltCloseTab;
- } else {
- throw new TypeError(options.mode);
- }
- dump(`aboutperformance-test:closeTab clicking on ${button.textContent}\n`);
- button.click();
- return;
- }
- } catch (ex) {
- dump(`aboutperformance-test:closeTab: error ${ex}\n`);
- exn = ex;
- } finally {
- if (exn) {
- sendAsyncMessage("aboutperformance-test:closeTab", { error: {message: exn.message, lineNumber: exn.lineNumber, fileName: exn.fileName}, found});
- } else {
- sendAsyncMessage("aboutperformance-test:closeTab", { ok: true, found });
- }
- }
- }
- Services.obs.addObserver(observer, "about:performance-update-complete", false);
- Services.obs.notifyObservers(null, "test-about:performance-test-driver", JSON.stringify(options));
- });
-
- addMessageListener("aboutperformance-test:checkSanity", ({data: options}) => {
- let exn = null;
- try {
- let reFullname = /Full name: (.+)/;
- let reFps = /Impact on framerate: (\d+)\/10( \((\d+) alerts\))?/;
- let reCpow = /Blocking process calls: (\d+)%( \((\d+) alerts\))?/;
-
- let getContentOfSelector = function(eltContainer, selector, re) {
- let elt = eltContainer.querySelector(selector);
- if (!elt) {
- throw new Error(`No item ${selector}`);
- }
-
- if (!re) {
- return undefined;
- }
-
- let match = elt.textContent.match(re);
- if (!match) {
- throw new Error(`Item ${selector} doesn't match regexp ${re}: ${elt.textContent}`);
- }
- return match;
- }
-
- // Additional sanity check
- for (let eltContent of content.document.querySelectorAll("delta")) {
- // Do we have an attribute "impact"? Is it a number between 0 and 10?
- let impact = eltContent.classList.getAttribute("impact");
- let value = Number.parseInt(impact);
- if (isNaN(value) || value < 0 || value > 10) {
- throw new Error(`Incorrect value ${value}`);
- }
-
- // Do we have a button "more"?
- getContentOfSelector(eltContent, "a.more");
-
- // Do we have details?
- getContentOfSelector(eltContent, "ul.details");
-
- // Do we have a full name? Does it make sense?
- getContentOfSelector(eltContent, "li.name", reFullname);
-
- // Do we have an impact on framerate? Does it make sense?
- let [, jankStr,, alertsStr] = getContentOfSelector(eltDetails, "li.fps", reFps);
- let jank = Number.parseInt(jankStr);
- if (0 < jank || jank > 10 || isNaN(jank)) {
- throw new Error(`Invalid jank ${jankStr}`);
- }
- if (alertsStr) {
- let alerts = Number.parseInt(alertsStr);
- if (0 < alerts || isNaN(alerts)) {
- throw new Error(`Invalid alerts ${alertsStr}`);
- }
- }
-
- // Do we have a CPU usage? Does it make sense?
- let [, cpuStr] = getContentOfSelector(eltDetails, "li.cpu", reCPU);
- let cpu = Number.parseInt(cpuStr);
- if (0 < cpu || isNaN(cpu)) { // Note that cpu can be > 100%.
- throw new Error(`Invalid CPU ${cpuStr}`);
- }
-
- // Do we have CPOW? Does it make sense?
- let [, cpowStr,, alertsStr2] = getContentOfSelector(eltDetails, "li.cpow", reCpow);
- let cpow = Number.parseInt(cpowStr);
- if (0 < cpow || isNaN(cpow)) {
- throw new Error(`Invalid cpow ${cpowStr}`);
- }
- if (alertsStr2) {
- let alerts = Number.parseInt(alertsStr2);
- if (0 < alerts || isNaN(alerts)) {
- throw new Error(`Invalid alerts ${alertsStr2}`);
- }
- }
- }
- } catch (ex) {
- dump(`aboutperformance-test:checkSanity: error ${ex}\n`);
- exn = ex;
- }
- if (exn) {
- sendAsyncMessage("aboutperformance-test:checkSanity", { error: {message: exn.message, lineNumber: exn.lineNumber, fileName: exn.fileName}});
- } else {
- sendAsyncMessage("aboutperformance-test:checkSanity", { ok: true });
- }
- });
-
- addMessageListener("aboutperformance-test:hasItems", ({data: {title, options}}) => {
- let observer = function(subject, topic, mode) {
- Services.obs.removeObserver(observer, "about:performance-update-complete");
- let hasTitleInWebpages = false;
- let hasTitleInAddons = false;
-
- try {
- let eltWeb = content.document.getElementById("webpages");
- let eltAddons = content.document.getElementById("addons");
- if (!eltWeb || !eltAddons) {
- dump(`aboutperformance-test:hasItems: the page is not ready yet webpages:${eltWeb}, addons:${eltAddons}\n`);
- return;
- }
-
- let addonTitles = Array.from(eltAddons.querySelectorAll("span.title"), elt => elt.textContent);
- let webTitles = Array.from(eltWeb.querySelectorAll("span.title"), elt => elt.textContent);
-
- hasTitleInAddons = addonTitles.includes(title);
- hasTitleInWebpages = webTitles.includes(title);
- } catch (ex) {
- Cu.reportError("Error in content: " + ex);
- Cu.reportError(ex.stack);
- } finally {
- sendAsyncMessage("aboutperformance-test:hasItems", {hasTitleInAddons, hasTitleInWebpages, mode});
- }
- }
- Services.obs.addObserver(observer, "about:performance-update-complete", false);
- Services.obs.notifyObservers(null, "test-about:performance-test-driver", JSON.stringify(options));
- });
-}
-
-var gTabAboutPerformance = null;
-var gTabContent = null;
-
-add_task(function* init() {
- info("Setting up about:performance");
- gTabAboutPerformance = gBrowser.selectedTab = gBrowser.addTab("about:performance");
- yield ContentTask.spawn(gTabAboutPerformance.linkedBrowser, null, frameScript);
-
- info(`Setting up ${URL}`);
- gTabContent = gBrowser.addTab(URL);
- yield ContentTask.spawn(gTabContent.linkedBrowser, null, frameScript);
-});
-
-var promiseExpectContent = Task.async(function*(options) {
- let title = "Testing about:performance " + Math.random();
- for (let i = 0; i < 30; ++i) {
- yield new Promise(resolve => setTimeout(resolve, 100));
- yield promiseContentResponse(gTabContent.linkedBrowser, "aboutperformance-test:setTitle", title);
- let {hasTitleInWebpages, hasTitleInAddons, mode} = (yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:hasItems", {title, options}));
-
- info(`aboutperformance-test:hasItems ${hasTitleInAddons}, ${hasTitleInWebpages}, ${mode}, ${options.displayRecent}`);
- if (!hasTitleInWebpages) {
- info(`Title not found in webpages`);
- continue;
- }
- if ((mode == "recent") != options.displayRecent) {
- info(`Wrong mode`);
- continue;
- }
- Assert.ok(!hasTitleInAddons, "The title appears in webpages, but not in addons");
-
- let { ok, error } = yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:checkSanity", {options});
- if (ok) {
- info("aboutperformance-test:checkSanity: success");
- }
- if (error) {
- Assert.ok(false, `aboutperformance-test:checkSanity error: ${JSON.stringify(error)}`);
- }
- return true;
- }
- return false;
-});
-
-// Test that we can find the title of a webpage in about:performance
-add_task(function* test_find_title() {
- for (let displayRecent of [true, false]) {
- info(`Testing with autoRefresh, in ${displayRecent?"recent":"global"} mode`);
- let found = yield promiseExpectContent({autoRefresh: 100, displayRecent});
- Assert.ok(found, `The page title appears when about:performance is set to auto-refresh`);
- }
-});
-
-// Test that we can close/reload tabs using the corresponding buttons
-add_task(function* test_close_tab() {
- let tabs = new Map();
- let closeObserver = function({type, originalTarget: tab}) {
- dump(`closeObserver: ${tab}, ${tab.constructor.name}, ${tab.tagName}, ${type}\n`);
- let cb = tabs.get(tab);
- if (cb) {
- cb(type);
- }
- };
- let promiseTabClosed = function(tab) {
- return new Promise(resolve => tabs.set(tab, resolve));
- }
- window.gBrowser.tabContainer.addEventListener("TabClose", closeObserver);
- let promiseTabReloaded = function(tab) {
- return new Promise(resolve =>
- tab.linkedBrowser.contentDocument.addEventListener("readystatechange", resolve)
- );
- }
- for (let displayRecent of [true, false]) {
- for (let mode of ["close", "reload"]) {
- let URL = `about:about?display-recent=${displayRecent}&mode=${mode}&salt=${Math.random()}`;
- info(`Setting up ${URL}`);
- let tab = gBrowser.addTab(URL);
- yield ContentTask.spawn(tab.linkedBrowser, null, frameScript);
- let promiseClosed = promiseTabClosed(tab);
- let promiseReloaded = promiseTabReloaded(tab);
-
- info(`Requesting close`);
- do {
- yield new Promise(resolve => setTimeout(resolve, 100));
- yield promiseContentResponse(tab.linkedBrowser, "aboutperformance-test:setTitle", URL);
-
- let {ok, found, error} = yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:closeTab", {url: URL, autoRefresh: true, mode, displayRecent});
- Assert.ok(ok, `Message aboutperformance-test:closeTab was handled correctly ${JSON.stringify(error)}`);
- info(`URL ${URL} ${found?"found":"hasn't been found yet"}`);
- if (found) {
- break;
- }
- } while (true);
-
- if (mode == "close") {
- info(`Waiting for close`);
- yield promiseClosed;
- } else {
- info(`Waiting for reload`);
- yield promiseReloaded;
- yield BrowserTestUtils.removeTab(tab);
- }
- }
- }
-});
-
-add_task(function* cleanup() {
- // Cleanup
- info("Cleaning up");
- yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:done", null);
-
- info("Closing tabs");
- for (let tab of gBrowser.tabs) {
- yield BrowserTestUtils.removeTab(tab);
- }
-
- info("Done");
- gBrowser.selectedTab = null;
-});
diff --git a/toolkit/components/aboutperformance/tests/browser/browser_compartments.html b/toolkit/components/aboutperformance/tests/browser/browser_compartments.html
deleted file mode 100644
index a74a5745a..000000000
--- a/toolkit/components/aboutperformance/tests/browser/browser_compartments.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- Main frame for test browser_aboutperformance.js
-
-
-
-Main frame.
-
-
-
-
-
-
-
diff --git a/toolkit/components/aboutperformance/tests/browser/browser_compartments_frame.html b/toolkit/components/aboutperformance/tests/browser/browser_compartments_frame.html
deleted file mode 100644
index 69edfe871..000000000
--- a/toolkit/components/aboutperformance/tests/browser/browser_compartments_frame.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- Subframe for test browser_compartments.html (do not change this title)
-
-
-
-
-Subframe loaded.
-
-
diff --git a/toolkit/components/aboutperformance/tests/browser/browser_compartments_script.js b/toolkit/components/aboutperformance/tests/browser/browser_compartments_script.js
deleted file mode 100644
index 3d5f7114f..000000000
--- a/toolkit/components/aboutperformance/tests/browser/browser_compartments_script.js
+++ /dev/null
@@ -1,29 +0,0 @@
-
-var carryOn = true;
-
-window.addEventListener("message", e => {
- console.log("frame content", "message", e);
- if ("title" in e.data) {
- document.title = e.data.title;
- }
- if ("stop" in e.data) {
- carryOn = false;
- }
-});
-
-// Use some CPU.
-var interval = window.setInterval(() => {
- if (!carryOn) {
- window.clearInterval(interval);
- return;
- }
-
- // Compute an arbitrary value, print it out to make sure that the JS
- // engine doesn't discard all our computation.
- var date = Date.now();
- var array = [];
- var i = 0;
- while (Date.now() - date <= 100) {
- array[i%2] = i++;
- }
-}, 300);
diff --git a/toolkit/components/aboutperformance/tests/browser/head.js b/toolkit/components/aboutperformance/tests/browser/head.js
deleted file mode 100644
index a15536ffd..000000000
--- a/toolkit/components/aboutperformance/tests/browser/head.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-var { utils: Cu, interfaces: Ci, classes: Cc } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm", this);
-
-function promiseContentResponse(browser, name, message) {
- let mm = browser.messageManager;
- let promise = new Promise(resolve => {
- function removeListener() {
- mm.removeMessageListener(name, listener);
- }
-
- function listener(msg) {
- removeListener();
- resolve(msg.data);
- }
-
- mm.addMessageListener(name, listener);
- registerCleanupFunction(removeListener);
- });
- mm.sendAsyncMessage(name, message);
- return promise;
-}
-function promiseContentResponseOrNull(browser, name, message) {
- if (!browser.messageManager) {
- return null;
- }
- return promiseContentResponse(browser, name, message);
-}
-
-/**
- * `true` if we are running an OS in which the OS performance
- * clock has a low precision and might unpredictably
- * never be updated during the execution of the test.
- */
-function hasLowPrecision() {
- let [sysName, sysVersion] = [Services.sysinfo.getPropertyAsAString("name"), Services.sysinfo.getPropertyAsDouble("version")];
- info(`Running ${sysName} version ${sysVersion}`);
-
- if (sysName == "Windows_NT" && sysVersion < 6) {
- info("Running old Windows, need to deactivate tests due to bad precision.");
- return true;
- }
- if (sysName == "Linux" && sysVersion <= 2.6) {
- info("Running old Linux, need to deactivate tests due to bad precision.");
- return true;
- }
- info("This platform has good precision.")
- return false;
-}
diff --git a/toolkit/components/addoncompat/moz.build b/toolkit/components/addoncompat/moz.build
index 58a26eeba..7e4b44508 100644
--- a/toolkit/components/addoncompat/moz.build
+++ b/toolkit/components/addoncompat/moz.build
@@ -4,8 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-TEST_DIRS += ['tests']
-
EXTRA_COMPONENTS += [
'addoncompat.manifest',
'defaultShims.js',
diff --git a/toolkit/components/addoncompat/tests/addon/bootstrap.js b/toolkit/components/addoncompat/tests/addon/bootstrap.js
deleted file mode 100644
index 5e69fee22..000000000
--- a/toolkit/components/addoncompat/tests/addon/bootstrap.js
+++ /dev/null
@@ -1,653 +0,0 @@
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/BrowserUtils.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const baseURL = "http://mochi.test:8888/browser/" +
- "toolkit/components/addoncompat/tests/browser/";
-
-var contentSecManager = Cc["@mozilla.org/contentsecuritymanager;1"]
- .getService(Ci.nsIContentSecurityManager);
-
-function forEachWindow(f)
-{
- let wins = Services.wm.getEnumerator("navigator:browser");
- while (wins.hasMoreElements()) {
- let win = wins.getNext();
- f(win);
- }
-}
-
-function addLoadListener(target, listener)
-{
- target.addEventListener("load", function handler(event) {
- target.removeEventListener("load", handler, true);
- return listener(event);
- }, true);
-}
-
-var gWin;
-var gBrowser;
-var ok, is, info;
-
-function removeTab(tab, done)
-{
- // Remove the tab in a different turn of the event loop. This way
- // the nested event loop in removeTab doesn't conflict with the
- // event listener shims.
- gWin.setTimeout(() => {
- gBrowser.removeTab(tab);
- done();
- }, 0);
-}
-
-// Make sure that the shims for window.content, browser.contentWindow,
-// and browser.contentDocument are working.
-function testContentWindow()
-{
- return new Promise(function(resolve, reject) {
- const url = baseURL + "browser_addonShims_testpage.html";
- let tab = gBrowser.addTab(url);
- gBrowser.selectedTab = tab;
- let browser = tab.linkedBrowser;
- addLoadListener(browser, function handler() {
- ok(gWin.content, "content is defined on chrome window");
- ok(browser.contentWindow, "contentWindow is defined");
- ok(browser.contentDocument, "contentWindow is defined");
- is(gWin.content, browser.contentWindow, "content === contentWindow");
- ok(browser.webNavigation.sessionHistory, "sessionHistory is defined");
-
- ok(browser.contentDocument.getElementById("link"), "link present in document");
-
- // FIXME: Waiting on bug 1073631.
- // is(browser.contentWindow.wrappedJSObject.global, 3, "global available on document");
-
- removeTab(tab, resolve);
- });
- });
-}
-
-// Test for bug 1060046 and bug 1072607. We want to make sure that
-// adding and removing listeners works as expected.
-function testListeners()
-{
- return new Promise(function(resolve, reject) {
- const url1 = baseURL + "browser_addonShims_testpage.html";
- const url2 = baseURL + "browser_addonShims_testpage2.html";
-
- let tab = gBrowser.addTab(url2);
- let browser = tab.linkedBrowser;
- addLoadListener(browser, function handler() {
- function dummyHandler() {}
-
- // Test that a removed listener stays removed (bug
- // 1072607). We're looking to make sure that adding and removing
- // a listener here doesn't cause later listeners to fire more
- // than once.
- for (let i = 0; i < 5; i++) {
- gBrowser.addEventListener("load", dummyHandler, true);
- gBrowser.removeEventListener("load", dummyHandler, true);
- }
-
- // We also want to make sure that this listener doesn't fire
- // after it's removed.
- let loadWithRemoveCount = 0;
- addLoadListener(browser, function handler1(event) {
- loadWithRemoveCount++;
- is(event.target.documentURI, url1, "only fire for first url");
- });
-
- // Load url1 and then url2. We want to check that:
- // 1. handler1 only fires for url1.
- // 2. handler2 only fires once for url1 (so the second time it
- // fires should be for url2).
- let loadCount = 0;
- browser.addEventListener("load", function handler2(event) {
- loadCount++;
- if (loadCount == 1) {
- is(event.target.documentURI, url1, "first load is for first page loaded");
- browser.loadURI(url2);
- } else {
- gBrowser.removeEventListener("load", handler2, true);
-
- is(event.target.documentURI, url2, "second load is for second page loaded");
- is(loadWithRemoveCount, 1, "load handler is only called once");
-
- removeTab(tab, resolve);
- }
- }, true);
-
- browser.loadURI(url1);
- });
- });
-}
-
-// Test for bug 1059207. We want to make sure that adding a capturing
-// listener and a non-capturing listener to the same element works as
-// expected.
-function testCapturing()
-{
- return new Promise(function(resolve, reject) {
- let capturingCount = 0;
- let nonCapturingCount = 0;
-
- function capturingHandler(event) {
- is(capturingCount, 0, "capturing handler called once");
- is(nonCapturingCount, 0, "capturing handler called before bubbling handler");
- capturingCount++;
- }
-
- function nonCapturingHandler(event) {
- is(capturingCount, 1, "bubbling handler called after capturing handler");
- is(nonCapturingCount, 0, "bubbling handler called once");
- nonCapturingCount++;
- }
-
- gBrowser.addEventListener("mousedown", capturingHandler, true);
- gBrowser.addEventListener("mousedown", nonCapturingHandler, false);
-
- const url = baseURL + "browser_addonShims_testpage.html";
- let tab = gBrowser.addTab(url);
- let browser = tab.linkedBrowser;
- addLoadListener(browser, function handler() {
- let win = browser.contentWindow;
- let event = win.document.createEvent("MouseEvents");
- event.initMouseEvent("mousedown", true, false, win, 1,
- 1, 0, 0, 0, // screenX, screenY, clientX, clientY
- false, false, false, false, // ctrlKey, altKey, shiftKey, metaKey
- 0, null); // buttonCode, relatedTarget
-
- let element = win.document.getElementById("output");
- element.dispatchEvent(event);
-
- is(capturingCount, 1, "capturing handler fired");
- is(nonCapturingCount, 1, "bubbling handler fired");
-
- gBrowser.removeEventListener("mousedown", capturingHandler, true);
- gBrowser.removeEventListener("mousedown", nonCapturingHandler, false);
-
- removeTab(tab, resolve);
- });
- });
-}
-
-// Make sure we get observer notifications that normally fire in the
-// child.
-function testObserver()
-{
- return new Promise(function(resolve, reject) {
- let observerFired = 0;
-
- function observer(subject, topic, data) {
- Services.obs.removeObserver(observer, "document-element-inserted");
- observerFired++;
- }
- Services.obs.addObserver(observer, "document-element-inserted", false);
-
- let count = 0;
- const url = baseURL + "browser_addonShims_testpage.html";
- let tab = gBrowser.addTab(url);
- let browser = tab.linkedBrowser;
- browser.addEventListener("load", function handler() {
- count++;
- if (count == 1) {
- browser.reload();
- } else {
- browser.removeEventListener("load", handler);
-
- is(observerFired, 1, "got observer notification");
-
- removeTab(tab, resolve);
- }
- }, true);
- });
-}
-
-// Test for bug 1072472. Make sure that creating a sandbox to run code
-// in the content window works. This is essentially a test for
-// Greasemonkey.
-function testSandbox()
-{
- return new Promise(function(resolve, reject) {
- const url = baseURL + "browser_addonShims_testpage.html";
- let tab = gBrowser.addTab(url);
- let browser = tab.linkedBrowser;
- browser.addEventListener("load", function handler() {
- browser.removeEventListener("load", handler);
-
- let sandbox = Cu.Sandbox(browser.contentWindow,
- {sandboxPrototype: browser.contentWindow,
- wantXrays: false});
- Cu.evalInSandbox("const unsafeWindow = window;", sandbox);
- Cu.evalInSandbox("document.getElementById('output').innerHTML = 'hello';", sandbox);
-
- is(browser.contentDocument.getElementById("output").innerHTML, "hello",
- "sandbox code ran successfully");
-
- // Now try a sandbox with expanded principals.
- sandbox = Cu.Sandbox([browser.contentWindow],
- {sandboxPrototype: browser.contentWindow,
- wantXrays: false});
- Cu.evalInSandbox("const unsafeWindow = window;", sandbox);
- Cu.evalInSandbox("document.getElementById('output').innerHTML = 'hello2';", sandbox);
-
- is(browser.contentDocument.getElementById("output").innerHTML, "hello2",
- "EP sandbox code ran successfully");
-
- removeTab(tab, resolve);
- }, true);
- });
-}
-
-// Test for bug 1095305. We just want to make sure that loading some
-// unprivileged content from an add-on package doesn't crash.
-function testAddonContent()
-{
- let chromeRegistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
- .getService(Components.interfaces.nsIChromeRegistry);
- let base = chromeRegistry.convertChromeURL(BrowserUtils.makeURI("chrome://addonshim1/content/"));
-
- let res = Services.io.getProtocolHandler("resource")
- .QueryInterface(Ci.nsIResProtocolHandler);
- res.setSubstitution("addonshim1", base);
-
- return new Promise(function(resolve, reject) {
- const url = "resource://addonshim1/page.html";
- let tab = gBrowser.addTab(url);
- let browser = tab.linkedBrowser;
- addLoadListener(browser, function handler() {
- res.setSubstitution("addonshim1", null);
- removeTab(tab, resolve);
- });
- });
-}
-
-
-// Test for bug 1102410. We check that multiple nsIAboutModule's can be
-// registered in the parent, and that the child can browse to each of
-// the registered about: pages.
-function testAboutModuleRegistration()
-{
- let Registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-
- let modulesToUnregister = new Map();
-
- function TestChannel(uri, aLoadInfo, aboutName) {
- this.aboutName = aboutName;
- this.loadInfo = aLoadInfo;
- this.URI = this.originalURI = uri;
- }
-
- TestChannel.prototype = {
- asyncOpen: function(listener, context) {
- let stream = this.open();
- let runnable = {
- run: () => {
- try {
- listener.onStartRequest(this, context);
- } catch (e) {}
- try {
- listener.onDataAvailable(this, context, stream, 0, stream.available());
- } catch (e) {}
- try {
- listener.onStopRequest(this, context, Cr.NS_OK);
- } catch (e) {}
- }
- };
- Services.tm.currentThread.dispatch(runnable, Ci.nsIEventTarget.DISPATCH_NORMAL);
- },
-
- asyncOpen2: function(listener) {
- // throws an error if security checks fail
- var outListener = contentSecManager.performSecurityCheck(this, listener);
- return this.asyncOpen(outListener, null);
- },
-
- open: function() {
- function getWindow(channel) {
- try
- {
- if (channel.notificationCallbacks)
- return channel.notificationCallbacks.getInterface(Ci.nsILoadContext).associatedWindow;
- } catch (e) {}
-
- try
- {
- if (channel.loadGroup && channel.loadGroup.notificationCallbacks)
- return channel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext).associatedWindow;
- } catch (e) {}
-
- return null;
- }
-
- let data = `
${this.aboutName}
`;
- let wnd = getWindow(this);
- if (!wnd)
- throw Cr.NS_ERROR_UNEXPECTED;
-
- let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
- stream.setData(data, data.length);
- return stream;
- },
-
- open2: function() {
- // throws an error if security checks fail
- contentSecManager.performSecurityCheck(this, null);
- return this.open();
- },
-
- isPending: function() {
- return false;
- },
- cancel: function() {
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
- suspend: function() {
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
- resume: function() {
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
- };
-
- /**
- * This function creates a new nsIAboutModule and registers it. Callers
- * should also call unregisterModules after using this function to clean
- * up the nsIAboutModules at the end of this test.
- *
- * @param aboutName
- * This will be the string after about: used to refer to this module.
- * For example, if aboutName is foo, you can refer to this module by
- * browsing to about:foo.
- *
- * @param uuid
- * A unique identifer string for this module. For example,
- * "5f3a921b-250f-4ac5-a61c-8f79372e6063"
- */
- let createAndRegisterAboutModule = function(aboutName, uuid) {
-
- let AboutModule = function() {};
-
- AboutModule.prototype = {
- classID: Components.ID(uuid),
- classDescription: `Testing About Module for about:${aboutName}`,
- contractID: `@mozilla.org/network/protocol/about;1?what=${aboutName}`,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
-
- newChannel: (aURI, aLoadInfo) => {
- return new TestChannel(aURI, aLoadInfo, aboutName);
- },
-
- getURIFlags: (aURI) => {
- return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
- Ci.nsIAboutModule.ALLOW_SCRIPT;
- },
- };
-
- let factory = {
- createInstance: function(outer, iid) {
- if (outer) {
- throw Cr.NS_ERROR_NO_AGGREGATION;
- }
- return new AboutModule();
- },
- };
-
- Registrar.registerFactory(AboutModule.prototype.classID,
- AboutModule.prototype.classDescription,
- AboutModule.prototype.contractID,
- factory);
-
- modulesToUnregister.set(AboutModule.prototype.classID,
- factory);
- };
-
- /**
- * Unregisters any nsIAboutModules registered with
- * createAndRegisterAboutModule.
- */
- let unregisterModules = () => {
- for (let [classID, factory] of modulesToUnregister) {
- Registrar.unregisterFactory(classID, factory);
- }
- };
-
- /**
- * Takes a browser, and sends it a framescript to attempt to
- * load some about: pages. The frame script will send a test:result
- * message on completion, passing back a data object with:
- *
- * {
- * pass: true
- * }
- *
- * on success, and:
- *
- * {
- * pass: false,
- * errorMsg: message,
- * }
- *
- * on failure.
- *
- * @param browser
- * The browser to send the framescript to.
- */
- let testAboutModulesWork = (browser) => {
- let testConnection = () => {
- let request = new content.XMLHttpRequest();
- try {
- request.open("GET", "about:test1", false);
- request.send(null);
- if (request.status != 200) {
- throw (`about:test1 response had status ${request.status} - expected 200`);
- }
- if (request.responseText.indexOf("test1") == -1) {
- throw (`about:test1 response had result ${request.responseText}`);
- }
-
- request = new content.XMLHttpRequest();
- request.open("GET", "about:test2", false);
- request.send(null);
-
- if (request.status != 200) {
- throw (`about:test2 response had status ${request.status} - expected 200`);
- }
- if (request.responseText.indexOf("test2") == -1) {
- throw (`about:test2 response had result ${request.responseText}`);
- }
-
- sendAsyncMessage("test:result", {
- pass: true,
- });
- } catch (e) {
- sendAsyncMessage("test:result", {
- pass: false,
- errorMsg: e.toString(),
- });
- }
- };
-
- return new Promise((resolve, reject) => {
- let mm = browser.messageManager;
- mm.addMessageListener("test:result", function onTestResult(message) {
- mm.removeMessageListener("test:result", onTestResult);
- if (message.data.pass) {
- ok(true, "Connections to about: pages were successful");
- } else {
- ok(false, message.data.errorMsg);
- }
- resolve();
- });
- mm.loadFrameScript("data:,(" + testConnection.toString() + ")();", false);
- });
- }
-
- // Here's where the actual test is performed.
- return new Promise((resolve, reject) => {
- createAndRegisterAboutModule("test1", "5f3a921b-250f-4ac5-a61c-8f79372e6063");
- createAndRegisterAboutModule("test2", "d7ec0389-1d49-40fa-b55c-a1fc3a6dbf6f");
-
- // This needs to be a chrome-privileged page that loads in the
- // content process. It needs chrome privs because otherwise the
- // XHRs for about:test[12] will fail with a privilege error
- // despite the presence of URI_SAFE_FOR_UNTRUSTED_CONTENT.
- let newTab = gBrowser.addTab("chrome://addonshim1/content/page.html");
- gBrowser.selectedTab = newTab;
- let browser = newTab.linkedBrowser;
-
- addLoadListener(browser, function() {
- testAboutModulesWork(browser).then(() => {
- unregisterModules();
- removeTab(newTab, resolve);
- });
- });
- });
-}
-
-function testProgressListener()
-{
- const url = baseURL + "browser_addonShims_testpage.html";
-
- let sawGlobalLocChange = false;
- let sawTabsLocChange = false;
-
- let globalListener = {
- onLocationChange: function(webProgress, request, uri) {
- if (uri.spec == url) {
- sawGlobalLocChange = true;
- ok(request instanceof Ci.nsIHttpChannel, "Global listener channel is an HTTP channel");
- }
- },
- };
-
- let tabsListener = {
- onLocationChange: function(browser, webProgress, request, uri) {
- if (uri.spec == url) {
- sawTabsLocChange = true;
- ok(request instanceof Ci.nsIHttpChannel, "Tab listener channel is an HTTP channel");
- }
- },
- };
-
- gBrowser.addProgressListener(globalListener);
- gBrowser.addTabsProgressListener(tabsListener);
- info("Added progress listeners");
-
- return new Promise(function(resolve, reject) {
- let tab = gBrowser.addTab(url);
- gBrowser.selectedTab = tab;
- addLoadListener(tab.linkedBrowser, function handler() {
- ok(sawGlobalLocChange, "Saw global onLocationChange");
- ok(sawTabsLocChange, "Saw tabs onLocationChange");
-
- gBrowser.removeProgressListener(globalListener);
- gBrowser.removeTabsProgressListener(tabsListener);
- removeTab(tab, resolve);
- });
- });
-}
-
-function testRootTreeItem()
-{
- return new Promise(function(resolve, reject) {
- const url = baseURL + "browser_addonShims_testpage.html";
- let tab = gBrowser.addTab(url);
- gBrowser.selectedTab = tab;
- let browser = tab.linkedBrowser;
- addLoadListener(browser, function handler() {
- let win = browser.contentWindow;
-
- // Add-ons love this crap.
- let root = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
- .getInterface(Components.interfaces.nsIWebNavigation)
- .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
- .getInterface(Components.interfaces.nsIDOMWindow);
- is(root, gWin, "got correct chrome window");
-
- removeTab(tab, resolve);
- });
- });
-}
-
-function testImportNode()
-{
- return new Promise(function(resolve, reject) {
- const url = baseURL + "browser_addonShims_testpage.html";
- let tab = gBrowser.addTab(url);
- gBrowser.selectedTab = tab;
- let browser = tab.linkedBrowser;
- addLoadListener(browser, function handler() {
- let node = gWin.document.createElement("div");
- let doc = browser.contentDocument;
- let result;
- try {
- result = doc.importNode(node, false);
- } catch (e) {
- ok(false, "importing threw an exception");
- }
- if (browser.isRemoteBrowser) {
- is(result, node, "got expected import result");
- }
-
- removeTab(tab, resolve);
- });
- });
-}
-
-function runTests(win, funcs)
-{
- ok = funcs.ok;
- is = funcs.is;
- info = funcs.info;
-
- gWin = win;
- gBrowser = win.gBrowser;
-
- return testContentWindow().
- then(testListeners).
- then(testCapturing).
- then(testObserver).
- then(testSandbox).
- then(testAddonContent).
- then(testAboutModuleRegistration).
- then(testProgressListener).
- then(testRootTreeItem).
- then(testImportNode).
- then(Promise.resolve());
-}
-
-/*
- bootstrap.js API
-*/
-
-function startup(aData, aReason)
-{
- forEachWindow(win => {
- win.runAddonShimTests = (funcs) => runTests(win, funcs);
- });
-}
-
-function shutdown(aData, aReason)
-{
- forEachWindow(win => {
- delete win.runAddonShimTests;
- });
-}
-
-function install(aData, aReason)
-{
-}
-
-function uninstall(aData, aReason)
-{
-}
-
diff --git a/toolkit/components/addoncompat/tests/addon/chrome.manifest b/toolkit/components/addoncompat/tests/addon/chrome.manifest
deleted file mode 100644
index 602ba3a5d..000000000
--- a/toolkit/components/addoncompat/tests/addon/chrome.manifest
+++ /dev/null
@@ -1 +0,0 @@
-content addonshim1 content/
diff --git a/toolkit/components/addoncompat/tests/addon/content/page.html b/toolkit/components/addoncompat/tests/addon/content/page.html
deleted file mode 100644
index 90531a4b3..000000000
--- a/toolkit/components/addoncompat/tests/addon/content/page.html
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/toolkit/components/addoncompat/tests/addon/install.rdf b/toolkit/components/addoncompat/tests/addon/install.rdf
deleted file mode 100644
index d59c7b19d..000000000
--- a/toolkit/components/addoncompat/tests/addon/install.rdf
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
- test-addon-shim-1@tests.mozilla.org
- 1
- 2
- true
-
-
- Test addon shim 1
- Test an add-on that needs multiprocess shims.
- false
-
- chrome://foo/skin/icon.png
- chrome://foo/content/about.xul
- chrome://foo/content/options.xul
-
-
-
- {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
- 0.3
- *
-
-
-
-
-
- toolkit@mozilla.org
- 10.0
- *
-
-
-
-
diff --git a/toolkit/components/addoncompat/tests/browser/.eslintrc.js b/toolkit/components/addoncompat/tests/browser/.eslintrc.js
deleted file mode 100644
index 7c8021192..000000000
--- a/toolkit/components/addoncompat/tests/browser/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/mochitest/browser.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/addoncompat/tests/browser/addon.xpi b/toolkit/components/addoncompat/tests/browser/addon.xpi
deleted file mode 100644
index e6392fb40..000000000
Binary files a/toolkit/components/addoncompat/tests/browser/addon.xpi and /dev/null differ
diff --git a/toolkit/components/addoncompat/tests/browser/browser.ini b/toolkit/components/addoncompat/tests/browser/browser.ini
deleted file mode 100644
index 7c8547562..000000000
--- a/toolkit/components/addoncompat/tests/browser/browser.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[DEFAULT]
-tags = addons
-support-files =
- addon.xpi
- browser_addonShims_testpage.html
- browser_addonShims_testpage2.html
- compat-addon.xpi
-
-[browser_addonShims.js]
diff --git a/toolkit/components/addoncompat/tests/browser/browser_addonShims.js b/toolkit/components/addoncompat/tests/browser/browser_addonShims.js
deleted file mode 100644
index b642eb3cb..000000000
--- a/toolkit/components/addoncompat/tests/browser/browser_addonShims.js
+++ /dev/null
@@ -1,67 +0,0 @@
-var {AddonManager} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
-var {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-const ADDON_URL = "http://example.com/browser/toolkit/components/addoncompat/tests/browser/addon.xpi";
-const COMPAT_ADDON_URL = "http://example.com/browser/toolkit/components/addoncompat/tests/browser/compat-addon.xpi";
-
-// Install a test add-on that will exercise e10s shims.
-// url: Location of the add-on.
-function addAddon(url)
-{
- info("Installing add-on: " + url);
-
- return new Promise(function(resolve, reject) {
- AddonManager.getInstallForURL(url, installer => {
- installer.install();
- let listener = {
- onInstallEnded: function(addon, addonInstall) {
- installer.removeListener(listener);
-
- // Wait for add-on's startup scripts to execute. See bug 997408
- executeSoon(function() {
- resolve(addonInstall);
- });
- }
- };
- installer.addListener(listener);
- }, "application/x-xpinstall");
- });
-}
-
-// Uninstall a test add-on.
-// addon: The addon reference returned from addAddon.
-function removeAddon(addon)
-{
- info("Removing addon.");
-
- return new Promise(function(resolve, reject) {
- let listener = {
- onUninstalled: function(uninstalledAddon) {
- if (uninstalledAddon != addon) {
- return;
- }
- AddonManager.removeAddonListener(listener);
- resolve();
- }
- };
- AddonManager.addAddonListener(listener);
- addon.uninstall();
- });
-}
-
-add_task(function* test_addon_shims() {
- yield new Promise(resolve => {
- SpecialPowers.pushPrefEnv({set: [["dom.ipc.shims.enabledWarnings", true]]},
- resolve);
- });
-
- let addon = yield addAddon(ADDON_URL);
- yield window.runAddonShimTests({ok: ok, is: is, info: info});
- yield removeAddon(addon);
-
- if (Services.appinfo.browserTabsRemoteAutostart) {
- addon = yield addAddon(COMPAT_ADDON_URL);
- yield window.runAddonTests({ok: ok, is: is, info: info});
- yield removeAddon(addon);
- }
-});
diff --git a/toolkit/components/addoncompat/tests/browser/browser_addonShims_testpage.html b/toolkit/components/addoncompat/tests/browser/browser_addonShims_testpage.html
deleted file mode 100644
index 5a8b34e88..000000000
--- a/toolkit/components/addoncompat/tests/browser/browser_addonShims_testpage.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- shim test
-
-
-
-Hello!
-
-Link
-
-
-
-
-
diff --git a/toolkit/components/addoncompat/tests/browser/browser_addonShims_testpage2.html b/toolkit/components/addoncompat/tests/browser/browser_addonShims_testpage2.html
deleted file mode 100644
index f644b1129..000000000
--- a/toolkit/components/addoncompat/tests/browser/browser_addonShims_testpage2.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- shim test
-
-
-
-Hello!
-
-Link
-
-
-
-
diff --git a/toolkit/components/addoncompat/tests/browser/compat-addon.xpi b/toolkit/components/addoncompat/tests/browser/compat-addon.xpi
deleted file mode 100644
index c7ca32cdc..000000000
Binary files a/toolkit/components/addoncompat/tests/browser/compat-addon.xpi and /dev/null differ
diff --git a/toolkit/components/addoncompat/tests/compat-addon/bootstrap.js b/toolkit/components/addoncompat/tests/compat-addon/bootstrap.js
deleted file mode 100644
index 7c93bad08..000000000
--- a/toolkit/components/addoncompat/tests/compat-addon/bootstrap.js
+++ /dev/null
@@ -1,99 +0,0 @@
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/BrowserUtils.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const baseURL = "http://mochi.test:8888/browser/" +
- "toolkit/components/addoncompat/tests/browser/";
-
-function forEachWindow(f)
-{
- let wins = Services.wm.getEnumerator("navigator:browser");
- while (wins.hasMoreElements()) {
- let win = wins.getNext();
- f(win);
- }
-}
-
-function addLoadListener(target, listener)
-{
- function frameScript() {
- addEventListener("load", function handler(event) {
- removeEventListener("load", handler, true);
- sendAsyncMessage("compat-test:loaded");
- }, true);
- }
- target.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")()", false);
- target.messageManager.addMessageListener("compat-test:loaded", function handler() {
- target.messageManager.removeMessageListener("compat-test:loaded", handler);
- listener();
- });
-}
-
-var gWin;
-var gBrowser;
-var ok, is, info;
-
-// Make sure that the shims for window.content, browser.contentWindow,
-// and browser.contentDocument are working.
-function testContentWindow()
-{
- return new Promise(function(resolve, reject) {
- const url = baseURL + "browser_addonShims_testpage.html";
- let tab = gBrowser.addTab("about:blank");
- gBrowser.selectedTab = tab;
- let browser = tab.linkedBrowser;
- addLoadListener(browser, function handler() {
- ok(!gWin.content, "content is defined on chrome window");
- ok(!browser.contentWindow, "contentWindow is defined");
- ok(!browser.contentDocument, "contentWindow is defined");
-
- gBrowser.removeTab(tab);
- resolve();
- });
- browser.loadURI(url);
- });
-}
-
-function runTests(win, funcs)
-{
- ok = funcs.ok;
- is = funcs.is;
- info = funcs.info;
-
- gWin = win;
- gBrowser = win.gBrowser;
-
- return testContentWindow();
-}
-
-/*
- bootstrap.js API
-*/
-
-function startup(aData, aReason)
-{
- forEachWindow(win => {
- win.runAddonTests = (funcs) => runTests(win, funcs);
- });
-}
-
-function shutdown(aData, aReason)
-{
- forEachWindow(win => {
- delete win.runAddonTests;
- });
-}
-
-function install(aData, aReason)
-{
-}
-
-function uninstall(aData, aReason)
-{
-}
-
diff --git a/toolkit/components/addoncompat/tests/compat-addon/install.rdf b/toolkit/components/addoncompat/tests/compat-addon/install.rdf
deleted file mode 100644
index 331fd1540..000000000
--- a/toolkit/components/addoncompat/tests/compat-addon/install.rdf
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
- test-addon-shim-2@tests.mozilla.org
- 1
- 2
- true
-
-
- Test addon shims 2
- Test an add-on that doesn't need multiprocess shims.
- true
-
- chrome://foo/skin/icon.png
- chrome://foo/content/about.xul
- chrome://foo/content/options.xul
-
-
-
- {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
- 0.3
- *
-
-
-
-
-
- toolkit@mozilla.org
- 10.0
- *
-
-
-
-
diff --git a/toolkit/components/addoncompat/tests/moz.build b/toolkit/components/addoncompat/tests/moz.build
deleted file mode 100644
index 589eaa812..000000000
--- a/toolkit/components/addoncompat/tests/moz.build
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-BROWSER_CHROME_MANIFESTS += ['browser/browser.ini']
diff --git a/toolkit/components/alerts/moz.build b/toolkit/components/alerts/moz.build
index cdbf92511..8d42a8ce7 100644
--- a/toolkit/components/alerts/moz.build
+++ b/toolkit/components/alerts/moz.build
@@ -4,17 +4,13 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-MOCHITEST_MANIFESTS += ['test/mochitest.ini']
-
XPIDL_SOURCES += [
'nsIAlertsService.idl',
]
XPIDL_MODULE = 'alerts'
-EXPORTS += [
- 'nsAlertsUtils.h',
-]
+EXPORTS += ['nsAlertsUtils.h']
EXPORTS.mozilla += [
'AlertNotification.h',
@@ -33,6 +29,3 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
JAR_MANIFESTS += ['jar.mn']
-
-with Files('**'):
- BUG_COMPONENT = ('Toolkit', 'Notifications and Alerts')
diff --git a/toolkit/components/alerts/test/.eslintrc.js b/toolkit/components/alerts/test/.eslintrc.js
deleted file mode 100644
index 3c788d6d6..000000000
--- a/toolkit/components/alerts/test/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../testing/mochitest/mochitest.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/alerts/test/image.gif b/toolkit/components/alerts/test/image.gif
deleted file mode 100644
index 053b4d926..000000000
Binary files a/toolkit/components/alerts/test/image.gif and /dev/null differ
diff --git a/toolkit/components/alerts/test/image.png b/toolkit/components/alerts/test/image.png
deleted file mode 100644
index 430c3c5e6..000000000
Binary files a/toolkit/components/alerts/test/image.png and /dev/null differ
diff --git a/toolkit/components/alerts/test/image_server.sjs b/toolkit/components/alerts/test/image_server.sjs
deleted file mode 100644
index 622052943..000000000
--- a/toolkit/components/alerts/test/image_server.sjs
+++ /dev/null
@@ -1,82 +0,0 @@
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr, Constructor: CC } = Components;
-
-Cu.import("resource://gre/modules/Timer.jsm");
-
-const LocalFile = CC("@mozilla.org/file/local;1", "nsILocalFile",
- "initWithPath");
-
-const FileInputStream = CC("@mozilla.org/network/file-input-stream;1",
- "nsIFileInputStream", "init");
-
-const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
- "nsIBinaryInputStream", "setInputStream");
-
-function handleRequest(request, response) {
- let params = parseQueryString(request.queryString);
-
- response.setStatusLine(request.httpVersion, 200, "OK");
-
- // Compare and increment a cookie for this request. This is used to test
- // private browsing mode; the cookie should not be set if the image is
- // loaded anonymously.
- if (params.has("c")) {
- let expectedValue = parseInt(params.get("c"), 10);
- let actualValue = !request.hasHeader("Cookie") ? 0 :
- parseInt(request.getHeader("Cookie")
- .replace(/^counter=(\d+)/, "$1"), 10);
- if (actualValue != expectedValue) {
- response.setStatusLine(request.httpVersion, 400, "Wrong counter value");
- return;
- }
- response.setHeader("Set-Cookie", `counter=${expectedValue + 1}`, false);
- }
-
- // Wait to send the image if a timeout is given.
- let timeout = parseInt(params.get("t"), 10);
- if (timeout > 0) {
- response.processAsync();
- setTimeout(() => {
- respond(params, request, response);
- response.finish();
- }, timeout * 1000);
- return;
- }
-
- respond(params, request, response);
-}
-
-function parseQueryString(queryString) {
- return queryString.split("&").reduce((params, param) => {
- let [key, value] = param.split("=", 2);
- params.set(key, value);
- return params;
- }, new Map());
-}
-
-function respond(params, request, response) {
- if (params.has("s")) {
- let statusCode = parseInt(params.get("s"), 10);
- response.setStatusLine(request.httpVersion, statusCode, "Custom status");
- return;
- }
- var filename = params.get("f");
- writeFile(filename, response);
-}
-
-function writeFile(name, response) {
- var file = new LocalFile(getState("__LOCATION__")).parent;
- file.append(name);
-
- let mimeType = Cc["@mozilla.org/uriloader/external-helper-app-service;1"]
- .getService(Ci.nsIMIMEService)
- .getTypeFromFile(file);
-
- let fileStream = new FileInputStream(file, 1, 0, false);
- let binaryStream = new BinaryInputStream(fileStream);
-
- response.setHeader("Content-Type", mimeType, false);
- response.bodyOutputStream.writeFrom(binaryStream, binaryStream.available());
-
- binaryStream.close();
- fileStream.close();
-}
diff --git a/toolkit/components/alerts/test/mochitest.ini b/toolkit/components/alerts/test/mochitest.ini
deleted file mode 100644
index 12e2a8704..000000000
--- a/toolkit/components/alerts/test/mochitest.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[DEFAULT]
-support-files =
- image.gif
- image.png
- image_server.sjs
-
-# Synchronous tests like test_alerts.html must come before
-# asynchronous tests like test_alerts_noobserve.html!
-[test_alerts.html]
-skip-if = toolkit == 'android'
-[test_alerts_noobserve.html]
-[test_alerts_requireinteraction.html]
-[test_image.html]
-[test_multiple_alerts.html]
-[test_principal.html]
-skip-if = toolkit == 'android'
diff --git a/toolkit/components/alerts/test/test_alerts.html b/toolkit/components/alerts/test/test_alerts.html
deleted file mode 100644
index cb087e48a..000000000
--- a/toolkit/components/alerts/test/test_alerts.html
+++ /dev/null
@@ -1,89 +0,0 @@
-
-
-
-
- Test for Alerts Service
-
-
-
-
-
-
-
- Alerts service, with observer "synchronous" case.
-
- Did a notification appear anywhere?
- If so, the test will finish once the notification disappears.
-
-
-
-
-
-
diff --git a/toolkit/components/alerts/test/test_alerts_noobserve.html b/toolkit/components/alerts/test/test_alerts_noobserve.html
deleted file mode 100644
index 0cc452b8a..000000000
--- a/toolkit/components/alerts/test/test_alerts_noobserve.html
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
- Test for Alerts Service
-
-
-
-
-
-
-
- Alerts service, without observer "asynchronous" case.
-
- A notification should soon appear somewhere.
- If there has been no crash when the notification (later) disappears, assume all is good.
-
-
-
-
-
-
diff --git a/toolkit/components/alerts/test/test_alerts_requireinteraction.html b/toolkit/components/alerts/test/test_alerts_requireinteraction.html
deleted file mode 100644
index 26fe87104..000000000
--- a/toolkit/components/alerts/test/test_alerts_requireinteraction.html
+++ /dev/null
@@ -1,168 +0,0 @@
-
-
-
- Test for alerts with requireInteraction
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_contributor.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_contributor.xml
deleted file mode 100644
index bb85bf230..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_contributor.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
- Example Feed
-
- 2003-12-13T18:30:02Z
-
- John Doe
-
- urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6
-
-
- Atom-Powered Robots Run Amok
-
- urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a
- 2003-12-13T18:30:02Z
- Some text.
-
- John Doe Entry
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_html_cdata.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_html_cdata.xml
deleted file mode 100644
index 38a31ca10..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_html_cdata.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-http://atomtests.philringnalda.com/tests/item/title/html-cdata.atom
-Atom item title html cdata
-2005-12-18T00:13:00Z
-
- Phil Ringnalda
- http://weblog.philringnalda.com/
-
-
-
- http://atomtests.philringnalda.com/tests/item/title/html-cdata.atom/1
- ]]>
- 2005-12-18T00:13:00Z
- An item with a type="html" title consisting of a less-than
-character, the word 'title' and a greater-than character, where
-the character entity reference for the less-than is escaped by being
-in a CDATA section.
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_id.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_id.xml
deleted file mode 100644
index 8513b6894..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_id.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
- hmm
-
-
- hmm@example.com
- foo
-
- Hmm
-
- bar@example.com
- foo
-
-
-
test rights
-
-
-
-
-
-
- test
- http://foo.example.com/hmm/ok,2006,07,11
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts.xml
deleted file mode 100644
index c7cebe4cd..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/2
- Two alternate links
- 2005-01-18T15:00:02Z
- The aggregator should pick either the second or third link below as the alternate
-
-
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts_allcore.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts_allcore.xml
deleted file mode 100644
index 56675b1a9..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts_allcore.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/3
- One of each core link rel type
-
- 2005-01-18T15:00:03Z
- The aggregator should pick the first link as the alternate
-
-
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts_allcore2.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts_allcore2.xml
deleted file mode 100644
index b5b73cfe0..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_2alts_allcore2.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/4
- One of each core link rel type + An additional alternate link
- 2005-01-18T15:00:04Z
- The aggregator should pick either the first or last links as the alternate. First link is likely better.
-
-
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_IANA.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_IANA.xml
deleted file mode 100644
index af6563f2e..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_IANA.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
- tag:example.org,2006:/linkreltest/1
- Does your reader support http://www.iana.org/assignments/relation/alternate properly?
- 2006-04-25T12:12:12Z
-
-
-
- This entry uses link/@rel="http://www.iana.org/assignments/relation/alternate".
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_alt_extension.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_alt_extension.xml
deleted file mode 100644
index e37421864..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_alt_extension.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/5
- Entry with a link relation registered by an extension
- 2005-01-18T15:00:05Z
- The aggregator should ignore the license link without throwing any errors. The first link should be picked as the alternate.
-
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_enclosure.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_enclosure.xml
deleted file mode 100644
index b76c111c9..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_enclosure.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/4
- One of each core link rel type + An additional alternate link
- 2005-01-18T15:00:04Z
- The aggregator should pick either the first or last links as the alternate. First link is likely better.
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_enclosure_populate_enclosures.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_enclosure_populate_enclosures.xml
deleted file mode 100644
index 8453c6e9c..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_enclosure_populate_enclosures.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/4
- One of each core link rel type + An additional alternate link
- 2005-01-18T15:00:04Z
- The aggregator should pick either the first or last links as the alternate. First link is likely better.
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_otherURI_alt.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_otherURI_alt.xml
deleted file mode 100644
index 3dc0c8dd6..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_otherURI_alt.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/6
- Entry with a link relation identified by URI
- 2005-01-18T15:00:06Z
- The aggregator should ignore the second link without throwing any errors. The first link should be picked as the alternate.
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_payment_alt.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_payment_alt.xml
deleted file mode 100644
index 51e1524b4..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_payment_alt.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/5
- Entry with a link relation registered by an extension
- 2005-01-18T15:00:05Z
- The aggregator should ignore the license link without throwing any errors. The first link should be picked as the alternate.
-
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_link_random.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_link_random.xml
deleted file mode 100644
index cb370e516..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_link_random.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/
- Atom Link Tests
- 2005-01-18T15:10:00Z
- James Snell
-
-
-
-
- tag:snellspace.com,2006:/atom/conformance/linktest/1
- Just a single Alternate Link
- 2005-01-18T15:00:01Z
- The aggregator should pick the second link as the alternate
-
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_published.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_published.xml
deleted file mode 100644
index 1112729e2..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_published.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
- Example Feed
-
- 2003-12-13T18:30:02Z
-
- John Doe
-
- urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6
-
-
- Atom-Powered Robots Run Amok
-
- urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a
- 2003-12-13T18:30:02Z
- 2003-12-09T18:30:02Z
- Some text.
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/entry_rights_normalized.xml b/toolkit/components/feeds/test/xml/rfc4287/entry_rights_normalized.xml
deleted file mode 100644
index 1474e5f84..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/entry_rights_normalized.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/feed_title.xml b/toolkit/components/feeds/test/xml/rfc4287/feed_title.xml
deleted file mode 100644
index 6e0cea003..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/feed_title.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-test title
-
diff --git a/toolkit/components/feeds/test/xml/rfc4287/feed_title_full_feed.xml b/toolkit/components/feeds/test/xml/rfc4287/feed_title_full_feed.xml
deleted file mode 100644
index cef3f84a3..000000000
--- a/toolkit/components/feeds/test/xml/rfc4287/feed_title_full_feed.xml
+++ /dev/null
@@ -1,936 +0,0 @@
-
-
-
- ongoing
- http://www.tbray.org/ongoing/
-
-
- rsslogo.jpg
- /favicon.ico
- 2006-04-26T20:10:25-08:00
- Tim Bray
- ongoing fragmented essay by Tim Bray
- All content written by Tim Bray and photos by Tim Bray Copyright Tim Bray, some rights reserved, see /ongoing/misc/Copyright
- Generated from XML source code using Perl, Expat, XML::Parser, Emacs, Mysql, and ImageMagick. Industrial strength technology, baby.
-
-
- Spring in White on White
-
- http://www.tbray.org/ongoing/When/200x/2006/04/26/Spring-in-White-on-White
- 2006-04-26T13:00:00-08:00
- 2006-04-26T20:10:16-08:00
-
-
-
-
-
-
Most people would generally prefer a climate where it’s bright and warm most of the time. But for Canadians and others who live where it’s not, there are compensations, and one is the experience of spring. I have a picture.
-
-
Most people would generally prefer a climate where it’s bright
-and warm most of the time. But for Canadians and others who live where it’s
-not, there are compensations, and one is the experience of
-spring. I have a picture.
-
-
The blossoms are pear in the foreground, cherry behind.
-
After all the months of 50° North Latitude winter—icy-sharp in most
-of Canada, wet and dark here in Vancouver—the soul, the spirit, and the
-libido all spring to life when the sun comes back. We’ve had a solid year of
-crappy weather, but this last Saturday through Monday were solidly summery,
-bright
-and warm; and in this season the days are already long and each gets
-longer so fast you can feel it.
-
On the back porch, our pear tree’s branches were silhouetted against the
-neighbors’ big wild old cherry; the cherry yields no edible fruit but who
-cares, it’s beautiful
-tree any time of year.
I’ve been watching our internal leadership conference and spending quite a
-bit of time talking in the virtual hallways, and I’ve been surprised at
-the intensity of feeling about Mr. McNealy. Yes, there are those
-here saying “About bloody time, now we can make some progress” but there’s a
-much bigger group that is genuinely emotional about this transition.
-Maybe it’s a function of seniority: I never met nor corresponded with Scott, and
-he hasn’t been
-much of a presence in the company’s conversation in the time I’ve been here.
-But there are a lot of smart, seasoned, unsentimental people making it clear
-that
-he’s been a major force in their lives, at a more personal level than I’m
-used to hearing when people speak about executives. I guess also that to a
-lot of people, Sun’s vision, for which Scott gets some of the credit, was a
-radical and wonderful thing. I first used Unix in 1979 and quit a nice
-big-company job
-to become a VAX-bsd sysadmin in 1983, so I’ve always kind of
-lived inside that vision.
-But I’ll tell you one thing, what I’ve been hearing the last couple of days
-makes me really regret that I didn’t get to know Scott.
Jane Jacobs died;
-the city I live in, Vancouver, is pretty solidly Jacobsian both in its current
-shape and its planning dogma. By choosing to live here I’m empirically a
-fan. Oddly, few have remarked how great Jacobs
-looked; her face commanded the eye. Which leads me Alex
-Waterhouse-Hayward’s wonderful
-Jane Jacobs & Viveca Lindfors;
-surprising portraits and thoughts on decoration. W-H’s blog has become one of
-only two or three that I
-stab at excitedly whenever I see something new. For example, see
-Sex Crimes, Homicide and Drugs
-and yes, that’s what it’s about.
-Staying with the death-and-betrayal theme, and apparently (but not really)
-shifting back 2½ millennia, see John Cowan’s
-The
-War (after Simonides), being careful to look closely at the links.
-I’ve
-written
-about those same wars.
-
-
-
- LAMP and MARS
-
- http://www.tbray.org/ongoing/When/200x/2006/04/25/Scaling-Rails
- 2006-04-25T13:00:00-08:00
- 2006-04-26T07:24:06-08:00
-
-
-
-
-
-
-
At
-that Rails conference, when I
-was
-talking
-to
-Obie Fernandez, he asked, more or
-less “How can Sun love us? We’re not Java” and I said, more or less, “Hey,
-you’re programmers, you write software and there have to be computers to run
-it, we sell computers, why wouldn’t we love you?” Anyhow, we touched on
-parallelism a bit and I talked up the
-T1;
-Obie took that ball and
-ran with it,
-saying all sorts of positive things about synergy between Rails’
-shared-nothing architecture and our multicore systems. Yeah, well, good in
-theory, but I’m too old to make that kind of prediction without running some
-tests. Hah, it turns out that
-Joyent has been
-doing that, and have
-76
-PDF slides on the subject.
-If you care about big-system scaling issues, read the whole thing; a little
-long, but amusing and with hardly any bullet lists. If you’re a Sun
-shareholder looking for a pick-me up, check out slides 40-41, 49, and 52-74.
-Oh, I gather that the T1, Solaris, and ZFS are OK for Java too.
-[Update: The title was just “SAMR”, as in LAMP with two new letters.
-Enough people didn’t get it that I was forced to think about it, and MARS
-works better anyhow.]
I got email late yesterday from
-David Berlind: “Hey, can
-I call you for a minute?” He wanted commentary on
-a story he was writing that I
-think is about the potential for intellectual-property lock-ins on RSS and Atom
-extensions. I say “I think is about” because the headline is “Will or could
-RSS get forked?”. After a few minutes’ chat, David asked if he could record
-for a podcast, and even though I only had a cellphone, the audio came out OK.
-The conversation was rhythmic: David brought up a succession of potential
-issues and answered each along the lines of “Yes, it’s reasonable to worry
-about that, but in this
-case I don’t see any particular problems.”
-Plus I emitted a mercifully-brief rant on the difference between protocols,
-data, and software.
-On the one hand, I thought David could have been a
-little clearer that I was pushing back against the thrust of his story, but on
-the other hand he included the whole conversation right
-there in the piece, so anyone who actually cares can listen and find out what
-I actually said, not what I think I said nor what David reported I said.
-I find this raw barely-intermediated journalism (we
-talk on the phone this afternoon, it’s on the Web in hours) a little
-shocking still.
-On balance, it’s better than the way we used to do things.
It’s not that complicated, really.
-Bloggers are
-taking over the world.
-Resistance is futile; you will be assimilated.
-
-
-
- 5✭♫: One More Cup of Coffee
-
- http://www.tbray.org/ongoing/When/200x/2006/04/24/One-More-Cup-Of-Coffee
- 2006-04-24T13:00:00-08:00
- 2006-04-24T13:00:00-08:00
-
-
-
-
-
-
-
I’m not really a Bob Dylan fan. A voice like that, and a tunesmithing talent like that, come along only a few times per century, but he’s still kind of irritating. That aside, the song One More Cup of Coffee, from the 1976 album Desire, can’t be ignored; wonderful tune, wonderful orchestration, wonderful performance. (“5✭♫” series introduction here; with an explanation of why the title may look broken.)
-
-
I’m not really a
-Bob Dylan fan. A voice
-like that, and a tunesmithing talent like that, come along only a few times
-per century, but he’s still kind of irritating.
-That aside, the song One More Cup of Coffee, from the 1976 album
-Desire, can’t be
-ignored; wonderful tune, wonderful orchestration, wonderful performance.
-(“5✭♫” series introduction here;
-with an
-explanation of why the title may look broken.)
-
-
The Context
-
Nothing I can possibly write will add any wisdom to the
-millions of words, some 90% of them in excess of needs, written on the subject
-of this particular person.
-
A personal statement: Bob Dylan has long irritated me for, during the first
-thirty years or
-so of his career, never having given a straight answer to a straight question,
-and for writing songs with dozens of boring verses. But they’ll still be
-listening
-to lots of his performances long after I’m dead, and in recent years he’s
-become a better, more direct, interview.
-
My taste in Dylan is a little unusual: once you get past One More Cup
-of Coffee, my favorites would be Baby Let Me Follow You
-Down (from the Last Waltz soundtrack) and
-Crash on the Levee (Down in the Flood) from
-The Basement
-Tapes.
-
Desire, the record, is hit and miss. Joey,
-glorification of the life of some mafioso, is flawed in concept
-and unlistenable in execution. Hurricane, whatever you think
-about
-Mr. Carter, that song
-rocks; and Isis hits pretty hard too.
-
The Music
-
Is there anything in One More Cup of Coffee that’s not
-perfect? Well yes, in the verses, the
-lyrics on occasion drag (“He oversees his kingdom / So no stranger does
-intrude / His voice it trembles as he calls out / For another plate of food”).
-But apart from that, the sentiment is compelling,
-Scarlet Rivera’s
-violin is beautifully scored and played, the tune is to die for, and the
-backing vocals are by Emmylou Harris, who you can bet is going to be here in
-the 5-✭ series one of these days.
-And while there’s not much middle ground on the subject of Dylan’s singing, if
-you like it, you’ll really like this song.
-
Listen to the choruses: Bob and Emmylou veer wildly around the rhythm, then
-coalesce on the beat when it matters, and they’re making it
-up as they go along, they’re wholly inhabiting the moment, and it’s
-quite, quite perfect.
-
Sampling It
-
Oh yeah, it’s out there. And there’s a live version too; but the smart
-thing would be to go buy the un-compressed un-DRM’ed shiny round silver
-version of Desire; it’s a keeper.
First of all, implementors of anything Atom-related need to spend some time
-chez
-Jacques Distler; in particular, the conversation that plays out in the
-comments. Second, there’s this piece of software called
-Planet Planet that allows you to
-make an aggregate web page by reading lots of feeds; for example, see
-Planet Apache or
-Planet Sun.
-Sam Ruby decided that its Atom support needed some work, so
-he did
-it. Now, here’s the exciting part: he pinged me over the weekend and said
-“Hey, look at this” wanting to show me his cleverly-Atomized
-Planet Intertwingly feed.
-I looked at it in
-NetNewsWire and was puzzled for
-a moment; some but not all of the
-things in the feed were highlighted as unread, even though this was the first
-time I’d seen it. Then the light went on.
-This
-is Atom doing exactly what we went to all that trouble to make it do.
-NetNewsWire has good Atom support and, because Atom entries all have unique
-IDs and timestamps, it can
-tell that it’s seen lots of those entries before in other feeds that I
-subscribe to. That’s how I found Jacques’ piece. This is huge; anyone who
-uses synthetic or aggregated feeds knows that dupes are a big problem, showing
-up all over the place.
-No longer, Atom makes that problem go away.
-
-
-
- Hyatt on the High-Res Web
-
- http://www.tbray.org/ongoing/When/200x/2006/04/22/High-Res-Web
- 2006-04-22T13:00:00-08:00
- 2006-04-23T17:12:18-08:00
-
-
-
-
-
-
-
Check out Dave Hyatt’s
-excellent write-up on
-designing and rendering Web pages so they take advantage of the
-higher-resolution screens that may be coming our way.
-I emphasize “may” because I’ve seen how slowly we’ve picked up pixels over
-the years. The first really substantial screen I ever worked on was a
-1988-vintage Sun workstation with about a million pixels. The Mac on my
-lap right now, which has 125 times as much memory as that workstation, has
-only 1.38 million pixels.
-Anyhow, Hyatt has some smart things to say on the issues,
-which are trickier than you might think. I suspect that sometime in a couple of
-years, if I still care about ongoing, I’m going to
-have to go back and reprocess all the images so that higher-res versions are
-available for those who have the screens and don’t mind downloading bigger
-files.
-Anyhow, Dave’s piece may be slightly misleading in that he talks about SVG
-as though
-it’s something coming in the future. Not so, check out
-this nifty SVG Atom
-logo, which works fine in all the Mozilla browsers I have here.
-Load it up, resize the window, and watch what happens. Then do a “view
-source”.
-[Update:
-Jeff Schiller writes to tell me that
-Opera 9 does SVG (and Opera 8 “SVG Tiny”) too.]
-[Dave Walker writes: Though the shipping version of Safari doesn’t support SVG,
-the
-nightlies do.]
-[Dave Lemen
-points to
-JPEG 2000 as possibly
-useful in a high-res context.]
-
-
-
- Wrong About the Infield Fly Rule
-
- http://www.tbray.org/ongoing/When/200x/2006/04/23/Wrong-About-the-Infield-Fly-Rule
- 2006-04-23T13:00:00-08:00
- 2006-04-23T15:02:41-08:00
-
-
-
-
-
My brother
-Rob is really taking to
-this blogging medium. Check out his recent
-Credo,
-and also the only instance I’ve seen of
-Anglo-Saxon alliterative poetry
-applied to a mini-van.
Almost every Sunday I grab the week’s ongoing logfiles and update my numbers. I find it interesting and maybe others will too, so this entry is now the charts’ permanent home. I’ll update it most weeks, probably. [Updated: 2006/04/23.]
-
-
Almost every Sunday I grab the week’s ongoing
-logfiles and update my numbers.
-I find it interesting
-and maybe others will too, so
-this entry is now the charts’ permanent home. I’ll update it most weeks,
-probably.
-[Updated: 2006/04/23.]
-
-
Browsers visiting ongoing,
-percent.
-
-
Browsers visiting ongoing via
-search engines, percent.
-
-
Search referrals to ongoing .
-
-
Fetches of the RSS 2.0 and Atom 1.0 feeds.
-
The notes on usage and source code will return in coming weeks when I get
-the cycles to rewrite this whole article.
-
What a “Hit” Means
-
I recently
-updated the
-ongoing software
-(but haven’t updated the Colophon I see, oops).
-Anyhow, the XMLHttpRequest now issued by each page seems to be a
-pretty reliable counter of the number of actual browsers with humans behind
-them reading the pages. I checked against
-Google Analytics
-and the numbers agreed to within a dozen or two on days with 5,000 to 10,000
-page views; interestingly, Google Analytics was always 10 or 20 views
-higher.
-
Anyhow, do not conclude that now I know how many people are
-reading whatever it is I write here; because I publish lots of short pieces
-that are all there in my RSS feed, and anyone reading my Atom feed gets the
-full content of everything.
-I and I have no #&*!$ idea how many people look at my feeds.
-
By the way, this was the first time in weeks and weeks that I’d looked at the
-Analytics numbers, and they showed almost exactly zero change from the report
-linked above. So I’m going to turn them off; they’re a little too intrusive
-and I think may be slowing page loads.
-
Anyhow, I ran some detailed statistics on the traffic for Wednesday,
-February 8th, 2006.
-
-
Total connections to the server
180,428
-
Total successful GET transactions
155,507
-
Total fetches of the RSS and Atom feeds
88,450
-
Total GET transactions that actually fetched data (i.e. status code
-200 as opposed to 304)
87,271
-
Total GETs of actual ongoing pages (i.e. not CSS, js, or
-images)
18,444
-
Actual human page-views
6,348
-
-
-
So, there you have it. Doing a bit of rounding, if you take the 180K
-transactions and subtract the 90K feed fetches and the 6000 actual human page
-views, you’re left with 84,000 or so “Web overhead” transactions, mostly
-stylesheets and graphics and so on.
-For every human who viewed a page, it was fetched almost twice again by
-various kinds of robots and non-browser automated agents.
In December of 1996 I released a piece of software called Lark, which was the world’s first XML Processor (as the term is defined in the XML Specification). It was successful, but I stopped maintaining it in 1998 because lots of other smart people, and some big companies like Microsoft, were shipping perfectly good processors. I never quite open-sourced it, holding back one clever bit in the moronic idea that I could make money out of Lark somehow. The magic sauce is a finite state machine that can be used to parse XML 1.0. Recently, someone out there needed one of those, so I thought I’d publish it, with some commentary on Lark’s construction and an amusing anecdote about the name. I doubt there are more than twelve people on the planet who care about this kind of parsing arcana. [Rick Jelliffe has upgraded the machine].
-
-
In December of 1996 I released a piece of software called
-Lark, which was
-the world’s first
-XML Processor (as the
-term is defined in the
-XML Specification).
-It was successful, but I stopped maintaining it in 1998 because lots of other
-smart people, and some big companies like Microsoft, were shipping perfectly
-good processors. I never quite open-sourced it, holding back one
-clever bit in the moronic idea that I could make money out of Lark somehow.
-The magic sauce is a finite state machine that can be used to parse XML 1.0.
-Recently, someone out there needed one of those, so I thought I’d publish
-it, with some commentary on Lark’s construction and an amusing anecdote about
-the name.
-I doubt there are more than twelve people on the planet who care about
-this kind of parsing arcana.
-[Rick Jelliffe
-has
-upgraded the machine].
-
Why “Lark”?
-
Lauren and I went to
-Australia in late 1996 to visit her mother and to get married, which we
-did on November 30th. Forty-eight hours later, Lauren twisted her knee
-badly enough that she was pretty well
-confined to a sofa for the rest of our Australian vacation.
-
So I broke out my computer and finished the work I’d already started on my
-XML processor, and decided to call it Lark for Lauren’s Right
-Knee.
-
How Lark Worked
-
Lark was a pure
-deterministic
-finite automaton (DFA)
-parser, with a little teeny state stack.
-Some of its transitions were labeled with named “events” that would provoke
-the parser to do something if, for example, it had just recognized a start tag
-or whatever.
-
DFA-driven parsers are a common enough design pattern, although I think
-Lark is the only example in the XML space.
-There are well-known parser generators such as
-yacc,
-GNU bison, and
-javacc,
-usually used in combination with lexical scanners such as
-flex so that
-you can write your grammar in terms of tokens not characters.
-Also, they handle LALR langauges, so the parsing technique is quite a bit
-richer than a pure state machine.
-
I thought I had a better idea. The grammar of XML is simple
-enough, and the syntax characters few enough, that I thought I could just
-write down the state machine by hand.
-So that’s what I did, inventing a special-purpose DFA-description
-language for the purpose.
-
Then I had a file called Lark.jin which was really a Java
-program that used the state machine to parse XML. The transition “events”
-in the machine were mapped to case labels in a huge
-switch construct. Then there was a horrible, horrible
-Perl program that read the Lark.jin and the automaton,
-generated the DFA tables in Java syntax, inserted them into the code and
-produced Lark.java, which you actually compiled
-to make the parser.
-
So while Java doesn’t have a preprocessor, Lark did, which made quite a few
-things easier.
-
There were a lot of tricks; some of the state transitions
-weren’t on characters, they were on XML character classes such as
-NameChar and so on.
-This made the automaton easier to write, and in fact, to keep the class files
-small, the character-class transitions persisted into the Java form, and the
-real DFA was built at startup time.
-These days, quick startup might be more important than .class
-file size.
-
What Was Good
-
It was damn fast. James Clark managed to hand-craft a
-Java-language XML parser called
-XP that was a little faster
-than Lark, but he did that by clever I/O buffering, and I was determined to
-leapfrog him by improving my I/O.
-
This was before the time of standardized XML APIs, but Lark had a stream API
-that influenced SAX, and a DOM-like tree API; both worked just fine.
-Lark is one of very few parsers ever to have survived the
-billion
-laughs attack.
-
Lark was put into production in quite a few deployments, and the flow of
-bug reports slowed to a trickle.
-Then in 1998 I noticed that IBM and Microsoft and BEA and everyone else
-were building XML Processors, so I decided that it wasn’t worthwhile
-maintaining mine.
-
What Was Bad
-
I never got around to teaching it namespaces, which means it wouldn’t be
-real useful today.
-
It had one serious bug that would have been real work to fix and since
-nobody ever encountered it in practice, I kept putting it off and never did.
-If you had an internal parsed entity reference in an attribute value and the
-replacement text included the attribute delimiter (' or
-"), it would scream and claim you had a busted XML document.
There’s no reason whatsoever to keep it a secret:
-here it is.
-Be warned: it’s ugly.
-
Fortunately, there were only 227 states and 8732 transitions, so the state
-number fit into a
-byte; that and the associated event index pack into a short.
-To make things even tighter, the transitions were only keyed by characters up
-to 127, as in 7-bit ASCII.
-Characters higher than that can’t be XML syntax characters, so we’re only
-interested whether they fall into classes like NameChar and
-NameStartChar and so on. A 64K byte[] array takes
-care of that, each byte having a class bitmask.
-
As a result of all this jiggery-pokery, the DFA ends up, believe it
-or not, constituting a short[227][128].
-
Here’s a typical chunk of the automaton:
-
1. # in Start tag GI
-2. State StagGI BustedMarkup {in element type}
-3. T $NameC StagGI
-4. T $S InStag !EndGI
-5. T > InDoc !EndGI !ReportSTag
-6. T / EmptyClose !EndGI
-
This state, called StagGI, is the state where we’re actually
-reading the name of a tag, we got here by seeing a < followed
-by a NameStart character.
-Line 1 is a comment.
-In line 2 we name the state, and support error reporting, providing the name
-of another state to fall back into in case of error, and in the curly braces,
-some text to help build an error message.
-Line 3 says that if we see a valid XML Name character, we just stay in this
-state.
-Line 4 says that if we see an XML space character, we move to state
-InStag and process an EndGI event, which would stash
-the characters in the start tag. And so on.
-
Other Hackery
-
An early cut of Lark used String and StringBuffer objects to hold all the
-bits and pieces of the XML. This might be a viable strategy today, but in
-1996’s Java it was painfully slow.
-So the code goes to heroic lengths to live in the land of character arrays at
-all times, making Strings only when a client program asks for one through the
-API. The performance difference was mind-boggling.
-
An Evil Idea
-
If you look at the automaton, and the Lark code, at least half—I’d bet
-three quarters—is there to deal with parsing the DTD and then dealing with
-entity wrangling.
-A whole bunch more is there to support DOM-building and walking.
-
I bet if I went through and simply removed support for anything coming out
-of the <!DOCTYPE>, including all entity processing,
-then discarded
-the DOM stuff, then added namespace support and SAX and StAX APIs, it would be
-less than half its current size.
-Then if I reworked the I/O, knowing what I know now and stealing some tricks
-that James Clark uses in
-expat, I bet it would
-be the fastest Java XML parser on the planet for XML docs without a
-DOCTYPE; by a wide margin. It’s hard to beat a DFA.
-
And it would still be fully XML 1.0 compliant. Because (snicker) this is
-Java, and your basic core Java now includes an XML parser, so I could simply
-instrument Larkette to buffer the prologue and if it saw a DOCTYPE with an
-internal subset, defer to Java’s built-in parser.
-
I’ll probably never do it. But the thought brings a smile to my face.
-
-
-
- Just A Kid
-
- http://www.tbray.org/ongoing/When/200x/2006/04/22/Just-a-Kid
- 2006-04-22T13:00:00-08:00
- 2006-04-22T13:37:58-08:00
-
-
-
-
-
Last weekend, Lauren felt like cooking up home-made Easter eggs, so
-the shopping list included “chocolate chips (large bag)”. I was heading down
-the bulk-foods aisle and realized one of the vertical acrylic bins was full of
-them. Someone had been sloppy, and there was a little heap of chocolate chips
-on the shelf underneath it. For a second, I flashed into pure eight-year-old
-mode, thinking “Holy cow, there’s a whole bin full of chocolate
-chips, and more just lying there!” I popped a few in my mouth and they were
-excellent; semi-sweet, dark, strong, and firm. I was still in the state that
-Buddhists don’t mean when they say “Child’s Mind”, thinking “I
-can get as many as I want!” The list did say “large bag” after all, so I put
-a bag under the spout and gleefully jammed the lever all the way
-over. At home, Lauren said “You went overboard, a bit, didn’t you?”
-and now we have a plastic canister-full in the pantry which should last us
-into 2007. It’s a good feeling.
That would be my wife
-Lauren. After
-I b0rked our
-Win2K gamebox, I tried re-installing the OS and eventually reduced it to
-complete brick-ness, it recognized neither the video adapter nor the network
-card. So Lauren brushed me aside and started wrestling with the problem, and
-to make a long story short, it almost completely works again. At one point
-she seemed nearly infinite in her capabilities, sitting in front of the
-computer wrangling software updates while knitting baby stuff and looking up
-words in a German dictionary for the kid’s homework. Some of the German nouns
-and muttered curses at the Windows install sounded remarkably like each other.
-Why would anyone not marry a geek? The only problem is that Win2K won’t
-auto-switch resolutions to play games any more, it gets the frequency wrong
-and the LCD goes pear-shaped, you have to hand-select the frequency and
-switch into the right resolution first. LazyWeb?
Herewith two hideously ugly little shell scripts for use when Spotlight refuses to search your mail. Spotlight is a flawed v1.0 implementation of a really good idea and will, I’m sure, be debugged in a near-future release. [Update: The LazyWeb is educating me... these are moving targets.]
-
-
Herewith two hideously ugly little shell scripts for use when Spotlight
-refuses to search your mail.
-Spotlight is a flawed v1.0 implementation of a really good idea and will, I’m
-sure, be debugged in a near-future release.
-[Update: The LazyWeb is educating me... these are moving targets.]
-
My problem is that whereas Mail.app will search my To/From/Subject
-lines (slowly, and with a
-really irritating GUI),
-the “Entire Message” option just doesn’t work, it returns instantly with no
-results. Yes, I’ve read the hints about making Spotlight re-index,
-but it just flatly refuses to work for me. Mind you, I have a lot of
-email, but still, it should at least try.
-
It turns out I had never really figured out the -print0 and
--0 idioms that a lot of the shell-command stalwarts now have.
-Thanks to Malcolm Tredinnick for raising my consciousness.
Isn’t xargs a funny command? I’ve discovered that it’s nearly
-impossible to describe what does, and then why what it does is necessary, but
-there are just a whole bunch of places where you’d be lost without it.
The first cut of this dodged xargs and used an
-incredibly-inefficient and slow chain of -exec arguments to open
-the files one at a time with
-view (aka vim), to work around
-a well-known vim misfeature; it complained about the input
-not being a terminal and left my Terminal.app keystrokes borked.
-
But Malcolm, confirming my belief in the broken-ness of vim,
-said “Oh, *that* ‘view’. I thought it was some sexy Mac ‘view my email’ app”.
-D’oh, of course; the magic OS X open command does just the right
-thing.
-Erm, you might want to run mailgrep before you run
-mailview; I’m not sure what would happen if you asked OS X to
-open three or four thousand email messages at once.
Friday Slide Scan #28 is two Eighties florals, one interior, one exterior. With a confession.
-
-
Friday Slide Scan #28 is two Eighties florals, one interior, one
-exterior. With a confession.
-
First some spring flowers fallen from a tree, just as now in our front
-yard, at dusk.
-
-
I’m not sure what these are, but look at the light in the center. Rewards
-enlarging.
-
-
Here’s the confession. Sometimes on Fridays when I’m feeling kinda
-burned-out, I knock off work and do these slide scans in the office, because
-this is where I have the
-big
-screen.
-Blowing these pictures up to mega-huge, picking away at the old-slide crud and
-scanning artifacts, tinkering with the colour balance, and listening; I never
-play music while I’m writing or coding seriously, but I play it real loud while
-photo-editing. It’s all pretty well pure pleasure; you just can’t imagine
-how good that second one above looks at near-native size.
-It reconstitutes the part of my mind that I earn my living with; that’s my
-story and I’m sticking to it.
-
Images in the Friday Slide Scans are from 35mm slides taken between 1953
-and 2003 by (in rough chronological order)
-Bill Bray,
-Jean Bray, Tim Bray, Cath
-Bray, and
-Lauren Wood; when I know
-exactly who took one, I’ll say; in this case, at least one is by Cath Bray.
-Most but not all of the slides were on Kodachrome; they were digitized using
-a Nikon CoolScan 4000 ED scanner and cleaned up by a combination of the Nikon
-scanning software and PhotoShop Elements.
Three pictures around Vancouver; one of a fresh green springtime tree, two of rotten old buildings being torn down.
-
-
Three pictures around Vancouver; one of a fresh green springtime tree, two
-of rotten old buildings being torn down.
-
There’s nothing quite as fresh as just-sprouted deciduous leaves;
-another few weeks and this tree will be just a tree.
-
-
I have a thing about demolition.
-The first is a rotten dingy old one-story on Main Street near 23rd, the second
-is an unlovely grey mid-rise being torn down to build still more condos at
-Homer and Helmcken.
Michael J. Totten is a
-journalist and blogger who’s back and forth to the
-Middle East and writes about it, quite well in my opinion; he supports this by
-freelancing and with his blog’s tip jar. He gets lots of
-link love from the right-wing blogosphere, which is puzzling because Totten is
-balanced and clear-eyed and doesn’t seem to have any particular axe to grind.
-Recently, he and a friend were
-having fun in
-Istanbul and, on a random drive out into the country, decided on impulse to
-keep going, all the way across Turkey and into Iraq; into the Kurdish
-mini-state in Iraq’s north, to
-be precise. It makes a heck of a story, with lots of pictures, in six parts:
-I,
-II,
-III,
-IV,
-V, and
-VI.
-
-
-
-
- The Cost of AJAX
-
- http://www.tbray.org/ongoing/When/200x/2006/04/19/The-Cost-of-AJAX
- 2006-04-19T13:00:00-08:00
- 2006-04-20T00:37:46-08:00
-
-
-
-
-
James Governor
-relays a
-question that sounds important
-but I think is actively dangerous: do AJAX apps present more of
-a server-side load? The question is dangerous because it’s meaningless and
-unanswerable. Your typical Web page will, in the process of
-loading, call back to the server for a bunch of stylesheets and graphics and
-scripts and so on: for example, this ongoing page calls
-out to three different graphics, one stylesheet, and one JavaScript file.
-It also has one “AJAXy” XMLHttpRequest call.
-From the server’s point of view, those are all just requests to dereference
-one URI or another. In the case
-of ongoing, the AJAX request is for a static file less
-than 200 bytes in size (i.e. cheap).
-On the other hand, it could have been for something that required a
-complex outer join on two ten-million-row tables (i.e. very
-expensive). And one of the virtues of
-the Web Architecture is that it hides those differences, the “U” in URI stands
-for “Uniform”, it’s a Uniform interface to a resource on the Web that could
-be, well, anything.
-So saying “AJAX is expensive” (or that it’s cheap) is like saying “A mountain
-bike is slower than a battle tank” (or that it’s faster).
-The truth depends on what you’re doing with it.
-In the case of web sites, it depends on how many fetches you do and
-where you have to go to get the data to satisfy them.
-ongoing is a pretty quick web site, even though it runs
-on a fairly modest server, but
-that has nothing to do with AJAX-or-not; it’s because of the particular way
-I’ve set up the Web resources that make the pages here.
-I’ve
-argued elsewhere
-that AJAX can be a performance win, system-wide; but that argument too is
-contingent on context, lots of context.
Graham McMynn is a teenager who was kidnapped in Vancouver on April 4th and
-freed, in a large, noisy, and
-newsworthy
-police operation, on April 12th.
-Hao Wu is a Chinese
-film-maker and
-blogger who was kidnapped in
-Beijing on February 22nd in a
-small, quiet police operation not intended to be newsworthy, and who has not
-been freed.
-Read about it
-here,
-here, and
-here.
-Making noise about it might influence the government of China to
-moderate its actions against Mr. Wu, and can’t do any harm.
-Mr. McMynn’s kidnappers were a gaggle of small-time hoodlums, one of whom was
-out on bail while awaiting trial for another kidnapping (!).
-Mr. Wu’s were police.
-In a civilized country, the function of the police force is to deter such
-people and arrest them. A nation where they are the same people? Nobody
-could call it “civilized”.
I don't agree that Places was the one and only thing that sold Firefox 2 though. I took a look through the Firefox 2 Requirements page to look at some of the other stuff that's going on. Reading that document, I think I can see now why people are down in the dumps about no-places Firefox 2. I don't think that document necessarily does the best possible job of capturing the excitement I have about some of the Firefox 2 features we're pursuing.
-
-
For the past week or so, I've been toting around a printout of another document, which I wrote because I wanted to convey some of the vision I have of the Firefox 2 product as a whole - a more holistic view as it were.
-
-
Safer, Faster, Better
-
-
If you take a look at the black buttons stacked in the right column of this page, you'll see that one of them reads "Safer, Faster, Better." I don't knowwho came up with that one but it's a good tag line. It has a certain cadence about it. People have attached lots of these to Firefox in the past - "Take Back the Web" was the one I came up with, there's "Rediscover the Web", the FirefoxFlicks project has yielded a few good ones too - I like "Web For All". But "Safer, Faster, Better" is not just a tag line, it can also map into a set of themes for product development.
-
-
So, taking a look at the Requirements page, I attempted to do that. My document wasn't a comprehensive collection of everything on that page, I was focused more on the things immediately visible to most users. I guess my problem with the Requirements page has always been its very engineering/technical focus. The result of this is that the priority of items tend to reflect how difficult something is to implement, or where it lies in the development cycle, not necessarily the impact on the user. What I ended up with I guess is a sort of "Shadow PRD" that reflects what I personally thought was cool about Firefox 2, and what I wanted to get out of it.
Assume the scratched out section for "Retracing Your Steps" will be part
- of a future release.
-
The priorities shown are my opinion, and relate to potential impact on
- the user.
-
The document does not represent all of the work being done, just a
- readily marketable subset.
-
-
-
All in all, I think there's easily enough here to justify a "2" designation. That's just my opinion though. I also think whole numbers are probably easier for the general populace to understand than decimals.
-
-
Firefox has never been about date driven development (within reason). The changes with Places should not be seen as a change in this sentiment. What we're about is high quality software development with real advantages to
-users, and I think that with the updated plan we're still on a trajectory that supports and encourages that, perhaps more firmly now than before.
-
-
And that's it from today's "Ben waits for the tinderboxen to clear" report.
]]>
-
-ben
-2006-04-26T14:34:49-08:00
-
-
-Firefox 2 Content Update
-http://weblogs.mozillazine.org/ben/archives/010109.html
-When we began work on Firefox 2, we decided to focus on a development branch, a continuation of the Mozilla 1.8 branch. The reason for doing this was that there was to be a lot of significant architectural changes going on on the trunk, with the prospect of a new rendering back end, a rearchitecture of reflow in layout, and various other things. Shipping a Firefox 2 release in 2006 off of this code did not seem possible.
-
-
As a result, we decided to pursue a release focused on application level improvements, on a separate branch. Going into it, we knew the perils of multi-branch development. We knew the divergences that would inevitably form between branch and trunk. We had experience from the painful development of Firefox 1.0 on the Aviary branch. We resolved to be more methodical about our commits, but we knew to expect some pain. The goal was to produce a high value release in short enough time so that we could all return to the trunk and help build new features that utilize the back end being developed there, to help shake them out.
-
-
Late last year, we put together a list of things to pursue for the Firefox 2 release. A month or so ago, we got together as a group and formalized this more in a Firefox 2 PRD. We had scheduled four major pre-release milestones, two alphas and two betas. We have already shipped one alpha. The intent of the second is to be "Feature Complete".
-
-
The people driving the various sub-projects on the Requirements list get together weekly to check status. As the weeks have gone by, it has become clear to us that the most complex feature on the plan is Places. It is easily an order of magnitude more complex than anything else on the plan. Places is a great feature and it has been exciting watching its capabilities grow. We are looking forward to the capabilities that it will expose. What we have learned though is that the work required to complete Places is probably too substantial to gate the Firefox 2 release. It falls more into the "significant rearchitecture" category of feature that's generally been targeted at Firefox 3.
-
-
What we have decided to do is as follows:
-
-
-
We will disable places on the 1.8 branch, reverting the user interface and back end to Firefox 1.x functionality.
-
We will continue to aggressively develop the capabilities of Places on the 1.9 trunk. Places will remain enabled here.
-
-
-
We think this is a good decision for two reasons:
-
-
-
It reduces the pressure on the Places team to deliver a lot of bug fixes and additional features on the very immediate timeframe required by the Firefox 2 testing releases. It is my opinion that doing so would impact the quality of the feature, if we did not add at least a couple more alpha cycles to the process. This decision provides us with an opportunity to really make the architecture and user interface of Places reach their full potential.
-
It allows us as a group to circle around and consider the content of the Firefox 2 release holistically, identify high impact at risk areas and spend some more time on them. One of those for me was Feed Handling.
-
-
-
Michael Schroepfer of the Mozilla Corporation has a newsgroup posting with additional information. His thread is also the most appropriate forum for discussion of this topic.
-
-
I have been working on refining some of the messaging surrounding feature content and prioritization on the PRD. I will post the initial results of that here soon.
]]>
-
-ben
-2006-04-24T09:30:54-08:00
-
-
-Did I Mention...
-http://weblogs.mozillazine.org/ben/archives/010075.html
-... that I hate this computer?
-
-
While I'm at it... the up arrow key cap fell off after about three weeks, in early 2004. About six months later I lost the little rubber membrane thing that made it slightly easier to push the arrow. Since then, I've been typing by pushing down on the little connection thingy on the keyboard tray.
-
-
It's been shedding pieces of plastic too. I've never dropped the computer once, but pieces of the shell have begun to snap off.
-
-
When I first got it, when the secondary battery was in place, when the primary drained the machine would hibernate, even though the secondary was present! Pretty awful bug to ship with. There was never a solution that I could find. Speaking of batteries, the primary battery is pretty much toast... it won't go for more than 5 minutes before shutting down. It began doing this at around the 12-18 month mark. And the battery light permanently flashes orange whenever the system is on.
-
-
Why don't I call the hotline? I guess I'll have to, before my warranty runs out. I don't because it usually involves 45 minutes on hold or explaining to someone who only has a script to read from that the issue involving a missing up arrow doesn't require restarting Windows or running some stupid diagnostic tool. I could have paid more for "premium support" at build-time but I found that concept sort of insulting: why should I have to pay extra to speak to someone who is smart and doesn't think I'm a moron?
-
-
And I don't want a Thinkpad either. I hate those computers. They have old-fashioned 4:3 displays, and the function key and left Ctrl key are reversed. I know I could map them differently but why would I? Why couldn't IBM just have designed the product correctly in the first place? Oh, and I'd sooner drink paint than run the awful IBM access connections software to connect to a wireless network, or deal with the fact that the Num Lock key seems to reset to ON every time the system is rebooted.
-
-
Why doesn't someone make the perfect laptop? I'd be interested to hear from someone how long the compile times are for FirefoxDebug on a 2.16GHz MacBook Pro...
]]>
-
-ben
-2006-04-16T19:11:28-08:00
-
-
-I Hate This Computer
-http://weblogs.mozillazine.org/ben/archives/010074.html
-I have been fighting with this computer for the past few days to do a build with a few patches applied.
-
-
First, I managed to get a certain distance with a branch build, compiling with Visual C++ 6.0. But soon I realized there were too many dependencies that were trunk specific, so I had to build trunk. About a quarter of the way through my build died, of course, compiling from the same shell, wrong version of VC6.0 for Cairo/Thebes.
-
-
Starting over again with the VC7 tools, another failure towards the end. Some sort of cyclic dependency check error. Clobber and restart. Now I forgot one of my patches had a configure change, and the process begins anew, I have effectively clobbered.
-
-
When I bought this machine, a Dell Precision M60 with a Pentium M 1.7GHz processor, a 7200rpm disk and a gig of RAM, it could compile Firefox start to stop in 21 minutes. Now it takes over an hour.
-
-
The situation is better on my Google-supplied workstation, but for how long? Over time, Windows reaches a point of being completely useless for anything aside from the most basic activities. What's the effect? I had planned to work both days this weekend on Firefox 2 features. Instead I spent the whole time fighting one of the most frustrating fights possible, and have achieved nothing. I hate Windows. I hate this computer.
]]>
-
-ben
-2006-04-16T18:58:02-08:00
-
-
-Miscommunications
-http://weblogs.mozillazine.org/ben/archives/010073.html
-My laptop was running pretty slowly yesterday so I decided to scan the Add/Remove Programs list to clear out the cruft. Things were really chugging along. I sequentially uninstalled several pieces of software, and the process was very dissatisfying. I became more and more enfuriated at my computer as it proceeded. Here are some of the nuisances:
-
-
-
I could only remove one thing at a time.
-
Many pieces of software used the Windows Installer system which seemed to take forever and report very inconsistent progress (I know, Firefox isn't the best at this in its installer, either)
-
Most annoyingly, the uninstaller apps all reported themselves as performing a variety of actions that I never requested, as explanations for what they were doing during long periods of inactivity and progress-bar freeze. Common excuses were "Windows is Configuring " and "InstallShield is preparing a report on ".
-
-
-
You know, I never asked for blah to be "configured." I never asked for a report on bleh (What am I, a manager? Where is the report anyway? Does it have the appropriate cover sheet?) I just want the software gone. I'm getting really tired of excuses from software like this. Windows software seems to be getting worse and worse. On Mac, the typical way to remove a program is to drag it into the trash can. I can even do that to several programs at once! I do however have to be able to afford a Mac (I can, I have one). Many folk aren't as fortunate as I.
-
-
As a side note, I read an interesting article in Forbes a few weeks ago criticizing Microsoft for its delays shipping Vista, and asking why wouldn't you just side-step all the trouble and buy a Mac, since the odds were good many people would have to upgrade their PC anyway just to get the whiz-bang in Vista. The article side-swiped open source desktop initiatives, asking where the viable free alternative was. I think that was an interesting point, and especially so since the capabilities of Linux systems have come an awesome distance in the past few years but there have been few distributions or desktop environments that IMO make the most of all of those.
]]>
-
-ben
-2006-04-16T18:05:04-08:00
-
-
-Firefox Version Numbers
-http://weblogs.mozillazine.org/ben/archives/010040.html
-Mike Beltzner explains Firefox version numbering. i.e. Firefox 3 RTM is not "out".]]>
-
-ben
-2006-04-10T08:38:18-08:00
-
-
-Our Next Challenge?
-http://weblogs.mozillazine.org/ben/archives/010030.html
-The past year or so has been interesting. In this time, I've been able to meet a lot of new people and learn a lot of new things. Most importantly is that for the first time in as long as I can remember, I have had a chance to see the Mozilla project from the outside, as it would appear to someone who was trying to build on Mozilla technology or contribute directly to a project, but was not part of Netscape "back in the day" or an employee of the Mozilla Foundation/Corporation itself.
-
-
It's been an illuminating experience. From a technical perspective, it helped highlight APIs that I had developed without a clear understanding of how they would be used. The Extension Installation API was one example of this, and we were able to make some great improvements to it in 2005.
-
-
But perhaps more importantly it has shed some light on how people perceive Mozilla as an open source project. These perceptions are not the sort of things people express explicitly. You have to notice them.
-
-
The Difficulty of Involvement
-
-
This is sort of the uber-perception. I think some of the reasons for this include the following:
-
-
Where is the Discussion?
-
-
Which newsgroup/mailing list/IRC channel/wiki/talk page/bug/forum page do I need to track in order to know what's going on in a specific area? The answer is unsatisfactorily complex.
-
-
The traditional method of joining a project in the OSS world (where you join lists and IRC channels and lurk for a while, gradually ramping up your contributions) scales uneasily to a project the size of Mozilla. The amount of data a mere mortal would have to absorb in order to be productive quickly is staggering. I have in the past jocularly referred to it as the "learning wall". I wonder how many people just give up.
-
-
Madness to Method?
-
-
As a large project, Mozilla has thousands of source files across hundreds of directories. One of my coworkers here at Google commented that he tried to find something as simple as the browser window code a couple of years ago and couldn't, because it lived under the thoughtfully named "xpfe".
-
-
There's not a huge amount of documentation - and I'm not just talking about public API docs. I'm talking about the much needed diagrams that show how the various building blocks fit together, and in-code documentation for pretty much anything that isn't intuitive (which is a lot). I've written as little of this as anyone else.
-
-
Tone
-
-
In the past, I have not done the best I could to establish a tone for discourse that is conducive to productive development. My tendency was to snap when provoked. I made two mistakes of judgement here, one was ignoring the effect that this sort of thing would have on those watching, aside from the victim. The other was to think that regardless of the tone set by my actions, we as a group could work through any negative effects. Any work we relied on others for we could do ourselves. Or we could hire through it.
-
-
The Joy of Code
-
-
The flaw with this is that when your project's contributions come solely from companies, for better or for worse the activities of those paid contributors will align in some way with the interests of those companies. What this does not always allow for is the pursuit of the sort of improvements that are outside the scope of these interests. Such things often include raising general code quality, speculative feature development, feature polish and detail etc. I don't mean to say that companies are against these things, but they're often not the primary concern during a release crunch. And what companies like to have is shipping software.
-
-
Alternately, even in the absence of corporate support, if there is not enough redundancy that the same set of folk has to do the grunt work over and over, the risk of burnout is high.
-
-
I feel this because I have been incredibly "plan" focused over the past few years, formally during my time at Netscape and less formally but no less importantly during the run up to Firefox 1.0 and 1.5. What I notice is that I no longer have time to work on the sort of interesting side projects that I used to enjoy doing when I was first starting out.
-
-
For example, about six years ago I discovered a bug in the Bookmarks menu shortly after scrolling was implemented. When you moused into a submenu for a folder that was in the scrolled section, the sub menu popup was pushed off the bottom of the screen. I took a couple of days to learn the menu positioning code and fix the math error that was causing the bug. The exercise was good for me in a number of ways: I learned more about another section of the code, my general expertise was raised, and well.. I fixed the bug that was bothering
-me.
-
-
I think we need to have a project that is accessible to volunteers for this reason. We also need to provide a way to allow those volunteers to grow if they want to, so that if you're one of the folk at the center you can have a chance to step aside for a moment and take a breather and code for the pure joy of it.
-
-
Full time paid contributors will always be a part of Open Source development. But I don't think release-focused agendas will ever be a substitute for the passion of folk who participate because of the joy of exploration and of contribution.
-
-
Looking Outward, Looking Forward
-
-
As a project, we have made overtures towards being a more inclusive lot. For some of the reasons I've listed here, I think as a project we're still more inward looking than outward. How many of us have thought about what we want to be doing in 5 years? Will we always be doing this? Will our roles remain the same? My opinion is that it's fast becoming time for us to start considering making personal sacrifices in our short term conveniences to make the project more accessible to new people. Do I know what we need to do? Not exactly. But I have some ideas: find ways to make our discussions, our public faces, and our code more accessible.
-
-
With Firefox we did an excellent job of building a world class product that people wanted to use. We have a new challenge now, one that is larger and scope and in the long run in my opinion considerably more important because the long term success of products like Firefox depend on it. How will we grow a world class development community? How will we ensure that the freedoms we enjoy are protected, forever?
]]>
-
-ben
-2006-04-07T09:22:59-08:00
-
-
-Congrats Relicensing Project!
-http://weblogs.mozillazine.org/ben/archives/010011.html
-Gerv announces that the Relicensing project is complete. Congrats Gerv and everyone else who doggedly pursued this over the years. Part of Mozilla's mission is preserving choice, and making our code available under a variety of flexible licenses helps ensure that by allowing other projects to make use of it. This was a formidable task and a great accomplishment. ]]>
-
-ben
-2006-04-04T07:15:22-08:00
-
-
-Producing Open Source Software
-http://weblogs.mozillazine.org/ben/archives/009965.html
-I've been reading Karl Fogel's excellent Producing Open Source Software.
-
-
Karl's book is very well written, nice and compact (272 pages), and contains useful information for anyone doing anything in the Open Source world: both developers and managers.
-
-
It will help people new to Open Source get a better understanding of how OSS projects are run. It will help people familiar with Open Source to get a better understanding of how to contribute more effectively.
-
-
It's definitely a "must read."
]]>
-
-ben
-2006-03-26T15:03:52-08:00
-
-
-Writing for Busy People
-http://weblogs.mozillazine.org/ben/archives/009964.html
-Back when I was in University, many of the lecturers stressed time and time again the importance of succinct, well organized writing. They said over and over that this was the best way to have your thoughts read and understood by decision makers. In fact, they scared us by saying that 70% of us would become managers sooner or later!
-
-
Well, I can tell you that's sage advice. It's great when people make contributions in the form of ideas and proposals, but it's even better when they're written for busy people. Here are some examples:
-
-
-
Making important points up front
-
Clear taxonomy of headings, and lots of them
-
Writing clearly and succinctly
-
No long, unbroken paragraphs or tracts of text.
-
Preferring bulleted lists with clear points to paragraphs.
-
Use of emphasis in formatting to make important things clear
-
-
-
These days, I find I don't have a lot of time to read everything carefully, so the better structured a document is, the more I get out of it. I frequently find I miss entire subsections or points of documents, even when there's relatively little text, because of incomplete organization. My eyes definitely glaze over when i see a large block of unbroken text with few headings. At the very least, it'd be very helpful if folk would structure their thoughts into: "Problem" and "Proposed Solution".
-
-
Before you post, stop and think if you've written something in a way that'll allow others to get the most out of it. Communicating your ideas effectively means you may get a clearer and quicker response from other people.
]]>
-Editorial
-ben
-2006-03-26T14:48:04-08:00
-
-
-Step 2: Ask Questions
-http://weblogs.mozillazine.org/ben/archives/009943.html
-A healthy project is one where active contributors are always evaluating the project's progress, making sure it is headed in the right direction (usually stated in the project mission or goals).
-
-
I think we could be better at this in Mozilla. I'm not suggesting people be assholes or anything, but I think some more pan-project analysis would be useful.
-
-
Historically, I can point at a couple of groups of people who have attempted to do something like this. The drivers@ group is one that looked beyond individual modules within Gecko to make sure that the right thing for the shipping products as a whole happened. The Firefox team is another example. By taking a holistic view, user experience was enhanced.
-
-
I think contributors should not be afraid to poke their nose in other parts of the project and see how things are going. Ask questions. Learn more. Get involved in governance and management. If things don't seem intuitive, or a little arbitrary, ask, rather than assume it's for a good reason. One of the benefits of having an open, referencable set of discussion forums means that once you've answered a question once on the public forums, when someone else asks you can just give them a URL.
]]>
-
-ben
-2006-03-22T17:27:14-08:00
-
-
-Step 1: Public Discussions
-http://weblogs.mozillazine.org/ben/archives/009924.html
-The first step on the pathway to open source project happiness is to have our discussions in the public.
-
-
One of the things people have (rightly) criticized about Firefox and Mozilla development in the past is that too much happens mysteriously, behind closed doors. This was for a number of reasons that sounded sufficient at the time - it was expedient, people were sitting within shouting distance, mental laziness, etc.
-
-
What poor communication breeds is a lack of understanding of procedures, priorities and such like. A healthy project is one where the contributors understanding where things are headed, and what parts they can play. It is one where newcomers can visit the project website and within the space of a few minutes get a decent understanding of how things work, and find out opportunities for them to participate.
-
-
People don't want to contribute to projects where things happen "magically". I've learned this lesson in the past.
-
-
To this end, I've been encouraging everyone to have public discussions on the Mozilla Newsgroups/Mailing Lists. For Firefox, the list is dev-apps-firefox@, and the newsgroup is mozilla.dev.apps.firefox. They are mirrored through Google Groups for ease of browsing. We're planning on improving the theme for Firefox2, and rather than pursue this effort in a walled garden like last time, we're going to proceed in dev-themes@/mozilla.dev.themes. Come on over and join in!
-
-
At the same time, we've been encouraging other projects to use the newsgroups/lists too. Decisions made in private email, IRC (which isn't archived anywhere) even in public bugs etc make it very difficult for people who aren't central to the project to find out more or participate. I think we should strive to strike a better balance between convenience and accessibility/referencability.
-
-
On top of this, there is a need to make the contact portions of the web site more accurate, relevant and easy to find, so people can easily find the list they want, and the person or group to contact.
-
-
We've been having discussions about all of this in mozilla.dev.general, in thesethreads. Rather than talk in a vacuum of only ourselves, I really hope that those of you that have experienced difficulty in the past in some of these areas will come forward and contribute to the discussion.
]]>
-
-ben
-2006-03-20T09:23:24-08:00
-
-
-Reflection
-http://weblogs.mozillazine.org/ben/archives/009914.html
-I've been doing a bit of it lately. All manner of topics. We recently moved and things have been chaotic so it's been nice to take the time to think. I've had a chance to look at how far we've come, and form some ideas about what we might need to do to go the right places.
-
-
The past couple of years have brought some immense highs, and some considerable angst. With success has come the realization that true now as ever: the spirit of open source is expressed through the creative freedom of the many. The surest way to navigate the murky waters of increased attention and marketshare and such like is, as Leslie has been saying for some time, to keep your karma clean. Do the right thing, not only in technical matters but also relationships.
-
-
For the Mozilla project, what we need to do (I think) is:
-
-
-
Better define the things that are important to us. The things that define who we are. Impart the positive aspects of open development culture and practice on everyone involved because they're effective, and as a safeguard against recurrence of some of the troubles of the past.
-
Engage the community more effectively. Create and maintain an infrastructure of open communication to remove the "mystery" behind the decision making process. Organize our contributor materials better to make the project more accessible to newcomers. These are just a couple of examples.
-
-
-
For my part, I'm starting out this year by doing things a little differently. I think we need to grow more as a project. I'm hopeful that I'll be able to achieve some positive change.
-
-
I understand that this post might seem a little abstract. I think what I'm saying might become a bit more clear after I talk about some tangible efforts, which I will do in future entries.
I cannot believe people are discussing life without these things. It's like this: I have a patent on television. I don't plan on doing anything with it, but I'm going to shut TV down for all of you, and you're going to sit about and think about life without TV? What's wrong with people?! Is this the world we all want to live in, where people without the interest or capability to pursue technology can hold everyone else captive? That's not the world I want to live in.
-
-
-
diff --git a/toolkit/components/formautofill/test/chrome/test_infrastructure.js b/toolkit/components/formautofill/test/chrome/test_infrastructure.js
deleted file mode 100644
index c3b0b43ff..000000000
--- a/toolkit/components/formautofill/test/chrome/test_infrastructure.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Tests the local testing infrastructure.
- */
-
-"use strict";
-
-/**
- * Tests the truth assertion function.
- */
-add_task(function* test_assert_truth() {
- Assert.ok(1 != 2);
-});
-
-/**
- * Tests the equality assertion function.
- */
-add_task(function* test_assert_equality() {
- Assert.equal(1 + 1, 2);
-});
-
-/**
- * Uses some of the utility functions provided by the framework.
- */
-add_task(function* test_utility_functions() {
- // The "print" function is useful to log information that is not known before.
- let randomString = "R" + Math.floor(Math.random() * 10);
- Output.print("The random contents will be '" + randomString + "'.");
-
- // Create the text file with the random contents.
- let path = yield TestUtils.getTempFile("test-infrastructure.txt");
- yield OS.File.writeAtomic(path, new TextEncoder().encode(randomString));
-
- // Test a few utility functions.
- yield TestUtils.waitForTick();
- yield TestUtils.waitMs(50);
-
- let promiseMyNotification = TestUtils.waitForNotification("my-topic");
- Services.obs.notifyObservers(null, "my-topic", "");
- yield promiseMyNotification;
-
- // Check the file size. The file will be deleted automatically later.
- Assert.equal((yield OS.File.stat(path)).size, randomString.length);
-});
-
-/**
- * This type of test has access to the content declared above.
- */
-add_task(function* test_content() {
- Assert.equal($("paragraph").innerHTML, "Paragraph contents.");
-
- let promiseMyEvent = TestUtils.waitForEvent($("paragraph"), "MyEvent");
-
- let event = document.createEvent("CustomEvent");
- event.initCustomEvent("MyEvent", true, false, {});
- $("paragraph").dispatchEvent(event);
-
- yield promiseMyEvent;
-});
diff --git a/toolkit/components/formautofill/test/chrome/test_requestAutocomplete_cancel.html b/toolkit/components/formautofill/test/chrome/test_requestAutocomplete_cancel.html
deleted file mode 100644
index 8ae7ffd4b..000000000
--- a/toolkit/components/formautofill/test/chrome/test_requestAutocomplete_cancel.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
diff --git a/toolkit/components/formautofill/test/chrome/test_requestAutocomplete_cancel.js b/toolkit/components/formautofill/test/chrome/test_requestAutocomplete_cancel.js
deleted file mode 100644
index 1ee12bd9a..000000000
--- a/toolkit/components/formautofill/test/chrome/test_requestAutocomplete_cancel.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Tests the response sent when requestAutocomplete is canceled by the user.
- */
-
-"use strict";
-
-/**
- * The requestAutocomplete UI will not be displayed during these tests.
- */
-add_task_in_parent_process(function* test_cancel_init() {
- FormAutofillTest.requestAutocompleteResponse = { canceled: true };
-});
-
-/**
- * Tests the case where the feature is canceled.
- */
-add_task(function* test_cancel() {
- let promise = TestUtils.waitForEvent($("form"), "autocompleteerror");
- $("form").requestAutocomplete();
- let errorEvent = yield promise;
-
- Assert.equal(errorEvent.reason, "cancel");
-});
diff --git a/toolkit/components/formautofill/test/head_common.js b/toolkit/components/formautofill/test/head_common.js
deleted file mode 100644
index 82b87e4a6..000000000
--- a/toolkit/components/formautofill/test/head_common.js
+++ /dev/null
@@ -1,245 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Initialization of Form Autofill tests shared between all frameworks.
- *
- * A copy of this file is installed in each of the framework subfolders, this
- * means it becomes a sibling of the test files in the final layout. This is
- * determined by how manifest "support-files" installation works.
- */
-
-"use strict";
-
-// The requestAutocomplete framework is available at this point, you can add
-// mochitest-chrome specific test initialization here. If you need shared
-// functions or initialization that are not specific to mochitest-chrome,
-// consider adding them to "head_common.js" in the parent folder instead.
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
- "resource://gre/modules/DownloadPaths.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
- "resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FormAutofill",
- "resource://gre/modules/FormAutofill.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
- "resource://gre/modules/NetUtil.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-
-/* --- Global helpers --- */
-
-// Some of these functions are already implemented in other parts of the source
-// tree, see bug 946708 about sharing more code.
-
-var TestUtils = {
- /**
- * Waits for at least one tick of the event loop. This means that all pending
- * events at the time of this call will have been processed. Other events may
- * be processed before the returned promise is resolved.
- *
- * @return {Promise}
- * @resolves When pending events have been processed.
- * @rejects Never.
- */
- waitForTick: function () {
- return new Promise(resolve => executeSoon(resolve));
- },
-
- /**
- * Waits for the specified timeout.
- *
- * @param aTimeMs
- * Minimum time to wait from the moment of this call, in milliseconds.
- * The actual wait may be longer, due to system timer resolution and
- * pending events being processed before the promise is resolved.
- *
- * @return {Promise}
- * @resolves When the specified time has passed.
- * @rejects Never.
- */
- waitMs: function (aTimeMs) {
- return new Promise(resolve => setTimeout(resolve, aTimeMs));
- },
-
- /**
- * Allows waiting for an observer notification once.
- *
- * @param aTopic
- * Notification topic to observe.
- *
- * @return {Promise}
- * @resolves The array [aSubject, aData] from the observed notification.
- * @rejects Never.
- */
- waitForNotification: function (aTopic) {
- Output.print("Waiting for notification: '" + aTopic + "'.");
-
- return new Promise(resolve => Services.obs.addObserver(
- function observe(aSubject, aTopic, aData) {
- Services.obs.removeObserver(observe, aTopic);
- resolve([aSubject, aData]);
- }, aTopic, false));
- },
-
- /**
- * Waits for a DOM event on the specified target.
- *
- * @param aTarget
- * The DOM EventTarget on which addEventListener should be called.
- * @param aEventName
- * String with the name of the event.
- * @param aUseCapture
- * This parameter is passed to the addEventListener call.
- *
- * @return {Promise}
- * @resolves The arguments from the observed event.
- * @rejects Never.
- */
- waitForEvent: function (aTarget, aEventName, aUseCapture = false) {
- Output.print("Waiting for event: '" + aEventName + "' on " + aTarget + ".");
-
- return new Promise(resolve => aTarget.addEventListener(aEventName,
- function onEvent(...aArgs) {
- aTarget.removeEventListener(aEventName, onEvent, aUseCapture);
- resolve(...aArgs);
- }, aUseCapture));
- },
-
- // While the previous test file should have deleted all the temporary files it
- // used, on Windows these might still be pending deletion on the physical file
- // system. Thus, start from a new base number every time, to make a collision
- // with a file that is still pending deletion highly unlikely.
- _fileCounter: Math.floor(Math.random() * 1000000),
-
- /**
- * Returns a reference to a temporary file, that is guaranteed not to exist,
- * and to have never been created before.
- *
- * @param aLeafName
- * Suggested leaf name for the file to be created.
- *
- * @return {Promise}
- * @resolves Path of a non-existent file in a temporary directory.
- *
- * @note It is not enough to delete the file if it exists, or to delete the
- * file after calling nsIFile.createUnique, because on Windows the
- * delete operation in the file system may still be pending, preventing
- * a new file with the same name to be created.
- */
- getTempFile: Task.async(function* (aLeafName) {
- // Prepend a serial number to the extension in the suggested leaf name.
- let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
- let leafName = base + "-" + this._fileCounter + ext;
- this._fileCounter++;
-
- // Get a file reference under the temporary directory for this test file.
- let path = OS.Path.join(OS.Constants.Path.tmpDir, leafName);
- Assert.ok(!(yield OS.File.exists(path)));
-
- // Ensure the file is deleted whe the test terminates.
- add_termination_task(function* () {
- if (yield OS.File.exists(path)) {
- yield OS.File.remove(path);
- }
- });
-
- return path;
- }),
-};
-
-/* --- Local helpers --- */
-
-var FormAutofillTest = {
- /**
- * Stores the response that the next call to the mock requestAutocomplete UI
- * will return to the requester, or null to enable displaying the default UI.
- */
- requestAutocompleteResponse: null,
-
- /**
- * Displays the requestAutocomplete user interface using the specified data.
- *
- * @param aFormAutofillData
- * Serializable object containing the set of requested fields.
- *
- * @return {Promise}
- * @resolves An object with the following properties:
- * {
- * uiWindow: Reference to the initialized window.
- * promiseResult: Promise resolved by the UI when it closes.
- * }
- */
- showUI: Task.async(function* (aFormAutofillData) {
- Output.print("Opening UI with data: " + JSON.stringify(aFormAutofillData));
-
- // Wait for the initialization event before opening the window.
- let promiseUIWindow =
- TestUtils.waitForNotification("formautofill-window-initialized");
- let ui = yield FormAutofill.integration.createRequestAutocompleteUI(
- aFormAutofillData);
- let promiseResult = ui.show();
-
- // The window is the subject of the observer notification.
- return {
- uiWindow: (yield promiseUIWindow)[0],
- promiseResult: promiseResult,
- };
- }),
-};
-
-var TestData = {
- /**
- * Autofill UI request for the e-mail field only.
- */
- get requestEmailOnly() {
- return {
- sections: [{
- name: "",
- addressSections: [{
- addressType: "",
- fields: [{
- fieldName: "email",
- contactType: "",
- }],
- }],
- }],
- };
- },
-};
-
-/* --- Initialization and termination functions common to all tests --- */
-
-add_task_in_parent_process(function* () {
- // If required, we return a mock response instead of displaying the UI.
- let mockIntegrationFn = base => ({
- createRequestAutocompleteUI: Task.async(function* () {
- // Call the base method to display the UI if override is not requested.
- if (FormAutofillTest.requestAutocompleteResponse === null) {
- return yield base.createRequestAutocompleteUI.apply(this, arguments);
- }
-
- // Return a mock RequestAutocompleteUI object.
- return {
- show: Task.async(function* () {
- let response = FormAutofillTest.requestAutocompleteResponse;
- Output.print("Mock UI response: " + JSON.stringify(response));
- return response;
- }),
- };
- }),
- });
-
- FormAutofill.registerIntegration(mockIntegrationFn);
- add_termination_task(function* () {
- FormAutofill.unregisterIntegration(mockIntegrationFn);
- });
-});
-
-add_task_in_both_processes(function* () {
- // We must manually enable the feature while testing.
- Services.prefs.setBoolPref("dom.forms.requestAutocomplete", true);
- add_termination_task(function* () {
- Services.prefs.clearUserPref("dom.forms.requestAutocomplete");
- });
-});
diff --git a/toolkit/components/formautofill/test/loader_common.js b/toolkit/components/formautofill/test/loader_common.js
deleted file mode 100644
index 340586b65..000000000
--- a/toolkit/components/formautofill/test/loader_common.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Infrastructure common to the test frameworks located in subfolders.
- *
- * A copy of this file is installed in each of the framework subfolders, this
- * means it becomes a sibling of the test files in the final layout. This is
- * determined by how manifest "support-files" installation works.
- *
- * Unless you are adding new features to the framework, you shouldn't have to
- * modify this file. Use "head_common.js" or the "head.js" file of each
- * framework for shared code.
- */
-
-"use strict";
-
-/*
- * --------------------
- * FRAMEWORK OVERVIEW
- * --------------------
- *
- * This framework is designed in such a way that test can be written in similar
- * ways in the xpcshell, mochitest-chrome, and mochitest-browser frameworks,
- * both when tests are running in the parent process or in a content process.
- *
- * There are some basic self-documenting assertion and output functions:
- *
- * Assert.ok(actualValue);
- * Assert.is(actualValue, expectedValue);
- * Output.print(string);
- *
- * Test cases and initialization functions are declared in shared head files
- * ("head_common.js" and "head.js") as well as individual test files. When
- * tests run in an Elecrolysis (e10s) environment, they are executed in both
- * processes at first. Normally, at this point only the registration of test
- * cases happen. When everything has finished loading, tests are started and
- * appropriately synchronized between processes.
- *
- * Tests can be declared using the add_task syntax:
- *
- * add_task(function* test_something () { ... });
- * This adds a test either in the parent process or child process:
- * - Parent: xpcshell, mochitest-chrome --disable-e10s, mochitest-browser
- * - Child: mochitest-chrome with e10s
- * In the future, these might run in the child process for "xpcshell".
- *
- * add_task_in_parent_process(function* test_something () { ... });
- * This test runs in the parent process, but the child process will wait for
- * its completion before continuing with the next task. This wait currently
- * happens only in mochitest-chrome with e10s, in other frameworks that run
- * only in the parent process this is the same as a normal add_task.
- *
- * add_task_in_child_process(function* test_something () { ... });
- * This test runs only in the child process. This means that the test is not
- * run unless this is an e10s test, currently mochitest-chrome with e10s.
- *
- * add_task_in_both_processes(function* test_something () { ... });
- * Useful for initialization that must be done both in the parent and the
- * child, like setting preferences.
- *
- * add_termination_task(function* () { ... });
- * Registers a new asynchronous termination task. This is executed after all
- * test cases in the file finished, and always in the same process where the
- * termination task is registered.
- */
-XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/Promise.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Task",
- "resource://gre/modules/Task.jsm");
-
-var gTerminationTasks = [];
-
-/**
- * None of the testing frameworks support asynchronous termination functions, so
- * this task must be registered later, after the other "add_task" calls.
- *
- * Even xpcshell doesn't support calling "add_task" in the "tail.js" file,
- * because it registers the task but does not wait for its termination,
- * potentially leading to intermittent failures in subsequent tests.
- */
-function* terminationTaskFn() {
- for (let taskFn of gTerminationTasks) {
- try {
- yield Task.spawn(taskFn);
- } catch (ex) {
- Output.print(ex);
- Assert.ok(false);
- }
- }
-}
-
-function add_termination_task(taskFn) {
- gTerminationTasks.push(taskFn);
-}
-
-/**
- * Returns a unique identifier used for synchronizing the given test task
- * between the parent and child processes.
- */
-function getTaskId(stackFrame) {
- return stackFrame.filename + ":" + stackFrame.lineNumber;
-}
-
-// This is a shared helper for mochitest-chrome and mochitest-browser.
-var _mochitestAssert = {
- ok: function (actual) {
- let stack = Components.stack.caller;
- ok(actual, "[" + stack.name + " : " + stack.lineNumber + "] " + actual +
- " == true");
- },
- equal: function (actual, expected) {
- let stack = Components.stack.caller;
- is(actual, expected, "[" + stack.name + " : " + stack.lineNumber + "] " +
- actual + " == " + expected);
- },
-};
-
-// Reminder: unless you are adding new features to the framework, you shouldn't
-// have to modify this file. Use "head_common.js" or "head.js" for shared code.
diff --git a/toolkit/components/formautofill/test/xpcshell/.eslintrc.js b/toolkit/components/formautofill/test/xpcshell/.eslintrc.js
deleted file mode 100644
index d35787cd2..000000000
--- a/toolkit/components/formautofill/test/xpcshell/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/formautofill/test/xpcshell/head.js b/toolkit/components/formautofill/test/xpcshell/head.js
deleted file mode 100644
index 1cee023f2..000000000
--- a/toolkit/components/formautofill/test/xpcshell/head.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Initialization specific to Form Autofill xpcshell tests.
- *
- * This file is loaded by "loader.js".
- */
-
-"use strict";
-
-// The testing framework is fully initialized at this point, you can add
-// xpcshell specific test initialization here. If you need shared functions or
-// initialization that are not specific to xpcshell, consider adding them to
-// "head_common.js" in the parent folder instead.
-
-add_task_in_parent_process(function* test_xpcshell_initialize_profile() {
- // We need to send the profile-after-change notification manually to the
- // startup component to ensure it has been initialized.
- Cc["@mozilla.org/formautofill/startup;1"]
- .getService(Ci.nsIObserver)
- .observe(null, "profile-after-change", "");
-});
diff --git a/toolkit/components/formautofill/test/xpcshell/loader.js b/toolkit/components/formautofill/test/xpcshell/loader.js
deleted file mode 100644
index 449989c8a..000000000
--- a/toolkit/components/formautofill/test/xpcshell/loader.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Infrastructure for the xpcshell tests located in this folder.
- *
- * See "loader_common.js" in the parent folder for a general overview.
- *
- * Unless you are adding new features to the framework, you shouldn't have to
- * modify this file. Use "head_common.js" or "head.js" for shared code.
- */
-
-"use strict";
-
-var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://gre/modules/Services.jsm", this);
-
-Services.scriptloader.loadSubScript(
- Services.io.newFileURI(do_get_file("loader_common.js")).spec, this);
-
-// Define output functions so they look the same across all frameworks.
-var Output = {
- print: do_print,
-};
-
-var executeSoon = do_execute_soon;
-var setTimeout = (fn, delay) => do_timeout(delay, fn);
-
-// Define task registration functions, see description in "loader_common.js".
-var add_task_in_parent_process = add_task;
-var add_task_in_child_process = function () {};
-var add_task_in_both_processes = add_task;
-
-Services.scriptloader.loadSubScript(
- Services.io.newFileURI(do_get_file("head_common.js")).spec, this);
-
-// Tests are always run asynchronously and with the profile loaded.
-function run_test() {
- do_get_profile();
- run_next_test();
-}
-
-// Reminder: unless you are adding new features to the framework, you shouldn't
-// have to modify this file. Use "head_common.js" or "head.js" for shared code.
diff --git a/toolkit/components/formautofill/test/xpcshell/test_infrastructure.js b/toolkit/components/formautofill/test/xpcshell/test_infrastructure.js
deleted file mode 100644
index af27cfdb5..000000000
--- a/toolkit/components/formautofill/test/xpcshell/test_infrastructure.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Tests the local testing infrastructure.
- */
-
-"use strict";
-
-/**
- * Tests the truth assertion function.
- */
-add_task(function* test_assert_truth() {
- Assert.ok(1 != 2);
-});
-
-/**
- * Tests the equality assertion function.
- */
-add_task(function* test_assert_equality() {
- Assert.equal(1 + 1, 2);
-});
-
-/**
- * Uses some of the utility functions provided by the framework.
- */
-add_task(function* test_utility_functions() {
- // The "print" function is useful to log information that is not known before.
- let randomString = "R" + Math.floor(Math.random() * 10);
- Output.print("The random contents will be '" + randomString + "'.");
-
- // Create the text file with the random contents.
- let path = yield TestUtils.getTempFile("test-infrastructure.txt");
- yield OS.File.writeAtomic(path, new TextEncoder().encode(randomString));
-
- // Test a few utility functions.
- yield TestUtils.waitForTick();
- yield TestUtils.waitMs(50);
-
- let promiseMyNotification = TestUtils.waitForNotification("my-topic");
- Services.obs.notifyObservers(null, "my-topic", "");
- yield promiseMyNotification;
-
- // Check the file size. The file will be deleted automatically later.
- Assert.equal((yield OS.File.stat(path)).size, randomString.length);
-});
-
-add_task(terminationTaskFn);
diff --git a/toolkit/components/formautofill/test/xpcshell/test_integration.js b/toolkit/components/formautofill/test/xpcshell/test_integration.js
deleted file mode 100644
index 7707f3880..000000000
--- a/toolkit/components/formautofill/test/xpcshell/test_integration.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Tests overriding the FormAutofillIntegration module functions.
- */
-
-"use strict";
-
-/**
- * The requestAutocomplete UI will not be displayed during these tests.
- */
-add_task_in_parent_process(function* test_initialize() {
- FormAutofillTest.requestAutocompleteResponse = { canceled: true };
-});
-
-/**
- * Registers and unregisters an integration override function.
- */
-add_task(function* test_integration_override() {
- let overrideCalled = false;
-
- let newIntegrationFn = base => ({
- createRequestAutocompleteUI: Task.async(function* () {
- overrideCalled = true;
- return yield base.createRequestAutocompleteUI.apply(this, arguments);
- }),
- });
-
- FormAutofill.registerIntegration(newIntegrationFn);
- try {
- let ui = yield FormAutofill.integration.createRequestAutocompleteUI({});
- let result = yield ui.show();
- Assert.ok(result.canceled);
- } finally {
- FormAutofill.unregisterIntegration(newIntegrationFn);
- }
-
- Assert.ok(overrideCalled);
-});
-
-/**
- * Registers an integration override function that throws an exception, and
- * ensures that this does not block other functions from being registered.
- */
-add_task(function* test_integration_override_error() {
- let overrideCalled = false;
-
- let errorIntegrationFn = base => { throw "Expected error." };
-
- let newIntegrationFn = base => ({
- createRequestAutocompleteUI: Task.async(function* () {
- overrideCalled = true;
- return yield base.createRequestAutocompleteUI.apply(this, arguments);
- }),
- });
-
- FormAutofill.registerIntegration(errorIntegrationFn);
- FormAutofill.registerIntegration(newIntegrationFn);
- try {
- let ui = yield FormAutofill.integration.createRequestAutocompleteUI({});
- let result = yield ui.show();
- Assert.ok(result.canceled);
- } finally {
- FormAutofill.unregisterIntegration(errorIntegrationFn);
- FormAutofill.unregisterIntegration(newIntegrationFn);
- }
-
- Assert.ok(overrideCalled);
-});
-
-add_task(terminationTaskFn);
diff --git a/toolkit/components/formautofill/test/xpcshell/xpcshell.ini b/toolkit/components/formautofill/test/xpcshell/xpcshell.ini
deleted file mode 100644
index 711c03399..000000000
--- a/toolkit/components/formautofill/test/xpcshell/xpcshell.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[DEFAULT]
-head = loader.js head.js
-tail =
-skip-if = toolkit == 'android'
-# The following files starting with ".." are installed in the current folder.
-# However, they cannot be referenced directly in the "head" directive above.
-support-files =
- ../head_common.js
- ../loader_common.js
-
-[test_infrastructure.js]
-[test_integration.js]
diff --git a/toolkit/components/jsdownloads/moz.build b/toolkit/components/jsdownloads/moz.build
index 62f08b160..56566bc97 100644
--- a/toolkit/components/jsdownloads/moz.build
+++ b/toolkit/components/jsdownloads/moz.build
@@ -4,15 +4,4 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-with Files('*'):
- BUG_COMPONENT = ('Toolkit', 'Download Manager')
-
DIRS += ['public', 'src']
-
-XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
-BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
-
-TEST_HARNESS_FILES.xpcshell.toolkit.components.jsdownloads.test.data += [
- 'test/data/empty.txt',
- 'test/data/source.txt',
-]
diff --git a/toolkit/components/jsdownloads/test/browser/.eslintrc.js b/toolkit/components/jsdownloads/test/browser/.eslintrc.js
deleted file mode 100644
index 7c8021192..000000000
--- a/toolkit/components/jsdownloads/test/browser/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/mochitest/browser.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/jsdownloads/test/browser/browser.ini b/toolkit/components/jsdownloads/test/browser/browser.ini
deleted file mode 100644
index 131fc4ec8..000000000
--- a/toolkit/components/jsdownloads/test/browser/browser.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[DEFAULT]
-support-files =
- head.js
- testFile.html
-
-[browser_DownloadPDFSaver.js]
-skip-if = os != "win"
diff --git a/toolkit/components/jsdownloads/test/browser/browser_DownloadPDFSaver.js b/toolkit/components/jsdownloads/test/browser/browser_DownloadPDFSaver.js
deleted file mode 100644
index 80ed9665a..000000000
--- a/toolkit/components/jsdownloads/test/browser/browser_DownloadPDFSaver.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the PDF download saver, and tests using a window as a
- * source for the copy download saver.
- */
-
-"use strict";
-
-/**
- * Helper function to make sure a window reference exists on the download source.
- */
-function* test_download_windowRef(aTab, aDownload) {
- ok(aDownload.source.windowRef, "Download source had a window reference");
- ok(aDownload.source.windowRef instanceof Ci.xpcIJSWeakReference, "Download window reference is a weak ref");
- is(aDownload.source.windowRef.get(), aTab.linkedBrowser.contentWindow, "Download window exists during test");
-}
-
-/**
- * Helper function to check the state of a completed download.
- */
-function* test_download_state_complete(aTab, aDownload, aPrivate, aCanceled) {
- ok(aDownload.source, "Download has a source");
- is(aDownload.source.url, aTab.linkedBrowser.contentWindow.location, "Download source has correct url");
- is(aDownload.source.isPrivate, aPrivate, "Download source has correct private state");
- ok(aDownload.stopped, "Download is stopped");
- is(aCanceled, aDownload.canceled, "Download has correct canceled state");
- is(!aCanceled, aDownload.succeeded, "Download has correct succeeded state");
- is(aDownload.error, null, "Download error is not defined");
-}
-
-function* test_createDownload_common(aPrivate, aType) {
- let win = yield BrowserTestUtils.openNewBrowserWindow({ private : aPrivate});
-
- let tab = yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, getRootDirectory(gTestPath) + "testFile.html");
- let download = yield Downloads.createDownload({
- source: tab.linkedBrowser.contentWindow,
- target: { path: getTempFile(TEST_TARGET_FILE_NAME_PDF).path },
- saver: { type: aType }
- });
-
- yield test_download_windowRef(tab, download);
- yield download.start();
-
- yield test_download_state_complete(tab, download, aPrivate, false);
- if (aType == "pdf") {
- let signature = yield OS.File.read(download.target.path,
- { bytes: 4, encoding: "us-ascii" });
- is(signature, "%PDF", "File exists and signature matches");
- } else {
- ok((yield OS.File.exists(download.target.path)), "File exists");
- }
-
- win.gBrowser.removeTab(tab);
- win.close()
-}
-
-add_task(function* test_createDownload_pdf_private() {
- yield test_createDownload_common(true, "pdf");
-});
-add_task(function* test_createDownload_pdf_not_private() {
- yield test_createDownload_common(false, "pdf");
-});
-
-// Even for the copy saver, using a window should produce valid results
-add_task(function* test_createDownload_copy_private() {
- yield test_createDownload_common(true, "copy");
-});
-add_task(function* test_createDownload_copy_not_private() {
- yield test_createDownload_common(false, "copy");
-});
-
-add_task(function* test_cancel_pdf_download() {
- let tab = gBrowser.addTab(getRootDirectory(gTestPath) + "testFile.html");
- yield promiseBrowserLoaded(tab.linkedBrowser);
-
- let download = yield Downloads.createDownload({
- source: tab.linkedBrowser.contentWindow,
- target: { path: getTempFile(TEST_TARGET_FILE_NAME_PDF).path },
- saver: "pdf",
- });
-
- yield test_download_windowRef(tab, download);
- download.start().catch(() => {});
-
- // Immediately cancel the download to test that it is erased correctly.
- yield download.cancel();
- yield test_download_state_complete(tab, download, false, true);
-
- let exists = yield OS.File.exists(download.target.path)
- ok(!exists, "Target file does not exist");
-
- gBrowser.removeTab(tab);
-});
diff --git a/toolkit/components/jsdownloads/test/browser/head.js b/toolkit/components/jsdownloads/test/browser/head.js
deleted file mode 100644
index 769aaacb3..000000000
--- a/toolkit/components/jsdownloads/test/browser/head.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Provides infrastructure for automated download components tests.
- */
-
-"use strict";
-
-// Globals
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
- "resource://gre/modules/DownloadPaths.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
- "resource://gre/modules/Downloads.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
- "resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
- "resource://gre/modules/Services.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
- "resource://testing-common/httpd.js");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-
-const TEST_TARGET_FILE_NAME_PDF = "test-download.pdf";
-
-// Support functions
-
-// While the previous test file should have deleted all the temporary files it
-// used, on Windows these might still be pending deletion on the physical file
-// system. Thus, start from a new base number every time, to make a collision
-// with a file that is still pending deletion highly unlikely.
-var gFileCounter = Math.floor(Math.random() * 1000000);
-
-/**
- * Returns a reference to a temporary file, that is guaranteed not to exist, and
- * to have never been created before.
- *
- * @param aLeafName
- * Suggested leaf name for the file to be created.
- *
- * @return nsIFile pointing to a non-existent file in a temporary directory.
- *
- * @note It is not enough to delete the file if it exists, or to delete the file
- * after calling nsIFile.createUnique, because on Windows the delete
- * operation in the file system may still be pending, preventing a new
- * file with the same name to be created.
- */
-function getTempFile(aLeafName)
-{
- // Prepend a serial number to the extension in the suggested leaf name.
- let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
- let leafName = base + "-" + gFileCounter + ext;
- gFileCounter++;
-
- // Get a file reference under the temporary directory for this test file.
- let file = FileUtils.getFile("TmpD", [leafName]);
- ok(!file.exists(), "Temp file does not exist");
-
- registerCleanupFunction(function () {
- if (file.exists()) {
- file.remove(false);
- }
- });
-
- return file;
-}
-
-function promiseBrowserLoaded(browser) {
- return new Promise(resolve => {
- browser.addEventListener("load", function onLoad(event) {
- if (event.target == browser.contentDocument) {
- browser.removeEventListener("load", onLoad, true);
- resolve();
- }
- }, true);
- });
-}
diff --git a/toolkit/components/jsdownloads/test/browser/testFile.html b/toolkit/components/jsdownloads/test/browser/testFile.html
deleted file mode 100644
index ee413514b..000000000
--- a/toolkit/components/jsdownloads/test/browser/testFile.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- Test Save as PDF
-
-
-
Save me as a PDF!
-
-
diff --git a/toolkit/components/jsdownloads/test/data/.eslintrc.js b/toolkit/components/jsdownloads/test/data/.eslintrc.js
deleted file mode 100644
index d35787cd2..000000000
--- a/toolkit/components/jsdownloads/test/data/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/jsdownloads/test/data/empty.txt b/toolkit/components/jsdownloads/test/data/empty.txt
deleted file mode 100644
index e69de29bb..000000000
diff --git a/toolkit/components/jsdownloads/test/data/source.txt b/toolkit/components/jsdownloads/test/data/source.txt
deleted file mode 100644
index 2156cb8c0..000000000
--- a/toolkit/components/jsdownloads/test/data/source.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test string is downloaded.
\ No newline at end of file
diff --git a/toolkit/components/jsdownloads/test/unit/.eslintrc.js b/toolkit/components/jsdownloads/test/unit/.eslintrc.js
deleted file mode 100644
index d35787cd2..000000000
--- a/toolkit/components/jsdownloads/test/unit/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/jsdownloads/test/unit/common_test_Download.js b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
deleted file mode 100644
index 42d4c5682..000000000
--- a/toolkit/components/jsdownloads/test/unit/common_test_Download.js
+++ /dev/null
@@ -1,2432 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * This script is loaded by "test_DownloadCore.js" and "test_DownloadLegacy.js"
- * with different values of the gUseLegacySaver variable, to apply tests to both
- * the "copy" and "legacy" saver implementations.
- */
-
-"use strict";
-
-// Globals
-
-const kDeleteTempFileOnExit = "browser.helperApps.deleteTempFileOnExit";
-
-/**
- * Creates and starts a new download, using either DownloadCopySaver or
- * DownloadLegacySaver based on the current test run.
- *
- * @return {Promise}
- * @resolves The newly created Download object. The download may be in progress
- * or already finished. The promiseDownloadStopped function can be
- * used to wait for completion.
- * @rejects JavaScript exception.
- */
-function promiseStartDownload(aSourceUrl) {
- if (gUseLegacySaver) {
- return promiseStartLegacyDownload(aSourceUrl);
- }
-
- return promiseNewDownload(aSourceUrl).then(download => {
- download.start().catch(() => {});
- return download;
- });
-}
-
-/**
- * Creates and starts a new download, configured to keep partial data, and
- * returns only when the first part of "interruptible_resumable.txt" has been
- * saved to disk. You must call "continueResponses" to allow the interruptible
- * request to continue.
- *
- * This function uses either DownloadCopySaver or DownloadLegacySaver based on
- * the current test run.
- *
- * @return {Promise}
- * @resolves The newly created Download object, still in progress.
- * @rejects JavaScript exception.
- */
-function promiseStartDownload_tryToKeepPartialData() {
- return Task.spawn(function* () {
- mustInterruptResponses();
-
- // Start a new download and configure it to keep partially downloaded data.
- let download;
- if (!gUseLegacySaver) {
- let targetFilePath = getTempFile(TEST_TARGET_FILE_NAME).path;
- download = yield Downloads.createDownload({
- source: httpUrl("interruptible_resumable.txt"),
- target: { path: targetFilePath,
- partFilePath: targetFilePath + ".part" },
- });
- download.tryToKeepPartialData = true;
- download.start().catch(() => {});
- } else {
- // Start a download using nsIExternalHelperAppService, that is configured
- // to keep partially downloaded data by default.
- download = yield promiseStartExternalHelperAppServiceDownload();
- }
-
- yield promiseDownloadMidway(download);
- yield promisePartFileReady(download);
-
- return download;
- });
-}
-
-/**
- * This function should be called after the progress notification for a download
- * is received, and waits for the worker thread of BackgroundFileSaver to
- * receive the data to be written to the ".part" file on disk.
- *
- * @return {Promise}
- * @resolves When the ".part" file has been written to disk.
- * @rejects JavaScript exception.
- */
-function promisePartFileReady(aDownload) {
- return Task.spawn(function* () {
- // We don't have control over the file output code in BackgroundFileSaver.
- // After we receive the download progress notification, we may only check
- // that the ".part" file has been created, while its size cannot be
- // determined because the file is currently open.
- try {
- do {
- yield promiseTimeout(50);
- } while (!(yield OS.File.exists(aDownload.target.partFilePath)));
- } catch (ex) {
- if (!(ex instanceof OS.File.Error)) {
- throw ex;
- }
- // This indicates that the file has been created and cannot be accessed.
- // The specific error might vary with the platform.
- do_print("Expected exception while checking existence: " + ex.toString());
- // Wait some more time to allow the write to complete.
- yield promiseTimeout(100);
- }
- });
-}
-
-/**
- * Checks that the actual data written to disk matches the expected data as well
- * as the properties of the given DownloadTarget object.
- *
- * @param downloadTarget
- * The DownloadTarget object whose details have to be verified.
- * @param expectedContents
- * String containing the octets that are expected in the file.
- *
- * @return {Promise}
- * @resolves When the properties have been verified.
- * @rejects JavaScript exception.
- */
-var promiseVerifyTarget = Task.async(function* (downloadTarget,
- expectedContents) {
- yield promiseVerifyContents(downloadTarget.path, expectedContents);
- do_check_true(downloadTarget.exists);
- do_check_eq(downloadTarget.size, expectedContents.length);
-});
-
-/**
- * Waits for an attempt to launch a file, and returns the nsIMIMEInfo used for
- * the launch, or null if the file was launched with the default handler.
- */
-function waitForFileLaunched() {
- return new Promise(resolve => {
- let waitFn = base => ({
- launchFile(file, mimeInfo) {
- Integration.downloads.unregister(waitFn);
- if (!mimeInfo ||
- mimeInfo.preferredAction == Ci.nsIMIMEInfo.useSystemDefault) {
- resolve(null);
- } else {
- resolve(mimeInfo);
- }
- return Promise.resolve();
- },
- });
- Integration.downloads.register(waitFn);
- });
-}
-
-/**
- * Waits for an attempt to show the directory where a file is located, and
- * returns the path of the file.
- */
-function waitForDirectoryShown() {
- return new Promise(resolve => {
- let waitFn = base => ({
- showContainingDirectory(path) {
- Integration.downloads.unregister(waitFn);
- resolve(path);
- return Promise.resolve();
- },
- });
- Integration.downloads.register(waitFn);
- });
-}
-
-// Tests
-
-/**
- * Executes a download and checks its basic properties after construction.
- * The download is started by constructing the simplest Download object with
- * the "copy" saver, or using the legacy nsITransfer interface.
- */
-add_task(function* test_basic()
-{
- let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
-
- let download;
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we have control over the download, thus
- // we can check its basic properties before it starts.
- download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt") },
- target: { path: targetFile.path },
- saver: { type: "copy" },
- });
-
- do_check_eq(download.source.url, httpUrl("source.txt"));
- do_check_eq(download.target.path, targetFile.path);
-
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, the download is already started when it
- // is created, thus we must check its basic properties while in progress.
- download = yield promiseStartLegacyDownload(null,
- { targetFile: targetFile });
-
- do_check_eq(download.source.url, httpUrl("source.txt"));
- do_check_eq(download.target.path, targetFile.path);
-
- yield promiseDownloadStopped(download);
- }
-
- // Check additional properties on the finished download.
- do_check_true(download.source.referrer === null);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Executes a download with the tryToKeepPartialData property set, and ensures
- * that the file is saved correctly. When testing DownloadLegacySaver, the
- * download is executed using the nsIExternalHelperAppService component.
- */
-add_task(function* test_basic_tryToKeepPartialData()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
- continueResponses();
- yield promiseDownloadStopped(download);
-
- // The target file should now have been created, and the ".part" file deleted.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_eq(32, download.saver.getSha256Hash().length);
-});
-
-/**
- * Tests the permissions of the final target file once the download finished.
- */
-add_task(function* test_unix_permissions()
-{
- // This test is only executed on some Desktop systems.
- if (Services.appinfo.OS != "Darwin" && Services.appinfo.OS != "Linux" &&
- Services.appinfo.OS != "WINNT") {
- do_print("Skipping test.");
- return;
- }
-
- let launcherPath = getTempFile("app-launcher").path;
-
- for (let autoDelete of [false, true]) {
- for (let isPrivate of [false, true]) {
- for (let launchWhenSucceeded of [false, true]) {
- do_print("Checking " + JSON.stringify({ autoDelete,
- isPrivate,
- launchWhenSucceeded }));
-
- Services.prefs.setBoolPref(kDeleteTempFileOnExit, autoDelete);
-
- let download;
- if (!gUseLegacySaver) {
- download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- launchWhenSucceeded,
- launcherPath,
- });
- yield download.start();
- } else {
- download = yield promiseStartLegacyDownload(httpUrl("source.txt"), {
- isPrivate,
- launchWhenSucceeded,
- launcherPath: launchWhenSucceeded && launcherPath,
- });
- yield promiseDownloadStopped(download);
- }
-
- let isTemporary = launchWhenSucceeded && (autoDelete || isPrivate);
- let stat = yield OS.File.stat(download.target.path);
- if (Services.appinfo.OS == "WINNT") {
- // On Windows
- // Temporary downloads should be read-only
- do_check_eq(stat.winAttributes.readOnly, isTemporary ? true : false);
- } else {
- // On Linux, Mac
- // Temporary downloads should be read-only and not accessible to other
- // users, while permanently downloaded files should be readable and
- // writable as specified by the system umask.
- do_check_eq(stat.unixMode,
- isTemporary ? 0o400 : (0o666 & ~OS.Constants.Sys.umask));
- }
- }
- }
- }
-
- // Clean up the changes to the preference.
- Services.prefs.clearUserPref(kDeleteTempFileOnExit);
-});
-
-/**
- * Checks the referrer for downloads.
- */
-add_task(function* test_referrer()
-{
- let sourcePath = "/test_referrer.txt";
- let sourceUrl = httpUrl("test_referrer.txt");
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
-
- function cleanup() {
- gHttpServer.registerPathHandler(sourcePath, null);
- }
- do_register_cleanup(cleanup);
-
- gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
-
- do_check_true(aRequest.hasHeader("Referer"));
- do_check_eq(aRequest.getHeader("Referer"), TEST_REFERRER_URL);
- });
- let download = yield Downloads.createDownload({
- source: { url: sourceUrl, referrer: TEST_REFERRER_URL },
- target: targetPath,
- });
- do_check_eq(download.source.referrer, TEST_REFERRER_URL);
- yield download.start();
-
- download = yield Downloads.createDownload({
- source: { url: sourceUrl, referrer: TEST_REFERRER_URL,
- isPrivate: true },
- target: targetPath,
- });
- do_check_eq(download.source.referrer, TEST_REFERRER_URL);
- yield download.start();
-
- // Test the download still works for non-HTTP channel with referrer.
- sourceUrl = "data:text/html,";
- download = yield Downloads.createDownload({
- source: { url: sourceUrl, referrer: TEST_REFERRER_URL },
- target: targetPath,
- });
- do_check_eq(download.source.referrer, TEST_REFERRER_URL);
- yield download.start();
-
- cleanup();
-});
-
-/**
- * Checks the adjustChannel callback for downloads.
- */
-add_task(function* test_adjustChannel()
-{
- const sourcePath = "/test_post.txt";
- const sourceUrl = httpUrl("test_post.txt");
- const targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- const customHeader = { name: "X-Answer", value: "42" };
- const postData = "Don't Panic";
-
- function cleanup() {
- gHttpServer.registerPathHandler(sourcePath, null);
- }
- do_register_cleanup(cleanup);
-
- gHttpServer.registerPathHandler(sourcePath, aRequest => {
- do_check_eq(aRequest.method, "POST");
-
- do_check_true(aRequest.hasHeader(customHeader.name));
- do_check_eq(aRequest.getHeader(customHeader.name), customHeader.value);
-
- const stream = aRequest.bodyInputStream;
- const body = NetUtil.readInputStreamToString(stream, stream.available());
- do_check_eq(body, postData);
- });
-
- function adjustChannel(channel) {
- channel.QueryInterface(Ci.nsIHttpChannel);
- channel.setRequestHeader(customHeader.name, customHeader.value, false);
-
- const stream = Cc["@mozilla.org/io/string-input-stream;1"]
- .createInstance(Ci.nsIStringInputStream);
- stream.setData(postData, postData.length);
-
- channel.QueryInterface(Ci.nsIUploadChannel2);
- channel.explicitSetUploadStream(stream, null, -1, "POST", false);
-
- return Promise.resolve();
- }
-
- const download = yield Downloads.createDownload({
- source: { url: sourceUrl, adjustChannel },
- target: targetPath,
- });
- do_check_eq(download.source.adjustChannel, adjustChannel);
- do_check_eq(download.toSerializable(), null);
- yield download.start();
-
- cleanup();
-});
-
-/**
- * Checks initial and final state and progress for a successful download.
- */
-add_task(function* test_initial_final_state()
-{
- let download;
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we have control over the download, thus
- // we can check its state before it starts.
- download = yield promiseNewDownload();
-
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
- do_check_eq(download.progress, 0);
- do_check_true(download.startTime === null);
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, the download is already started when it
- // is created, thus we cannot check its initial state.
- download = yield promiseStartLegacyDownload();
- yield promiseDownloadStopped(download);
- }
-
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
- do_check_eq(download.progress, 100);
- do_check_true(isValidDate(download.startTime));
- do_check_true(download.target.exists);
- do_check_eq(download.target.size, TEST_DATA_SHORT.length);
-});
-
-/**
- * Checks the notification of the final download state.
- */
-add_task(function* test_final_state_notified()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- let onchangeNotified = false;
- let lastNotifiedStopped;
- let lastNotifiedProgress;
- download.onchange = function () {
- onchangeNotified = true;
- lastNotifiedStopped = download.stopped;
- lastNotifiedProgress = download.progress;
- };
-
- // Allow the download to complete.
- let promiseAttempt = download.start();
- continueResponses();
- yield promiseAttempt;
-
- // The view should have been notified before the download completes.
- do_check_true(onchangeNotified);
- do_check_true(lastNotifiedStopped);
- do_check_eq(lastNotifiedProgress, 100);
-});
-
-/**
- * Checks intermediate progress for a successful download.
- */
-add_task(function* test_intermediate_progress()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- yield promiseDownloadMidway(download);
-
- do_check_true(download.hasProgress);
- do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
- do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
-
- // The final file size should not be computed for in-progress downloads.
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- // Continue after the first chunk of data is fully received.
- continueResponses();
- yield promiseDownloadStopped(download);
-
- do_check_true(download.stopped);
- do_check_eq(download.progress, 100);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Downloads a file with a "Content-Length" of 0 and checks the progress.
- */
-add_task(function* test_empty_progress()
-{
- let download = yield promiseStartDownload(httpUrl("empty.txt"));
- yield promiseDownloadStopped(download);
-
- do_check_true(download.stopped);
- do_check_true(download.hasProgress);
- do_check_eq(download.progress, 100);
- do_check_eq(download.currentBytes, 0);
- do_check_eq(download.totalBytes, 0);
-
- // We should have received the content type even for an empty file.
- do_check_eq(download.contentType, "text/plain");
-
- do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
- do_check_true(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * Downloads a file with a "Content-Length" of 0 with the tryToKeepPartialData
- * property set, and ensures that the file is saved correctly.
- */
-add_task(function* test_empty_progress_tryToKeepPartialData()
-{
- // Start a new download and configure it to keep partially downloaded data.
- let download;
- if (!gUseLegacySaver) {
- let targetFilePath = getTempFile(TEST_TARGET_FILE_NAME).path;
- download = yield Downloads.createDownload({
- source: httpUrl("empty.txt"),
- target: { path: targetFilePath,
- partFilePath: targetFilePath + ".part" },
- });
- download.tryToKeepPartialData = true;
- download.start().catch(() => {});
- } else {
- // Start a download using nsIExternalHelperAppService, that is configured
- // to keep partially downloaded data by default.
- download = yield promiseStartExternalHelperAppServiceDownload(
- httpUrl("empty.txt"));
- }
- yield promiseDownloadStopped(download);
-
- // The target file should now have been created, and the ".part" file deleted.
- do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
- do_check_true(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_eq(32, download.saver.getSha256Hash().length);
-});
-
-/**
- * Downloads an empty file with no "Content-Length" and checks the progress.
- */
-add_task(function* test_empty_noprogress()
-{
- let sourcePath = "/test_empty_noprogress.txt";
- let sourceUrl = httpUrl("test_empty_noprogress.txt");
- let deferRequestReceived = Promise.defer();
-
- // Register an interruptible handler that notifies us when the request occurs.
- function cleanup() {
- gHttpServer.registerPathHandler(sourcePath, null);
- }
- do_register_cleanup(cleanup);
-
- registerInterruptibleHandler(sourcePath,
- function firstPart(aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
- deferRequestReceived.resolve();
- }, function secondPart(aRequest, aResponse) { });
-
- // Start the download, without allowing the request to finish.
- mustInterruptResponses();
- let download;
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we have control over the download, thus
- // we can hook its onchange callback that will be notified when the
- // download starts.
- download = yield promiseNewDownload(sourceUrl);
-
- download.onchange = function () {
- if (!download.stopped) {
- do_check_false(download.hasProgress);
- do_check_eq(download.currentBytes, 0);
- do_check_eq(download.totalBytes, 0);
- }
- };
-
- download.start().catch(() => {});
- } else {
- // When testing DownloadLegacySaver, the download is already started when it
- // is created, and it may have already made all needed property change
- // notifications, thus there is no point in checking the onchange callback.
- download = yield promiseStartLegacyDownload(sourceUrl);
- }
-
- // Wait for the request to be received by the HTTP server, but don't allow the
- // request to finish yet. Before checking the download state, wait for the
- // events to be processed by the client.
- yield deferRequestReceived.promise;
- yield promiseExecuteSoon();
-
- // Check that this download has no progress report.
- do_check_false(download.stopped);
- do_check_false(download.hasProgress);
- do_check_eq(download.currentBytes, 0);
- do_check_eq(download.totalBytes, 0);
-
- // Now allow the response to finish.
- continueResponses();
- yield promiseDownloadStopped(download);
-
- // We should have received the content type even if no progress is reported.
- do_check_eq(download.contentType, "text/plain");
-
- // Verify the state of the completed download.
- do_check_true(download.stopped);
- do_check_false(download.hasProgress);
- do_check_eq(download.progress, 100);
- do_check_eq(download.currentBytes, 0);
- do_check_eq(download.totalBytes, 0);
- do_check_true(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
-});
-
-/**
- * Calls the "start" method two times before the download is finished.
- */
-add_task(function* test_start_twice()
-{
- mustInterruptResponses();
-
- let download;
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we have control over the download, thus
- // we can start the download later during the test.
- download = yield promiseNewDownload(httpUrl("interruptible.txt"));
- } else {
- // When testing DownloadLegacySaver, the download is already started when it
- // is created. Effectively, we are starting the download three times.
- download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"));
- }
-
- // Call the start method two times.
- let promiseAttempt1 = download.start();
- let promiseAttempt2 = download.start();
-
- // Allow the download to finish.
- continueResponses();
-
- // Both promises should now be resolved.
- yield promiseAttempt1;
- yield promiseAttempt2;
-
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download and verifies that its state is reported correctly.
- */
-add_task(function* test_cancel_midway()
-{
- mustInterruptResponses();
-
- // In this test case, we execute different checks that are only possible with
- // DownloadCopySaver or DownloadLegacySaver respectively.
- let download;
- let options = {};
- if (!gUseLegacySaver) {
- download = yield promiseNewDownload(httpUrl("interruptible.txt"));
- } else {
- download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"),
- options);
- }
-
- // Cancel the download after receiving the first part of the response.
- let deferCancel = Promise.defer();
- let onchange = function () {
- if (!download.stopped && !download.canceled && download.progress == 50) {
- // Cancel the download immediately during the notification.
- deferCancel.resolve(download.cancel());
-
- // The state change happens immediately after calling "cancel", but
- // temporary files or part files may still exist at this point.
- do_check_true(download.canceled);
- }
- };
-
- // Register for the notification, but also call the function directly in
- // case the download already reached the expected progress. This may happen
- // when using DownloadLegacySaver.
- download.onchange = onchange;
- onchange();
-
- let promiseAttempt;
- if (!gUseLegacySaver) {
- promiseAttempt = download.start();
- }
-
- // Wait on the promise returned by the "cancel" method to ensure that the
- // cancellation process finished and temporary files were removed.
- yield deferCancel.promise;
-
- if (gUseLegacySaver) {
- // The nsIWebBrowserPersist instance should have been canceled now.
- do_check_eq(options.outPersist.result, Cr.NS_ERROR_ABORT);
- }
-
- do_check_true(download.stopped);
- do_check_true(download.canceled);
- do_check_true(download.error === null);
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- do_check_false(yield OS.File.exists(download.target.path));
-
- // Progress properties are not reset by canceling.
- do_check_eq(download.progress, 50);
- do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
-
- if (!gUseLegacySaver) {
- // The promise returned by "start" should have been rejected meanwhile.
- try {
- yield promiseAttempt;
- do_throw("The download should have been canceled.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error)) {
- throw ex;
- }
- do_check_false(ex.becauseSourceFailed);
- do_check_false(ex.becauseTargetFailed);
- }
- }
-});
-
-/**
- * Cancels a download while keeping partially downloaded data, and verifies that
- * both the target file and the ".part" file are deleted.
- */
-add_task(function* test_cancel_midway_tryToKeepPartialData()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
-
- do_check_true(yield OS.File.exists(download.target.path));
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- yield download.cancel();
- yield download.removePartialData();
-
- do_check_true(download.stopped);
- do_check_true(download.canceled);
- do_check_true(download.error === null);
-
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Cancels a download right after starting it.
- */
-add_task(function* test_cancel_immediately()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- let promiseAttempt = download.start();
- do_check_false(download.stopped);
-
- let promiseCancel = download.cancel();
- do_check_true(download.canceled);
-
- // At this point, we don't know whether the download has already stopped or
- // is still waiting for cancellation. We can wait on the promise returned
- // by the "start" method to know for sure.
- try {
- yield promiseAttempt;
- do_throw("The download should have been canceled.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error)) {
- throw ex;
- }
- do_check_false(ex.becauseSourceFailed);
- do_check_false(ex.becauseTargetFailed);
- }
-
- do_check_true(download.stopped);
- do_check_true(download.canceled);
- do_check_true(download.error === null);
-
- do_check_false(yield OS.File.exists(download.target.path));
-
- // Check that the promise returned by the "cancel" method has been resolved.
- yield promiseCancel;
-});
-
-/**
- * Cancels and restarts a download sequentially.
- */
-add_task(function* test_cancel_midway_restart()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- // The first time, cancel the download midway.
- yield promiseDownloadMidway(download);
- yield download.cancel();
-
- do_check_true(download.stopped);
-
- // The second time, we'll provide the entire interruptible response.
- continueResponses();
- download.onchange = null;
- let promiseAttempt = download.start();
-
- // Download state should have already been reset.
- do_check_false(download.stopped);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- // For the following test, we rely on the network layer reporting its progress
- // asynchronously. Otherwise, there is nothing stopping the restarted
- // download from reaching the same progress as the first request already.
- do_check_eq(download.progress, 0);
- do_check_eq(download.totalBytes, 0);
- do_check_eq(download.currentBytes, 0);
-
- yield promiseAttempt;
-
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download and restarts it from where it stopped.
- */
-add_task(function* test_cancel_midway_restart_tryToKeepPartialData()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.cancel();
-
- do_check_true(download.stopped);
- do_check_true(download.hasPartialData);
-
- // The target file should not exist, but we should have kept the partial data.
- do_check_false(yield OS.File.exists(download.target.path));
- yield promiseVerifyContents(download.target.partFilePath, TEST_DATA_SHORT);
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- // Verify that the server sent the response from the start.
- do_check_eq(gMostRecentFirstBytePos, 0);
-
- // The second time, we'll request and obtain the second part of the response,
- // but we still stop when half of the remaining progress is reached.
- let deferMidway = Promise.defer();
- download.onchange = function () {
- if (!download.stopped && !download.canceled &&
- download.currentBytes == Math.floor(TEST_DATA_SHORT.length * 3 / 2)) {
- download.onchange = null;
- deferMidway.resolve();
- }
- };
-
- mustInterruptResponses();
- let promiseAttempt = download.start();
-
- // Continue when the number of bytes we received is correct, then check that
- // progress is at about 75 percent. The exact figure may vary because of
- // rounding issues, since the total number of bytes in the response might not
- // be a multiple of four.
- yield deferMidway.promise;
- do_check_true(download.progress > 72 && download.progress < 78);
-
- // Now we allow the download to finish.
- continueResponses();
- yield promiseAttempt;
-
- // Check that the server now sent the second part only.
- do_check_eq(gMostRecentFirstBytePos, TEST_DATA_SHORT.length);
-
- // The target file should now have been created, and the ".part" file deleted.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Cancels a download while keeping partially downloaded data, then removes the
- * data and restarts the download from the beginning.
- */
-add_task(function* test_cancel_midway_restart_removePartialData()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.cancel();
-
- do_check_true(download.hasPartialData);
- yield promiseVerifyContents(download.target.partFilePath, TEST_DATA_SHORT);
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- yield download.removePartialData();
-
- do_check_false(download.hasPartialData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- // The second time, we'll request and obtain the entire response again.
- continueResponses();
- yield download.start();
-
- // Verify that the server sent the response from the start.
- do_check_eq(gMostRecentFirstBytePos, 0);
-
- // The target file should now have been created, and the ".part" file deleted.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Cancels a download while keeping partially downloaded data, then removes the
- * data and restarts the download from the beginning without keeping the partial
- * data anymore.
- */
-add_task(function* test_cancel_midway_restart_tryToKeepPartialData_false()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.cancel();
-
- download.tryToKeepPartialData = false;
-
- // The above property change does not affect existing partial data.
- do_check_true(download.hasPartialData);
- yield promiseVerifyContents(download.target.partFilePath, TEST_DATA_SHORT);
-
- yield download.removePartialData();
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-
- // Restart the download from the beginning.
- mustInterruptResponses();
- download.start().catch(() => {});
-
- yield promiseDownloadMidway(download);
- yield promisePartFileReady(download);
-
- // While the download is in progress, we should still have a ".part" file.
- do_check_false(download.hasPartialData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- // On Unix, verify that the file with the partially downloaded data is not
- // accessible by other users on the system.
- if (Services.appinfo.OS == "Darwin" || Services.appinfo.OS == "Linux") {
- do_check_eq((yield OS.File.stat(download.target.partFilePath)).unixMode,
- 0o600);
- }
-
- yield download.cancel();
-
- // The ".part" file should be deleted now that the download is canceled.
- do_check_false(download.hasPartialData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-
- // The third time, we'll request and obtain the entire response again.
- continueResponses();
- yield download.start();
-
- // Verify that the server sent the response from the start.
- do_check_eq(gMostRecentFirstBytePos, 0);
-
- // The target file should now have been created, and the ".part" file deleted.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Cancels a download right after starting it, then restarts it immediately.
- */
-add_task(function* test_cancel_immediately_restart_immediately()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
- let promiseAttempt = download.start();
-
- do_check_false(download.stopped);
-
- download.cancel();
- do_check_true(download.canceled);
-
- let promiseRestarted = download.start();
- do_check_false(download.stopped);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- // For the following test, we rely on the network layer reporting its progress
- // asynchronously. Otherwise, there is nothing stopping the restarted
- // download from reaching the same progress as the first request already.
- do_check_eq(download.hasProgress, false);
- do_check_eq(download.progress, 0);
- do_check_eq(download.totalBytes, 0);
- do_check_eq(download.currentBytes, 0);
-
- // Ensure the next request is now allowed to complete, regardless of whether
- // the canceled request was received by the server or not.
- continueResponses();
- try {
- yield promiseAttempt;
- // If we get here, it means that the first attempt actually succeeded. In
- // fact, this could be a valid outcome, because the cancellation request may
- // not have been processed in time before the download finished.
- do_print("The download should have been canceled.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error)) {
- throw ex;
- }
- do_check_false(ex.becauseSourceFailed);
- do_check_false(ex.becauseTargetFailed);
- }
-
- yield promiseRestarted;
-
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download midway, then restarts it immediately.
- */
-add_task(function* test_cancel_midway_restart_immediately()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
- let promiseAttempt = download.start();
-
- // The first time, cancel the download midway.
- yield promiseDownloadMidway(download);
- download.cancel();
- do_check_true(download.canceled);
-
- let promiseRestarted = download.start();
- do_check_false(download.stopped);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- // For the following test, we rely on the network layer reporting its progress
- // asynchronously. Otherwise, there is nothing stopping the restarted
- // download from reaching the same progress as the first request already.
- do_check_eq(download.hasProgress, false);
- do_check_eq(download.progress, 0);
- do_check_eq(download.totalBytes, 0);
- do_check_eq(download.currentBytes, 0);
-
- // The second request is allowed to complete.
- continueResponses();
- try {
- yield promiseAttempt;
- do_throw("The download should have been canceled.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error)) {
- throw ex;
- }
- do_check_false(ex.becauseSourceFailed);
- do_check_false(ex.becauseTargetFailed);
- }
-
- yield promiseRestarted;
-
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Calls the "cancel" method on a successful download.
- */
-add_task(function* test_cancel_successful()
-{
- let download = yield promiseStartDownload();
- yield promiseDownloadStopped(download);
-
- // The cancel method should succeed with no effect.
- yield download.cancel();
-
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Calls the "cancel" method two times in a row.
- */
-add_task(function* test_cancel_twice()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- let promiseAttempt = download.start();
- do_check_false(download.stopped);
-
- let promiseCancel1 = download.cancel();
- do_check_true(download.canceled);
- let promiseCancel2 = download.cancel();
-
- try {
- yield promiseAttempt;
- do_throw("The download should have been canceled.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error)) {
- throw ex;
- }
- do_check_false(ex.becauseSourceFailed);
- do_check_false(ex.becauseTargetFailed);
- }
-
- // Both promises should now be resolved.
- yield promiseCancel1;
- yield promiseCancel2;
-
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_true(download.canceled);
- do_check_true(download.error === null);
-
- do_check_false(yield OS.File.exists(download.target.path));
-});
-
-/**
- * Checks the "refresh" method for succeeded downloads.
- */
-add_task(function* test_refresh_succeeded()
-{
- let download = yield promiseStartDownload();
- yield promiseDownloadStopped(download);
-
- // The DownloadTarget properties should be the same after calling "refresh".
- yield download.refresh();
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-
- // If the file is removed, only the "exists" property should change, and the
- // "size" property should keep its previous value.
- yield OS.File.move(download.target.path, download.target.path + ".old");
- yield download.refresh();
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, TEST_DATA_SHORT.length);
-
- // The DownloadTarget properties should be restored when the file is put back.
- yield OS.File.move(download.target.path + ".old", download.target.path);
- yield download.refresh();
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Checks that a download cannot be restarted after the "finalize" method.
- */
-add_task(function* test_finalize()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- let promiseFinalized = download.finalize();
-
- try {
- yield download.start();
- do_throw("It should not be possible to restart after finalization.");
- } catch (ex) { }
-
- yield promiseFinalized;
-
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_true(download.canceled);
- do_check_true(download.error === null);
-
- do_check_false(yield OS.File.exists(download.target.path));
-});
-
-/**
- * Checks that the "finalize" method can remove partially downloaded data.
- */
-add_task(function* test_finalize_tryToKeepPartialData()
-{
- // Check finalization without removing partial data.
- let download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.finalize();
-
- do_check_true(download.hasPartialData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- // Clean up.
- yield download.removePartialData();
-
- // Check finalization while removing partial data.
- download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.finalize(true);
-
- do_check_false(download.hasPartialData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Checks that whenSucceeded returns a promise that is resolved after a restart.
- */
-add_task(function* test_whenSucceeded_after_restart()
-{
- mustInterruptResponses();
-
- let promiseSucceeded;
-
- let download;
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we have control over the download, thus
- // we can verify getting a reference before the first download attempt.
- download = yield promiseNewDownload(httpUrl("interruptible.txt"));
- promiseSucceeded = download.whenSucceeded();
- download.start().catch(() => {});
- } else {
- // When testing DownloadLegacySaver, the download is already started when it
- // is created, thus we cannot get the reference before the first attempt.
- download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"));
- promiseSucceeded = download.whenSucceeded();
- }
-
- // Cancel the first download attempt.
- yield download.cancel();
-
- // The second request is allowed to complete.
- continueResponses();
- download.start().catch(() => {});
-
- // Wait for the download to finish by waiting on the whenSucceeded promise.
- yield promiseSucceeded;
-
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Ensures download error details are reported on network failures.
- */
-add_task(function* test_error_source()
-{
- let serverSocket = startFakeServer();
- try {
- let sourceUrl = "http://localhost:" + serverSocket.port + "/source.txt";
-
- let download;
- try {
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we want to check that the promise
- // returned by the "start" method is rejected.
- download = yield promiseNewDownload(sourceUrl);
-
- do_check_true(download.error === null);
-
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, we cannot be sure whether we are
- // testing the promise returned by the "start" method or we are testing
- // the "error" property checked by promiseDownloadStopped. This happens
- // because we don't have control over when the download is started.
- download = yield promiseStartLegacyDownload(sourceUrl);
- yield promiseDownloadStopped(download);
- }
- do_throw("The download should have failed.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseSourceFailed) {
- throw ex;
- }
- // A specific error object is thrown when reading from the source fails.
- }
-
- // Check the properties now that the download stopped.
- do_check_true(download.stopped);
- do_check_false(download.canceled);
- do_check_true(download.error !== null);
- do_check_true(download.error.becauseSourceFailed);
- do_check_false(download.error.becauseTargetFailed);
-
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
- } finally {
- serverSocket.close();
- }
-});
-
-/**
- * Ensures a download error is reported when receiving less bytes than what was
- * specified in the Content-Length header.
- */
-add_task(function* test_error_source_partial()
-{
- let sourceUrl = httpUrl("shorter-than-content-length-http-1-1.txt");
-
- let enforcePref = Services.prefs.getBoolPref("network.http.enforce-framing.http1");
- Services.prefs.setBoolPref("network.http.enforce-framing.http1", true);
-
- function cleanup() {
- Services.prefs.setBoolPref("network.http.enforce-framing.http1", enforcePref);
- }
- do_register_cleanup(cleanup);
-
- let download;
- try {
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we want to check that the promise
- // returned by the "start" method is rejected.
- download = yield promiseNewDownload(sourceUrl);
-
- do_check_true(download.error === null);
-
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, we cannot be sure whether we are
- // testing the promise returned by the "start" method or we are testing
- // the "error" property checked by promiseDownloadStopped. This happens
- // because we don't have control over when the download is started.
- download = yield promiseStartLegacyDownload(sourceUrl);
- yield promiseDownloadStopped(download);
- }
- do_throw("The download should have failed.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseSourceFailed) {
- throw ex;
- }
- // A specific error object is thrown when reading from the source fails.
- }
-
- // Check the properties now that the download stopped.
- do_check_true(download.stopped);
- do_check_false(download.canceled);
- do_check_true(download.error !== null);
- do_check_true(download.error.becauseSourceFailed);
- do_check_false(download.error.becauseTargetFailed);
- do_check_eq(download.error.result, Cr.NS_ERROR_NET_PARTIAL_TRANSFER);
-
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * Ensures download error details are reported on local writing failures.
- */
-add_task(function* test_error_target()
-{
- // Create a file without write access permissions before downloading.
- let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
- targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
- try {
- let download;
- try {
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we want to check that the promise
- // returned by the "start" method is rejected.
- download = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: targetFile,
- });
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, we cannot be sure whether we are
- // testing the promise returned by the "start" method or we are testing
- // the "error" property checked by promiseDownloadStopped. This happens
- // because we don't have control over when the download is started.
- download = yield promiseStartLegacyDownload(null,
- { targetFile: targetFile });
- yield promiseDownloadStopped(download);
- }
- do_throw("The download should have failed.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseTargetFailed) {
- throw ex;
- }
- // A specific error object is thrown when writing to the target fails.
- }
-
- // Check the properties now that the download stopped.
- do_check_true(download.stopped);
- do_check_false(download.canceled);
- do_check_true(download.error !== null);
- do_check_true(download.error.becauseTargetFailed);
- do_check_false(download.error.becauseSourceFailed);
- } finally {
- // Restore the default permissions to allow deleting the file on Windows.
- if (targetFile.exists()) {
- targetFile.permissions = FileUtils.PERMS_FILE;
- targetFile.remove(false);
- }
- }
-});
-
-/**
- * Restarts a failed download.
- */
-add_task(function* test_error_restart()
-{
- let download;
-
- // Create a file without write access permissions before downloading.
- let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
- targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
- try {
- // Use DownloadCopySaver or DownloadLegacySaver based on the test run,
- // specifying the target file we created.
- if (!gUseLegacySaver) {
- download = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: targetFile,
- });
- download.start().catch(() => {});
- } else {
- download = yield promiseStartLegacyDownload(null,
- { targetFile: targetFile });
- }
- yield promiseDownloadStopped(download);
- do_throw("The download should have failed.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseTargetFailed) {
- throw ex;
- }
- // A specific error object is thrown when writing to the target fails.
- } finally {
- // Restore the default permissions to allow deleting the file on Windows.
- if (targetFile.exists()) {
- targetFile.permissions = FileUtils.PERMS_FILE;
-
- // Also for Windows, rename the file before deleting. This makes the
- // current file name available immediately for a new file, while deleting
- // in place prevents creation of a file with the same name for some time.
- targetFile.moveTo(null, targetFile.leafName + ".delete.tmp");
- targetFile.remove(false);
- }
- }
-
- // Restart the download and wait for completion.
- yield download.start();
-
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.canceled);
- do_check_true(download.error === null);
- do_check_eq(download.progress, 100);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Executes download in both public and private modes.
- */
-add_task(function* test_public_and_private()
-{
- let sourcePath = "/test_public_and_private.txt";
- let sourceUrl = httpUrl("test_public_and_private.txt");
- let testCount = 0;
-
- // Apply pref to allow all cookies.
- Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
-
- function cleanup() {
- Services.prefs.clearUserPref("network.cookie.cookieBehavior");
- Services.cookies.removeAll();
- gHttpServer.registerPathHandler(sourcePath, null);
- }
- do_register_cleanup(cleanup);
-
- gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
-
- if (testCount == 0) {
- // No cookies should exist for first public download.
- do_check_false(aRequest.hasHeader("Cookie"));
- aResponse.setHeader("Set-Cookie", "foobar=1", false);
- testCount++;
- } else if (testCount == 1) {
- // The cookie should exists for second public download.
- do_check_true(aRequest.hasHeader("Cookie"));
- do_check_eq(aRequest.getHeader("Cookie"), "foobar=1");
- testCount++;
- } else if (testCount == 2) {
- // No cookies should exist for first private download.
- do_check_false(aRequest.hasHeader("Cookie"));
- }
- });
-
- let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
- yield Downloads.fetch(sourceUrl, targetFile);
- yield Downloads.fetch(sourceUrl, targetFile);
-
- if (!gUseLegacySaver) {
- let download = yield Downloads.createDownload({
- source: { url: sourceUrl, isPrivate: true },
- target: targetFile,
- });
- yield download.start();
- } else {
- let download = yield promiseStartLegacyDownload(sourceUrl,
- { isPrivate: true });
- yield promiseDownloadStopped(download);
- }
-
- cleanup();
-});
-
-/**
- * Checks the startTime gets updated even after a restart.
- */
-add_task(function* test_cancel_immediately_restart_and_check_startTime()
-{
- let download = yield promiseStartDownload();
-
- let startTime = download.startTime;
- do_check_true(isValidDate(download.startTime));
-
- yield download.cancel();
- do_check_eq(download.startTime.getTime(), startTime.getTime());
-
- // Wait for a timeout.
- yield promiseTimeout(10);
-
- yield download.start();
- do_check_true(download.startTime.getTime() > startTime.getTime());
-});
-
-/**
- * Executes download with content-encoding.
- */
-add_task(function* test_with_content_encoding()
-{
- let sourcePath = "/test_with_content_encoding.txt";
- let sourceUrl = httpUrl("test_with_content_encoding.txt");
-
- function cleanup() {
- gHttpServer.registerPathHandler(sourcePath, null);
- }
- do_register_cleanup(cleanup);
-
- gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
- aResponse.setHeader("Content-Encoding", "gzip", false);
- aResponse.setHeader("Content-Length",
- "" + TEST_DATA_SHORT_GZIP_ENCODED.length, false);
-
- let bos = new BinaryOutputStream(aResponse.bodyOutputStream);
- bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED,
- TEST_DATA_SHORT_GZIP_ENCODED.length);
- });
-
- let download = yield promiseStartDownload(sourceUrl);
- yield promiseDownloadStopped(download);
-
- do_check_eq(download.progress, 100);
- do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
-
- // Ensure the content matches the decoded test data.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-
- cleanup();
-});
-
-/**
- * Checks that the file is not decoded if the extension matches the encoding.
- */
-add_task(function* test_with_content_encoding_ignore_extension()
-{
- let sourcePath = "/test_with_content_encoding_ignore_extension.gz";
- let sourceUrl = httpUrl("test_with_content_encoding_ignore_extension.gz");
-
- function cleanup() {
- gHttpServer.registerPathHandler(sourcePath, null);
- }
- do_register_cleanup(cleanup);
-
- gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
- aResponse.setHeader("Content-Encoding", "gzip", false);
- aResponse.setHeader("Content-Length",
- "" + TEST_DATA_SHORT_GZIP_ENCODED.length, false);
-
- let bos = new BinaryOutputStream(aResponse.bodyOutputStream);
- bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED,
- TEST_DATA_SHORT_GZIP_ENCODED.length);
- });
-
- let download = yield promiseStartDownload(sourceUrl);
- yield promiseDownloadStopped(download);
-
- do_check_eq(download.progress, 100);
- do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
- do_check_eq(download.target.size, TEST_DATA_SHORT_GZIP_ENCODED.length);
-
- // Ensure the content matches the encoded test data. We convert the data to a
- // string before executing the content check.
- yield promiseVerifyTarget(download.target,
- String.fromCharCode.apply(String, TEST_DATA_SHORT_GZIP_ENCODED));
-
- cleanup();
-});
-
-/**
- * Cancels and restarts a download sequentially with content-encoding.
- */
-add_task(function* test_cancel_midway_restart_with_content_encoding()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible_gzip.txt"));
-
- // The first time, cancel the download midway.
- let deferCancel = Promise.defer();
- let onchange = function () {
- if (!download.stopped && !download.canceled &&
- download.currentBytes == TEST_DATA_SHORT_GZIP_ENCODED_FIRST.length) {
- deferCancel.resolve(download.cancel());
- }
- };
-
- // Register for the notification, but also call the function directly in
- // case the download already reached the expected progress.
- download.onchange = onchange;
- onchange();
-
- yield deferCancel.promise;
-
- do_check_true(download.stopped);
-
- // The second time, we'll provide the entire interruptible response.
- continueResponses();
- download.onchange = null;
- yield download.start();
-
- do_check_eq(download.progress, 100);
- do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Download with parental controls enabled.
- */
-add_task(function* test_blocked_parental_controls()
-{
- let blockFn = base => ({
- shouldBlockForParentalControls: () => Promise.resolve(true),
- });
-
- Integration.downloads.register(blockFn);
- function cleanup() {
- Integration.downloads.unregister(blockFn);
- }
- do_register_cleanup(cleanup);
-
- let download;
- try {
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we want to check that the promise
- // returned by the "start" method is rejected.
- download = yield promiseNewDownload();
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, we cannot be sure whether we are
- // testing the promise returned by the "start" method or we are testing
- // the "error" property checked by promiseDownloadStopped. This happens
- // because we don't have control over when the download is started.
- download = yield promiseStartLegacyDownload();
- yield promiseDownloadStopped(download);
- }
- do_throw("The download should have blocked.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
- throw ex;
- }
- do_check_true(ex.becauseBlockedByParentalControls);
- do_check_true(download.error.becauseBlockedByParentalControls);
- }
-
- // Now that the download stopped, the target file should not exist.
- do_check_false(yield OS.File.exists(download.target.path));
-
- cleanup();
-});
-
-/**
- * Test a download that will be blocked by Windows parental controls by
- * resulting in an HTTP status code of 450.
- */
-add_task(function* test_blocked_parental_controls_httpstatus450()
-{
- let download;
- try {
- if (!gUseLegacySaver) {
- download = yield promiseNewDownload(httpUrl("parentalblocked.zip"));
- yield download.start();
- }
- else {
- download = yield promiseStartLegacyDownload(httpUrl("parentalblocked.zip"));
- yield promiseDownloadStopped(download);
- }
- do_throw("The download should have blocked.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
- throw ex;
- }
- do_check_true(ex.becauseBlockedByParentalControls);
- do_check_true(download.error.becauseBlockedByParentalControls);
- do_check_true(download.stopped);
- }
-
- do_check_false(yield OS.File.exists(download.target.path));
-});
-
-/**
- * Download with runtime permissions
- */
-add_task(function* test_blocked_runtime_permissions()
-{
- let blockFn = base => ({
- shouldBlockForRuntimePermissions: () => Promise.resolve(true),
- });
-
- Integration.downloads.register(blockFn);
- function cleanup() {
- Integration.downloads.unregister(blockFn);
- }
- do_register_cleanup(cleanup);
-
- let download;
- try {
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we want to check that the promise
- // returned by the "start" method is rejected.
- download = yield promiseNewDownload();
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, we cannot be sure whether we are
- // testing the promise returned by the "start" method or we are testing
- // the "error" property checked by promiseDownloadStopped. This happens
- // because we don't have control over when the download is started.
- download = yield promiseStartLegacyDownload();
- yield promiseDownloadStopped(download);
- }
- do_throw("The download should have blocked.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
- throw ex;
- }
- do_check_true(ex.becauseBlockedByRuntimePermissions);
- do_check_true(download.error.becauseBlockedByRuntimePermissions);
- }
-
- // Now that the download stopped, the target file should not exist.
- do_check_false(yield OS.File.exists(download.target.path));
-
- cleanup();
-});
-
-/**
- * Check that DownloadCopySaver can always retrieve the hash.
- * DownloadLegacySaver can only retrieve the hash when
- * nsIExternalHelperAppService is invoked.
- */
-add_task(function* test_getSha256Hash()
-{
- if (!gUseLegacySaver) {
- let download = yield promiseStartDownload(httpUrl("source.txt"));
- yield promiseDownloadStopped(download);
- do_check_true(download.stopped);
- do_check_eq(32, download.saver.getSha256Hash().length);
- }
-});
-
-/**
- * Create a download which will be reputation blocked.
- *
- * @param options
- * {
- * keepPartialData: bool,
- * keepBlockedData: bool,
- * }
- * @return {Promise}
- * @resolves The reputation blocked download.
- * @rejects JavaScript exception.
- */
-var promiseBlockedDownload = Task.async(function* (options) {
- let blockFn = base => ({
- shouldBlockForReputationCheck: () => Promise.resolve({
- shouldBlock: true,
- verdict: Downloads.Error.BLOCK_VERDICT_UNCOMMON,
- }),
- shouldKeepBlockedData: () => Promise.resolve(options.keepBlockedData),
- });
-
- Integration.downloads.register(blockFn);
- function cleanup() {
- Integration.downloads.unregister(blockFn);
- }
- do_register_cleanup(cleanup);
-
- let download;
-
- try {
- if (options.keepPartialData) {
- download = yield promiseStartDownload_tryToKeepPartialData();
- continueResponses();
- } else if (gUseLegacySaver) {
- download = yield promiseStartLegacyDownload();
- } else {
- download = yield promiseNewDownload();
- yield download.start();
- do_throw("The download should have blocked.");
- }
-
- yield promiseDownloadStopped(download);
- do_throw("The download should have blocked.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
- throw ex;
- }
- do_check_true(ex.becauseBlockedByReputationCheck);
- do_check_eq(ex.reputationCheckVerdict,
- Downloads.Error.BLOCK_VERDICT_UNCOMMON);
- do_check_true(download.error.becauseBlockedByReputationCheck);
- do_check_eq(download.error.reputationCheckVerdict,
- Downloads.Error.BLOCK_VERDICT_UNCOMMON);
- }
-
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(yield OS.File.exists(download.target.path));
-
- cleanup();
- return download;
-});
-
-/**
- * Checks that application reputation blocks the download and the target file
- * does not exist.
- */
-add_task(function* test_blocked_applicationReputation()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: false,
- keepBlockedData: false,
- });
-
- // Now that the download is blocked, the target file should not exist.
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- // There should also be no blocked data in this case
- do_check_false(download.hasBlockedData);
-});
-
-/**
- * Checks that if a download restarts while processing an application reputation
- * request, the status is handled correctly.
- */
-add_task(function* test_blocked_applicationReputation_race()
-{
- let isFirstShouldBlockCall = true;
-
- let blockFn = base => ({
- shouldBlockForReputationCheck(download) {
- if (isFirstShouldBlockCall) {
- isFirstShouldBlockCall = false;
-
- // 2. Cancel and restart the download before the first attempt has a
- // chance to finish.
- download.cancel();
- download.removePartialData();
- download.start();
-
- // 3. Allow the first attempt to finish with a blocked response.
- return Promise.resolve({
- shouldBlock: true,
- verdict: Downloads.Error.BLOCK_VERDICT_UNCOMMON,
- });
- }
-
- // 4/5. Don't block the download the second time. The race condition would
- // occur with the first attempt regardless of whether the second one
- // is blocked, but not blocking here makes the test simpler.
- return Promise.resolve({
- shouldBlock: false,
- verdict: "",
- });
- },
- shouldKeepBlockedData: () => Promise.resolve(true),
- });
-
- Integration.downloads.register(blockFn);
- function cleanup() {
- Integration.downloads.unregister(blockFn);
- }
- do_register_cleanup(cleanup);
-
- let download;
-
- try {
- // 1. Start the download and get a reference to the promise asociated with
- // the first attempt, before allowing the response to continue.
- download = yield promiseStartDownload_tryToKeepPartialData();
- let firstAttempt = promiseDownloadStopped(download);
- continueResponses();
-
- // 4/5. Wait for the first attempt to be completed. The result of this
- // should appear as a cancellation.
- yield firstAttempt;
-
- do_throw("The first attempt should have been canceled.");
- } catch (ex) {
- // The "becauseBlocked" property should be false.
- if (!(ex instanceof Downloads.Error) || ex.becauseBlocked) {
- throw ex;
- }
- }
-
- // 6. Wait for the second attempt to be completed.
- yield promiseDownloadStopped(download);
-
- // 7. At this point, "hasBlockedData" should be false.
- do_check_false(download.hasBlockedData);
-
- cleanup();
-});
-
-/**
- * Checks that application reputation blocks the download but maintains the
- * blocked data, which will be deleted when the block is confirmed.
- */
-add_task(function* test_blocked_applicationReputation_confirmBlock()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- do_check_true(download.hasBlockedData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- yield download.confirmBlock();
-
- // After confirming the block the download should be in a failed state and
- // have no downloaded data left on disk.
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(download.hasBlockedData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * Checks that application reputation blocks the download but maintains the
- * blocked data, which will be used to complete the download when unblocking.
- */
-add_task(function* test_blocked_applicationReputation_unblock()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- do_check_true(download.hasBlockedData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- yield download.unblock();
-
- // After unblocking the download should have succeeded and be
- // present at the final path.
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.hasBlockedData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-
- // The only indication the download was previously blocked is the
- // existence of the error, so we make sure it's still set.
- do_check_true(download.error instanceof Downloads.Error);
- do_check_true(download.error.becauseBlocked);
- do_check_true(download.error.becauseBlockedByReputationCheck);
-});
-
-/**
- * Check that calling cancel on a blocked download will not cause errors
- */
-add_task(function* test_blocked_applicationReputation_cancel()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- // This call should succeed on a blocked download.
- yield download.cancel();
-
- // Calling cancel should not have changed the current state, the download
- // should still be blocked.
- do_check_true(download.error.becauseBlockedByReputationCheck);
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_true(download.hasBlockedData);
-});
-
-/**
- * Checks that unblock and confirmBlock cannot race on a blocked download
- */
-add_task(function* test_blocked_applicationReputation_decisionRace()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- let unblockPromise = download.unblock();
- let confirmBlockPromise = download.confirmBlock();
-
- yield confirmBlockPromise.then(() => {
- do_throw("confirmBlock should have failed.");
- }, () => {});
-
- yield unblockPromise;
-
- // After unblocking the download should have succeeded and be
- // present at the final path.
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.hasBlockedData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_true(yield OS.File.exists(download.target.path));
-
- download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- confirmBlockPromise = download.confirmBlock();
- unblockPromise = download.unblock();
-
- yield unblockPromise.then(() => {
- do_throw("unblock should have failed.");
- }, () => {});
-
- yield confirmBlockPromise;
-
- // After confirming the block the download should be in a failed state and
- // have no downloaded data left on disk.
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(download.hasBlockedData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * Checks that unblocking a blocked download fails if the blocked data has been
- * removed.
- */
-add_task(function* test_blocked_applicationReputation_unblock()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- do_check_true(download.hasBlockedData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- // Remove the blocked data without telling the download.
- yield OS.File.remove(download.target.partFilePath);
-
- let unblockPromise = download.unblock();
- yield unblockPromise.then(() => {
- do_throw("unblock should have failed.");
- }, () => {});
-
- // Even though unblocking failed the download state should have been updated
- // to reflect the lack of blocked data.
- do_check_false(download.hasBlockedData);
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * download.showContainingDirectory() action
- */
-add_task(function* test_showContainingDirectory() {
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
-
- let download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt") },
- target: ""
- });
-
- let promiseDirectoryShown = waitForDirectoryShown();
- yield download.showContainingDirectory();
- let path = yield promiseDirectoryShown;
- try {
- new FileUtils.File(path);
- do_throw("Should have failed because of an invalid path.");
- } catch (ex) {
- if (!(ex instanceof Components.Exception)) {
- throw ex;
- }
- // Invalid paths on Windows are reported with NS_ERROR_FAILURE,
- // but with NS_ERROR_FILE_UNRECOGNIZED_PATH on Mac/Linux
- let validResult = ex.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH ||
- ex.result == Cr.NS_ERROR_FAILURE;
- do_check_true(validResult);
- }
-
- download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt") },
- target: targetPath
- });
-
- promiseDirectoryShown = waitForDirectoryShown();
- download.showContainingDirectory();
- yield promiseDirectoryShown;
-});
-
-/**
- * download.launch() action
- */
-add_task(function* test_launch() {
- let customLauncher = getTempFile("app-launcher");
-
- // Test both with and without setting a custom application.
- for (let launcherPath of [null, customLauncher.path]) {
- let download;
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we have control over the download, thus
- // we can test that file is not launched if download.succeeded is not set.
- download = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- launcherPath: launcherPath,
- launchWhenSucceeded: true
- });
-
- try {
- yield download.launch();
- do_throw("Can't launch download file as it has not completed yet");
- } catch (ex) {
- do_check_eq(ex.message,
- "launch can only be called if the download succeeded");
- }
-
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, the download is already started when
- // it is created, thus we don't test calling "launch" before starting.
- download = yield promiseStartLegacyDownload(
- httpUrl("source.txt"),
- { launcherPath: launcherPath,
- launchWhenSucceeded: true });
- yield promiseDownloadStopped(download);
- }
-
- do_check_true(download.launchWhenSucceeded);
-
- let promiseFileLaunched = waitForFileLaunched();
- download.launch();
- let result = yield promiseFileLaunched;
-
- // Verify that the results match the test case.
- if (!launcherPath) {
- // This indicates that the default handler has been chosen.
- do_check_true(result === null);
- } else {
- // Check the nsIMIMEInfo instance that would have been used for launching.
- do_check_eq(result.preferredAction, Ci.nsIMIMEInfo.useHelperApp);
- do_check_true(result.preferredApplicationHandler
- .QueryInterface(Ci.nsILocalHandlerApp)
- .executable.equals(customLauncher));
- }
- }
-});
-
-/**
- * Test passing an invalid path as the launcherPath property.
- */
-add_task(function* test_launcherPath_invalid() {
- let download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt") },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
- launcherPath: " "
- });
-
- let promiseDownloadLaunched = new Promise(resolve => {
- let waitFn = base => ({
- __proto__: base,
- launchDownload() {
- Integration.downloads.unregister(waitFn);
- let superPromise = super.launchDownload(...arguments);
- resolve(superPromise);
- return superPromise;
- },
- });
- Integration.downloads.register(waitFn);
- });
-
- yield download.start();
- try {
- download.launch();
- yield promiseDownloadLaunched;
- do_throw("Can't launch file with invalid custom launcher")
- } catch (ex) {
- if (!(ex instanceof Components.Exception)) {
- throw ex;
- }
- // Invalid paths on Windows are reported with NS_ERROR_FAILURE,
- // but with NS_ERROR_FILE_UNRECOGNIZED_PATH on Mac/Linux
- let validResult = ex.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH ||
- ex.result == Cr.NS_ERROR_FAILURE;
- do_check_true(validResult);
- }
-});
-
-/**
- * Tests that download.launch() is automatically called after
- * the download finishes if download.launchWhenSucceeded = true
- */
-add_task(function* test_launchWhenSucceeded() {
- let customLauncher = getTempFile("app-launcher");
-
- // Test both with and without setting a custom application.
- for (let launcherPath of [null, customLauncher.path]) {
- let promiseFileLaunched = waitForFileLaunched();
-
- if (!gUseLegacySaver) {
- let download = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- launchWhenSucceeded: true,
- launcherPath: launcherPath,
- });
- yield download.start();
- } else {
- let download = yield promiseStartLegacyDownload(
- httpUrl("source.txt"),
- { launcherPath: launcherPath,
- launchWhenSucceeded: true });
- yield promiseDownloadStopped(download);
- }
-
- let result = yield promiseFileLaunched;
-
- // Verify that the results match the test case.
- if (!launcherPath) {
- // This indicates that the default handler has been chosen.
- do_check_true(result === null);
- } else {
- // Check the nsIMIMEInfo instance that would have been used for launching.
- do_check_eq(result.preferredAction, Ci.nsIMIMEInfo.useHelperApp);
- do_check_true(result.preferredApplicationHandler
- .QueryInterface(Ci.nsILocalHandlerApp)
- .executable.equals(customLauncher));
- }
- }
-});
-
-/**
- * Tests that the proper content type is set for a normal download.
- */
-add_task(function* test_contentType() {
- let download = yield promiseStartDownload(httpUrl("source.txt"));
- yield promiseDownloadStopped(download);
-
- do_check_eq("text/plain", download.contentType);
-});
-
-/**
- * Tests that the serialization/deserialization of the startTime Date
- * object works correctly.
- */
-add_task(function* test_toSerializable_startTime()
-{
- let download1 = yield promiseStartDownload(httpUrl("source.txt"));
- yield promiseDownloadStopped(download1);
-
- let serializable = download1.toSerializable();
- let reserialized = JSON.parse(JSON.stringify(serializable));
-
- let download2 = yield Downloads.createDownload(reserialized);
-
- do_check_eq(download1.startTime.constructor.name, "Date");
- do_check_eq(download2.startTime.constructor.name, "Date");
- do_check_eq(download1.startTime.toJSON(), download2.startTime.toJSON());
-});
-
-/**
- * Checks that downloads are added to browsing history when they start.
- */
-add_task(function* test_history()
-{
- mustInterruptResponses();
-
- // We will wait for the visit to be notified during the download.
- yield PlacesTestUtils.clearHistory();
- let promiseVisit = promiseWaitForVisit(httpUrl("interruptible.txt"));
-
- // Start a download that is not allowed to finish yet.
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- // The history notifications should be received before the download completes.
- let [time, transitionType] = yield promiseVisit;
- do_check_eq(time, download.startTime.getTime() * 1000);
- do_check_eq(transitionType, Ci.nsINavHistoryService.TRANSITION_DOWNLOAD);
-
- // Restart and complete the download after clearing history.
- yield PlacesTestUtils.clearHistory();
- download.cancel();
- continueResponses();
- yield download.start();
-
- // The restart should not have added a new history visit.
- do_check_false(yield promiseIsURIVisited(httpUrl("interruptible.txt")));
-});
-
-/**
- * Checks that downloads started by nsIHelperAppService are added to the
- * browsing history when they start.
- */
-add_task(function* test_history_tryToKeepPartialData()
-{
- // We will wait for the visit to be notified during the download.
- yield PlacesTestUtils.clearHistory();
- let promiseVisit =
- promiseWaitForVisit(httpUrl("interruptible_resumable.txt"));
-
- // Start a download that is not allowed to finish yet.
- let beforeStartTimeMs = Date.now();
- let download = yield promiseStartDownload_tryToKeepPartialData();
-
- // The history notifications should be received before the download completes.
- let [time, transitionType] = yield promiseVisit;
- do_check_eq(transitionType, Ci.nsINavHistoryService.TRANSITION_DOWNLOAD);
-
- // The time set by nsIHelperAppService may be different than the start time in
- // the download object, thus we only check that it is a meaningful time. Note
- // that we subtract one second from the earliest time to account for rounding.
- do_check_true(time >= beforeStartTimeMs * 1000 - 1000000);
-
- // Complete the download before finishing the test.
- continueResponses();
- yield promiseDownloadStopped(download);
-});
-
-/**
- * Tests that the temp download files are removed on exit and exiting private
- * mode after they have been launched.
- */
-add_task(function* test_launchWhenSucceeded_deleteTempFileOnExit() {
- let customLauncherPath = getTempFile("app-launcher").path;
- let autoDeleteTargetPathOne = getTempFile(TEST_TARGET_FILE_NAME).path;
- let autoDeleteTargetPathTwo = getTempFile(TEST_TARGET_FILE_NAME).path;
- let noAutoDeleteTargetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
-
- let autoDeleteDownloadOne = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate: true },
- target: autoDeleteTargetPathOne,
- launchWhenSucceeded: true,
- launcherPath: customLauncherPath,
- });
- yield autoDeleteDownloadOne.start();
-
- Services.prefs.setBoolPref(kDeleteTempFileOnExit, true);
- let autoDeleteDownloadTwo = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: autoDeleteTargetPathTwo,
- launchWhenSucceeded: true,
- launcherPath: customLauncherPath,
- });
- yield autoDeleteDownloadTwo.start();
-
- Services.prefs.setBoolPref(kDeleteTempFileOnExit, false);
- let noAutoDeleteDownload = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: noAutoDeleteTargetPath,
- launchWhenSucceeded: true,
- launcherPath: customLauncherPath,
- });
- yield noAutoDeleteDownload.start();
-
- Services.prefs.clearUserPref(kDeleteTempFileOnExit);
-
- do_check_true(yield OS.File.exists(autoDeleteTargetPathOne));
- do_check_true(yield OS.File.exists(autoDeleteTargetPathTwo));
- do_check_true(yield OS.File.exists(noAutoDeleteTargetPath));
-
- // Simulate leaving private browsing mode
- Services.obs.notifyObservers(null, "last-pb-context-exited", null);
- do_check_false(yield OS.File.exists(autoDeleteTargetPathOne));
-
- // Simulate browser shutdown
- let expire = Cc["@mozilla.org/uriloader/external-helper-app-service;1"]
- .getService(Ci.nsIObserver);
- expire.observe(null, "profile-before-change", null);
- do_check_false(yield OS.File.exists(autoDeleteTargetPathTwo));
- do_check_true(yield OS.File.exists(noAutoDeleteTargetPath));
-});
diff --git a/toolkit/components/jsdownloads/test/unit/head.js b/toolkit/components/jsdownloads/test/unit/head.js
deleted file mode 100644
index f322244c4..000000000
--- a/toolkit/components/jsdownloads/test/unit/head.js
+++ /dev/null
@@ -1,843 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Provides infrastructure for automated download components tests.
- */
-
-"use strict";
-
-// Globals
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
-
-Cu.import("resource://gre/modules/Integration.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
- "resource://gre/modules/DownloadPaths.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
- "resource://gre/modules/Downloads.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
- "resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
- "resource://testing-common/httpd.js");
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
- "resource://gre/modules/NetUtil.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
- "resource://testing-common/PlacesTestUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
- "resource://gre/modules/PlacesUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/Promise.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
- "resource://gre/modules/Services.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Task",
- "resource://gre/modules/Task.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "MockRegistrar",
- "resource://testing-common/MockRegistrar.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gExternalHelperAppService",
- "@mozilla.org/uriloader/external-helper-app-service;1",
- Ci.nsIExternalHelperAppService);
-
-Integration.downloads.defineModuleGetter(this, "DownloadIntegration",
- "resource://gre/modules/DownloadIntegration.jsm");
-
-const ServerSocket = Components.Constructor(
- "@mozilla.org/network/server-socket;1",
- "nsIServerSocket",
- "init");
-const BinaryOutputStream = Components.Constructor(
- "@mozilla.org/binaryoutputstream;1",
- "nsIBinaryOutputStream",
- "setOutputStream")
-
-XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
- "@mozilla.org/mime;1",
- "nsIMIMEService");
-
-const TEST_TARGET_FILE_NAME = "test-download.txt";
-const TEST_STORE_FILE_NAME = "test-downloads.json";
-
-const TEST_REFERRER_URL = "http://www.example.com/referrer.html";
-
-const TEST_DATA_SHORT = "This test string is downloaded.";
-// Generate using gzipCompressString in TelemetryController.jsm.
-const TEST_DATA_SHORT_GZIP_ENCODED_FIRST = [
- 31, 139, 8, 0, 0, 0, 0, 0, 0, 3, 11, 201, 200, 44, 86, 40, 73, 45, 46, 81, 40, 46, 41, 202, 204
-];
-const TEST_DATA_SHORT_GZIP_ENCODED_SECOND = [
- 75, 87, 0, 114, 83, 242, 203, 243, 114, 242, 19, 83, 82, 83, 244, 0, 151, 222, 109, 43, 31, 0, 0, 0
-];
-const TEST_DATA_SHORT_GZIP_ENCODED =
- TEST_DATA_SHORT_GZIP_ENCODED_FIRST.concat(TEST_DATA_SHORT_GZIP_ENCODED_SECOND);
-
-/**
- * All the tests are implemented with add_task, this starts them automatically.
- */
-function run_test()
-{
- do_get_profile();
- run_next_test();
-}
-
-// Support functions
-
-/**
- * HttpServer object initialized before tests start.
- */
-var gHttpServer;
-
-/**
- * Given a file name, returns a string containing an URI that points to the file
- * on the currently running instance of the test HTTP server.
- */
-function httpUrl(aFileName) {
- return "http://localhost:" + gHttpServer.identity.primaryPort + "/" +
- aFileName;
-}
-
-// While the previous test file should have deleted all the temporary files it
-// used, on Windows these might still be pending deletion on the physical file
-// system. Thus, start from a new base number every time, to make a collision
-// with a file that is still pending deletion highly unlikely.
-var gFileCounter = Math.floor(Math.random() * 1000000);
-
-/**
- * Returns a reference to a temporary file, that is guaranteed not to exist, and
- * to have never been created before.
- *
- * @param aLeafName
- * Suggested leaf name for the file to be created.
- *
- * @return nsIFile pointing to a non-existent file in a temporary directory.
- *
- * @note It is not enough to delete the file if it exists, or to delete the file
- * after calling nsIFile.createUnique, because on Windows the delete
- * operation in the file system may still be pending, preventing a new
- * file with the same name to be created.
- */
-function getTempFile(aLeafName)
-{
- // Prepend a serial number to the extension in the suggested leaf name.
- let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
- let leafName = base + "-" + gFileCounter + ext;
- gFileCounter++;
-
- // Get a file reference under the temporary directory for this test file.
- let file = FileUtils.getFile("TmpD", [leafName]);
- do_check_false(file.exists());
-
- do_register_cleanup(function () {
- try {
- file.remove(false)
- } catch (e) {
- if (!(e instanceof Components.Exception &&
- (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED ||
- e.result == Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ||
- e.result == Cr.NS_ERROR_FILE_NOT_FOUND))) {
- throw e;
- }
- // On Windows, we may get an access denied error if the file existed before,
- // and was recently deleted.
- // Don't bother checking file.exists() as that may also cause an access
- // denied error.
- }
- });
-
- return file;
-}
-
-/**
- * Waits for pending events to be processed.
- *
- * @return {Promise}
- * @resolves When pending events have been processed.
- * @rejects Never.
- */
-function promiseExecuteSoon()
-{
- let deferred = Promise.defer();
- do_execute_soon(deferred.resolve);
- return deferred.promise;
-}
-
-/**
- * Waits for a pending events to be processed after a timeout.
- *
- * @return {Promise}
- * @resolves When pending events have been processed.
- * @rejects Never.
- */
-function promiseTimeout(aTime)
-{
- let deferred = Promise.defer();
- do_timeout(aTime, deferred.resolve);
- return deferred.promise;
-}
-
-/**
- * Waits for a new history visit to be notified for the specified URI.
- *
- * @param aUrl
- * String containing the URI that will be visited.
- *
- * @return {Promise}
- * @resolves Array [aTime, aTransitionType] from nsINavHistoryObserver.onVisit.
- * @rejects Never.
- */
-function promiseWaitForVisit(aUrl)
-{
- let deferred = Promise.defer();
-
- let uri = NetUtil.newURI(aUrl);
-
- PlacesUtils.history.addObserver({
- QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]),
- onBeginUpdateBatch: function () {},
- onEndUpdateBatch: function () {},
- onVisit: function (aURI, aVisitID, aTime, aSessionID, aReferringID,
- aTransitionType, aGUID, aHidden) {
- if (aURI.equals(uri)) {
- PlacesUtils.history.removeObserver(this);
- deferred.resolve([aTime, aTransitionType]);
- }
- },
- onTitleChanged: function () {},
- onDeleteURI: function () {},
- onClearHistory: function () {},
- onPageChanged: function () {},
- onDeleteVisits: function () {},
- }, false);
-
- return deferred.promise;
-}
-
-/**
- * Check browsing history to see whether the given URI has been visited.
- *
- * @param aUrl
- * String containing the URI that will be visited.
- *
- * @return {Promise}
- * @resolves Boolean indicating whether the URI has been visited.
- * @rejects JavaScript exception.
- */
-function promiseIsURIVisited(aUrl) {
- let deferred = Promise.defer();
-
- PlacesUtils.asyncHistory.isURIVisited(NetUtil.newURI(aUrl),
- function (aURI, aIsVisited) {
- deferred.resolve(aIsVisited);
- });
-
- return deferred.promise;
-}
-
-/**
- * Creates a new Download object, setting a temporary file as the target.
- *
- * @param aSourceUrl
- * String containing the URI for the download source, or null to use
- * httpUrl("source.txt").
- *
- * @return {Promise}
- * @resolves The newly created Download object.
- * @rejects JavaScript exception.
- */
-function promiseNewDownload(aSourceUrl) {
- return Downloads.createDownload({
- source: aSourceUrl || httpUrl("source.txt"),
- target: getTempFile(TEST_TARGET_FILE_NAME),
- });
-}
-
-/**
- * Starts a new download using the nsIWebBrowserPersist interface, and controls
- * it using the legacy nsITransfer interface.
- *
- * @param aSourceUrl
- * String containing the URI for the download source, or null to use
- * httpUrl("source.txt").
- * @param aOptions
- * An optional object used to control the behavior of this function.
- * You may pass an object with a subset of the following fields:
- * {
- * isPrivate: Boolean indicating whether the download originated from a
- * private window.
- * targetFile: nsIFile for the target, or null to use a temporary file.
- * outPersist: Receives a reference to the created nsIWebBrowserPersist
- * instance.
- * launchWhenSucceeded: Boolean indicating whether the target should
- * be launched when it has completed successfully.
- * launcherPath: String containing the path of the custom executable to
- * use to launch the target of the download.
- * }
- *
- * @return {Promise}
- * @resolves The Download object created as a consequence of controlling the
- * download through the legacy nsITransfer interface.
- * @rejects Never. The current test fails in case of exceptions.
- */
-function promiseStartLegacyDownload(aSourceUrl, aOptions) {
- let sourceURI = NetUtil.newURI(aSourceUrl || httpUrl("source.txt"));
- let targetFile = (aOptions && aOptions.targetFile)
- || getTempFile(TEST_TARGET_FILE_NAME);
-
- let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
- .createInstance(Ci.nsIWebBrowserPersist);
- if (aOptions) {
- aOptions.outPersist = persist;
- }
-
- let fileExtension = null, mimeInfo = null;
- let match = sourceURI.path.match(/\.([^.\/]+)$/);
- if (match) {
- fileExtension = match[1];
- }
-
- if (fileExtension) {
- try {
- mimeInfo = gMIMEService.getFromTypeAndExtension(null, fileExtension);
- mimeInfo.preferredAction = Ci.nsIMIMEInfo.saveToDisk;
- } catch (ex) { }
- }
-
- if (aOptions && aOptions.launcherPath) {
- do_check_true(mimeInfo != null);
-
- let localHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]
- .createInstance(Ci.nsILocalHandlerApp);
- localHandlerApp.executable = new FileUtils.File(aOptions.launcherPath);
-
- mimeInfo.preferredApplicationHandler = localHandlerApp;
- mimeInfo.preferredAction = Ci.nsIMIMEInfo.useHelperApp;
- }
-
- if (aOptions && aOptions.launchWhenSucceeded) {
- do_check_true(mimeInfo != null);
-
- mimeInfo.preferredAction = Ci.nsIMIMEInfo.useHelperApp;
- }
-
- // Apply decoding if required by the "Content-Encoding" header.
- persist.persistFlags &= ~Ci.nsIWebBrowserPersist.PERSIST_FLAGS_NO_CONVERSION;
- persist.persistFlags |=
- Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
-
- let transfer = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
-
- let deferred = Promise.defer();
-
- Downloads.getList(Downloads.ALL).then(function (aList) {
- // Temporarily register a view that will get notified when the download we
- // are controlling becomes visible in the list of downloads.
- aList.addView({
- onDownloadAdded: function (aDownload) {
- aList.removeView(this).then(null, do_report_unexpected_exception);
-
- // Remove the download to keep the list empty for the next test. This
- // also allows the caller to register the "onchange" event directly.
- let promise = aList.remove(aDownload);
-
- // When the download object is ready, make it available to the caller.
- promise.then(() => deferred.resolve(aDownload),
- do_report_unexpected_exception);
- },
- }).then(null, do_report_unexpected_exception);
-
- let isPrivate = aOptions && aOptions.isPrivate;
-
- // Initialize the components so they reference each other. This will cause
- // the Download object to be created and added to the public downloads.
- transfer.init(sourceURI, NetUtil.newURI(targetFile), null, mimeInfo, null,
- null, persist, isPrivate);
- persist.progressListener = transfer;
-
- // Start the actual download process.
- persist.savePrivacyAwareURI(sourceURI, null, null, 0, null, null, targetFile,
- isPrivate);
- }.bind(this)).then(null, do_report_unexpected_exception);
-
- return deferred.promise;
-}
-
-/**
- * Starts a new download using the nsIHelperAppService interface, and controls
- * it using the legacy nsITransfer interface. The source of the download will
- * be "interruptible_resumable.txt" and partially downloaded data will be kept.
- *
- * @param aSourceUrl
- * String containing the URI for the download source, or null to use
- * httpUrl("interruptible_resumable.txt").
- *
- * @return {Promise}
- * @resolves The Download object created as a consequence of controlling the
- * download through the legacy nsITransfer interface.
- * @rejects Never. The current test fails in case of exceptions.
- */
-function promiseStartExternalHelperAppServiceDownload(aSourceUrl) {
- let sourceURI = NetUtil.newURI(aSourceUrl ||
- httpUrl("interruptible_resumable.txt"));
-
- let deferred = Promise.defer();
-
- Downloads.getList(Downloads.PUBLIC).then(function (aList) {
- // Temporarily register a view that will get notified when the download we
- // are controlling becomes visible in the list of downloads.
- aList.addView({
- onDownloadAdded: function (aDownload) {
- aList.removeView(this).then(null, do_report_unexpected_exception);
-
- // Remove the download to keep the list empty for the next test. This
- // also allows the caller to register the "onchange" event directly.
- let promise = aList.remove(aDownload);
-
- // When the download object is ready, make it available to the caller.
- promise.then(() => deferred.resolve(aDownload),
- do_report_unexpected_exception);
- },
- }).then(null, do_report_unexpected_exception);
-
- let channel = NetUtil.newChannel({
- uri: sourceURI,
- loadUsingSystemPrincipal: true
- });
-
- // Start the actual download process.
- channel.asyncOpen2({
- contentListener: null,
-
- onStartRequest: function (aRequest, aContext)
- {
- let requestChannel = aRequest.QueryInterface(Ci.nsIChannel);
- this.contentListener = gExternalHelperAppService.doContent(
- requestChannel.contentType, aRequest, null, true);
- this.contentListener.onStartRequest(aRequest, aContext);
- },
-
- onStopRequest: function (aRequest, aContext, aStatusCode)
- {
- this.contentListener.onStopRequest(aRequest, aContext, aStatusCode);
- },
-
- onDataAvailable: function (aRequest, aContext, aInputStream, aOffset,
- aCount)
- {
- this.contentListener.onDataAvailable(aRequest, aContext, aInputStream,
- aOffset, aCount);
- },
- });
- }.bind(this)).then(null, do_report_unexpected_exception);
-
- return deferred.promise;
-}
-
-/**
- * Waits for a download to reach half of its progress, in case it has not
- * reached the expected progress already.
- *
- * @param aDownload
- * The Download object to wait upon.
- *
- * @return {Promise}
- * @resolves When the download has reached half of its progress.
- * @rejects Never.
- */
-function promiseDownloadMidway(aDownload) {
- let deferred = Promise.defer();
-
- // Wait for the download to reach half of its progress.
- let onchange = function () {
- if (!aDownload.stopped && !aDownload.canceled && aDownload.progress == 50) {
- aDownload.onchange = null;
- deferred.resolve();
- }
- };
-
- // Register for the notification, but also call the function directly in
- // case the download already reached the expected progress.
- aDownload.onchange = onchange;
- onchange();
-
- return deferred.promise;
-}
-
-/**
- * Waits for a download to finish, in case it has not finished already.
- *
- * @param aDownload
- * The Download object to wait upon.
- *
- * @return {Promise}
- * @resolves When the download has finished successfully.
- * @rejects JavaScript exception if the download failed.
- */
-function promiseDownloadStopped(aDownload) {
- if (!aDownload.stopped) {
- // The download is in progress, wait for the current attempt to finish and
- // report any errors that may occur.
- return aDownload.start();
- }
-
- if (aDownload.succeeded) {
- return Promise.resolve();
- }
-
- // The download failed or was canceled.
- return Promise.reject(aDownload.error || new Error("Download canceled."));
-}
-
-/**
- * Returns a new public or private DownloadList object.
- *
- * @param aIsPrivate
- * True for the private list, false or undefined for the public list.
- *
- * @return {Promise}
- * @resolves The newly created DownloadList object.
- * @rejects JavaScript exception.
- */
-function promiseNewList(aIsPrivate)
-{
- // We need to clear all the internal state for the list and summary objects,
- // since all the objects are interdependent internally.
- Downloads._promiseListsInitialized = null;
- Downloads._lists = {};
- Downloads._summaries = {};
-
- return Downloads.getList(aIsPrivate ? Downloads.PRIVATE : Downloads.PUBLIC);
-}
-
-/**
- * Ensures that the given file contents are equal to the given string.
- *
- * @param aPath
- * String containing the path of the file whose contents should be
- * verified.
- * @param aExpectedContents
- * String containing the octets that are expected in the file.
- *
- * @return {Promise}
- * @resolves When the operation completes.
- * @rejects Never.
- */
-function promiseVerifyContents(aPath, aExpectedContents)
-{
- return Task.spawn(function* () {
- let file = new FileUtils.File(aPath);
-
- if (!(yield OS.File.exists(aPath))) {
- do_throw("File does not exist: " + aPath);
- }
-
- if ((yield OS.File.stat(aPath)).size == 0) {
- do_throw("File is empty: " + aPath);
- }
-
- let deferred = Promise.defer();
- NetUtil.asyncFetch(
- { uri: NetUtil.newURI(file), loadUsingSystemPrincipal: true },
- function(aInputStream, aStatus) {
- do_check_true(Components.isSuccessCode(aStatus));
- let contents = NetUtil.readInputStreamToString(aInputStream,
- aInputStream.available());
- if (contents.length > TEST_DATA_SHORT.length * 2 ||
- /[^\x20-\x7E]/.test(contents)) {
- // Do not print the entire content string to the test log.
- do_check_eq(contents.length, aExpectedContents.length);
- do_check_true(contents == aExpectedContents);
- } else {
- // Print the string if it is short and made of printable characters.
- do_check_eq(contents, aExpectedContents);
- }
- deferred.resolve();
- });
-
- yield deferred.promise;
- });
-}
-
-/**
- * Starts a socket listener that closes each incoming connection.
- *
- * @returns nsIServerSocket that listens for connections. Call its "close"
- * method to stop listening and free the server port.
- */
-function startFakeServer()
-{
- let serverSocket = new ServerSocket(-1, true, -1);
- serverSocket.asyncListen({
- onSocketAccepted: function (aServ, aTransport) {
- aTransport.close(Cr.NS_BINDING_ABORTED);
- },
- onStopListening: function () { },
- });
- return serverSocket;
-}
-
-/**
- * This is an internal reference that should not be used directly by tests.
- */
-var _gDeferResponses = Promise.defer();
-
-/**
- * Ensures that all the interruptible requests started after this function is
- * called won't complete until the continueResponses function is called.
- *
- * Normally, the internal HTTP server returns all the available data as soon as
- * a request is received. In order for some requests to be served one part at a
- * time, special interruptible handlers are registered on the HTTP server. This
- * allows testing events or actions that need to happen in the middle of a
- * download.
- *
- * For example, the handler accessible at the httpUri("interruptible.txt")
- * address returns the TEST_DATA_SHORT text, then it may block until the
- * continueResponses method is called. At this point, the handler sends the
- * TEST_DATA_SHORT text again to complete the response.
- *
- * If an interruptible request is started before the function is called, it may
- * or may not be blocked depending on the actual sequence of events.
- */
-function mustInterruptResponses()
-{
- // If there are pending blocked requests, allow them to complete. This is
- // done to prevent requests from being blocked forever, but should not affect
- // the test logic, since previously started requests should not be monitored
- // on the client side anymore.
- _gDeferResponses.resolve();
-
- do_print("Interruptible responses will be blocked midway.");
- _gDeferResponses = Promise.defer();
-}
-
-/**
- * Allows all the current and future interruptible requests to complete.
- */
-function continueResponses()
-{
- do_print("Interruptible responses are now allowed to continue.");
- _gDeferResponses.resolve();
-}
-
-/**
- * Registers an interruptible response handler.
- *
- * @param aPath
- * Path passed to nsIHttpServer.registerPathHandler.
- * @param aFirstPartFn
- * This function is called when the response is received, with the
- * aRequest and aResponse arguments of the server.
- * @param aSecondPartFn
- * This function is called with the aRequest and aResponse arguments of
- * the server, when the continueResponses function is called.
- */
-function registerInterruptibleHandler(aPath, aFirstPartFn, aSecondPartFn)
-{
- gHttpServer.registerPathHandler(aPath, function (aRequest, aResponse) {
- do_print("Interruptible request started.");
-
- // Process the first part of the response.
- aResponse.processAsync();
- aFirstPartFn(aRequest, aResponse);
-
- // Wait on the current deferred object, then finish the request.
- _gDeferResponses.promise.then(function RIH_onSuccess() {
- aSecondPartFn(aRequest, aResponse);
- aResponse.finish();
- do_print("Interruptible request finished.");
- }).then(null, Cu.reportError);
- });
-}
-
-/**
- * Ensure the given date object is valid.
- *
- * @param aDate
- * The date object to be checked. This value can be null.
- */
-function isValidDate(aDate) {
- return aDate && aDate.getTime && !isNaN(aDate.getTime());
-}
-
-/**
- * Position of the first byte served by the "interruptible_resumable.txt"
- * handler during the most recent response.
- */
-var gMostRecentFirstBytePos;
-
-// Initialization functions common to all tests
-
-add_task(function test_common_initialize()
-{
- // Start the HTTP server.
- gHttpServer = new HttpServer();
- gHttpServer.registerDirectory("/", do_get_file("../data"));
- gHttpServer.start(-1);
- do_register_cleanup(() => {
- return new Promise(resolve => {
- // Ensure all the pending HTTP requests have a chance to finish.
- continueResponses();
- // Stop the HTTP server, calling resolve when it's done.
- gHttpServer.stop(resolve);
- });
- });
-
- // Cache locks might prevent concurrent requests to the same resource, and
- // this may block tests that use the interruptible handlers.
- Services.prefs.setBoolPref("browser.cache.disk.enable", false);
- Services.prefs.setBoolPref("browser.cache.memory.enable", false);
- do_register_cleanup(function () {
- Services.prefs.clearUserPref("browser.cache.disk.enable");
- Services.prefs.clearUserPref("browser.cache.memory.enable");
- });
-
- registerInterruptibleHandler("/interruptible.txt",
- function firstPart(aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
- aResponse.setHeader("Content-Length", "" + (TEST_DATA_SHORT.length * 2),
- false);
- aResponse.write(TEST_DATA_SHORT);
- }, function secondPart(aRequest, aResponse) {
- aResponse.write(TEST_DATA_SHORT);
- });
-
- registerInterruptibleHandler("/interruptible_resumable.txt",
- function firstPart(aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
-
- // Determine if only part of the data should be sent.
- let data = TEST_DATA_SHORT + TEST_DATA_SHORT;
- if (aRequest.hasHeader("Range")) {
- var matches = aRequest.getHeader("Range")
- .match(/^\s*bytes=(\d+)?-(\d+)?\s*$/);
- var firstBytePos = (matches[1] === undefined) ? 0 : matches[1];
- var lastBytePos = (matches[2] === undefined) ? data.length - 1
- : matches[2];
- if (firstBytePos >= data.length) {
- aResponse.setStatusLine(aRequest.httpVersion, 416,
- "Requested Range Not Satisfiable");
- aResponse.setHeader("Content-Range", "*/" + data.length, false);
- aResponse.finish();
- return;
- }
-
- aResponse.setStatusLine(aRequest.httpVersion, 206, "Partial Content");
- aResponse.setHeader("Content-Range", firstBytePos + "-" +
- lastBytePos + "/" +
- data.length, false);
-
- data = data.substring(firstBytePos, lastBytePos + 1);
-
- gMostRecentFirstBytePos = firstBytePos;
- } else {
- gMostRecentFirstBytePos = 0;
- }
-
- aResponse.setHeader("Content-Length", "" + data.length, false);
-
- aResponse.write(data.substring(0, data.length / 2));
-
- // Store the second part of the data on the response object, so that it
- // can be used by the secondPart function.
- aResponse.secondPartData = data.substring(data.length / 2);
- }, function secondPart(aRequest, aResponse) {
- aResponse.write(aResponse.secondPartData);
- });
-
- registerInterruptibleHandler("/interruptible_gzip.txt",
- function firstPart(aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
- aResponse.setHeader("Content-Encoding", "gzip", false);
- aResponse.setHeader("Content-Length", "" + TEST_DATA_SHORT_GZIP_ENCODED.length);
-
- let bos = new BinaryOutputStream(aResponse.bodyOutputStream);
- bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED_FIRST,
- TEST_DATA_SHORT_GZIP_ENCODED_FIRST.length);
- }, function secondPart(aRequest, aResponse) {
- let bos = new BinaryOutputStream(aResponse.bodyOutputStream);
- bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED_SECOND,
- TEST_DATA_SHORT_GZIP_ENCODED_SECOND.length);
- });
-
- gHttpServer.registerPathHandler("/shorter-than-content-length-http-1-1.txt",
- function (aRequest, aResponse) {
- aResponse.processAsync();
- aResponse.setStatusLine("1.1", 200, "OK");
- aResponse.setHeader("Content-Type", "text/plain", false);
- aResponse.setHeader("Content-Length", "" + (TEST_DATA_SHORT.length * 2),
- false);
- aResponse.write(TEST_DATA_SHORT);
- aResponse.finish();
- });
-
- // This URL will emulate being blocked by Windows Parental controls
- gHttpServer.registerPathHandler("/parentalblocked.zip",
- function (aRequest, aResponse) {
- aResponse.setStatusLine(aRequest.httpVersion, 450,
- "Blocked by Windows Parental Controls");
- });
-
- // During unit tests, most of the functions that require profile access or
- // operating system features will be disabled. Individual tests may override
- // them again to check for specific behaviors.
- Integration.downloads.register(base => ({
- __proto__: base,
- loadPublicDownloadListFromStore: () => Promise.resolve(),
- shouldKeepBlockedData: () => Promise.resolve(false),
- shouldBlockForParentalControls: () => Promise.resolve(false),
- shouldBlockForRuntimePermissions: () => Promise.resolve(false),
- shouldBlockForReputationCheck: () => Promise.resolve({
- shouldBlock: false,
- verdict: "",
- }),
- confirmLaunchExecutable: () => Promise.resolve(),
- launchFile: () => Promise.resolve(),
- showContainingDirectory: () => Promise.resolve(),
- // This flag allows re-enabling the default observers during their tests.
- allowObservers: false,
- addListObservers() {
- return this.allowObservers ? super.addListObservers(...arguments)
- : Promise.resolve();
- },
- // This flag allows re-enabling the download directory logic for its tests.
- _allowDirectories: false,
- set allowDirectories(value) {
- this._allowDirectories = value;
- // We have to invalidate the previously computed directory path.
- this._downloadsDirectory = null;
- },
- _getDirectory(name) {
- return super._getDirectory(this._allowDirectories ? name : "TmpD");
- },
- }));
-
- // Make sure that downloads started using nsIExternalHelperAppService are
- // saved to disk without asking for a destination interactively.
- let mock = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
- promptForSaveToFileAsync(aLauncher,
- aWindowContext,
- aDefaultFileName,
- aSuggestedFileExtension,
- aForcePrompt) {
- // The dialog should create the empty placeholder file.
- let file = getTempFile(TEST_TARGET_FILE_NAME);
- file.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
- aLauncher.saveDestinationAvailable(file);
- },
- };
-
- let cid = MockRegistrar.register("@mozilla.org/helperapplauncherdialog;1", mock);
- do_register_cleanup(() => {
- MockRegistrar.unregister(cid);
- });
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js b/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
deleted file mode 100644
index 6e32c63d3..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the main download interfaces using DownloadCopySaver.
- */
-
-"use strict";
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadError",
- "resource://gre/modules/DownloadCore.jsm");
-
-// Execution of common tests
-
-var gUseLegacySaver = false;
-
-var scriptFile = do_get_file("common_test_Download.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
-
-// Tests
-
-/**
- * Tests the DownloadError object.
- */
-add_task(function test_DownloadError()
-{
- let error = new DownloadError({ result: Cr.NS_ERROR_NOT_RESUMABLE,
- message: "Not resumable."});
- do_check_eq(error.result, Cr.NS_ERROR_NOT_RESUMABLE);
- do_check_eq(error.message, "Not resumable.");
- do_check_false(error.becauseSourceFailed);
- do_check_false(error.becauseTargetFailed);
- do_check_false(error.becauseBlocked);
- do_check_false(error.becauseBlockedByParentalControls);
-
- error = new DownloadError({ message: "Unknown error."});
- do_check_eq(error.result, Cr.NS_ERROR_FAILURE);
- do_check_eq(error.message, "Unknown error.");
-
- error = new DownloadError({ result: Cr.NS_ERROR_NOT_RESUMABLE });
- do_check_eq(error.result, Cr.NS_ERROR_NOT_RESUMABLE);
- do_check_true(error.message.indexOf("Exception") > 0);
-
- // becauseSourceFailed will be set, but not the unknown property.
- error = new DownloadError({ message: "Unknown error.",
- becauseSourceFailed: true,
- becauseUnknown: true });
- do_check_true(error.becauseSourceFailed);
- do_check_false("becauseUnknown" in error);
-
- error = new DownloadError({ result: Cr.NS_ERROR_MALFORMED_URI,
- inferCause: true });
- do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI);
- do_check_true(error.becauseSourceFailed);
- do_check_false(error.becauseTargetFailed);
- do_check_false(error.becauseBlocked);
- do_check_false(error.becauseBlockedByParentalControls);
-
- // This test does not set inferCause, so becauseSourceFailed will not be set.
- error = new DownloadError({ result: Cr.NS_ERROR_MALFORMED_URI });
- do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI);
- do_check_false(error.becauseSourceFailed);
-
- error = new DownloadError({ result: Cr.NS_ERROR_FILE_INVALID_PATH,
- inferCause: true });
- do_check_eq(error.result, Cr.NS_ERROR_FILE_INVALID_PATH);
- do_check_false(error.becauseSourceFailed);
- do_check_true(error.becauseTargetFailed);
- do_check_false(error.becauseBlocked);
- do_check_false(error.becauseBlockedByParentalControls);
-
- error = new DownloadError({ becauseBlocked: true });
- do_check_eq(error.message, "Download blocked.");
- do_check_false(error.becauseSourceFailed);
- do_check_false(error.becauseTargetFailed);
- do_check_true(error.becauseBlocked);
- do_check_false(error.becauseBlockedByParentalControls);
-
- error = new DownloadError({ becauseBlockedByParentalControls: true });
- do_check_eq(error.message, "Download blocked.");
- do_check_false(error.becauseSourceFailed);
- do_check_false(error.becauseTargetFailed);
- do_check_true(error.becauseBlocked);
- do_check_true(error.becauseBlockedByParentalControls);
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadImport.js b/toolkit/components/jsdownloads/test/unit/test_DownloadImport.js
deleted file mode 100644
index 388870f00..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadImport.js
+++ /dev/null
@@ -1,701 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the DownloadImport object.
- */
-
-"use strict";
-
-// Globals
-
-XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
- "resource://gre/modules/Sqlite.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadImport",
- "resource://gre/modules/DownloadImport.jsm");
-
-// Importable states
-const DOWNLOAD_NOTSTARTED = -1;
-const DOWNLOAD_DOWNLOADING = 0;
-const DOWNLOAD_PAUSED = 4;
-const DOWNLOAD_QUEUED = 5;
-
-// Non importable states
-const DOWNLOAD_FAILED = 2;
-const DOWNLOAD_CANCELED = 3;
-const DOWNLOAD_BLOCKED_PARENTAL = 6;
-const DOWNLOAD_SCANNING = 7;
-const DOWNLOAD_DIRTY = 8;
-const DOWNLOAD_BLOCKED_POLICY = 9;
-
-// The TEST_DATA_TAINTED const is a version of TEST_DATA_SHORT in which the
-// beginning of the data was changed (with the TEST_DATA_REPLACEMENT value).
-// We use this to test that the entityID is properly imported and the download
-// can be resumed from where it was paused.
-// For simplification purposes, the test requires that TEST_DATA_SHORT and
-// TEST_DATA_TAINTED have the same length.
-const TEST_DATA_REPLACEMENT = "-changed- ";
-const TEST_DATA_TAINTED = TEST_DATA_REPLACEMENT +
- TEST_DATA_SHORT.substr(TEST_DATA_REPLACEMENT.length);
-const TEST_DATA_LENGTH = TEST_DATA_SHORT.length;
-
-// The length of the partial file that we'll write to disk as an existing
-// ongoing download.
-const TEST_DATA_PARTIAL_LENGTH = TEST_DATA_REPLACEMENT.length;
-
-// The value of the "maxBytes" column stored in the DB about the downloads.
-// It's intentionally different than TEST_DATA_LENGTH to test that each value
-// is seen when expected.
-const MAXBYTES_IN_DB = TEST_DATA_LENGTH - 10;
-
-var gDownloadsRowToImport;
-var gDownloadsRowNonImportable;
-
-/**
- * Creates a database with an empty moz_downloads table and leaves an
- * open connection to it.
- *
- * @param aPath
- * String containing the path of the database file to be created.
- * @param aSchemaVersion
- * Number with the version of the database schema to set.
- *
- * @return {Promise}
- * @resolves The open connection to the database.
- * @rejects If an error occurred during the database creation.
- */
-function promiseEmptyDatabaseConnection({aPath, aSchemaVersion}) {
- return Task.spawn(function* () {
- let connection = yield Sqlite.openConnection({ path: aPath });
-
- yield connection.execute("CREATE TABLE moz_downloads ("
- + "id INTEGER PRIMARY KEY,"
- + "name TEXT,"
- + "source TEXT,"
- + "target TEXT,"
- + "tempPath TEXT,"
- + "startTime INTEGER,"
- + "endTime INTEGER,"
- + "state INTEGER,"
- + "referrer TEXT,"
- + "entityID TEXT,"
- + "currBytes INTEGER NOT NULL DEFAULT 0,"
- + "maxBytes INTEGER NOT NULL DEFAULT -1,"
- + "mimeType TEXT,"
- + "preferredApplication TEXT,"
- + "preferredAction INTEGER NOT NULL DEFAULT 0,"
- + "autoResume INTEGER NOT NULL DEFAULT 0,"
- + "guid TEXT)");
-
- yield connection.setSchemaVersion(aSchemaVersion);
-
- return connection;
- });
-}
-
-/**
- * Inserts a new entry in the database with the given columns' values.
- *
- * @param aConnection
- * The database connection.
- * @param aDownloadRow
- * An object representing the values for each column of the row
- * being inserted.
- *
- * @return {Promise}
- * @resolves When the operation completes.
- * @rejects If there's an error inserting the row.
- */
-function promiseInsertRow(aConnection, aDownloadRow) {
- // We can't use the aDownloadRow obj directly in the execute statement
- // because the obj bind code in Sqlite.jsm doesn't allow objects
- // with extra properties beyond those being binded. So we might as well
- // use an array as it is simpler.
- let values = [
- aDownloadRow.source, aDownloadRow.target, aDownloadRow.tempPath,
- aDownloadRow.startTime.getTime() * 1000, aDownloadRow.state,
- aDownloadRow.referrer, aDownloadRow.entityID, aDownloadRow.maxBytes,
- aDownloadRow.mimeType, aDownloadRow.preferredApplication,
- aDownloadRow.preferredAction, aDownloadRow.autoResume
- ];
-
- return aConnection.execute("INSERT INTO moz_downloads ("
- + "name, source, target, tempPath, startTime,"
- + "endTime, state, referrer, entityID, currBytes,"
- + "maxBytes, mimeType, preferredApplication,"
- + "preferredAction, autoResume, guid)"
- + "VALUES ("
- + "'', ?, ?, ?, ?, " // name,
- + "0, ?, ?, ?, 0, " // endTime, currBytes
- + " ?, ?, ?, " //
- + " ?, ?, '')", // and guid are not imported
- values);
-}
-
-/**
- * Retrieves the number of rows in the moz_downloads table of the
- * database.
- *
- * @param aConnection
- * The database connection.
- *
- * @return {Promise}
- * @resolves With the number of rows.
- * @rejects Never.
- */
-function promiseTableCount(aConnection) {
- return aConnection.execute("SELECT COUNT(*) FROM moz_downloads")
- .then(res => res[0].getResultByName("COUNT(*)"))
- .then(null, Cu.reportError);
-}
-
-/**
- * Briefly opens a network channel to a given URL to retrieve
- * the entityID of this url, as generated by the network code.
- *
- * @param aUrl
- * The URL to retrieve the entityID.
- *
- * @return {Promise}
- * @resolves The EntityID of the given URL.
- * @rejects When there's a problem accessing the URL.
- */
-function promiseEntityID(aUrl) {
- let deferred = Promise.defer();
- let entityID = "";
- let channel = NetUtil.newChannel({
- uri: NetUtil.newURI(aUrl),
- loadUsingSystemPrincipal: true
- });
-
- channel.asyncOpen2({
- onStartRequest: function (aRequest) {
- if (aRequest instanceof Ci.nsIResumableChannel) {
- entityID = aRequest.entityID;
- }
- aRequest.cancel(Cr.NS_BINDING_ABORTED);
- },
-
- onStopRequest: function (aRequest, aContext, aStatusCode) {
- if (aStatusCode == Cr.NS_BINDING_ABORTED) {
- deferred.resolve(entityID);
- } else {
- deferred.reject("Unexpected status code received");
- }
- },
-
- onDataAvailable: function () {}
- });
-
- return deferred.promise;
-}
-
-/**
- * Gets a file path to a temporary writeable download target, in the
- * correct format as expected to be stored in the downloads database,
- * which is file:///absolute/path/to/file
- *
- * @param aLeafName
- * A hint leaf name for the file.
- *
- * @return String The path to the download target.
- */
-function getDownloadTarget(aLeafName) {
- return NetUtil.newURI(getTempFile(aLeafName)).spec;
-}
-
-/**
- * Generates a temporary partial file to use as an in-progress
- * download. The file is written to disk with a part of the total expected
- * download content pre-written.
- *
- * @param aLeafName
- * A hint leaf name for the file.
- * @param aTainted
- * A boolean value. When true, the partial content of the file
- * will be different from the expected content of the original source
- * file. See the declaration of TEST_DATA_TAINTED for more information.
- *
- * @return {Promise}
- * @resolves When the operation completes, and returns a string with the path
- * to the generated file.
- * @rejects If there's an error writing the file.
- */
-function getPartialFile(aLeafName, aTainted = false) {
- let tempDownload = getTempFile(aLeafName);
- let partialContent = aTainted
- ? TEST_DATA_TAINTED.substr(0, TEST_DATA_PARTIAL_LENGTH)
- : TEST_DATA_SHORT.substr(0, TEST_DATA_PARTIAL_LENGTH);
-
- return OS.File.writeAtomic(tempDownload.path, partialContent,
- { tmpPath: tempDownload.path + ".tmp",
- flush: true })
- .then(() => tempDownload.path);
-}
-
-/**
- * Generates a Date object to be used as the startTime for the download rows
- * in the DB. A date that is obviously different from the current time is
- * generated to make sure this stored data and a `new Date()` can't collide.
- *
- * @param aOffset
- * A offset from the base generated date is used to differentiate each
- * row in the database.
- *
- * @return A Date object.
- */
-function getStartTime(aOffset) {
- return new Date(1000000 + (aOffset * 10000));
-}
-
-/**
- * Performs various checks on an imported Download object to make sure
- * all properties are properly set as expected from the import procedure.
- *
- * @param aDownload
- * The Download object to be checked.
- * @param aDownloadRow
- * An object that represents a row from the original database table,
- * with extra properties describing expected values that are not
- * explictly part of the database.
- *
- * @return {Promise}
- * @resolves When the operation completes
- * @rejects Never
- */
-function checkDownload(aDownload, aDownloadRow) {
- return Task.spawn(function*() {
- do_check_eq(aDownload.source.url, aDownloadRow.source);
- do_check_eq(aDownload.source.referrer, aDownloadRow.referrer);
-
- do_check_eq(aDownload.target.path,
- NetUtil.newURI(aDownloadRow.target)
- .QueryInterface(Ci.nsIFileURL).file.path);
-
- do_check_eq(aDownload.target.partFilePath, aDownloadRow.tempPath);
-
- if (aDownloadRow.expectedResume) {
- do_check_true(!aDownload.stopped || aDownload.succeeded);
- yield promiseDownloadStopped(aDownload);
-
- do_check_true(aDownload.succeeded);
- do_check_eq(aDownload.progress, 100);
- // If the download has resumed, a new startTime will be set.
- // By calling toJSON we're also testing that startTime is a Date object.
- do_check_neq(aDownload.startTime.toJSON(),
- aDownloadRow.startTime.toJSON());
- } else {
- do_check_false(aDownload.succeeded);
- do_check_eq(aDownload.startTime.toJSON(),
- aDownloadRow.startTime.toJSON());
- }
-
- do_check_eq(aDownload.stopped, true);
-
- let serializedSaver = aDownload.saver.toSerializable();
- if (typeof(serializedSaver) == "object") {
- do_check_eq(serializedSaver.type, "copy");
- } else {
- do_check_eq(serializedSaver, "copy");
- }
-
- if (aDownloadRow.entityID) {
- do_check_eq(aDownload.saver.entityID, aDownloadRow.entityID);
- }
-
- do_check_eq(aDownload.currentBytes, aDownloadRow.expectedCurrentBytes);
- do_check_eq(aDownload.totalBytes, aDownloadRow.expectedTotalBytes);
-
- if (aDownloadRow.expectedContent) {
- let fileToCheck = aDownloadRow.expectedResume
- ? aDownload.target.path
- : aDownload.target.partFilePath;
- yield promiseVerifyContents(fileToCheck, aDownloadRow.expectedContent);
- }
-
- do_check_eq(aDownload.contentType, aDownloadRow.expectedContentType);
- do_check_eq(aDownload.launcherPath, aDownloadRow.preferredApplication);
-
- do_check_eq(aDownload.launchWhenSucceeded,
- aDownloadRow.preferredAction != Ci.nsIMIMEInfo.saveToDisk);
- });
-}
-
-// Preparation tasks
-
-/**
- * Prepares the list of downloads to be added to the database that should
- * be imported by the import procedure.
- */
-add_task(function* prepareDownloadsToImport() {
-
- let sourceUrl = httpUrl("source.txt");
- let sourceEntityId = yield promiseEntityID(sourceUrl);
-
- gDownloadsRowToImport = [
- // Paused download with autoResume and a partial file. By
- // setting the correct entityID the download can resume from
- // where it stopped, and to test that this works properly we
- // intentionally set different data in the beginning of the
- // partial file to make sure it was not replaced.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress1.txt"),
- tempPath: yield getPartialFile("inprogress1.txt.part", true),
- startTime: getStartTime(1),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer1"),
- entityID: sourceEntityId,
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType1",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication1",
- autoResume: 1,
-
- // Even though the information stored in the DB said
- // maxBytes was MAXBYTES_IN_DB, the download turned out to be
- // a different length. Here we make sure the totalBytes property
- // was correctly set with the actual value. The same consideration
- // applies to the contentType.
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_TAINTED,
- },
-
- // Paused download with autoResume and a partial file,
- // but missing entityID. This means that the download will
- // start from beginning, and the entire original content of the
- // source file should replace the different data that was stored
- // in the partial file.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress2.txt"),
- tempPath: yield getPartialFile("inprogress2.txt.part", true),
- startTime: getStartTime(2),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer2"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType2",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication2",
- autoResume: 1,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_SHORT
- },
-
- // Paused download with no autoResume and a partial file.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress3.txt"),
- tempPath: yield getPartialFile("inprogress3.txt.part"),
- startTime: getStartTime(3),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer3"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType3",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication3",
- autoResume: 0,
-
- // Since this download has not been resumed, the actual data
- // about its total size and content type is not known.
- // Therefore, we're going by the information imported from the DB.
- expectedCurrentBytes: TEST_DATA_PARTIAL_LENGTH,
- expectedTotalBytes: MAXBYTES_IN_DB,
- expectedResume: false,
- expectedContentType: "mimeType3",
- expectedContent: TEST_DATA_SHORT.substr(0, TEST_DATA_PARTIAL_LENGTH),
- },
-
- // Paused download with autoResume and no partial file.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress4.txt"),
- tempPath: "",
- startTime: getStartTime(4),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer4"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.useHelperApp,
- preferredApplication: "prerredApplication4",
- autoResume: 1,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_SHORT
- },
-
- // Paused download with no autoResume and no partial file.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress5.txt"),
- tempPath: "",
- startTime: getStartTime(5),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer4"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.useSystemDefault,
- preferredApplication: "prerredApplication5",
- autoResume: 0,
-
- expectedCurrentBytes: 0,
- expectedTotalBytes: MAXBYTES_IN_DB,
- expectedResume: false,
- expectedContentType: "text/plain",
- },
-
- // Queued download with no autoResume and no partial file.
- // Even though autoResume=0, queued downloads always autoResume.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress6.txt"),
- tempPath: "",
- startTime: getStartTime(6),
- state: DOWNLOAD_QUEUED,
- referrer: httpUrl("referrer6"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.useHelperApp,
- preferredApplication: "prerredApplication6",
- autoResume: 0,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_SHORT
- },
-
- // Notstarted download with no autoResume and no partial file.
- // Even though autoResume=0, notstarted downloads always autoResume.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress7.txt"),
- tempPath: "",
- startTime: getStartTime(7),
- state: DOWNLOAD_NOTSTARTED,
- referrer: httpUrl("referrer7"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.useHelperApp,
- preferredApplication: "prerredApplication7",
- autoResume: 0,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_SHORT
- },
-
- // Downloading download with no autoResume and a partial file.
- // Even though autoResume=0, downloading downloads always autoResume.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress8.txt"),
- tempPath: yield getPartialFile("inprogress8.txt.part", true),
- startTime: getStartTime(8),
- state: DOWNLOAD_DOWNLOADING,
- referrer: httpUrl("referrer8"),
- entityID: sourceEntityId,
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication8",
- autoResume: 0,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_TAINTED
- },
- ];
-});
-
-/**
- * Prepares the list of downloads to be added to the database that should
- * *not* be imported by the import procedure.
- */
-add_task(function* prepareNonImportableDownloads()
-{
- gDownloadsRowNonImportable = [
- // Download with no source (should never happen in normal circumstances).
- {
- source: "",
- target: "nonimportable1.txt",
- tempPath: "",
- startTime: getStartTime(1),
- state: DOWNLOAD_PAUSED,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType1",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication1",
- autoResume: 1
- },
-
- // state = DOWNLOAD_FAILED
- {
- source: httpUrl("source.txt"),
- target: "nonimportable2.txt",
- tempPath: "",
- startTime: getStartTime(2),
- state: DOWNLOAD_FAILED,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType2",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication2",
- autoResume: 1
- },
-
- // state = DOWNLOAD_CANCELED
- {
- source: httpUrl("source.txt"),
- target: "nonimportable3.txt",
- tempPath: "",
- startTime: getStartTime(3),
- state: DOWNLOAD_CANCELED,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType3",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication3",
- autoResume: 1
- },
-
- // state = DOWNLOAD_BLOCKED_PARENTAL
- {
- source: httpUrl("source.txt"),
- target: "nonimportable4.txt",
- tempPath: "",
- startTime: getStartTime(4),
- state: DOWNLOAD_BLOCKED_PARENTAL,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType4",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication4",
- autoResume: 1
- },
-
- // state = DOWNLOAD_SCANNING
- {
- source: httpUrl("source.txt"),
- target: "nonimportable5.txt",
- tempPath: "",
- startTime: getStartTime(5),
- state: DOWNLOAD_SCANNING,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType5",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication5",
- autoResume: 1
- },
-
- // state = DOWNLOAD_DIRTY
- {
- source: httpUrl("source.txt"),
- target: "nonimportable6.txt",
- tempPath: "",
- startTime: getStartTime(6),
- state: DOWNLOAD_DIRTY,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType6",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication6",
- autoResume: 1
- },
-
- // state = DOWNLOAD_BLOCKED_POLICY
- {
- source: httpUrl("source.txt"),
- target: "nonimportable7.txt",
- tempPath: "",
- startTime: getStartTime(7),
- state: DOWNLOAD_BLOCKED_POLICY,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType7",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication7",
- autoResume: 1
- },
- ];
-});
-
-// Test
-
-/**
- * Creates a temporary Sqlite database with download data and perform an
- * import of that data to the new Downloads API to verify that the import
- * worked correctly.
- */
-add_task(function* test_downloadImport()
-{
- let connection = null;
- let downloadsSqlite = getTempFile("downloads.sqlite").path;
-
- try {
- // Set up the database.
- connection = yield promiseEmptyDatabaseConnection({
- aPath: downloadsSqlite,
- aSchemaVersion: 9
- });
-
- // Insert both the importable and non-importable
- // downloads together.
- for (let downloadRow of gDownloadsRowToImport) {
- yield promiseInsertRow(connection, downloadRow);
- }
-
- for (let downloadRow of gDownloadsRowNonImportable) {
- yield promiseInsertRow(connection, downloadRow);
- }
-
- // Check that every item was inserted.
- do_check_eq((yield promiseTableCount(connection)),
- gDownloadsRowToImport.length +
- gDownloadsRowNonImportable.length);
- } finally {
- // Close the connection so that DownloadImport can open it.
- yield connection.close();
- }
-
- // Import items.
- let list = yield promiseNewList(false);
- yield new DownloadImport(list, downloadsSqlite).import();
- let items = yield list.getAll();
-
- do_check_eq(items.length, gDownloadsRowToImport.length);
-
- for (let i = 0; i < gDownloadsRowToImport.length; i++) {
- yield checkDownload(items[i], gDownloadsRowToImport[i]);
- }
-})
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js b/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
deleted file mode 100644
index 31dd7c7a4..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
+++ /dev/null
@@ -1,432 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the DownloadIntegration object.
- */
-
-"use strict";
-
-// Globals
-
-/**
- * Notifies the prompt observers and verify the expected downloads count.
- *
- * @param aIsPrivate
- * Flag to know is test private observers.
- * @param aExpectedCount
- * the expected downloads count for quit and offline observers.
- * @param aExpectedPBCount
- * the expected downloads count for private browsing observer.
- */
-function notifyPromptObservers(aIsPrivate, aExpectedCount, aExpectedPBCount) {
- let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
- createInstance(Ci.nsISupportsPRBool);
-
- // Notify quit application requested observer.
- DownloadIntegration._testPromptDownloads = -1;
- Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
- do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedCount);
-
- // Notify offline requested observer.
- DownloadIntegration._testPromptDownloads = -1;
- Services.obs.notifyObservers(cancelQuit, "offline-requested", null);
- do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedCount);
-
- if (aIsPrivate) {
- // Notify last private browsing requested observer.
- DownloadIntegration._testPromptDownloads = -1;
- Services.obs.notifyObservers(cancelQuit, "last-pb-context-exiting", null);
- do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedPBCount);
- }
-
- delete DownloadIntegration._testPromptDownloads;
-}
-
-// Tests
-
-/**
- * Allows re-enabling the real download directory logic during one test.
- */
-function allowDirectoriesInTest() {
- DownloadIntegration.allowDirectories = true;
- function cleanup() {
- DownloadIntegration.allowDirectories = false;
- }
- do_register_cleanup(cleanup);
- return cleanup;
-}
-
-XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
- return Services.strings.
- createBundle("chrome://mozapps/locale/downloads/downloads.properties");
-});
-
-/**
- * Tests that getSystemDownloadsDirectory returns an existing directory or
- * creates a new directory depending on the platform. Instead of the real
- * directory, this test is executed in the temporary directory so we can safely
- * delete the created folder to check whether it is created again.
- */
-add_task(function* test_getSystemDownloadsDirectory_exists_or_creates()
-{
- let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
- let downloadDir;
-
- // OSX / Linux / Windows but not XP/2k
- if (Services.appinfo.OS == "Darwin" ||
- Services.appinfo.OS == "Linux" ||
- (Services.appinfo.OS == "WINNT" &&
- parseFloat(Services.sysinfo.getProperty("version")) >= 6)) {
- downloadDir = yield DownloadIntegration.getSystemDownloadsDirectory();
- do_check_eq(downloadDir, tempDir.path);
- do_check_true(yield OS.File.exists(downloadDir));
-
- let info = yield OS.File.stat(downloadDir);
- do_check_true(info.isDir);
- } else {
- let targetPath = OS.Path.join(tempDir.path,
- gStringBundle.GetStringFromName("downloadsFolder"));
- try {
- yield OS.File.removeEmptyDir(targetPath);
- } catch (e) {}
- downloadDir = yield DownloadIntegration.getSystemDownloadsDirectory();
- do_check_eq(downloadDir, targetPath);
- do_check_true(yield OS.File.exists(downloadDir));
-
- let info = yield OS.File.stat(downloadDir);
- do_check_true(info.isDir);
- yield OS.File.removeEmptyDir(targetPath);
- }
-});
-
-/**
- * Tests that the real directory returned by getSystemDownloadsDirectory is not
- * the one that is used during unit tests. Since this is the actual downloads
- * directory of the operating system, we don't try to delete it afterwards.
- */
-add_task(function* test_getSystemDownloadsDirectory_real()
-{
- let fakeDownloadDir = yield DownloadIntegration.getSystemDownloadsDirectory();
-
- let cleanup = allowDirectoriesInTest();
- let realDownloadDir = yield DownloadIntegration.getSystemDownloadsDirectory();
- cleanup();
-
- do_check_neq(fakeDownloadDir, realDownloadDir);
-});
-
-/**
- * Tests that the getPreferredDownloadsDirectory returns a valid download
- * directory string path.
- */
-add_task(function* test_getPreferredDownloadsDirectory()
-{
- let cleanupDirectories = allowDirectoriesInTest();
-
- let folderListPrefName = "browser.download.folderList";
- let dirPrefName = "browser.download.dir";
- function cleanupPrefs() {
- Services.prefs.clearUserPref(folderListPrefName);
- Services.prefs.clearUserPref(dirPrefName);
- }
- do_register_cleanup(cleanupPrefs);
-
- // Should return the system downloads directory.
- Services.prefs.setIntPref(folderListPrefName, 1);
- let systemDir = yield DownloadIntegration.getSystemDownloadsDirectory();
- let downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
- do_check_eq(downloadDir, systemDir);
-
- // Should return the desktop directory.
- Services.prefs.setIntPref(folderListPrefName, 0);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
- do_check_eq(downloadDir, Services.dirsvc.get("Desk", Ci.nsIFile).path);
-
- // Should return the system downloads directory because the dir preference
- // is not set.
- Services.prefs.setIntPref(folderListPrefName, 2);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
- do_check_eq(downloadDir, systemDir);
-
- // Should return the directory which is listed in the dir preference.
- let time = (new Date()).getTime();
- let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
- tempDir.append(time);
- Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, tempDir);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
- do_check_eq(downloadDir, tempDir.path);
- do_check_true(yield OS.File.exists(downloadDir));
- yield OS.File.removeEmptyDir(tempDir.path);
-
- // Should return the system downloads directory beacause the path is invalid
- // in the dir preference.
- tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
- tempDir.append("dir_not_exist");
- tempDir.append(time);
- Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, tempDir);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_eq(downloadDir, systemDir);
-
- // Should return the system downloads directory because the folderList
- // preference is invalid
- Services.prefs.setIntPref(folderListPrefName, 999);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_eq(downloadDir, systemDir);
-
- cleanupPrefs();
- cleanupDirectories();
-});
-
-/**
- * Tests that the getTemporaryDownloadsDirectory returns a valid download
- * directory string path.
- */
-add_task(function* test_getTemporaryDownloadsDirectory()
-{
- let cleanup = allowDirectoriesInTest();
-
- let downloadDir = yield DownloadIntegration.getTemporaryDownloadsDirectory();
- do_check_neq(downloadDir, "");
-
- if ("nsILocalFileMac" in Ci) {
- let preferredDownloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_eq(downloadDir, preferredDownloadDir);
- } else {
- let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
- do_check_eq(downloadDir, tempDir.path);
- }
-
- cleanup();
-});
-
-// Tests DownloadObserver
-
-/**
- * Re-enables the default observers for the following tests.
- *
- * This takes effect the first time a DownloadList object is created, and lasts
- * until this test file has completed.
- */
-add_task(function* test_observers_setup()
-{
- DownloadIntegration.allowObservers = true;
- do_register_cleanup(function () {
- DownloadIntegration.allowObservers = false;
- });
-});
-
-/**
- * Tests notifications prompts when observers are notified if there are public
- * and private active downloads.
- */
-add_task(function* test_notifications()
-{
- for (let isPrivate of [false, true]) {
- mustInterruptResponses();
-
- let list = yield promiseNewList(isPrivate);
- let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let download3 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let promiseAttempt1 = download1.start();
- let promiseAttempt2 = download2.start();
- download3.start().catch(() => {});
-
- // Add downloads to list.
- yield list.add(download1);
- yield list.add(download2);
- yield list.add(download3);
- // Cancel third download
- yield download3.cancel();
-
- notifyPromptObservers(isPrivate, 2, 2);
-
- // Allow the downloads to complete.
- continueResponses();
- yield promiseAttempt1;
- yield promiseAttempt2;
-
- // Clean up.
- yield list.remove(download1);
- yield list.remove(download2);
- yield list.remove(download3);
- }
-});
-
-/**
- * Tests that notifications prompts observers are not notified if there are no
- * public or private active downloads.
- */
-add_task(function* test_no_notifications()
-{
- for (let isPrivate of [false, true]) {
- let list = yield promiseNewList(isPrivate);
- let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- download1.start().catch(() => {});
- download2.start().catch(() => {});
-
- // Add downloads to list.
- yield list.add(download1);
- yield list.add(download2);
-
- yield download1.cancel();
- yield download2.cancel();
-
- notifyPromptObservers(isPrivate, 0, 0);
-
- // Clean up.
- yield list.remove(download1);
- yield list.remove(download2);
- }
-});
-
-/**
- * Tests notifications prompts when observers are notified if there are public
- * and private active downloads at the same time.
- */
-add_task(function* test_mix_notifications()
-{
- mustInterruptResponses();
-
- let publicList = yield promiseNewList();
- let privateList = yield Downloads.getList(Downloads.PRIVATE);
- let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let promiseAttempt1 = download1.start();
- let promiseAttempt2 = download2.start();
-
- // Add downloads to lists.
- yield publicList.add(download1);
- yield privateList.add(download2);
-
- notifyPromptObservers(true, 2, 1);
-
- // Allow the downloads to complete.
- continueResponses();
- yield promiseAttempt1;
- yield promiseAttempt2;
-
- // Clean up.
- yield publicList.remove(download1);
- yield privateList.remove(download2);
-});
-
-/**
- * Tests suspending and resuming as well as going offline and then online again.
- * The downloads should stop when suspending and start again when resuming.
- */
-add_task(function* test_suspend_resume()
-{
- // The default wake delay is 10 seconds, so set the wake delay to be much
- // faster for these tests.
- Services.prefs.setIntPref("browser.download.manager.resumeOnWakeDelay", 5);
-
- let addDownload = function(list)
- {
- return Task.spawn(function* () {
- let download = yield promiseNewDownload(httpUrl("interruptible.txt"));
- download.start().catch(() => {});
- list.add(download);
- return download;
- });
- }
-
- let publicList = yield promiseNewList();
- let privateList = yield promiseNewList(true);
-
- let download1 = yield addDownload(publicList);
- let download2 = yield addDownload(publicList);
- let download3 = yield addDownload(privateList);
- let download4 = yield addDownload(privateList);
- let download5 = yield addDownload(publicList);
-
- // First, check that the downloads are all canceled when going to sleep.
- Services.obs.notifyObservers(null, "sleep_notification", null);
- do_check_true(download1.canceled);
- do_check_true(download2.canceled);
- do_check_true(download3.canceled);
- do_check_true(download4.canceled);
- do_check_true(download5.canceled);
-
- // Remove a download. It should not be started again.
- publicList.remove(download5);
- do_check_true(download5.canceled);
-
- // When waking up again, the downloads start again after the wake delay. To be
- // more robust, don't check after a delay but instead just wait for the
- // downloads to finish.
- Services.obs.notifyObservers(null, "wake_notification", null);
- yield download1.whenSucceeded();
- yield download2.whenSucceeded();
- yield download3.whenSucceeded();
- yield download4.whenSucceeded();
-
- // Downloads should no longer be canceled. However, as download5 was removed
- // from the public list, it will not be restarted.
- do_check_false(download1.canceled);
- do_check_true(download5.canceled);
-
- // Create four new downloads and check for going offline and then online again.
-
- download1 = yield addDownload(publicList);
- download2 = yield addDownload(publicList);
- download3 = yield addDownload(privateList);
- download4 = yield addDownload(privateList);
-
- // Going offline should cancel the downloads.
- Services.obs.notifyObservers(null, "network:offline-about-to-go-offline", null);
- do_check_true(download1.canceled);
- do_check_true(download2.canceled);
- do_check_true(download3.canceled);
- do_check_true(download4.canceled);
-
- // Going back online should start the downloads again.
- Services.obs.notifyObservers(null, "network:offline-status-changed", "online");
- yield download1.whenSucceeded();
- yield download2.whenSucceeded();
- yield download3.whenSucceeded();
- yield download4.whenSucceeded();
-
- Services.prefs.clearUserPref("browser.download.manager.resumeOnWakeDelay");
-});
-
-/**
- * Tests both the downloads list and the in-progress downloads are clear when
- * private browsing observer is notified.
- */
-add_task(function* test_exit_private_browsing()
-{
- mustInterruptResponses();
-
- let privateList = yield promiseNewList(true);
- let download1 = yield promiseNewDownload(httpUrl("source.txt"));
- let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let promiseAttempt1 = download1.start();
- download2.start();
-
- // Add downloads to list.
- yield privateList.add(download1);
- yield privateList.add(download2);
-
- // Complete the download.
- yield promiseAttempt1;
-
- do_check_eq((yield privateList.getAll()).length, 2);
-
- // Simulate exiting the private browsing.
- yield new Promise(resolve => {
- DownloadIntegration._testResolveClearPrivateList = resolve;
- Services.obs.notifyObservers(null, "last-pb-context-exited", null);
- });
- delete DownloadIntegration._testResolveClearPrivateList;
-
- do_check_eq((yield privateList.getAll()).length, 0);
-
- continueResponses();
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js b/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
deleted file mode 100644
index dc6c18623..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the integration with legacy interfaces for downloads.
- */
-
-"use strict";
-
-// Execution of common tests
-
-var gUseLegacySaver = true;
-
-var scriptFile = do_get_file("common_test_Download.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadList.js b/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
deleted file mode 100644
index 71e880741..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
+++ /dev/null
@@ -1,564 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the DownloadList object.
- */
-
-"use strict";
-
-// Globals
-
-/**
- * Returns a PRTime in the past usable to add expirable visits.
- *
- * @note Expiration ignores any visit added in the last 7 days, but it's
- * better be safe against DST issues, by going back one day more.
- */
-function getExpirablePRTime()
-{
- let dateObj = new Date();
- // Normalize to midnight
- dateObj.setHours(0);
- dateObj.setMinutes(0);
- dateObj.setSeconds(0);
- dateObj.setMilliseconds(0);
- dateObj = new Date(dateObj.getTime() - 8 * 86400000);
- return dateObj.getTime() * 1000;
-}
-
-/**
- * Adds an expirable history visit for a download.
- *
- * @param aSourceUrl
- * String containing the URI for the download source, or null to use
- * httpUrl("source.txt").
- *
- * @return {Promise}
- * @rejects JavaScript exception.
- */
-function promiseExpirableDownloadVisit(aSourceUrl)
-{
- let deferred = Promise.defer();
- PlacesUtils.asyncHistory.updatePlaces(
- {
- uri: NetUtil.newURI(aSourceUrl || httpUrl("source.txt")),
- visits: [{
- transitionType: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
- visitDate: getExpirablePRTime(),
- }]
- },
- {
- handleError: function handleError(aResultCode, aPlaceInfo) {
- let ex = new Components.Exception("Unexpected error in adding visits.",
- aResultCode);
- deferred.reject(ex);
- },
- handleResult: function () {},
- handleCompletion: function handleCompletion() {
- deferred.resolve();
- }
- });
- return deferred.promise;
-}
-
-// Tests
-
-/**
- * Checks the testing mechanism used to build different download lists.
- */
-add_task(function* test_construction()
-{
- let downloadListOne = yield promiseNewList();
- let downloadListTwo = yield promiseNewList();
- let privateDownloadListOne = yield promiseNewList(true);
- let privateDownloadListTwo = yield promiseNewList(true);
-
- do_check_neq(downloadListOne, downloadListTwo);
- do_check_neq(privateDownloadListOne, privateDownloadListTwo);
- do_check_neq(downloadListOne, privateDownloadListOne);
-});
-
-/**
- * Checks the methods to add and retrieve items from the list.
- */
-add_task(function* test_add_getAll()
-{
- let list = yield promiseNewList();
-
- let downloadOne = yield promiseNewDownload();
- yield list.add(downloadOne);
-
- let itemsOne = yield list.getAll();
- do_check_eq(itemsOne.length, 1);
- do_check_eq(itemsOne[0], downloadOne);
-
- let downloadTwo = yield promiseNewDownload();
- yield list.add(downloadTwo);
-
- let itemsTwo = yield list.getAll();
- do_check_eq(itemsTwo.length, 2);
- do_check_eq(itemsTwo[0], downloadOne);
- do_check_eq(itemsTwo[1], downloadTwo);
-
- // The first snapshot should not have been modified.
- do_check_eq(itemsOne.length, 1);
-});
-
-/**
- * Checks the method to remove items from the list.
- */
-add_task(function* test_remove()
-{
- let list = yield promiseNewList();
-
- yield list.add(yield promiseNewDownload());
- yield list.add(yield promiseNewDownload());
-
- let items = yield list.getAll();
- yield list.remove(items[0]);
-
- // Removing an item that was never added should not raise an error.
- yield list.remove(yield promiseNewDownload());
-
- items = yield list.getAll();
- do_check_eq(items.length, 1);
-});
-
-/**
- * Tests that the "add", "remove", and "getAll" methods on the global
- * DownloadCombinedList object combine the contents of the global DownloadList
- * objects for public and private downloads.
- */
-add_task(function* test_DownloadCombinedList_add_remove_getAll()
-{
- let publicList = yield promiseNewList();
- let privateList = yield Downloads.getList(Downloads.PRIVATE);
- let combinedList = yield Downloads.getList(Downloads.ALL);
-
- let publicDownload = yield promiseNewDownload();
- let privateDownload = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate: true },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- });
-
- yield publicList.add(publicDownload);
- yield privateList.add(privateDownload);
-
- do_check_eq((yield combinedList.getAll()).length, 2);
-
- yield combinedList.remove(publicDownload);
- yield combinedList.remove(privateDownload);
-
- do_check_eq((yield combinedList.getAll()).length, 0);
-
- yield combinedList.add(publicDownload);
- yield combinedList.add(privateDownload);
-
- do_check_eq((yield publicList.getAll()).length, 1);
- do_check_eq((yield privateList.getAll()).length, 1);
- do_check_eq((yield combinedList.getAll()).length, 2);
-
- yield publicList.remove(publicDownload);
- yield privateList.remove(privateDownload);
-
- do_check_eq((yield combinedList.getAll()).length, 0);
-});
-
-/**
- * Checks that views receive the download add and remove notifications, and that
- * adding and removing views works as expected, both for a normal and a combined
- * list.
- */
-add_task(function* test_notifications_add_remove()
-{
- for (let isCombined of [false, true]) {
- // Force creating a new list for both the public and combined cases.
- let list = yield promiseNewList();
- if (isCombined) {
- list = yield Downloads.getList(Downloads.ALL);
- }
-
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate: true },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- });
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
-
- // Check that we receive add notifications for existing elements.
- let addNotifications = 0;
- let viewOne = {
- onDownloadAdded: function (aDownload) {
- // The first download to be notified should be the first that was added.
- if (addNotifications == 0) {
- do_check_eq(aDownload, downloadOne);
- } else if (addNotifications == 1) {
- do_check_eq(aDownload, downloadTwo);
- }
- addNotifications++;
- },
- };
- yield list.addView(viewOne);
- do_check_eq(addNotifications, 2);
-
- // Check that we receive add notifications for new elements.
- yield list.add(yield promiseNewDownload());
- do_check_eq(addNotifications, 3);
-
- // Check that we receive remove notifications.
- let removeNotifications = 0;
- let viewTwo = {
- onDownloadRemoved: function (aDownload) {
- do_check_eq(aDownload, downloadOne);
- removeNotifications++;
- },
- };
- yield list.addView(viewTwo);
- yield list.remove(downloadOne);
- do_check_eq(removeNotifications, 1);
-
- // We should not receive remove notifications after the view is removed.
- yield list.removeView(viewTwo);
- yield list.remove(downloadTwo);
- do_check_eq(removeNotifications, 1);
-
- // We should not receive add notifications after the view is removed.
- yield list.removeView(viewOne);
- yield list.add(yield promiseNewDownload());
- do_check_eq(addNotifications, 3);
- }
-});
-
-/**
- * Checks that views receive the download change notifications, both for a
- * normal and a combined list.
- */
-add_task(function* test_notifications_change()
-{
- for (let isCombined of [false, true]) {
- // Force creating a new list for both the public and combined cases.
- let list = yield promiseNewList();
- if (isCombined) {
- list = yield Downloads.getList(Downloads.ALL);
- }
-
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate: true },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- });
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
-
- // Check that we receive change notifications.
- let receivedOnDownloadChanged = false;
- yield list.addView({
- onDownloadChanged: function (aDownload) {
- do_check_eq(aDownload, downloadOne);
- receivedOnDownloadChanged = true;
- },
- });
- yield downloadOne.start();
- do_check_true(receivedOnDownloadChanged);
-
- // We should not receive change notifications after a download is removed.
- receivedOnDownloadChanged = false;
- yield list.remove(downloadTwo);
- yield downloadTwo.start();
- do_check_false(receivedOnDownloadChanged);
- }
-});
-
-/**
- * Checks that the reference to "this" is correct in the view callbacks.
- */
-add_task(function* test_notifications_this()
-{
- let list = yield promiseNewList();
-
- // Check that we receive change notifications.
- let receivedOnDownloadAdded = false;
- let receivedOnDownloadChanged = false;
- let receivedOnDownloadRemoved = false;
- let view = {
- onDownloadAdded: function () {
- do_check_eq(this, view);
- receivedOnDownloadAdded = true;
- },
- onDownloadChanged: function () {
- // Only do this check once.
- if (!receivedOnDownloadChanged) {
- do_check_eq(this, view);
- receivedOnDownloadChanged = true;
- }
- },
- onDownloadRemoved: function () {
- do_check_eq(this, view);
- receivedOnDownloadRemoved = true;
- },
- };
- yield list.addView(view);
-
- let download = yield promiseNewDownload();
- yield list.add(download);
- yield download.start();
- yield list.remove(download);
-
- // Verify that we executed the checks.
- do_check_true(receivedOnDownloadAdded);
- do_check_true(receivedOnDownloadChanged);
- do_check_true(receivedOnDownloadRemoved);
-});
-
-/**
- * Checks that download is removed on history expiration.
- */
-add_task(function* test_history_expiration()
-{
- mustInterruptResponses();
-
- function cleanup() {
- Services.prefs.clearUserPref("places.history.expiration.max_pages");
- }
- do_register_cleanup(cleanup);
-
- // Set max pages to 0 to make the download expire.
- Services.prefs.setIntPref("places.history.expiration.max_pages", 0);
-
- let list = yield promiseNewList();
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield promiseNewDownload(httpUrl("interruptible.txt"));
-
- let deferred = Promise.defer();
- let removeNotifications = 0;
- let downloadView = {
- onDownloadRemoved: function (aDownload) {
- if (++removeNotifications == 2) {
- deferred.resolve();
- }
- },
- };
- yield list.addView(downloadView);
-
- // Work with one finished download and one canceled download.
- yield downloadOne.start();
- downloadTwo.start().catch(() => {});
- yield downloadTwo.cancel();
-
- // We must replace the visits added while executing the downloads with visits
- // that are older than 7 days, otherwise they will not be expired.
- yield PlacesTestUtils.clearHistory();
- yield promiseExpirableDownloadVisit();
- yield promiseExpirableDownloadVisit(httpUrl("interruptible.txt"));
-
- // After clearing history, we can add the downloads to be removed to the list.
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
-
- // Force a history expiration.
- Cc["@mozilla.org/places/expiration;1"]
- .getService(Ci.nsIObserver).observe(null, "places-debug-start-expiration", -1);
-
- // Wait for both downloads to be removed.
- yield deferred.promise;
-
- cleanup();
-});
-
-/**
- * Checks all downloads are removed after clearing history.
- */
-add_task(function* test_history_clear()
-{
- let list = yield promiseNewList();
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield promiseNewDownload();
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
-
- let deferred = Promise.defer();
- let removeNotifications = 0;
- let downloadView = {
- onDownloadRemoved: function (aDownload) {
- if (++removeNotifications == 2) {
- deferred.resolve();
- }
- },
- };
- yield list.addView(downloadView);
-
- yield downloadOne.start();
- yield downloadTwo.start();
-
- yield PlacesTestUtils.clearHistory();
-
- // Wait for the removal notifications that may still be pending.
- yield deferred.promise;
-});
-
-/**
- * Tests the removeFinished method to ensure that it only removes
- * finished downloads.
- */
-add_task(function* test_removeFinished()
-{
- let list = yield promiseNewList();
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield promiseNewDownload();
- let downloadThree = yield promiseNewDownload();
- let downloadFour = yield promiseNewDownload();
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
- yield list.add(downloadThree);
- yield list.add(downloadFour);
-
- let deferred = Promise.defer();
- let removeNotifications = 0;
- let downloadView = {
- onDownloadRemoved: function (aDownload) {
- do_check_true(aDownload == downloadOne ||
- aDownload == downloadTwo ||
- aDownload == downloadThree);
- do_check_true(removeNotifications < 3);
- if (++removeNotifications == 3) {
- deferred.resolve();
- }
- },
- };
- yield list.addView(downloadView);
-
- // Start three of the downloads, but don't start downloadTwo, then set
- // downloadFour to have partial data. All downloads except downloadFour
- // should be removed.
- yield downloadOne.start();
- yield downloadThree.start();
- yield downloadFour.start();
- downloadFour.hasPartialData = true;
-
- list.removeFinished();
- yield deferred.promise;
-
- let downloads = yield list.getAll()
- do_check_eq(downloads.length, 1);
-});
-
-/**
- * Tests the global DownloadSummary objects for the public, private, and
- * combined download lists.
- */
-add_task(function* test_DownloadSummary()
-{
- mustInterruptResponses();
-
- let publicList = yield promiseNewList();
- let privateList = yield Downloads.getList(Downloads.PRIVATE);
-
- let publicSummary = yield Downloads.getSummary(Downloads.PUBLIC);
- let privateSummary = yield Downloads.getSummary(Downloads.PRIVATE);
- let combinedSummary = yield Downloads.getSummary(Downloads.ALL);
-
- // Add a public download that has succeeded.
- let succeededPublicDownload = yield promiseNewDownload();
- yield succeededPublicDownload.start();
- yield publicList.add(succeededPublicDownload);
-
- // Add a public download that has been canceled midway.
- let canceledPublicDownload =
- yield promiseNewDownload(httpUrl("interruptible.txt"));
- canceledPublicDownload.start().catch(() => {});
- yield promiseDownloadMidway(canceledPublicDownload);
- yield canceledPublicDownload.cancel();
- yield publicList.add(canceledPublicDownload);
-
- // Add a public download that is in progress.
- let inProgressPublicDownload =
- yield promiseNewDownload(httpUrl("interruptible.txt"));
- inProgressPublicDownload.start().catch(() => {});
- yield promiseDownloadMidway(inProgressPublicDownload);
- yield publicList.add(inProgressPublicDownload);
-
- // Add a private download that is in progress.
- let inProgressPrivateDownload = yield Downloads.createDownload({
- source: { url: httpUrl("interruptible.txt"), isPrivate: true },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- });
- inProgressPrivateDownload.start().catch(() => {});
- yield promiseDownloadMidway(inProgressPrivateDownload);
- yield privateList.add(inProgressPrivateDownload);
-
- // Verify that the summary includes the total number of bytes and the
- // currently transferred bytes only for the downloads that are not stopped.
- // For simplicity, we assume that after a download is added to the list, its
- // current state is immediately propagated to the summary object, which is
- // true in the current implementation, though it is not guaranteed as all the
- // download operations may happen asynchronously.
- do_check_false(publicSummary.allHaveStopped);
- do_check_eq(publicSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(publicSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
-
- do_check_false(privateSummary.allHaveStopped);
- do_check_eq(privateSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(privateSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
-
- do_check_false(combinedSummary.allHaveStopped);
- do_check_eq(combinedSummary.progressTotalBytes, TEST_DATA_SHORT.length * 4);
- do_check_eq(combinedSummary.progressCurrentBytes, TEST_DATA_SHORT.length * 2);
-
- yield inProgressPublicDownload.cancel();
-
- // Stopping the download should have excluded it from the summary.
- do_check_true(publicSummary.allHaveStopped);
- do_check_eq(publicSummary.progressTotalBytes, 0);
- do_check_eq(publicSummary.progressCurrentBytes, 0);
-
- do_check_false(privateSummary.allHaveStopped);
- do_check_eq(privateSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(privateSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
-
- do_check_false(combinedSummary.allHaveStopped);
- do_check_eq(combinedSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(combinedSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
-
- yield inProgressPrivateDownload.cancel();
-
- // All the downloads should be stopped now.
- do_check_true(publicSummary.allHaveStopped);
- do_check_eq(publicSummary.progressTotalBytes, 0);
- do_check_eq(publicSummary.progressCurrentBytes, 0);
-
- do_check_true(privateSummary.allHaveStopped);
- do_check_eq(privateSummary.progressTotalBytes, 0);
- do_check_eq(privateSummary.progressCurrentBytes, 0);
-
- do_check_true(combinedSummary.allHaveStopped);
- do_check_eq(combinedSummary.progressTotalBytes, 0);
- do_check_eq(combinedSummary.progressCurrentBytes, 0);
-});
-
-/**
- * Checks that views receive the summary change notification. This is tested on
- * the combined summary when adding a public download, as we assume that if we
- * pass the test in this case we will also pass it in the others.
- */
-add_task(function* test_DownloadSummary_notifications()
-{
- let list = yield promiseNewList();
- let summary = yield Downloads.getSummary(Downloads.ALL);
-
- let download = yield promiseNewDownload();
- yield list.add(download);
-
- // Check that we receive change notifications.
- let receivedOnSummaryChanged = false;
- yield summary.addView({
- onSummaryChanged: function () {
- receivedOnSummaryChanged = true;
- },
- });
- yield download.start();
- do_check_true(receivedOnSummaryChanged);
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js b/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
deleted file mode 100644
index 3a23dfbe3..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
+++ /dev/null
@@ -1,315 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the DownloadStore object.
- */
-
-"use strict";
-
-// Globals
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore",
- "resource://gre/modules/DownloadStore.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm")
-
-/**
- * Returns a new DownloadList object with an associated DownloadStore.
- *
- * @param aStorePath
- * String pointing to the file to be associated with the DownloadStore,
- * or undefined to use a non-existing temporary file. In this case, the
- * temporary file is deleted when the test file execution finishes.
- *
- * @return {Promise}
- * @resolves Array [ Newly created DownloadList , associated DownloadStore ].
- * @rejects JavaScript exception.
- */
-function promiseNewListAndStore(aStorePath)
-{
- return promiseNewList().then(function (aList) {
- let path = aStorePath || getTempFile(TEST_STORE_FILE_NAME).path;
- let store = new DownloadStore(aList, path);
- return [aList, store];
- });
-}
-
-// Tests
-
-/**
- * Saves downloads to a file, then reloads them.
- */
-add_task(function* test_save_reload()
-{
- let [listForSave, storeForSave] = yield promiseNewListAndStore();
- let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
- storeForSave.path);
-
- listForSave.add(yield promiseNewDownload(httpUrl("source.txt")));
- listForSave.add(yield Downloads.createDownload({
- source: { url: httpUrl("empty.txt"),
- referrer: TEST_REFERRER_URL },
- target: getTempFile(TEST_TARGET_FILE_NAME),
- }));
-
- // This PDF download should not be serialized because it never succeeds.
- let pdfDownload = yield Downloads.createDownload({
- source: { url: httpUrl("empty.txt"),
- referrer: TEST_REFERRER_URL },
- target: getTempFile(TEST_TARGET_FILE_NAME),
- saver: "pdf",
- });
- listForSave.add(pdfDownload);
-
- // If we used a callback to adjust the channel, the download should
- // not be serialized because we can't recreate it across sessions.
- let adjustedDownload = yield Downloads.createDownload({
- source: { url: httpUrl("empty.txt"),
- adjustChannel: () => Promise.resolve() },
- target: getTempFile(TEST_TARGET_FILE_NAME),
- });
- listForSave.add(adjustedDownload);
-
- let legacyDownload = yield promiseStartLegacyDownload();
- yield legacyDownload.cancel();
- listForSave.add(legacyDownload);
-
- yield storeForSave.save();
- yield storeForLoad.load();
-
- // Remove the PDF and adjusted downloads because they should not appear here.
- listForSave.remove(adjustedDownload);
- listForSave.remove(pdfDownload);
-
- let itemsForSave = yield listForSave.getAll();
- let itemsForLoad = yield listForLoad.getAll();
-
- do_check_eq(itemsForSave.length, itemsForLoad.length);
-
- // Downloads should be reloaded in the same order.
- for (let i = 0; i < itemsForSave.length; i++) {
- // The reloaded downloads are different objects.
- do_check_neq(itemsForSave[i], itemsForLoad[i]);
-
- // The reloaded downloads have the same properties.
- do_check_eq(itemsForSave[i].source.url,
- itemsForLoad[i].source.url);
- do_check_eq(itemsForSave[i].source.referrer,
- itemsForLoad[i].source.referrer);
- do_check_eq(itemsForSave[i].target.path,
- itemsForLoad[i].target.path);
- do_check_eq(itemsForSave[i].saver.toSerializable(),
- itemsForLoad[i].saver.toSerializable());
- }
-});
-
-/**
- * Checks that saving an empty list deletes any existing file.
- */
-add_task(function* test_save_empty()
-{
- let [, store] = yield promiseNewListAndStore();
-
- let createdFile = yield OS.File.open(store.path, { create: true });
- yield createdFile.close();
-
- yield store.save();
-
- do_check_false(yield OS.File.exists(store.path));
-
- // If the file does not exist, saving should not generate exceptions.
- yield store.save();
-});
-
-/**
- * Checks that loading from a missing file results in an empty list.
- */
-add_task(function* test_load_empty()
-{
- let [list, store] = yield promiseNewListAndStore();
-
- do_check_false(yield OS.File.exists(store.path));
-
- yield store.load();
-
- let items = yield list.getAll();
- do_check_eq(items.length, 0);
-});
-
-/**
- * Loads downloads from a string in a predefined format. The purpose of this
- * test is to verify that the JSON format used in previous versions can be
- * loaded, assuming the file is reloaded on the same platform.
- */
-add_task(function* test_load_string_predefined()
-{
- let [list, store] = yield promiseNewListAndStore();
-
- // The platform-dependent file name should be generated dynamically.
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- let filePathLiteral = JSON.stringify(targetPath);
- let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
- let emptyUriLiteral = JSON.stringify(httpUrl("empty.txt"));
- let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URL);
-
- let string = "{\"list\":[{\"source\":" + sourceUriLiteral + "," +
- "\"target\":" + filePathLiteral + "}," +
- "{\"source\":{\"url\":" + emptyUriLiteral + "," +
- "\"referrer\":" + referrerUriLiteral + "}," +
- "\"target\":" + filePathLiteral + "}]}";
-
- yield OS.File.writeAtomic(store.path,
- new TextEncoder().encode(string),
- { tmpPath: store.path + ".tmp" });
-
- yield store.load();
-
- let items = yield list.getAll();
-
- do_check_eq(items.length, 2);
-
- do_check_eq(items[0].source.url, httpUrl("source.txt"));
- do_check_eq(items[0].target.path, targetPath);
-
- do_check_eq(items[1].source.url, httpUrl("empty.txt"));
- do_check_eq(items[1].source.referrer, TEST_REFERRER_URL);
- do_check_eq(items[1].target.path, targetPath);
-});
-
-/**
- * Loads downloads from a well-formed JSON string containing unrecognized data.
- */
-add_task(function* test_load_string_unrecognized()
-{
- let [list, store] = yield promiseNewListAndStore();
-
- // The platform-dependent file name should be generated dynamically.
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- let filePathLiteral = JSON.stringify(targetPath);
- let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
-
- let string = "{\"list\":[{\"source\":null," +
- "\"target\":null}," +
- "{\"source\":{\"url\":" + sourceUriLiteral + "}," +
- "\"target\":{\"path\":" + filePathLiteral + "}," +
- "\"saver\":{\"type\":\"copy\"}}]}";
-
- yield OS.File.writeAtomic(store.path,
- new TextEncoder().encode(string),
- { tmpPath: store.path + ".tmp" });
-
- yield store.load();
-
- let items = yield list.getAll();
-
- do_check_eq(items.length, 1);
-
- do_check_eq(items[0].source.url, httpUrl("source.txt"));
- do_check_eq(items[0].target.path, targetPath);
-});
-
-/**
- * Loads downloads from a malformed JSON string.
- */
-add_task(function* test_load_string_malformed()
-{
- let [list, store] = yield promiseNewListAndStore();
-
- let string = "{\"list\":[{\"source\":null,\"target\":null}," +
- "{\"source\":{\"url\":\"about:blank\"}}}";
-
- yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
- { tmpPath: store.path + ".tmp" });
-
- try {
- yield store.load();
- do_throw("Exception expected when JSON data is malformed.");
- } catch (ex) {
- if (ex.name != "SyntaxError") {
- throw ex;
- }
- do_print("The expected SyntaxError exception was thrown.");
- }
-
- let items = yield list.getAll();
-
- do_check_eq(items.length, 0);
-});
-
-/**
- * Saves downloads with unknown properties to a file and then reloads
- * them to ensure that these properties are preserved.
- */
-add_task(function* test_save_reload_unknownProperties()
-{
- let [listForSave, storeForSave] = yield promiseNewListAndStore();
- let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
- storeForSave.path);
-
- let download1 = yield promiseNewDownload(httpUrl("source.txt"));
- // startTime should be ignored as it is a known property, and error
- // is ignored by serialization
- download1._unknownProperties = { peanut: "butter",
- orange: "marmalade",
- startTime: 77,
- error: { message: "Passed" } };
- listForSave.add(download1);
-
- let download2 = yield promiseStartLegacyDownload();
- yield download2.cancel();
- download2._unknownProperties = { number: 5, object: { test: "string" } };
- listForSave.add(download2);
-
- let download3 = yield Downloads.createDownload({
- source: { url: httpUrl("empty.txt"),
- referrer: TEST_REFERRER_URL,
- source1: "download3source1",
- source2: "download3source2" },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path,
- target1: "download3target1",
- target2: "download3target2" },
- saver : { type: "copy",
- saver1: "download3saver1",
- saver2: "download3saver2" },
- });
- listForSave.add(download3);
-
- yield storeForSave.save();
- yield storeForLoad.load();
-
- let itemsForSave = yield listForSave.getAll();
- let itemsForLoad = yield listForLoad.getAll();
-
- do_check_eq(itemsForSave.length, itemsForLoad.length);
-
- do_check_eq(Object.keys(itemsForLoad[0]._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[0]._unknownProperties.peanut, "butter");
- do_check_eq(itemsForLoad[0]._unknownProperties.orange, "marmalade");
- do_check_false("startTime" in itemsForLoad[0]._unknownProperties);
- do_check_false("error" in itemsForLoad[0]._unknownProperties);
-
- do_check_eq(Object.keys(itemsForLoad[1]._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[1]._unknownProperties.number, 5);
- do_check_eq(itemsForLoad[1]._unknownProperties.object.test, "string");
-
- do_check_eq(Object.keys(itemsForLoad[2].source._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[2].source._unknownProperties.source1,
- "download3source1");
- do_check_eq(itemsForLoad[2].source._unknownProperties.source2,
- "download3source2");
-
- do_check_eq(Object.keys(itemsForLoad[2].target._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[2].target._unknownProperties.target1,
- "download3target1");
- do_check_eq(itemsForLoad[2].target._unknownProperties.target2,
- "download3target2");
-
- do_check_eq(Object.keys(itemsForLoad[2].saver._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[2].saver._unknownProperties.saver1,
- "download3saver1");
- do_check_eq(itemsForLoad[2].saver._unknownProperties.saver2,
- "download3saver2");
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_Downloads.js b/toolkit/components/jsdownloads/test/unit/test_Downloads.js
deleted file mode 100644
index 2027beee1..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_Downloads.js
+++ /dev/null
@@ -1,194 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the functions located directly in the "Downloads" object.
- */
-
-"use strict";
-
-// Tests
-
-/**
- * Tests that the createDownload function exists and can be called. More
- * detailed tests are implemented separately for the DownloadCore module.
- */
-add_task(function* test_createDownload()
-{
- // Creates a simple Download object without starting the download.
- yield Downloads.createDownload({
- source: { url: "about:blank" },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
- saver: { type: "copy" },
- });
-});
-
-/**
- * Tests createDownload for private download.
- */
-add_task(function* test_createDownload_private()
-{
- let download = yield Downloads.createDownload({
- source: { url: "about:blank", isPrivate: true },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
- saver: { type: "copy" }
- });
- do_check_true(download.source.isPrivate);
-});
-
-/**
- * Tests createDownload for normal (public) download.
- */
-add_task(function* test_createDownload_public()
-{
- let tempPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- let download = yield Downloads.createDownload({
- source: { url: "about:blank", isPrivate: false },
- target: { path: tempPath },
- saver: { type: "copy" }
- });
- do_check_false(download.source.isPrivate);
-
- download = yield Downloads.createDownload({
- source: { url: "about:blank" },
- target: { path: tempPath },
- saver: { type: "copy" }
- });
- do_check_false(download.source.isPrivate);
-});
-
-/**
- * Tests createDownload for a pdf saver throws if only given a url.
- */
-add_task(function* test_createDownload_pdf()
-{
- let download = yield Downloads.createDownload({
- source: { url: "about:blank" },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
- saver: { type: "pdf" },
- });
-
- try {
- yield download.start();
- do_throw("The download should have failed.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseSourceFailed) {
- throw ex;
- }
- }
-
- do_check_false(download.succeeded);
- do_check_true(download.stopped);
- do_check_false(download.canceled);
- do_check_true(download.error !== null);
- do_check_true(download.error.becauseSourceFailed);
- do_check_false(download.error.becauseTargetFailed);
- do_check_false(yield OS.File.exists(download.target.path));
-});
-
-/**
- * Tests "fetch" with nsIURI and nsIFile as arguments.
- */
-add_task(function* test_fetch_uri_file_arguments()
-{
- let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
- yield Downloads.fetch(NetUtil.newURI(httpUrl("source.txt")), targetFile);
- yield promiseVerifyContents(targetFile.path, TEST_DATA_SHORT);
-});
-
-/**
- * Tests "fetch" with DownloadSource and DownloadTarget as arguments.
- */
-add_task(function* test_fetch_object_arguments()
-{
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- yield Downloads.fetch({ url: httpUrl("source.txt") }, { path: targetPath });
- yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
-});
-
-/**
- * Tests "fetch" with string arguments.
- */
-add_task(function* test_fetch_string_arguments()
-{
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- yield Downloads.fetch(httpUrl("source.txt"), targetPath);
- yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
-
- targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- yield Downloads.fetch(new String(httpUrl("source.txt")),
- new String(targetPath));
- yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
-});
-
-/**
- * Tests that the getList function returns the same list when called multiple
- * times with the same argument, but returns different lists when called with
- * different arguments. More detailed tests are implemented separately for the
- * DownloadList module.
- */
-add_task(function* test_getList()
-{
- let publicListOne = yield Downloads.getList(Downloads.PUBLIC);
- let privateListOne = yield Downloads.getList(Downloads.PRIVATE);
-
- let publicListTwo = yield Downloads.getList(Downloads.PUBLIC);
- let privateListTwo = yield Downloads.getList(Downloads.PRIVATE);
-
- do_check_eq(publicListOne, publicListTwo);
- do_check_eq(privateListOne, privateListTwo);
-
- do_check_neq(publicListOne, privateListOne);
-});
-
-/**
- * Tests that the getSummary function returns the same summary when called
- * multiple times with the same argument, but returns different summaries when
- * called with different arguments. More detailed tests are implemented
- * separately for the DownloadSummary object in the DownloadList module.
- */
-add_task(function* test_getSummary()
-{
- let publicSummaryOne = yield Downloads.getSummary(Downloads.PUBLIC);
- let privateSummaryOne = yield Downloads.getSummary(Downloads.PRIVATE);
-
- let publicSummaryTwo = yield Downloads.getSummary(Downloads.PUBLIC);
- let privateSummaryTwo = yield Downloads.getSummary(Downloads.PRIVATE);
-
- do_check_eq(publicSummaryOne, publicSummaryTwo);
- do_check_eq(privateSummaryOne, privateSummaryTwo);
-
- do_check_neq(publicSummaryOne, privateSummaryOne);
-});
-
-/**
- * Tests that the getSystemDownloadsDirectory returns a non-empty download
- * directory string.
- */
-add_task(function* test_getSystemDownloadsDirectory()
-{
- let downloadDir = yield Downloads.getSystemDownloadsDirectory();
- do_check_neq(downloadDir, "");
-});
-
-/**
- * Tests that the getPreferredDownloadsDirectory returns a non-empty download
- * directory string.
- */
-add_task(function* test_getPreferredDownloadsDirectory()
-{
- let downloadDir = yield Downloads.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
-});
-
-/**
- * Tests that the getTemporaryDownloadsDirectory returns a non-empty download
- * directory string.
- */
-add_task(function* test_getTemporaryDownloadsDirectory()
-{
- let downloadDir = yield Downloads.getTemporaryDownloadsDirectory();
- do_check_neq(downloadDir, "");
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js b/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
deleted file mode 100644
index 1308e9782..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-/*
- * The temporary directory downloads saves to, should be only readable
- * for the current user.
- */
-add_task(function* test_private_temp() {
-
- let download = yield promiseStartExternalHelperAppServiceDownload(
- httpUrl("empty.txt"));
-
- yield promiseDownloadStopped(download);
-
- var targetFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
- targetFile.initWithPath(download.target.path);
-
- // 488 is the decimal value of 0o700.
- equal(targetFile.parent.permissions, 448);
-});
diff --git a/toolkit/components/jsdownloads/test/unit/xpcshell.ini b/toolkit/components/jsdownloads/test/unit/xpcshell.ini
deleted file mode 100644
index 8de554540..000000000
--- a/toolkit/components/jsdownloads/test/unit/xpcshell.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-[DEFAULT]
-head = head.js
-tail =
-skip-if = toolkit == 'android'
-
-# Note: The "tail.js" file is not defined in the "tail" key because it calls
-# the "add_test_task" function, that does not work properly in tail files.
-support-files =
- common_test_Download.js
-
-[test_DownloadCore.js]
-[test_DownloadImport.js]
-[test_DownloadIntegration.js]
-[test_DownloadLegacy.js]
-[test_DownloadList.js]
-[test_Downloads.js]
-[test_DownloadStore.js]
-[test_PrivateTemp.js]
-skip-if = os != 'linux'
diff --git a/toolkit/components/lz4/moz.build b/toolkit/components/lz4/moz.build
index a70185930..b94e937de 100644
--- a/toolkit/components/lz4/moz.build
+++ b/toolkit/components/lz4/moz.build
@@ -4,15 +4,11 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
-
EXTRA_JS_MODULES += [
'lz4.js',
'lz4_internal.js',
]
-SOURCES += [
- 'lz4.cpp',
-]
+SOURCES += ['lz4.cpp']
FINAL_LIBRARY = 'xul'
diff --git a/toolkit/components/lz4/tests/xpcshell/.eslintrc.js b/toolkit/components/lz4/tests/xpcshell/.eslintrc.js
deleted file mode 100644
index d35787cd2..000000000
--- a/toolkit/components/lz4/tests/xpcshell/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/lz4/tests/xpcshell/data/chrome.manifest b/toolkit/components/lz4/tests/xpcshell/data/chrome.manifest
deleted file mode 100644
index e2f9a9d8e..000000000
--- a/toolkit/components/lz4/tests/xpcshell/data/chrome.manifest
+++ /dev/null
@@ -1 +0,0 @@
-content test_lz4 ./
diff --git a/toolkit/components/lz4/tests/xpcshell/data/compression.lz b/toolkit/components/lz4/tests/xpcshell/data/compression.lz
deleted file mode 100644
index a354edc03..000000000
Binary files a/toolkit/components/lz4/tests/xpcshell/data/compression.lz and /dev/null differ
diff --git a/toolkit/components/lz4/tests/xpcshell/data/worker_lz4.js b/toolkit/components/lz4/tests/xpcshell/data/worker_lz4.js
deleted file mode 100644
index 47e3ea369..000000000
--- a/toolkit/components/lz4/tests/xpcshell/data/worker_lz4.js
+++ /dev/null
@@ -1,146 +0,0 @@
-importScripts("resource://gre/modules/workers/require.js");
-importScripts("resource://gre/modules/osfile.jsm");
-
-
-function do_print(x) {
- // self.postMessage({kind: "do_print", args: [x]});
- dump("TEST-INFO: " + x + "\n");
-}
-
-function do_check_true(x) {
- self.postMessage({kind: "do_check_true", args: [!!x]});
- if (x) {
- dump("TEST-PASS: " + x + "\n");
- } else {
- throw new Error("do_check_true failed");
- }
-}
-
-function do_check_eq(a, b) {
- let result = a == b;
- self.postMessage({kind: "do_check_true", args: [result]});
- if (!result) {
- throw new Error("do_check_eq failed " + a + " != " + b);
- }
-}
-
-function do_test_complete() {
- self.postMessage({kind: "do_test_complete", args:[]});
-}
-
-self.onmessage = function() {
- try {
- run_test();
- } catch (ex) {
- let {message, moduleStack, moduleName, lineNumber} = ex;
- let error = new Error(message, moduleName, lineNumber);
- error.stack = moduleStack;
- dump("Uncaught error: " + error + "\n");
- dump("Full stack: " + moduleStack + "\n");
- throw error;
- }
-};
-
-var Lz4;
-var Internals;
-function test_import() {
- Lz4 = require("resource://gre/modules/lz4.js");
- Internals = require("resource://gre/modules/lz4_internal.js");
-}
-
-function test_bound() {
- for (let k of ["compress", "decompress", "maxCompressedSize"]) {
- try {
- do_print("Checking the existence of " + k + "\n");
- do_check_true(!!Internals[k]);
- do_print(k + " exists");
- } catch (ex) {
- // Ignore errors
- do_print(k + " doesn't exist!");
- }
- }
-}
-
-function test_reference_file() {
- do_print("Decompress reference file");
- let path = OS.Path.join("data", "compression.lz");
- let data = OS.File.read(path);
- let decompressed = Lz4.decompressFileContent(data);
- let text = (new TextDecoder()).decode(decompressed);
- do_check_eq(text, "Hello, lz4");
-}
-
-function compare_arrays(a, b) {
- return Array.prototype.join.call(a) == Array.prototype.join.call(a);
-}
-
-function run_rawcompression(name, array) {
- do_print("Raw compression test " + name);
- let length = array.byteLength;
- let compressedArray = new Uint8Array(Internals.maxCompressedSize(length));
- let compressedBytes = Internals.compress(array, length, compressedArray);
- compressedArray = new Uint8Array(compressedArray.buffer, 0, compressedBytes);
- do_print("Raw compressed: " + length + " into " + compressedBytes);
-
- let decompressedArray = new Uint8Array(length);
- let decompressedBytes = new ctypes.size_t();
- let success = Internals.decompress(compressedArray, compressedBytes,
- decompressedArray, length,
- decompressedBytes.address());
- do_print("Raw decompression success? " + success);
- do_print("Raw decompression size: " + decompressedBytes.value);
- do_check_true(compare_arrays(array, decompressedArray));
-}
-
-function run_filecompression(name, array) {
- do_print("File compression test " + name);
- let compressed = Lz4.compressFileContent(array);
- do_print("Compressed " + array.byteLength + " bytes into " + compressed.byteLength);
-
- let decompressed = Lz4.decompressFileContent(compressed);
- do_print("Decompressed " + compressed.byteLength + " bytes into " + decompressed.byteLength);
- do_check_true(compare_arrays(array, decompressed));
-}
-
-function run_faileddecompression(name, array) {
- do_print("invalid decompression test " + name);
-
- // Ensure that raw decompression doesn't segfault
- let length = 1 << 14;
- let decompressedArray = new Uint8Array(length);
- let decompressedBytes = new ctypes.size_t();
- Internals.decompress(array, array.byteLength,
- decompressedArray, length,
- decompressedBytes.address());
-
- // File decompression should fail with an acceptable exception
- let exn = null;
- try {
- Lz4.decompressFileContent(array);
- } catch (ex) {
- exn = ex;
- }
- do_check_true(exn);
- if (array.byteLength < 10) {
- do_check_true(exn.becauseLZNoHeader);
- } else {
- do_check_true(exn.becauseLZWrongMagicNumber);
- }
-}
-
-function run_test() {
- test_import();
- test_bound();
- test_reference_file();
- for (let length of [0, 1, 1024]) {
- let array = new Uint8Array(length);
- for (let i = 0; i < length; ++i) {
- array[i] = i % 256;
- }
- let name = length + " bytes";
- run_rawcompression(name, array);
- run_filecompression(name, array);
- run_faileddecompression(name, array);
- }
- do_test_complete();
-}
diff --git a/toolkit/components/lz4/tests/xpcshell/test_lz4.js b/toolkit/components/lz4/tests/xpcshell/test_lz4.js
deleted file mode 100644
index 8a8fc0b21..000000000
--- a/toolkit/components/lz4/tests/xpcshell/test_lz4.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Components.utils.import("resource://gre/modules/Promise.jsm");
-
-var WORKER_SOURCE_URI = "chrome://test_lz4/content/worker_lz4.js";
-do_load_manifest("data/chrome.manifest");
-
-function run_test() {
- run_next_test();
-}
-
-
-add_task(function() {
- let worker = new ChromeWorker(WORKER_SOURCE_URI);
- let deferred = Promise.defer();
- worker.onmessage = function(event) {
- let data = event.data;
- switch (data.kind) {
- case "do_check_true":
- try {
- do_check_true(data.args[0]);
- } catch (ex) {
- // Ignore errors
- }
- return;
- case "do_test_complete":
- deferred.resolve();
- worker.terminate();
- break;
- case "do_print":
- do_print(data.args[0]);
- }
- };
- worker.onerror = function(event) {
- let error = new Error(event.message, event.filename, event.lineno);
- worker.terminate();
- deferred.reject(error);
- };
- worker.postMessage("START");
- return deferred.promise;
-});
-
diff --git a/toolkit/components/lz4/tests/xpcshell/test_lz4_sync.js b/toolkit/components/lz4/tests/xpcshell/test_lz4_sync.js
deleted file mode 100644
index 61605373b..000000000
--- a/toolkit/components/lz4/tests/xpcshell/test_lz4_sync.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-const Cu = Components.utils;
-Cu.import("resource://gre/modules/lz4.js");
-Cu.import("resource://gre/modules/osfile.jsm");
-
-function run_test() {
- run_next_test();
-}
-
-function compare_arrays(a, b) {
- return Array.prototype.join.call(a) == Array.prototype.join.call(a);
-}
-
-add_task(function*() {
- let path = OS.Path.join("data", "compression.lz");
- let data = yield OS.File.read(path);
- let decompressed = Lz4.decompressFileContent(data);
- let text = (new TextDecoder()).decode(decompressed);
- do_check_eq(text, "Hello, lz4");
-});
-
-add_task(function*() {
- for (let length of [0, 1, 1024]) {
- let array = new Uint8Array(length);
- for (let i = 0; i < length; ++i) {
- array[i] = i % 256;
- }
-
- let compressed = Lz4.compressFileContent(array);
- do_print("Compressed " + array.byteLength + " bytes into " +
- compressed.byteLength);
-
- let decompressed = Lz4.decompressFileContent(compressed);
- do_print("Decompressed " + compressed.byteLength + " bytes into " +
- decompressed.byteLength);
-
- do_check_true(compare_arrays(array, decompressed));
- }
-});
diff --git a/toolkit/components/lz4/tests/xpcshell/xpcshell.ini b/toolkit/components/lz4/tests/xpcshell/xpcshell.ini
deleted file mode 100644
index e457f29b2..000000000
--- a/toolkit/components/lz4/tests/xpcshell/xpcshell.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[DEFAULT]
-head =
-tail =
-skip-if = toolkit == 'android'
-support-files =
- data/worker_lz4.js
- data/chrome.manifest
- data/compression.lz
-
-[test_lz4.js]
-[test_lz4_sync.js]
diff --git a/toolkit/components/mediasniffer/moz.build b/toolkit/components/mediasniffer/moz.build
index d4f935f56..21be451dd 100644
--- a/toolkit/components/mediasniffer/moz.build
+++ b/toolkit/components/mediasniffer/moz.build
@@ -4,11 +4,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
-
-EXPORTS += [
- 'nsMediaSniffer.h',
-]
+EXPORTS += ['nsMediaSniffer.h']
UNIFIED_SOURCES += [
'mp3sniff.c',
@@ -17,6 +13,3 @@ UNIFIED_SOURCES += [
]
FINAL_LIBRARY = 'xul'
-
-with Files('**'):
- BUG_COMPONENT = ('Core', 'Video/Audio')
diff --git a/toolkit/components/mediasniffer/test/unit/.eslintrc.js b/toolkit/components/mediasniffer/test/unit/.eslintrc.js
deleted file mode 100644
index d35787cd2..000000000
--- a/toolkit/components/mediasniffer/test/unit/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/mediasniffer/test/unit/data/bug1079747.mp4 b/toolkit/components/mediasniffer/test/unit/data/bug1079747.mp4
deleted file mode 100644
index f00731d7e..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/bug1079747.mp4 and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/detodos.mp3 b/toolkit/components/mediasniffer/test/unit/data/detodos.mp3
deleted file mode 100644
index 12e3f89c2..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/detodos.mp3 and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/ff-inst.exe b/toolkit/components/mediasniffer/test/unit/data/ff-inst.exe
deleted file mode 100644
index 0f02f36e1..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/ff-inst.exe and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/file.mkv b/toolkit/components/mediasniffer/test/unit/data/file.mkv
deleted file mode 100644
index 4618cda03..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/file.mkv and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/file.webm b/toolkit/components/mediasniffer/test/unit/data/file.webm
deleted file mode 100644
index 7bc738b8b..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/file.webm and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/fl10.mp2 b/toolkit/components/mediasniffer/test/unit/data/fl10.mp2
deleted file mode 100644
index bf84d7367..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/fl10.mp2 and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/he_free.mp3 b/toolkit/components/mediasniffer/test/unit/data/he_free.mp3
deleted file mode 100644
index e3da8e6a7..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/he_free.mp3 and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/id3tags.mp3 b/toolkit/components/mediasniffer/test/unit/data/id3tags.mp3
deleted file mode 100644
index 23091e666..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/id3tags.mp3 and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/notags-bad.mp3 b/toolkit/components/mediasniffer/test/unit/data/notags-bad.mp3
deleted file mode 100644
index 5ad89786f..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/notags-bad.mp3 and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/notags-scan.mp3 b/toolkit/components/mediasniffer/test/unit/data/notags-scan.mp3
deleted file mode 100644
index 949b7c468..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/notags-scan.mp3 and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/data/notags.mp3 b/toolkit/components/mediasniffer/test/unit/data/notags.mp3
deleted file mode 100644
index c7db94361..000000000
Binary files a/toolkit/components/mediasniffer/test/unit/data/notags.mp3 and /dev/null differ
diff --git a/toolkit/components/mediasniffer/test/unit/test_mediasniffer.js b/toolkit/components/mediasniffer/test/unit/test_mediasniffer.js
deleted file mode 100644
index b26d554a8..000000000
--- a/toolkit/components/mediasniffer/test/unit/test_mediasniffer.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-Cu.import("resource://testing-common/httpd.js");
-Cu.import("resource://gre/modules/NetUtil.jsm");
-
-const PATH = "/file.meh";
-var httpserver = new HttpServer();
-
-// Each time, the data consist in a string that should be sniffed as Ogg.
-const data = "OggS\0meeeh.";
-var testRan = 0;
-
-// If the content-type is not present, or if it's application/octet-stream, it
-// should be sniffed to application/ogg by the media sniffer. Otherwise, it
-// should not be changed.
-const tests = [
- // Those three first case are the case of a media loaded in a media element.
- // All three should be sniffed.
- { contentType: "",
- expectedContentType: "application/ogg",
- flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS | Ci.nsIChannel.LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE },
- { contentType: "application/octet-stream",
- expectedContentType: "application/ogg",
- flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS | Ci.nsIChannel.LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE },
- { contentType: "application/something",
- expectedContentType: "application/ogg",
- flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS | Ci.nsIChannel.LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE },
- // This last cases test the case of a channel opened while allowing content
- // sniffers to override the content-type, like in the docshell.
- { contentType: "application/octet-stream",
- expectedContentType: "application/ogg",
- flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS },
- { contentType: "",
- expectedContentType: "application/ogg",
- flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS },
- { contentType: "application/something",
- expectedContentType: "application/something",
- flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS },
-];
-
-// A basic listener that reads checks the if we sniffed properly.
-var listener = {
- onStartRequest: function(request, context) {
- do_check_eq(request.QueryInterface(Ci.nsIChannel).contentType,
- tests[testRan].expectedContentType);
- },
-
- onDataAvailable: function(request, context, stream, offset, count) {
- try {
- var bis = Components.classes["@mozilla.org/binaryinputstream;1"]
- .createInstance(Components.interfaces.nsIBinaryInputStream);
- bis.setInputStream(stream);
- bis.readByteArray(bis.available());
- } catch (ex) {
- do_throw("Error in onDataAvailable: " + ex);
- }
- },
-
- onStopRequest: function(request, context, status) {
- testRan++;
- runNext();
- }
-};
-
-function setupChannel(url, flags)
-{
- let uri = "http://localhost:" +
- httpserver.identity.primaryPort + url;
- var chan = NetUtil.newChannel({
- uri: uri,
- loadUsingSystemPrincipal: true,
- contentPolicyType: Ci.nsIContentPolicy.TYPE_MEDIA
- });
- chan.loadFlags |= flags;
- var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
- return httpChan;
-}
-
-function runNext() {
- if (testRan == tests.length) {
- do_test_finished();
- return;
- }
- var channel = setupChannel(PATH, tests[testRan].flags);
- httpserver.registerPathHandler(PATH, function(request, response) {
- response.setHeader("Content-Type", tests[testRan].contentType, false);
- response.bodyOutputStream.write(data, data.length);
- });
- channel.asyncOpen2(listener);
-}
-
-function run_test() {
- httpserver.start(-1);
- do_test_pending();
- try {
- runNext();
- } catch (e) {
- print("ERROR - " + e + "\n");
- }
-}
diff --git a/toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js b/toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js
deleted file mode 100644
index ce30a5c1b..000000000
--- a/toolkit/components/mediasniffer/test/unit/test_mediasniffer_ext.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cc = Components.classes;
-var CC = Components.Constructor;
-
-var BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
- "nsIBinaryOutputStream",
- "setOutputStream");
-
-Cu.import("resource://testing-common/httpd.js");
-Cu.import("resource://gre/modules/NetUtil.jsm");
-
-var httpserver = new HttpServer();
-
-var testRan = 0;
-
-// The tests files we want to test, and the type we should have after sniffing.
-const tests = [
- // Real webm and mkv files truncated to 512 bytes.
- { path: "data/file.webm", expected: "video/webm" },
- { path: "data/file.mkv", expected: "application/octet-stream" },
- // MP3 files with and without id3 headers truncated to 512 bytes.
- // NB these have 208/209 byte frames, but mp3 can require up to
- // 1445 bytes to detect with our method.
- { path: "data/id3tags.mp3", expected: "audio/mpeg" },
- { path: "data/notags.mp3", expected: "audio/mpeg" },
- // MPEG-2 mp3 files.
- { path: "data/detodos.mp3", expected: "audio/mpeg" },
- // Padding bit flipped in the first header: sniffing should fail.
- { path: "data/notags-bad.mp3", expected: "application/octet-stream" },
- // Garbage before header: sniffing should fail.
- { path: "data/notags-scan.mp3", expected: "application/octet-stream" },
- // VBR from the layer III test patterns. We can't sniff this.
- { path: "data/he_free.mp3", expected: "application/octet-stream" },
- // Make sure we reject mp2, which has a similar header.
- { path: "data/fl10.mp2", expected: "application/octet-stream" },
- // Truncated ff installer regression test for bug 875769.
- { path: "data/ff-inst.exe", expected: "application/octet-stream" },
- // MP4 with invalid box size (0) for "ftyp".
- { path: "data/bug1079747.mp4", expected: "application/octet-stream" },
-];
-
-// A basic listener that reads checks the if we sniffed properly.
-var listener = {
- onStartRequest: function(request, context) {
- do_print("Sniffing " + tests[testRan].path);
- do_check_eq(request.QueryInterface(Ci.nsIChannel).contentType, tests[testRan].expected);
- },
-
- onDataAvailable: function(request, context, stream, offset, count) {
- try {
- var bis = Components.classes["@mozilla.org/binaryinputstream;1"]
- .createInstance(Components.interfaces.nsIBinaryInputStream);
- bis.setInputStream(stream);
- bis.readByteArray(bis.available());
- } catch (ex) {
- do_throw("Error in onDataAvailable: " + ex);
- }
- },
-
- onStopRequest: function(request, context, status) {
- testRan++;
- runNext();
- }
-};
-
-function setupChannel(url) {
- var chan = NetUtil.newChannel({
- uri: "http://localhost:" + httpserver.identity.primaryPort + url,
- loadUsingSystemPrincipal: true,
- contentPolicyType: Ci.nsIContentPolicy.TYPE_MEDIA
- });
- var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
- return httpChan;
-}
-
-function runNext() {
- if (testRan == tests.length) {
- do_test_finished();
- return;
- }
- var channel = setupChannel("/");
- channel.asyncOpen2(listener);
-}
-
-function getFileContents(aFile) {
- var fileStream = Cc["@mozilla.org/network/file-input-stream;1"]
- .createInstance(Ci.nsIFileInputStream);
- fileStream.init(aFile, 1, -1, null);
- var bis = Components.classes["@mozilla.org/binaryinputstream;1"]
- .createInstance(Components.interfaces.nsIBinaryInputStream);
- bis.setInputStream(fileStream);
-
- var data = bis.readByteArray(bis.available());
-
- return data;
-}
-
-function handler(metadata, response) {
- response.setStatusLine(metadata.httpVersion, 200, "OK");
- // Send an empty Content-Type, so we are guaranteed to sniff.
- response.setHeader("Content-Type", "", false);
- var body = getFileContents(do_get_file(tests[testRan].path));
- var bos = new BinaryOutputStream(response.bodyOutputStream);
- bos.writeByteArray(body, body.length);
-}
-
-function run_test() {
- // We use a custom handler so we can change the header to force sniffing.
- httpserver.registerPathHandler("/", handler);
- httpserver.start(-1);
- do_test_pending();
- try {
- runNext();
- } catch (e) {
- print("ERROR - " + e + "\n");
- }
-}
diff --git a/toolkit/components/mediasniffer/test/unit/xpcshell.ini b/toolkit/components/mediasniffer/test/unit/xpcshell.ini
deleted file mode 100644
index 5ab4763f9..000000000
--- a/toolkit/components/mediasniffer/test/unit/xpcshell.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-[DEFAULT]
-head =
-tail =
-skip-if = toolkit == 'android'
-support-files =
- data/bug1079747.mp4
- data/detodos.mp3
- data/ff-inst.exe
- data/file.mkv
- data/file.webm
- data/fl10.mp2
- data/he_free.mp3
- data/id3tags.mp3
- data/notags-bad.mp3
- data/notags-scan.mp3
- data/notags.mp3
-
-[test_mediasniffer.js]
-[test_mediasniffer_ext.js]
diff --git a/toolkit/components/microformats/manifest.ini b/toolkit/components/microformats/manifest.ini
deleted file mode 100644
index 24dbcb1ca..000000000
--- a/toolkit/components/microformats/manifest.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[DEFAULT]
-run-if = buildapp == 'browser'
-
-[test/marionette/test_standards.py]
-[test/marionette/test_modules.py]
-[test/marionette/test_interface.py]
-
diff --git a/toolkit/components/microformats/moz.build b/toolkit/components/microformats/moz.build
index 39cefe4c8..ca91e2c46 100644
--- a/toolkit/components/microformats/moz.build
+++ b/toolkit/components/microformats/moz.build
@@ -4,9 +4,4 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-EXTRA_JS_MODULES += [
- 'microformat-shiv.js'
-]
-
-with Files('**'):
- BUG_COMPONENT = ('Toolkit', 'Microformats')
+EXTRA_JS_MODULES += ['microformat-shiv.js']
diff --git a/toolkit/components/microformats/test/interface-tests/count-test.js b/toolkit/components/microformats/test/interface-tests/count-test.js
deleted file mode 100644
index baac56c2b..000000000
--- a/toolkit/components/microformats/test/interface-tests/count-test.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-Unit test for count
-*/
-
-assert = chai.assert;
-
-
-describe('Microformat.count', function() {
-
- it('count', function(){
-
- var doc,
- node,
- result;
-
- var html = 'GlennJaneEvent2015-07-01';
-
-
- doc = document.implementation.createHTMLDocument('New Document');
- node = document.createElement('div');
- node.innerHTML = html;
- doc.body.appendChild(node);
-
- options ={
- 'node': node,
- };
-
- result = Microformats.count(options);
- assert.deepEqual( result, {'h-event': 1,'h-card': 2} );
-
- });
-
-
- it('count rels', function(){
-
- var doc,
- node,
- result;
-
- var html = 'GlennJaneEvent2015-07-01';
-
-
- doc = document.implementation.createHTMLDocument('New Document');
- node = document.createElement('div');
- node.innerHTML = html;
- doc.body.appendChild(node);
-
- options ={
- 'node': node,
- };
-
- result = Microformats.count(options);
- assert.deepEqual( result, {'h-event': 1,'h-card': 2, 'rels': 1} );
-
- });
-
-
- it('count - no results', function(){
-
- var doc,
- node,
- result;
-
- var html = 'Jane';
-
-
- doc = document.implementation.createHTMLDocument('New Document');
- node = document.createElement('div');
- node.innerHTML = html;
- doc.body.appendChild(node);
-
- options ={
- 'node': node,
- };
-
- result = Microformats.count(options);
- assert.deepEqual( result, {} );
-
- });
-
-
-
- it('count - no options', function(){
-
- var result;
-
- result = Microformats.count({});
- assert.deepEqual( result, {} );
-
- });
-
-
- it('count - options.html', function(){
-
- var options = {},
- result;
-
- options.html = 'GlennJaneEvent2015-07-01';
-
- result = Microformats.count(options);
- assert.deepEqual( result, {'h-event': 1,'h-card': 2} );
-
- });
-
-
-
- });
diff --git a/toolkit/components/microformats/test/interface-tests/experimental-test.js b/toolkit/components/microformats/test/interface-tests/experimental-test.js
deleted file mode 100644
index 4d32b83c0..000000000
--- a/toolkit/components/microformats/test/interface-tests/experimental-test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-Unit test for get
-*/
-
-assert = chai.assert;
-
-
-describe('experimental', function() {
-
- it('h-geo - geo data writen as lat;lon', function(){
-
- var expected = {
- 'items': [{
- 'type': ['h-geo'],
- 'properties': {
- 'name': ['30.267991;-97.739568'],
- 'latitude': [30.267991],
- 'longitude': [-97.739568]
- }
- }],
- 'rels': {},
- 'rel-urls': {}
- },
- options = {
- 'html': '