Bug 1422163 - Part 2 - Make a new test for clearing all site data with the new dialog. r=Gijs

MozReview-Commit-ID: 6Lt3hPZ1YiO

--HG--
rename : browser/components/preferences/in-content/tests/browser_siteData.js => browser/components/preferences/in-content/tests/browser_clearSiteData.js
extra : rebase_source : 95afde93b99de1b25afd6bd132e006f98089dc2e
This commit is contained in:
Johann Hofmann 2018-01-10 12:25:04 +01:00
parent 1dd2560f1b
commit 013b06d761
5 changed files with 257 additions and 204 deletions

View File

@ -41,6 +41,7 @@ skip-if = os != "win" || (os == "win" && os_version == "6.1")
# This test tests the windows-specific app selection dialog, so can't run on non-Windows.
# Skip the test on Window 7, see the detail at Bug 1381706.
[browser_checkspelling.js]
[browser_clearSiteData.js]
[browser_connection.js]
[browser_connection_bug388287.js]
[browser_cookies_exceptions.js]

View File

@ -0,0 +1,201 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
ChromeUtils.import("resource:///modules/SitePermissions.jsm");
const { SiteDataManager } = ChromeUtils.import("resource:///modules/SiteDataManager.jsm", {});
const { DownloadUtils } = ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm", {});
const TEST_QUOTA_USAGE_HOST = "example.com";
const TEST_QUOTA_USAGE_ORIGIN = "https://" + TEST_QUOTA_USAGE_HOST;
const TEST_QUOTA_USAGE_URL = TEST_QUOTA_USAGE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/site_data_test.html";
const TEST_OFFLINE_HOST = "example.org";
const TEST_OFFLINE_ORIGIN = "https://" + TEST_OFFLINE_HOST;
const TEST_OFFLINE_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/offline/offline.html";
const TEST_SERVICE_WORKER_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/service_worker_test.html";
// XXX: The intermittent bug 1331851
// The implementation of nsICacheStorageConsumptionObserver must be passed as weak referenced,
// so we must hold this observer here well. If we didn't, there would be a chance that
// in Linux debug test run the observer was released before the operation at gecko was completed
// (may be because of a relatively quicker GC cycle or a relatively slower operation).
// As a result of that, we would never get the cache usage we want so the test would fail from timeout.
const cacheUsageGetter = {
_promise: null,
_resolve: null,
get() {
if (!this._promise) {
this._promise = new Promise(resolve => {
this._resolve = resolve;
Services.cache2.asyncGetDiskConsumption(this);
});
}
return this._promise;
},
// nsICacheStorageConsumptionObserver implementations
onNetworkCacheDiskConsumption(usage) {
cacheUsageGetter._promise = null;
cacheUsageGetter._resolve(usage);
},
QueryInterface: XPCOMUtils.generateQI([
Components.interfaces.nsICacheStorageConsumptionObserver,
Components.interfaces.nsISupportsWeakReference
]),
};
async function testClearData(clearSiteData, clearCache) {
let quotaURI = Services.io.newURI(TEST_QUOTA_USAGE_ORIGIN);
SitePermissions.set(quotaURI, "persistent-storage", SitePermissions.ALLOW);
// Open a test site which saves into appcache.
await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_OFFLINE_URL);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
// Fill indexedDB with test data.
// Don't wait for the page to load, to register the content event handler as quickly as possible.
// If this test goes intermittent, we might have to tell the page to wait longer before
// firing the event.
BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL, false);
await BrowserTestUtils.waitForContentEvent(
gBrowser.selectedBrowser, "test-indexedDB-done", false, null, true);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
// Register some service workers.
await loadServiceWorkerTestPage(TEST_SERVICE_WORKER_URL);
await promiseServiceWorkerRegisteredFor(TEST_SERVICE_WORKER_URL);
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
// Test the initial states.
let cacheUsage = await cacheUsageGetter.get();
let quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
let totalUsage = await SiteDataManager.getTotalUsage();
Assert.greater(cacheUsage, 0, "The cache usage should not be 0");
Assert.greater(quotaUsage, 0, "The quota usage should not be 0");
Assert.greater(totalUsage, 0, "The total usage should not be 0");
let doc = gBrowser.selectedBrowser.contentDocument;
let clearSiteDataButton = doc.getElementById("clearSiteDataButton");
let dialogOpened = promiseLoadSubDialog("chrome://browser/content/preferences/clearSiteData.xul");
clearSiteDataButton.doCommand();
let dialogWin = await dialogOpened;
// Convert the usage numbers in the same way the UI does it to assert
// that they're displayed in the dialog.
let [convertedTotalUsage] = DownloadUtils.convertByteUnits(totalUsage);
let [convertedCacheUsage] = DownloadUtils.convertByteUnits(cacheUsage);
let clearSiteDataLabel = dialogWin.document.getElementById("clearSiteDataLabel");
let clearCacheLabel = dialogWin.document.getElementById("clearCacheLabel");
// The usage details are filled asynchronously, so we assert that they're present by
// waiting for them to be filled in.
await Promise.all([
TestUtils.waitForCondition(
() => clearSiteDataLabel.value && clearSiteDataLabel.value.includes(convertedTotalUsage), "Should show the quota usage"),
TestUtils.waitForCondition(
() => clearCacheLabel.value && clearCacheLabel.value.includes(convertedCacheUsage), "Should show the cache usage")
]);
// Check the boxes according to our test input.
let clearSiteDataCheckbox = dialogWin.document.getElementById("clearSiteData");
let clearCacheCheckbox = dialogWin.document.getElementById("clearCache");
clearSiteDataCheckbox.checked = clearSiteData;
clearCacheCheckbox.checked = clearCache;
// Some additional promises/assertions to wait for
// when deleting site data.
let acceptPromise;
let updatePromise;
let cookiesClearedPromise;
if (clearSiteData) {
acceptPromise = promiseAlertDialogOpen("accept");
updatePromise = promiseSiteDataManagerSitesUpdated();
cookiesClearedPromise = promiseCookiesCleared();
}
let dialogClosed = BrowserTestUtils.waitForEvent(dialogWin, "unload");
let clearButton = dialogWin.document.getElementById("clearButton");
if (!clearSiteData && !clearCache) {
// Simulate user input on one of the checkboxes to trigger the event listener for
// disabling the clearButton.
clearCacheCheckbox.doCommand();
// Check that the clearButton gets disabled by unchecking both options.
await TestUtils.waitForCondition(() => clearButton.disabled, "Clear button should be disabled");
let cancelButton = dialogWin.document.getElementById("cancelButton");
// Cancel, since we can't delete anything.
cancelButton.click();
} else {
// Delete stuff!
clearButton.click();
}
// For site data we display an extra warning dialog, make sure
// to accept it.
if (clearSiteData) {
await acceptPromise;
}
await dialogClosed;
if (clearSiteData) {
await updatePromise;
await cookiesClearedPromise;
await promiseServiceWorkersCleared();
quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
totalUsage = await SiteDataManager.getTotalUsage();
is(quotaUsage, 0, "The quota usage should be removed");
is(totalUsage, 0, "The total usage should be removed");
// Check that the size label in about:preferences updates after we cleared data.
await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
let sizeLabel = content.document.getElementById("totalSiteDataSize");
await ContentTaskUtils.waitForCondition(
() => sizeLabel.textContent.includes("0"), "Site data size label should have updated.");
});
} else {
quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
totalUsage = await SiteDataManager.getTotalUsage();
Assert.greater(quotaUsage, 0, "The quota usage should not be 0");
Assert.greater(totalUsage, 0, "The total usage should not be 0");
}
let desiredPermissionState = clearSiteData ? SitePermissions.UNKNOWN : SitePermissions.ALLOW;
let permission = SitePermissions.get(quotaURI, "persistent-storage");
is(permission.state, desiredPermissionState, "Should have the correct permission state.");
cacheUsage = await cacheUsageGetter.get();
if (clearCache) {
is(cacheUsage, 0, "The cache usage should be removed");
} else {
Assert.greater(cacheUsage, 0, "The cache usage should not be 0");
}
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await SiteDataManager.removeAll();
}
// Test opening the "Clear All Data" dialog and cancelling.
add_task(async function() {
await testClearData(false, false);
});
// Test opening the "Clear All Data" dialog and removing all site data.
add_task(async function() {
await testClearData(true, false);
});
// Test opening the "Clear All Data" dialog and removing all cache.
add_task(async function() {
await testClearData(false, true);
});
// Test opening the "Clear All Data" dialog and removing everything.
add_task(async function() {
await testClearData(true, true);
});

