From 28f51339d1898626a7200e57a0c57f65d92368b1 Mon Sep 17 00:00:00 2001 From: Dorel Luca Date: Thu, 7 Feb 2019 13:55:33 +0200 Subject: [PATCH] Backed out 3 changesets (bug 1523272) for Browser-chrome and tv failures in browser/components/preferences/in-content/tests/siteData/browser_siteData3.js Backed out changeset ddf39b3e96df (bug 1523272) Backed out changeset 8fbf00832008 (bug 1523272) Backed out changeset 7250b9f956b6 (bug 1523272) --- .../test/sanitize/SiteDataTestUtils.jsm | 42 ++-- .../test/sanitize/browser_cookiePermission.js | 5 +- .../tests/siteData/browser_siteData2.js | 104 ++++----- .../tests/siteData/browser_siteData3.js | 202 ++++++++++++------ .../siteData/browser_siteData_multi_select.js | 75 ++++--- .../in-content/tests/siteData/head.js | 77 +++++-- browser/modules/SiteDataManager.jsm | 116 +++++----- .../modules/test/unit/test_SiteDataManager.js | 148 ------------- browser/modules/test/unit/xpcshell.ini | 1 - 9 files changed, 363 insertions(+), 407 deletions(-) delete mode 100644 browser/modules/test/unit/test_SiteDataManager.js diff --git a/browser/base/content/test/sanitize/SiteDataTestUtils.jsm b/browser/base/content/test/sanitize/SiteDataTestUtils.jsm index 3e24dcb756ca..af50a049b221 100644 --- a/browser/base/content/test/sanitize/SiteDataTestUtils.jsm +++ b/browser/base/content/test/sanitize/SiteDataTestUtils.jsm @@ -15,8 +15,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "swm", "@mozilla.org/serviceworkers/manager;1", "nsIServiceWorkerManager"); -XPCOMUtils.defineLazyGlobalGetters(this, ["indexedDB", "Blob"]); - /** * This module assists with tasks around testing functionality that shows * or clears site data. @@ -27,44 +25,31 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["indexedDB", "Blob"]); var SiteDataTestUtils = { /** - * Makes an origin have persistent data storage. - * - * @param {String} origin - the origin of the site to give persistent storage - * - * @returns a Promise that resolves when storage was persisted - */ - persist(origin, value = Services.perms.ALLOW_ACTION) { - return new Promise(resolve => { - let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin); - Services.perms.addFromPrincipal(principal, "persistent-storage", value); - Services.qms.persist(principal).callback = () => resolve(); - }); - }, - - /** - * Adds a new blob entry to a dummy indexedDB database for the specified origin. + * Adds a new entry to a dummy indexedDB database for the specified origin. * * @param {String} origin - the origin of the site to add test data for - * @param {Number} size [optional] - the size of the entry in bytes + * @param {String} name [optional] - the entry key + * @param {String} value [optional] - the entry value + * @param {Object} originAttributes [optional] - the originAttributes * * @returns a Promise that resolves when the data was added successfully. */ - addToIndexedDB(origin, size = 1024) { + addToIndexedDB(origin, key = "foo", value = "bar", originAttributes = {}) { return new Promise(resolve => { - let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin); + let uri = Services.io.newURI(origin); + let principal = + Services.scriptSecurityManager.createCodebasePrincipal(uri, originAttributes); let request = indexedDB.openForPrincipal(principal, "TestDatabase", 1); request.onupgradeneeded = function(e) { let db = e.target.result; - db.createObjectStore("TestStore"); + db.createObjectStore("TestStore", { keyPath: "id" }); }; request.onsuccess = function(e) { let db = e.target.result; let tx = db.transaction("TestStore", "readwrite"); let store = tx.objectStore("TestStore"); tx.oncomplete = resolve; - let buffer = new ArrayBuffer(size); - let blob = new Blob([buffer]); - store.add(blob, Cu.now()); + store.put({ id: key, description: value}); }; }); }, @@ -78,8 +63,8 @@ var SiteDataTestUtils = { * @param {String} value [optional] - the cookie value */ addToCookies(origin, name = "foo", value = "bar") { - let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin); - Services.cookies.add(principal.URI.host, principal.URI.pathQueryRef, name, value, + let uri = Services.io.newURI(origin); + Services.cookies.add(uri.host, uri.pathQueryRef, name, value, false, false, false, Date.now() + 24000 * 60 * 60, {}, Ci.nsICookie2.SAMESITE_UNSET); }, @@ -136,7 +121,8 @@ var SiteDataTestUtils = { */ getQuotaUsage(origin) { return new Promise(resolve => { - let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin); + let uri = Services.io.newURI(origin); + let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); Services.qms.getUsageForPrincipal(principal, request => resolve(request.result.usage)); }); }, diff --git a/browser/base/content/test/sanitize/browser_cookiePermission.js b/browser/base/content/test/sanitize/browser_cookiePermission.js index 897c2e91b1fb..74745dc07696 100644 --- a/browser/base/content/test/sanitize/browser_cookiePermission.js +++ b/browser/base/content/test/sanitize/browser_cookiePermission.js @@ -18,9 +18,8 @@ function checkDataForAboutURL() { } function createIndexedDB(host, originAttributes) { - let uri = Services.io.newURI("https://" + host); - let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, originAttributes); - return SiteDataTestUtils.addToIndexedDB(principal.origin); + return SiteDataTestUtils.addToIndexedDB("https://" + host, "foo", "bar", + originAttributes); } function checkIndexedDB(host, originAttributes) { diff --git a/browser/components/preferences/in-content/tests/siteData/browser_siteData2.js b/browser/components/preferences/in-content/tests/siteData/browser_siteData2.js index e929c9c9d00c..d8aed9b70131 100644 --- a/browser/components/preferences/in-content/tests/siteData/browser_siteData2.js +++ b/browser/components/preferences/in-content/tests/siteData/browser_siteData2.js @@ -12,8 +12,8 @@ function assertAllSitesNotListed(win) { } // Test selecting and removing all sites one by one -add_task(async function test_selectRemove() { - let hosts = await addTestData([ +add_task(async function() { + mockSiteDataManager.register(SiteDataManager, [ { usage: 1024, origin: "https://account.xyz.com", @@ -22,6 +22,7 @@ add_task(async function test_selectRemove() { { usage: 1024, origin: "https://shopping.xyz.com", + persisted: false, }, { usage: 1024, @@ -31,11 +32,12 @@ add_task(async function test_selectRemove() { { usage: 1024, origin: "http://email.bar.com", + persisted: false, }, ]); + let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host); let updatePromise = promiseSiteDataManagerSitesUpdated(); - await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); await updatePromise; await openSiteDataSettingsDialog(); @@ -48,7 +50,7 @@ add_task(async function test_selectRemove() { let settingsDialogClosePromise = null; // Test the initial state - assertSitesListed(doc, hosts); + assertSitesListed(doc, fakeHosts); // Test the "Cancel" button settingsDialogClosePromise = promiseSettingsDialogClose(); @@ -59,7 +61,7 @@ add_task(async function test_selectRemove() { cancelBtn.doCommand(); await settingsDialogClosePromise; await openSiteDataSettingsDialog(); - assertSitesListed(doc, hosts); + assertSitesListed(doc, fakeHosts); // Test the "Save Changes" button but cancelling save let cancelPromise = BrowserTestUtils.promiseAlertDialogOpen("cancel"); @@ -74,7 +76,7 @@ add_task(async function test_selectRemove() { cancelBtn.doCommand(); await settingsDialogClosePromise; await openSiteDataSettingsDialog(); - assertSitesListed(doc, hosts); + assertSitesListed(doc, fakeHosts); // Test the "Save Changes" button and accepting save let acceptPromise = BrowserTestUtils.promiseAlertDialogOpen("accept"); @@ -91,7 +93,7 @@ add_task(async function test_selectRemove() { await openSiteDataSettingsDialog(); assertAllSitesNotListed(win); - await SiteDataTestUtils.clear(); + await mockSiteDataManager.unregister(); BrowserTestUtils.removeTab(gBrowser.selectedTab); function removeAllSitesOneByOne() { @@ -107,8 +109,8 @@ add_task(async function test_selectRemove() { }); // Test selecting and removing partial sites -add_task(async function test_removePartialSites() { - let hosts = await addTestData([ +add_task(async function() { + mockSiteDataManager.register(SiteDataManager, [ { usage: 1024, origin: "https://account.xyz.com", @@ -139,10 +141,15 @@ add_task(async function test_removePartialSites() { origin: "https://127.0.0.1", persisted: false, }, + { + usage: 1024, + origin: "https://[0:0:0:0:0:0:0:1]", + persisted: true, + }, ]); + let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host); let updatePromise = promiseSiteDataManagerSitesUpdated(); - await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); await updatePromise; await openSiteDataSettingsDialog(); @@ -156,18 +163,18 @@ add_task(async function test_removePartialSites() { let settingsDialogClosePromise = null; // Test the initial state - assertSitesListed(doc, hosts); + assertSitesListed(doc, fakeHosts); // Test the "Cancel" button settingsDialogClosePromise = promiseSettingsDialogClose(); frameDoc = win.gSubDialog._topDialog._frame.contentDocument; cancelBtn = frameDoc.getElementById("cancel"); - await removeSelectedSite(hosts.slice(0, 2)); - assertSitesListed(doc, hosts.slice(2)); + removeSelectedSite(fakeHosts.slice(0, 2)); + assertSitesListed(doc, fakeHosts.slice(2)); cancelBtn.doCommand(); await settingsDialogClosePromise; await openSiteDataSettingsDialog(); - assertSitesListed(doc, hosts); + assertSitesListed(doc, fakeHosts); // Test the "Save Changes" button but canceling save removeDialogOpenPromise = BrowserTestUtils.promiseAlertDialogOpen("cancel", REMOVE_DIALOG_URL); @@ -175,49 +182,44 @@ add_task(async function test_removePartialSites() { frameDoc = win.gSubDialog._topDialog._frame.contentDocument; saveBtn = frameDoc.getElementById("save"); cancelBtn = frameDoc.getElementById("cancel"); - await removeSelectedSite(hosts.slice(0, 2)); - assertSitesListed(doc, hosts.slice(2)); + removeSelectedSite(fakeHosts.slice(0, 2)); + assertSitesListed(doc, fakeHosts.slice(2)); saveBtn.doCommand(); await removeDialogOpenPromise; cancelBtn.doCommand(); await settingsDialogClosePromise; await openSiteDataSettingsDialog(); - assertSitesListed(doc, hosts); + assertSitesListed(doc, fakeHosts); // Test the "Save Changes" button and accepting save removeDialogOpenPromise = BrowserTestUtils.promiseAlertDialogOpen("accept", REMOVE_DIALOG_URL); settingsDialogClosePromise = promiseSettingsDialogClose(); frameDoc = win.gSubDialog._topDialog._frame.contentDocument; saveBtn = frameDoc.getElementById("save"); - await removeSelectedSite(hosts.slice(0, 2)); - assertSitesListed(doc, hosts.slice(2)); + removeSelectedSite(fakeHosts.slice(0, 2)); + assertSitesListed(doc, fakeHosts.slice(2)); saveBtn.doCommand(); await removeDialogOpenPromise; await settingsDialogClosePromise; await openSiteDataSettingsDialog(); - assertSitesListed(doc, hosts.slice(2)); + assertSitesListed(doc, fakeHosts.slice(2)); - await SiteDataTestUtils.clear(); + await mockSiteDataManager.unregister(); BrowserTestUtils.removeTab(gBrowser.selectedTab); - function removeSelectedSite(removeHosts) { + function removeSelectedSite(hosts) { frameDoc = win.gSubDialog._topDialog._frame.contentDocument; let removeBtn = frameDoc.getElementById("removeSelected"); is(removeBtn.disabled, true, "Should start with disabled removeSelected button"); let sitesList = frameDoc.getElementById("sitesList"); - removeHosts.forEach(host => { + hosts.forEach(host => { let site = sitesList.querySelector(`richlistitem[host="${host}"]`); if (site) { site.click(); let currentSelectedIndex = sitesList.selectedIndex; is(removeBtn.disabled, false, "Should enable the removeSelected button"); removeBtn.doCommand(); - let newSelectedIndex = sitesList.selectedIndex; - if (currentSelectedIndex >= sitesList.itemCount) { - is(newSelectedIndex, currentSelectedIndex - 1); - } else { - is(newSelectedIndex, currentSelectedIndex); - } + is(sitesList.selectedIndex, currentSelectedIndex); } else { ok(false, `Should not select and remove inexistent site of ${host}`); } @@ -227,7 +229,7 @@ add_task(async function test_removePartialSites() { // Test searching and then removing only visible sites add_task(async function() { - let hosts = await addTestData([ + mockSiteDataManager.register(SiteDataManager, [ { usage: 1024, origin: "https://account.xyz.com", @@ -249,9 +251,9 @@ add_task(async function() { persisted: false, }, ]); + let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host); let updatePromise = promiseSiteDataManagerSitesUpdated(); - await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); await updatePromise; await openSiteDataSettingsDialog(); @@ -263,7 +265,7 @@ add_task(async function() { let searchBox = frameDoc.getElementById("searchBox"); searchBox.value = "xyz"; searchBox.doCommand(); - assertSitesListed(doc, hosts.filter(host => host.includes("xyz"))); + assertSitesListed(doc, fakeHosts.filter(host => host.includes("xyz"))); // Test only removing all visible sites listed updatePromise = promiseSiteDataManagerSitesUpdated(); @@ -277,15 +279,15 @@ add_task(async function() { await settingsDialogClosePromise; await updatePromise; await openSiteDataSettingsDialog(); - assertSitesListed(doc, hosts.filter(host => !host.includes("xyz"))); + assertSitesListed(doc, fakeHosts.filter(host => !host.includes("xyz"))); - await SiteDataTestUtils.clear(); + await mockSiteDataManager.unregister(); BrowserTestUtils.removeTab(gBrowser.selectedTab); }); // Test dynamically clearing all site data add_task(async function() { - let hosts = await addTestData([ + mockSiteDataManager.register(SiteDataManager, [ { usage: 1024, origin: "https://account.xyz.com", @@ -297,28 +299,28 @@ add_task(async function() { persisted: false, }, ]); - - let updatePromise = promiseSiteDataManagerSitesUpdated(); + let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host); // Test the initial state + let updatePromise = promiseSiteDataManagerSitesUpdated(); await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); await updatePromise; await openSiteDataSettingsDialog(); let doc = gBrowser.selectedBrowser.contentDocument; - assertSitesListed(doc, hosts); + assertSitesListed(doc, fakeHosts); - await addTestData([ - { - usage: 1024, - origin: "http://cinema.bar.com", - persisted: true, - }, - { - usage: 1024, - origin: "http://email.bar.com", - persisted: false, - }, - ]); + // Add more sites dynamically + mockSiteDataManager.fakeSites.push({ + usage: 1024, + principal: Services.scriptSecurityManager + .createCodebasePrincipalFromOrigin("http://cinema.bar.com"), + persisted: true, + }, { + usage: 1024, + principal: Services.scriptSecurityManager + .createCodebasePrincipalFromOrigin("http://email.bar.com"), + persisted: false, + }); // Test clearing all site data dynamically let win = gBrowser.selectedBrowser.contentWindow; @@ -336,6 +338,6 @@ add_task(async function() { await openSiteDataSettingsDialog(); assertAllSitesNotListed(win); - await SiteDataTestUtils.clear(); + await mockSiteDataManager.unregister(); BrowserTestUtils.removeTab(gBrowser.selectedTab); }); diff --git a/browser/components/preferences/in-content/tests/siteData/browser_siteData3.js b/browser/components/preferences/in-content/tests/siteData/browser_siteData3.js index 3146ac817449..1fa44d79ef05 100644 --- a/browser/components/preferences/in-content/tests/siteData/browser_siteData3.js +++ b/browser/components/preferences/in-content/tests/siteData/browser_siteData3.js @@ -1,8 +1,8 @@ "use strict"; // Test not displaying sites which store 0 byte and don't have persistent storage. -add_task(async function test_exclusions() { - let hosts = await addTestData([ +add_task(async function() { + mockSiteDataManager.register(SiteDataManager, [ { usage: 0, origin: "https://account.xyz.com", @@ -30,22 +30,23 @@ add_task(async function test_exclusions() { persisted: false, }, ]); + let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host); let updatePromise = promiseSiteDataManagerSitesUpdated(); let doc = gBrowser.selectedBrowser.contentDocument; await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); await updatePromise; await openSiteDataSettingsDialog(); - assertSitesListed(doc, hosts.filter(host => host != "shopping.xyz.com")); + assertSitesListed(doc, fakeHosts.filter(host => host != "shopping.xyz.com")); - await SiteDataTestUtils.clear(); + await mockSiteDataManager.unregister(); BrowserTestUtils.removeTab(gBrowser.selectedTab); }); // Test grouping and listing sites across scheme, port and origin attributes by host -add_task(async function test_grouping() { - let quotaUsage = 7000000; - await addTestData([ +add_task(async function() { + const quotaUsage = 1024; + mockSiteDataManager.register(SiteDataManager, [ { usage: quotaUsage, origin: "https://account.xyz.com^userContextId=1", @@ -90,61 +91,40 @@ add_task(async function test_grouping() { is(columns[1].value, "5", "Should group cookies across scheme, port and origin attributes"); - let [value, unit] = DownloadUtils.convertByteUnits(quotaUsage * 4); - let l10nAttributes = frameDoc.l10n.getAttributes(columns[2]); - is(l10nAttributes.id, "site-usage-persistent", - "Should show the site as persistent if one origin is persistent."); - // The shown quota can be slightly larger than the raw data we put in (though it should - // never be smaller), but that doesn't really matter to us since we only want to test that - // the site data dialog accumulates this into a single column. - ok(parseFloat(l10nAttributes.args.value) >= parseFloat(value), - "Should show the correct accumulated quota size."); - is(l10nAttributes.args.unit, unit, "Should show the correct quota size unit."); + let [value, unit] = DownloadUtils.convertByteUnits(quotaUsage * mockSiteDataManager.fakeSites.length); + Assert.deepEqual(frameDoc.l10n.getAttributes(columns[2]), { + id: "site-usage-persistent", + args: { value, unit }, + }, "Should sum up usages across scheme, port, origin attributes and persistent status"); - await SiteDataTestUtils.clear(); + await mockSiteDataManager.unregister(); BrowserTestUtils.removeTab(gBrowser.selectedTab); }); // Test sorting -add_task(async function test_sorting() { - let testData = [ +add_task(async function() { + mockSiteDataManager.register(SiteDataManager, [ { - baseDomain: "xyz.com", usage: 1024, origin: "https://account.xyz.com", cookies: 6, persisted: true, }, { - baseDomain: "foo.com", usage: 1024 * 2, origin: "https://books.foo.com", cookies: 0, persisted: false, }, { - baseDomain: "bar.com", usage: 1024 * 3, origin: "http://cinema.bar.com", cookies: 3, persisted: true, }, - ]; - - await addTestData(testData); - - // Add a bunch of cookies with slight delay to enable testing - // by last storage access. - for (let site of testData) { - /* eslint-disable-next-line mozilla/no-arbitrary-setTimeout */ - await new Promise(r => setTimeout(r, 1500)); - SiteDataTestUtils.addToCookies(site.origin, Cu.now()); - site.cookies += 1; - site.lastAccessed = Cu.now(); - } + ]); let updatePromise = promiseSiteDataManagerSitesUpdated(); - await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); await updatePromise; await openSiteDataSettingsDialog(); @@ -155,50 +135,146 @@ add_task(async function test_sorting() { let hostCol = frameDoc.getElementById("hostCol"); let usageCol = frameDoc.getElementById("usageCol"); let cookiesCol = frameDoc.getElementById("cookiesCol"); - let lastAccessedCol = frameDoc.getElementById("lastAccessedCol"); let sitesList = frameDoc.getElementById("sitesList"); - function getHostOrder() { - let siteItems = sitesList.getElementsByTagName("richlistitem"); - return Array.from(siteItems).map(item => item.getAttribute("host")); - } - - // Test default sorting by usage, descending. - Assert.deepEqual(getHostOrder(), - ["cinema.bar.com", "books.foo.com", "account.xyz.com"], "Has sorted descending by usage"); + // Test default sorting + assertSortByUsage("descending"); // Test sorting on the usage column usageCol.click(); - Assert.deepEqual(getHostOrder(), - ["account.xyz.com", "books.foo.com", "cinema.bar.com"], "Has sorted ascending by usage"); + assertSortByUsage("ascending"); usageCol.click(); - Assert.deepEqual(getHostOrder(), - ["cinema.bar.com", "books.foo.com", "account.xyz.com"], "Has sorted descending by usage"); + assertSortByUsage("descending"); // Test sorting on the host column hostCol.click(); - Assert.deepEqual(getHostOrder(), - ["cinema.bar.com", "books.foo.com", "account.xyz.com"], "Has sorted ascending by base domain"); + assertSortByBaseDomain("ascending"); hostCol.click(); - Assert.deepEqual(getHostOrder(), - ["account.xyz.com", "books.foo.com", "cinema.bar.com"], "Has sorted descending by base domain"); + assertSortByBaseDomain("descending"); // Test sorting on the cookies column cookiesCol.click(); - Assert.deepEqual(getHostOrder(), - ["books.foo.com", "cinema.bar.com", "account.xyz.com"], "Has sorted ascending by cookies"); + assertSortByCookies("ascending"); cookiesCol.click(); - Assert.deepEqual(getHostOrder(), - ["account.xyz.com", "cinema.bar.com", "books.foo.com"], "Has sorted descending by cookies"); + assertSortByCookies("descending"); + + await mockSiteDataManager.unregister(); + BrowserTestUtils.removeTab(gBrowser.selectedTab); + + function assertSortByBaseDomain(order) { + let siteItems = sitesList.getElementsByTagName("richlistitem"); + for (let i = 0; i < siteItems.length - 1; ++i) { + let aHost = siteItems[i].getAttribute("host"); + let bHost = siteItems[i + 1].getAttribute("host"); + let a = findSiteByHost(aHost); + let b = findSiteByHost(bHost); + let result = a.baseDomain.localeCompare(b.baseDomain); + if (order == "ascending") { + Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by host"); + } else { + Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by host"); + } + } + } + + function assertSortByUsage(order) { + let siteItems = sitesList.getElementsByTagName("richlistitem"); + for (let i = 0; i < siteItems.length - 1; ++i) { + let aHost = siteItems[i].getAttribute("host"); + let bHost = siteItems[i + 1].getAttribute("host"); + let a = findSiteByHost(aHost); + let b = findSiteByHost(bHost); + let result = a.usage - b.usage; + if (order == "ascending") { + Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by usage"); + } else { + Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by usage"); + } + } + } + + function assertSortByCookies(order) { + let siteItems = sitesList.getElementsByTagName("richlistitem"); + for (let i = 0; i < siteItems.length - 1; ++i) { + let aHost = siteItems[i].getAttribute("host"); + let bHost = siteItems[i + 1].getAttribute("host"); + let a = findSiteByHost(aHost); + let b = findSiteByHost(bHost); + let result = a.cookies.length - b.cookies.length; + if (order == "ascending") { + Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by number of cookies"); + } else { + Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by number of cookies"); + } + } + } + + function findSiteByHost(host) { + return mockSiteDataManager.fakeSites.find(site => site.principal.URI.host == host); + } +}); + +// Test sorting based on access date (separate from cookies for simplicity, +// since cookies access date affects this as well, but we don't mock our cookies) +add_task(async function() { + mockSiteDataManager.register(SiteDataManager, [ + { + usage: 1024, + origin: "https://account.xyz.com", + persisted: true, + lastAccessed: (Date.now() - 120 * 1000) * 1000, + }, + { + usage: 1024 * 2, + origin: "https://books.foo.com", + persisted: false, + lastAccessed: (Date.now() - 240 * 1000) * 1000, + }, + { + usage: 1024 * 3, + origin: "http://cinema.bar.com", + persisted: true, + lastAccessed: Date.now() * 1000, + }, + ]); + + let updatePromise = promiseSiteDataManagerSitesUpdated(); + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + await updatePromise; + await openSiteDataSettingsDialog(); + + let dialog = content.gSubDialog._topDialog; + let dialogFrame = dialog._frame; + let frameDoc = dialogFrame.contentDocument; + let lastAccessedCol = frameDoc.getElementById("lastAccessedCol"); + let sitesList = frameDoc.getElementById("sitesList"); // Test sorting on the date column lastAccessedCol.click(); - await TestUtils.waitForCondition(() => getHostOrder().join(",") == ["account.xyz.com", "books.foo.com", "cinema.bar.com"].join(","), - "Has sorted ascending by date"); + assertSortByDate("ascending"); lastAccessedCol.click(); - await TestUtils.waitForCondition(() => getHostOrder().join(",") == ["cinema.bar.com", "books.foo.com", "account.xyz.com"].join(","), - "Has sorted descending by date"); + assertSortByDate("descending"); - await SiteDataTestUtils.clear(); + await mockSiteDataManager.unregister(); BrowserTestUtils.removeTab(gBrowser.selectedTab); + + function assertSortByDate(order) { + let siteItems = sitesList.getElementsByTagName("richlistitem"); + for (let i = 0; i < siteItems.length - 1; ++i) { + let aHost = siteItems[i].getAttribute("host"); + let bHost = siteItems[i + 1].getAttribute("host"); + let a = findSiteByHost(aHost); + let b = findSiteByHost(bHost); + let result = a.lastAccessed - b.lastAccessed; + if (order == "ascending") { + Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by date"); + } else { + Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order date"); + } + } + } + + function findSiteByHost(host) { + return mockSiteDataManager.fakeSites.find(site => site.principal.URI.host == host); + } }); diff --git a/browser/components/preferences/in-content/tests/siteData/browser_siteData_multi_select.js b/browser/components/preferences/in-content/tests/siteData/browser_siteData_multi_select.js index aecf10ff539a..34266fb22b14 100644 --- a/browser/components/preferences/in-content/tests/siteData/browser_siteData_multi_select.js +++ b/browser/components/preferences/in-content/tests/siteData/browser_siteData_multi_select.js @@ -2,40 +2,44 @@ // Test selecting and removing partial sites add_task(async function() { - await SiteDataTestUtils.clear(); - - let hosts = await addTestData([ + mockSiteDataManager.register(SiteDataManager, [ + { + usage: 1024, + origin: "https://account.xyz.com", + persisted: true, + }, + { + usage: 1024, + origin: "https://shopping.xyz.com", + persisted: false, + }, + { + usage: 1024, + origin: "http://cinema.bar.com", + persisted: true, + }, + { + usage: 1024, + origin: "http://email.bar.com", + persisted: false, + }, + { + usage: 1024, + origin: "https://s3-us-west-2.amazonaws.com", + persisted: true, + }, { usage: 1024, origin: "https://127.0.0.1", persisted: false, }, { - usage: 1024 * 4, - origin: "http://cinema.bar.com", + usage: 1024, + origin: "https://[0:0:0:0:0:0:0:1]", persisted: true, }, - { - usage: 1024 * 3, - origin: "http://email.bar.com", - persisted: false, - }, - { - usage: 1024 * 2, - origin: "https://s3-us-west-2.amazonaws.com", - persisted: true, - }, - { - usage: 1024 * 6, - origin: "https://account.xyz.com", - persisted: true, - }, - { - usage: 1024 * 5, - origin: "https://shopping.xyz.com", - persisted: false, - }, ]); + let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host); let updatePromise = promiseSiteDataManagerSitesUpdated(); await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); @@ -45,21 +49,18 @@ add_task(async function() { let doc = gBrowser.selectedBrowser.contentDocument; // Test the initial state - assertSitesListed(doc, hosts); + assertSitesListed(doc, fakeHosts); let win = gBrowser.selectedBrowser.contentWindow; let frameDoc = win.gSubDialog._topDialog._frame.contentDocument; let removeBtn = frameDoc.getElementById("removeSelected"); is(removeBtn.disabled, true, "Should start with disabled removeSelected button"); - let hostCol = frameDoc.getElementById("hostCol"); - hostCol.click(); - let removeDialogOpenPromise = BrowserTestUtils.promiseAlertDialogOpen("accept", REMOVE_DIALOG_URL); let settingsDialogClosePromise = promiseSettingsDialogClose(); // Select some sites to remove. let sitesList = frameDoc.getElementById("sitesList"); - hosts.slice(0, 2).forEach(host => { + fakeHosts.slice(0, 2).forEach(host => { let site = sitesList.querySelector(`richlistitem[host="${host}"]`); sitesList.addItemToSelection(site); }); @@ -67,10 +68,10 @@ add_task(async function() { is(removeBtn.disabled, false, "Should enable the removeSelected button"); removeBtn.doCommand(); is(sitesList.selectedIndex, 0, "Should select next item"); - assertSitesListed(doc, hosts.slice(2)); + assertSitesListed(doc, fakeHosts.slice(2)); // Select some other sites to remove with Delete. - hosts.slice(2, 4).forEach(host => { + fakeHosts.slice(2, 4).forEach(host => { let site = sitesList.querySelector(`richlistitem[host="${host}"]`); sitesList.addItemToSelection(site); }); @@ -78,21 +79,17 @@ add_task(async function() { is(removeBtn.disabled, false, "Should enable the removeSelected button"); EventUtils.synthesizeKey("VK_DELETE"); is(sitesList.selectedIndex, 0, "Should select next item"); - assertSitesListed(doc, hosts.slice(4)); + assertSitesListed(doc, fakeHosts.slice(4)); - updatePromise = promiseSiteDataManagerSitesUpdated(); let saveBtn = frameDoc.getElementById("save"); saveBtn.doCommand(); await removeDialogOpenPromise; await settingsDialogClosePromise; - - await updatePromise; await openSiteDataSettingsDialog(); - assertSitesListed(doc, hosts.slice(4)); + assertSitesListed(doc, fakeHosts.slice(4)); - await SiteDataTestUtils.clear(); + await mockSiteDataManager.unregister(); BrowserTestUtils.removeTab(gBrowser.selectedTab); }); - diff --git a/browser/components/preferences/in-content/tests/siteData/head.js b/browser/components/preferences/in-content/tests/siteData/head.js index 4762a8ed30fa..ed66b3d58467 100644 --- a/browser/components/preferences/in-content/tests/siteData/head.js +++ b/browser/components/preferences/in-content/tests/siteData/head.js @@ -127,29 +127,66 @@ function assertSitesListed(doc, hosts) { is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button"); } -async function addTestData(data) { - let hosts = []; +const mockSiteDataManager = { - for (let site of data) { - is(typeof site.origin, "string", "Passed an origin string into addTestData."); - if (site.persisted) { - await SiteDataTestUtils.persist(site.origin); + _SiteDataManager: null, + _originalQMS: null, + _originalRemoveQuotaUsage: null, + + getUsage(onUsageResult) { + let result = this.fakeSites.map(site => ({ + origin: site.principal.origin, + usage: site.usage, + persisted: site.persisted, + lastAccessed: site.lastAccessed, + })); + onUsageResult({ result, resultCode: Cr.NS_OK }); + }, + + _removeQuotaUsage(site) { + var target = site.principals[0].URI.host; + this.fakeSites = this.fakeSites.filter(fakeSite => { + return fakeSite.principal.URI.host != target; + }); + }, + + register(siteDataManager, fakeSites) { + this._SiteDataManager = siteDataManager; + this._originalQMS = this._SiteDataManager._qms; + this._SiteDataManager._qms = this; + this._originalRemoveQuotaUsage = this._SiteDataManager._removeQuotaUsage; + this._SiteDataManager._removeQuotaUsage = this._removeQuotaUsage.bind(this); + // Add some fake data. + this.fakeSites = fakeSites; + for (let site of fakeSites) { + if (!site.principal) { + site.principal = Services.scriptSecurityManager + .createCodebasePrincipalFromOrigin(site.origin); + } + + let uri = site.principal.URI; + try { + site.baseDomain = Services.eTLD.getBaseDomainFromHost(uri.host); + } catch (e) { + site.baseDomain = uri.host; + } + + // Add some cookies if needed. + for (let i = 0; i < (site.cookies || 0); i++) { + Services.cookies.add(uri.host, uri.pathQueryRef, Cu.now(), i, + false, false, false, Date.now() + 1000 * 60 * 60, {}, + Ci.nsICookie2.SAMESITE_UNSET); + } } + }, - if (site.usage) { - await SiteDataTestUtils.addToIndexedDB(site.origin, site.usage); - } - - for (let i = 0; i < (site.cookies || 0); i++) { - SiteDataTestUtils.addToCookies(site.origin, Cu.now()); - } - - let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(site.origin); - hosts.push(principal.URI.host); - } - - return hosts; -} + async unregister() { + await this._SiteDataManager.removeAll(); + this.fakeSites = null; + this._SiteDataManager._qms = this._originalQMS; + this._SiteDataManager._removeQuotaUsage = this._originalRemoveQuotaUsage; + }, +}; function promiseCookiesCleared() { return TestUtils.topicObserved("cookie-changed", (subj, data) => { diff --git a/browser/modules/SiteDataManager.jsm b/browser/modules/SiteDataManager.jsm index bb6305f6ab99..49ace509a68a 100644 --- a/browser/modules/SiteDataManager.jsm +++ b/browser/modules/SiteDataManager.jsm @@ -3,6 +3,11 @@ const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +ChromeUtils.defineModuleGetter(this, "OfflineAppCacheHelper", + "resource://gre/modules/offlineAppCache.jsm"); +ChromeUtils.defineModuleGetter(this, "ServiceWorkerCleanUp", + "resource://gre/modules/ServiceWorkerCleanUp.jsm"); + var EXPORTED_SYMBOLS = [ "SiteDataManager", ]; @@ -320,23 +325,6 @@ var SiteDataManager = { site.cookies = []; }, - // Returns a list of permissions from the permission manager that - // we consider part of "site data and cookies". - _getDeletablePermissions() { - let perms = []; - let enumerator = Services.perms.enumerator; - - while (enumerator.hasMoreElements()) { - let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission); - if (permission.type == "persistent-storage" || - permission.type == "storage-access") { - perms.push(permission); - } - } - - return perms; - }, - /** * Removes all site data for the specified list of hosts. * @@ -345,28 +333,35 @@ var SiteDataManager = { * manager has been updated. */ async remove(hosts) { - let perms = this._getDeletablePermissions(); + // Make sure we have up-to-date information. + await this._getQuotaUsage(); + this._updateAppCache(); + + let unknownHost = ""; let promises = []; for (let host of hosts) { - promises.push(new Promise(function(resolve) { - Services.clearData.deleteDataFromHost(host, true, - Ci.nsIClearDataService.CLEAR_COOKIES | - Ci.nsIClearDataService.CLEAR_DOM_STORAGES | - Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS | - Ci.nsIClearDataService.CLEAR_PLUGIN_DATA | - Ci.nsIClearDataService.CLEAR_EME | - Ci.nsIClearDataService.CLEAR_ALL_CACHES, resolve); - })); - - for (let perm of perms) { - if (Services.eTLD.hasRootDomain(perm.principal.URI.host, host)) { - Services.perms.removePermission(perm); - } + let site = this._sites.get(host); + if (site) { + // Clear localStorage & sessionStorage + Services.obs.notifyObservers(null, "extension:purge-localStorage", host); + Services.obs.notifyObservers(null, "browser:purge-sessionStorage", host); + this._removePermission(site); + this._removeAppCache(site); + this._removeCookies(site); + promises.push(ServiceWorkerCleanUp.removeFromHost(host)); + promises.push(this._removeQuotaUsage(site)); + } else { + unknownHost = host; + break; } } await Promise.all(promises); + if (unknownHost) { + throw `SiteDataManager: removing unknown site of ${unknownHost}`; + } + return this.updateSites(); }, @@ -410,41 +405,54 @@ var SiteDataManager = { * @returns a Promise that resolves when the data is cleared. */ async removeAll() { - await this.removeCache(); + this.removeCache(); return this.removeSiteData(); }, /** - * Clears all caches. - * - * @returns a Promise that resolves when the data is cleared. + * Clears the entire network cache. */ removeCache() { - return new Promise(function(resolve) { - Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL_CACHES, resolve); - }); + Services.cache2.clear(); }, /** - * Clears all site data, but not cache, because the UI offers - * that functionality separately. + * Clears all site data, which currently means + * - Cookies + * - AppCache + * - LocalStorage + * - ServiceWorkers + * - Quota Managed Storage + * - persistent-storage permissions * - * @returns a Promise that resolves when the data is cleared. + * @returns a Promise that resolves with the cache size on disk in bytes */ async removeSiteData() { - await new Promise(function(resolve) { - Services.clearData.deleteData( - Ci.nsIClearDataService.CLEAR_COOKIES | - Ci.nsIClearDataService.CLEAR_DOM_STORAGES | - Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS | - Ci.nsIClearDataService.CLEAR_EME | - Ci.nsIClearDataService.CLEAR_PLUGIN_DATA, resolve); - }); + // LocalStorage + Services.obs.notifyObservers(null, "extension:purge-localStorage"); - for (let permission of this._getDeletablePermissions()) { - Services.perms.removePermission(permission); + Services.cookies.removeAll(); + OfflineAppCacheHelper.clear(); + + await ServiceWorkerCleanUp.removeAll(); + + // Refresh sites using quota usage again. + // This is for the case: + // 1. User goes to the about:preferences Site Data section. + // 2. With the about:preferences opened, user visits another website. + // 3. The website saves to quota usage, like indexedDB. + // 4. User goes back to the Site Data section and commands to clear all site data. + // For this case, we should refresh the site list so not to miss the website in the step 3. + // We don't do "Clear All" on the quota manager like the cookie, appcache, http cache above + // because that would clear browser data as well too, + // see https://bugzilla.mozilla.org/show_bug.cgi?id=1312361#c9 + this._sites.clear(); + await this._getQuotaUsage(); + let promises = []; + for (let site of this._sites.values()) { + this._removePermission(site); + promises.push(this._removeQuotaUsage(site)); } - - return this.updateSites(); + return Promise.all(promises).then(() => this.updateSites()); }, }; diff --git a/browser/modules/test/unit/test_SiteDataManager.js b/browser/modules/test/unit/test_SiteDataManager.js deleted file mode 100644 index d181b3eb9e59..000000000000 --- a/browser/modules/test/unit/test_SiteDataManager.js +++ /dev/null @@ -1,148 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ -"use strict"; - -const EXAMPLE_ORIGIN = "https://www.example.com"; -const EXAMPLE_ORIGIN_2 = "https://example.org"; - -const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {SiteDataManager} = ChromeUtils.import("resource:///modules/SiteDataManager.jsm"); -const {SiteDataTestUtils} = ChromeUtils.import("resource://testing-common/SiteDataTestUtils.jsm"); -ChromeUtils.defineModuleGetter(this, "setTimeout", "resource://gre/modules/Timer.jsm"); -ChromeUtils.defineModuleGetter(this, "TestUtils", "resource://testing-common/TestUtils.jsm"); - -add_task(function setup() { - do_get_profile(); -}); - -add_task(async function testGetSites() { - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo1", "bar1"); - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo2", "bar2"); - await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096); - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN_2, "foo", "bar"); - await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048); - await SiteDataTestUtils.persist(EXAMPLE_ORIGIN_2); - - await SiteDataManager.updateSites(); - - let sites = await SiteDataManager.getSites(); - - let site1 = sites.find((site) => site.baseDomain == "example.com"); - let site2 = sites.find((site) => site.baseDomain == "example.org"); - - Assert.equal(site1.baseDomain, "example.com", "Has the correct base domain for example.com"); - Assert.equal(site1.host, "www.example.com", "Has the correct host for example.com"); - Assert.greater(site1.usage, 4096, "Has correct usage for example.com"); - Assert.equal(site1.persisted, false, "example.com is not persisted"); - Assert.equal(site1.cookies.length, 2, "Has correct number of cookies for example.com"); - Assert.ok(typeof site1.lastAccessed.getDate == "function", "lastAccessed for example.com is a Date"); - Assert.ok(site1.lastAccessed > Date.now() - 60 * 1000, "lastAccessed for example.com happened recently"); - - Assert.equal(site2.baseDomain, "example.org", "Has the correct base domain for example.org"); - Assert.equal(site2.host, "example.org", "Has the correct host for example.org"); - Assert.greater(site2.usage, 2048, "Has correct usage for example.org"); - Assert.equal(site2.persisted, true, "example.org is persisted"); - Assert.equal(site2.cookies.length, 1, "Has correct number of cookies for example.org"); - Assert.ok(typeof site2.lastAccessed.getDate == "function", "lastAccessed for example.org is a Date"); - Assert.ok(site2.lastAccessed > Date.now() - 60 * 1000, "lastAccessed for example.org happened recently"); - - await SiteDataTestUtils.clear(); -}); - -add_task(async function testGetTotalUsage() { - await SiteDataManager.updateSites(); - let sites = await SiteDataManager.getSites(); - Assert.equal(sites.length, 0, "SiteDataManager is empty"); - - await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096); - await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048); - - await SiteDataManager.updateSites(); - - let usage = await SiteDataManager.getTotalUsage(); - - Assert.greater(usage, 4096 + 2048, "Has the correct total usage."); - - await SiteDataTestUtils.clear(); -}); - -add_task(async function testRemove() { - await SiteDataManager.updateSites(); - - let uri = Services.io.newURI(EXAMPLE_ORIGIN); - Services.perms.add(uri, "camera", Services.perms.ALLOW_ACTION); - - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo1", "bar1"); - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo2", "bar2"); - await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096); - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN_2, "foo", "bar"); - await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048); - await SiteDataTestUtils.persist(EXAMPLE_ORIGIN_2); - - await SiteDataManager.updateSites(); - - let sites = await SiteDataManager.getSites(); - - Assert.equal(sites.length, 2, "Has two sites."); - - await SiteDataManager.remove(["www.example.com"]); - - sites = await SiteDataManager.getSites(); - - Assert.equal(sites.length, 1, "Has one site."); - Assert.equal(sites[0].host, "example.org", "Has not cleared data for example.org"); - - let usage = await SiteDataTestUtils.getQuotaUsage(EXAMPLE_ORIGIN); - Assert.equal(usage, 0, "Has cleared quota usage for example.com"); - - let cookies = Services.cookies.countCookiesFromHost("example.com"); - Assert.equal(cookies, 0, "Has cleared cookies for example.com"); - - let perm = Services.perms.testPermission(uri, "persistent-storage"); - Assert.equal(perm, Services.perms.UNKNOWN_ACTION, "Cleared the persistent-storage permission."); - perm = Services.perms.testPermission(uri, "camera"); - Assert.equal(perm, Services.perms.ALLOW_ACTION, "Did not clear other permissions."); - - Services.perms.remove(uri, "camera"); -}); - -add_task(async function testRemoveSiteData() { - let uri = Services.io.newURI(EXAMPLE_ORIGIN); - Services.perms.add(uri, "camera", Services.perms.ALLOW_ACTION); - - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo1", "bar1"); - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo2", "bar2"); - await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096); - SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN_2, "foo", "bar"); - await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048); - await SiteDataTestUtils.persist(EXAMPLE_ORIGIN_2); - - await SiteDataManager.updateSites(); - - let sites = await SiteDataManager.getSites(); - - Assert.equal(sites.length, 2, "Has two sites."); - - await SiteDataManager.removeSiteData(); - - sites = await SiteDataManager.getSites(); - - Assert.equal(sites.length, 0, "Has no sites."); - - let usage = await SiteDataTestUtils.getQuotaUsage(EXAMPLE_ORIGIN); - Assert.equal(usage, 0, "Has cleared quota usage for example.com"); - - usage = await SiteDataTestUtils.getQuotaUsage(EXAMPLE_ORIGIN_2); - Assert.equal(usage, 0, "Has cleared quota usage for example.org"); - - let cookies = Services.cookies.countCookiesFromHost("example.org"); - Assert.equal(cookies, 0, "Has cleared cookies for example.org"); - - let perm = Services.perms.testPermission(uri, "persistent-storage"); - Assert.equal(perm, Services.perms.UNKNOWN_ACTION, "Cleared the persistent-storage permission."); - perm = Services.perms.testPermission(uri, "camera"); - Assert.equal(perm, Services.perms.ALLOW_ACTION, "Did not clear other permissions."); - - Services.perms.remove(uri, "camera"); -}); diff --git a/browser/modules/test/unit/xpcshell.ini b/browser/modules/test/unit/xpcshell.ini index 75957a037d1c..e934e2613ec9 100644 --- a/browser/modules/test/unit/xpcshell.ini +++ b/browser/modules/test/unit/xpcshell.ini @@ -8,6 +8,5 @@ skip-if = toolkit == 'android' [test_LiveBookmarkMigrator.js] [test_Sanitizer_interrupted.js] [test_SitePermissions.js] -[test_SiteDataManager.js] [test_LaterRun.js] [test_discovery.js]