View File

@ -6,8 +6,6 @@
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
/* global sinon */
Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
const TEST_QUOTA_USAGE_HOST = "example.com";
const TEST_QUOTA_USAGE_ORIGIN = "https://" + TEST_QUOTA_USAGE_HOST;
@ -16,119 +14,18 @@ const TEST_OFFLINE_HOST = "example.org";
const TEST_OFFLINE_ORIGIN = "https://" + TEST_OFFLINE_HOST;
const TEST_OFFLINE_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/offline/offline.html";
const TEST_SERVICE_WORKER_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/service_worker_test.html";
const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm", {});
const { DownloadUtils } = ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm", {});
const { SiteDataManager } = ChromeUtils.import("resource:///modules/SiteDataManager.jsm", {});
const { OfflineAppCacheHelper } = ChromeUtils.import("resource:///modules/offlineAppCache.jsm", {});
XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager", "@mozilla.org/serviceworkers/manager;1", "nsIServiceWorkerManager");
const mockOfflineAppCacheHelper = {
clear: null,
originalClear: null,
register() {
this.originalClear = OfflineAppCacheHelper.clear;
this.clear = sinon.spy();
OfflineAppCacheHelper.clear = this.clear;
},
unregister() {
OfflineAppCacheHelper.clear = this.originalClear;
}
};
function getPersistentStoragePermStatus(origin) {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
return Services.perms.testExactPermissionFromPrincipal(principal, "persistent-storage");
}
function getQuotaUsage(origin) {
return new Promise(resolve => {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.qms.getUsageForPrincipal(principal, request => resolve(request.result.usage));
});
}
// XXX: The intermittent bug 1331851
// The implementation of nsICacheStorageConsumptionObserver must be passed as weak referenced,
// so we must hold this observer here well. If we didn't, there would be a chance that
// in Linux debug test run the observer was released before the operation at gecko was completed
// (may be because of a relatively quicker GC cycle or a relatively slower operation).
// As a result of that, we would never get the cache usage we want so the test would fail from timeout.
const cacheUsageGetter = {
_promise: null,
_resolve: null,
get() {
if (!this._promise) {
this._promise = new Promise(resolve => {
this._resolve = resolve;
Services.cache2.asyncGetDiskConsumption(this);
});
}
return this._promise;
},
// nsICacheStorageConsumptionObserver implementations
onNetworkCacheDiskConsumption(usage) {
cacheUsageGetter._promise = null;
cacheUsageGetter._resolve(usage);
},
QueryInterface: XPCOMUtils.generateQI([
Components.interfaces.nsICacheStorageConsumptionObserver,
Components.interfaces.nsISupportsWeakReference
]),
};
function promiseCookiesCleared() {
return TestUtils.topicObserved("cookie-changed", (subj, data) => {
return data === "cleared";
});
}
async function loadServiceWorkerTestPage(url) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await BrowserTestUtils.waitForCondition(() => {
return ContentTask.spawn(tab.linkedBrowser, {}, () =>
content.document.body.getAttribute("data-test-service-worker-registered") === "true");
}, `Fail to load service worker test ${url}`);
await BrowserTestUtils.removeTab(tab);
}
function promiseServiceWorkerRegisteredFor(url) {
return BrowserTestUtils.waitForCondition(() => {
try {
let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(url);
let sw = serviceWorkerManager.getRegistrationByPrincipal(principal, principal.URI.spec);
if (sw) {
ok(true, `Found the service worker registered for ${url}`);
return true;
}
} catch (e) {}
return false;
}, `Should register service worker for ${url}`);
}
function promiseServiceWorkersCleared() {
return BrowserTestUtils.waitForCondition(() => {
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
if (serviceWorkers.length == 0) {
ok(true, "Cleared all service workers");
return true;
}
return false;
}, "Should clear all service workers");
}
registerCleanupFunction(function() {
delete window.sinon;
mockOfflineAppCacheHelper.unregister();
});
// Test listing site using quota usage or site using appcache
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
@ -138,9 +35,9 @@ add_task(async function() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
// Open a test site which would save into quota manager
await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL);
// eslint-disable-next-line mozilla/no-cpows-in-tests
await waitForEvent(gBrowser.selectedBrowser.contentWindowAsCPOW, "test-indexedDB-done");
BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL);
await BrowserTestUtils.waitForContentEvent(
gBrowser.selectedBrowser, "test-indexedDB-done", false, null, true);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
let updatedPromise = promiseSiteDataManagerSitesUpdated();
@ -217,97 +114,6 @@ add_task(async function() {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
// Test the function of the "Clear All Data" button
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
addPersistentStoragePerm(TEST_QUOTA_USAGE_ORIGIN);
await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL);
// eslint-disable-next-line mozilla/no-cpows-in-tests
await waitForEvent(gBrowser.selectedBrowser.contentWindowAsCPOW, "test-indexedDB-done");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
// Test the initial states
let cacheUsage = await cacheUsageGetter.get();
let quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
let totalUsage = await SiteDataManager.getTotalUsage();
Assert.greater(cacheUsage, 0, "The cache usage should not be 0");
Assert.greater(quotaUsage, 0, "The quota usage should not be 0");
Assert.greater(totalUsage, 0, "The total usage should not be 0");
// Test cancelling "Clear All Data"
// Click "Clear All Data" button and then cancel
let doc = gBrowser.selectedBrowser.contentDocument;
let cancelPromise = promiseAlertDialogOpen("cancel");
let clearBtn = doc.getElementById("clearSiteDataButton");
clearBtn.doCommand();
await cancelPromise;
// Test the items are not removed
let status = getPersistentStoragePermStatus(TEST_QUOTA_USAGE_ORIGIN);
is(status, Ci.nsIPermissionManager.ALLOW_ACTION, "Should not remove permission");
cacheUsage = await cacheUsageGetter.get();
quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
totalUsage = await SiteDataManager.getTotalUsage();
Assert.greater(cacheUsage, 0, "The cache usage should not be 0");
Assert.greater(quotaUsage, 0, "The quota usage should not be 0");
Assert.greater(totalUsage, 0, "The total usage should not be 0");
// Test cancelling "Clear All Data" ends
// Test accepting "Clear All Data"
// Click "Clear All Data" button and then accept
let acceptPromise = promiseAlertDialogOpen("accept");
let updatePromise = promiseSiteDataManagerSitesUpdated();
let cookiesClearedPromise = promiseCookiesCleared();
mockOfflineAppCacheHelper.register();
clearBtn.doCommand();
await acceptPromise;
await updatePromise;
mockOfflineAppCacheHelper.unregister();
// Test all the items are removed
await cookiesClearedPromise;
ok(mockOfflineAppCacheHelper.clear.calledOnce, "Should clear app cache");
status = getPersistentStoragePermStatus(TEST_QUOTA_USAGE_ORIGIN);
is(status, Ci.nsIPermissionManager.UNKNOWN_ACTION, "Should remove permission");
cacheUsage = await cacheUsageGetter.get();
quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
totalUsage = await SiteDataManager.getTotalUsage();
is(cacheUsage, 0, "The cache usage should be removed");
is(quotaUsage, 0, "The quota usage should be removed");
is(totalUsage, 0, "The total usage should be removed");
// Test accepting "Clear All Data" ends
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
// Test clearing service wroker through the "Clear All" button
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
// Register a test service
await loadServiceWorkerTestPage(TEST_SERVICE_WORKER_URL);
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
// Test the initial states
await promiseServiceWorkerRegisteredFor(TEST_SERVICE_WORKER_URL);
// Click the "Clear All" button
let doc = gBrowser.selectedBrowser.contentDocument;
let clearBtn = doc.getElementById("clearSiteDataButton");
let acceptPromise = promiseAlertDialogOpen("accept");
let updatePromise = promiseSiteDataManagerSitesUpdated();
clearBtn.doCommand();
await acceptPromise;
await updatePromise;
await promiseServiceWorkersCleared();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
// Test clearing service wroker through the settings panel
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});

View File

@ -3,6 +3,8 @@
ChromeUtils.import("resource://gre/modules/Promise.jsm", this);
XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager", "@mozilla.org/serviceworkers/manager;1", "nsIServiceWorkerManager");
const kDefaultWait = 2000;
function is_hidden(aElement) {
@ -163,12 +165,6 @@ function promiseAlertDialogOpen(buttonAction) {
return promiseWindowDialogOpen(buttonAction, "chrome://global/content/commonDialog.xul");
}
function addPersistentStoragePerm(origin) {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.perms.addFromPrincipal(principal, "persistent-storage", Ci.nsIPermissionManager.ALLOW_ACTION);
}
function promiseSiteDataManagerSitesUpdated() {
return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
}
@ -259,3 +255,52 @@ const mockSiteDataManager = {
this._SiteDataManager._removeQuotaUsage = this._originalRemoveQuotaUsage;
}
};
function getQuotaUsage(origin) {
return new Promise(resolve => {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
Services.qms.getUsageForPrincipal(principal, request => resolve(request.result.usage));
});
}
function promiseCookiesCleared() {
return TestUtils.topicObserved("cookie-changed", (subj, data) => {
return data === "cleared";
});
}
async function loadServiceWorkerTestPage(url) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await BrowserTestUtils.waitForCondition(() => {
return ContentTask.spawn(tab.linkedBrowser, {}, () =>
content.document.body.getAttribute("data-test-service-worker-registered") === "true");
}, `Fail to load service worker test ${url}`);
await BrowserTestUtils.removeTab(tab);
}
function promiseServiceWorkersCleared() {
return BrowserTestUtils.waitForCondition(() => {
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
if (serviceWorkers.length == 0) {
ok(true, "Cleared all service workers");
return true;
}
return false;
}, "Should clear all service workers");
}
function promiseServiceWorkerRegisteredFor(url) {
return BrowserTestUtils.waitForCondition(() => {
try {
let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(url);
let sw = serviceWorkerManager.getRegistrationByPrincipal(principal, principal.URI.spec);
if (sw) {
ok(true, `Found the service worker registered for ${url}`);
return true;
}
} catch (e) {}
return false;
}, `Should register service worker for ${url}`);
}

View File

@ -21,7 +21,7 @@
let db = e.target.result;
let tx = db.transaction("TestStore", "readwrite");
let store = tx.objectStore("TestStore");
tx.oncomplete = () => window.dispatchEvent(new Event("test-indexedDB-done"));
tx.oncomplete = () => document.dispatchEvent(new CustomEvent("test-indexedDB-done", {bubbles: true, cancelable: false}));
store.put({ id: "test_id", description: "Site Data Test"});
};
</script>