diff options
Diffstat (limited to 'toolkit/components/places/tests/expiration')
12 files changed, 1129 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/expiration/.eslintrc.js b/toolkit/components/places/tests/expiration/.eslintrc.js new file mode 100644 index 0000000000..69e89d0054 --- /dev/null +++ b/toolkit/components/places/tests/expiration/.eslintrc.js @@ -0,0 +1,5 @@ +"use strict"; + +module.exports = { + extends: ["plugin:mozilla/xpcshell-test"], +}; diff --git a/toolkit/components/places/tests/expiration/head_expiration.js b/toolkit/components/places/tests/expiration/head_expiration.js new file mode 100644 index 0000000000..e124832b9f --- /dev/null +++ b/toolkit/components/places/tests/expiration/head_expiration.js @@ -0,0 +1,114 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * 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 { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +// Import common head. +{ + /* import-globals-from ../head_common.js */ + let commonFile = do_get_file("../head_common.js", false); + let uri = Services.io.newFileURI(commonFile); + Services.scriptloader.loadSubScript(uri.spec, this); +} + +// Put any other stuff relative to this test folder below. + +/** + * Causes expiration component to start, otherwise it would wait for the first + * history notification. + */ +function force_expiration_start() { + Cc["@mozilla.org/places/expiration;1"] + .getService(Ci.nsIObserver) + .observe(null, "testing-mode", null); +} + +/** + * Forces an expiration run. + * + * @param [optional] aLimit + * Limit for the expiration. Pass -1 for unlimited. + * Any other non-positive value will just expire orphans. + * + * @return {Promise} + * @resolves When expiration finishes. + * @rejects Never. + */ +function promiseForceExpirationStep(aLimit) { + let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED); + let expire = Cc["@mozilla.org/places/expiration;1"].getService( + Ci.nsIObserver + ); + expire.observe(null, "places-debug-start-expiration", aLimit); + return promise; +} + +/** + * Expiration preferences helpers. + */ + +function setInterval(aNewInterval) { + Services.prefs.setIntPref( + "places.history.expiration.interval_seconds", + aNewInterval + ); +} +function getInterval() { + return Services.prefs.getIntPref( + "places.history.expiration.interval_seconds" + ); +} +function clearInterval() { + try { + Services.prefs.clearUserPref("places.history.expiration.interval_seconds"); + } catch (ex) {} +} + +function setMaxPages(aNewMaxPages) { + Services.prefs.setIntPref( + "places.history.expiration.max_pages", + aNewMaxPages + ); +} +function getMaxPages() { + return Services.prefs.getIntPref("places.history.expiration.max_pages"); +} +function clearMaxPages() { + try { + Services.prefs.clearUserPref("places.history.expiration.max_pages"); + } catch (ex) {} +} + +function setHistoryEnabled(aHistoryEnabled) { + Services.prefs.setBoolPref("places.history.enabled", aHistoryEnabled); +} +function getHistoryEnabled() { + return Services.prefs.getBoolPref("places.history.enabled"); +} +function clearHistoryEnabled() { + try { + Services.prefs.clearUserPref("places.history.enabled"); + } catch (ex) {} +} + +/** + * Returns a PRTime in the past usable to add expirable visits. + * + * param [optional] daysAgo + * Expiration ignores any visit added in the last 7 days, so by default + * this will be set to 7. + * @note to be safe against DST issues we go back one day more. + */ +function getExpirablePRTime(daysAgo = 7) { + let dateObj = new Date(); + // Normalize to midnight + dateObj.setHours(0); + dateObj.setMinutes(0); + dateObj.setSeconds(0); + dateObj.setMilliseconds(0); + dateObj = new Date(dateObj.getTime() - (daysAgo + 1) * 86400000); + return dateObj.getTime() * 1000; +} diff --git a/toolkit/components/places/tests/expiration/test_annos_expire_never.js b/toolkit/components/places/tests/expiration/test_annos_expire_never.js new file mode 100644 index 0000000000..39c55ecc04 --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_annos_expire_never.js @@ -0,0 +1,72 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * 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/. */ + +/** + * What this is aimed to test: + * + * EXPIRE_NEVER annotations should be expired when a page is removed from the + * database. + * If the annotation is a page annotation this will happen when the page is + * expired, namely when the page has no visits and is not bookmarked. + */ + +add_task(async function test_annos_expire_never() { + // Set interval to a large value so we don't expire on it. + setInterval(3600); // 1h + + // Expire all expirable pages. + setMaxPages(0); + + // Add some visited page and a couple expire never annotations for each. + let now = getExpirablePRTime(); + for (let i = 0; i < 5; i++) { + let pageURI = uri("http://page_anno." + i + ".mozilla.org/"); + await PlacesTestUtils.addVisits({ uri: pageURI, visitDate: now++ }); + await PlacesUtils.history.update({ + url: pageURI, + annotations: new Map([ + ["page_expire1", "test"], + ["page_expire2", "test"], + ]), + }); + } + + let pages = await getPagesWithAnnotation("page_expire1"); + Assert.equal(pages.length, 5); + pages = await getPagesWithAnnotation("page_expire2"); + Assert.equal(pages.length, 5); + + // Add other visited page and a couple expire never annotations for each. + // We won't expire these visits, so the annotations should survive. + for (let i = 0; i < 5; i++) { + let pageURI = uri("http://persist_page_anno." + i + ".mozilla.org/"); + await PlacesTestUtils.addVisits({ uri: pageURI, visitDate: now++ }); + await PlacesUtils.history.update({ + url: pageURI, + annotations: new Map([ + ["page_persist1", "test"], + ["page_persist2", "test"], + ]), + }); + } + + pages = await getPagesWithAnnotation("page_persist1"); + Assert.equal(pages.length, 5); + pages = await getPagesWithAnnotation("page_persist2"); + Assert.equal(pages.length, 5); + + // Expire all visits for the first 5 pages and the bookmarks. + await promiseForceExpirationStep(5); + + pages = await getPagesWithAnnotation("page_expire1"); + Assert.equal(pages.length, 0); + pages = await getPagesWithAnnotation("page_expire2"); + Assert.equal(pages.length, 0); + pages = await getPagesWithAnnotation("page_persist1"); + Assert.equal(pages.length, 5); + pages = await getPagesWithAnnotation("page_persist2"); + Assert.equal(pages.length, 5); +}); diff --git a/toolkit/components/places/tests/expiration/test_clearHistory.js b/toolkit/components/places/tests/expiration/test_clearHistory.js new file mode 100644 index 0000000000..a4684f0269 --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_clearHistory.js @@ -0,0 +1,57 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * 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/. */ + +/** + * What this is aimed to test: + * + * History.clear() should expire everything but bookmarked pages and valid + * annos. + */ + +add_task(async function test_historyClear() { + // Set interval to a large value so we don't expire on it. + setInterval(3600); // 1h + + // Expire all expirable pages. + setMaxPages(0); + + // Add some bookmarked page with visit and annotations. + for (let i = 0; i < 5; i++) { + let pageURI = uri("http://item_anno." + i + ".mozilla.org/"); + // This visit will be expired. + await PlacesTestUtils.addVisits({ uri: pageURI }); + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: pageURI, + title: null, + }); + // Will persist because the page is bookmarked. + await PlacesUtils.history.update({ + url: pageURI, + annotations: new Map([["persist", "test"]]), + }); + } + + // Add some visited page and annotations for each. + for (let i = 0; i < 5; i++) { + // All page annotations related to these expired pages are expected to + // expire as well. + let pageURI = uri("http://page_anno." + i + ".mozilla.org/"); + await PlacesTestUtils.addVisits({ uri: pageURI }); + await PlacesUtils.history.update({ + url: pageURI, + annotations: new Map([["expire", "test"]]), + }); + } + + // Expire all visits for the bookmarks + await PlacesUtils.history.clear(); + + Assert.equal((await getPagesWithAnnotation("expire")).length, 0); + + let pages = await getPagesWithAnnotation("persist"); + Assert.equal(pages.length, 5); +}); diff --git a/toolkit/components/places/tests/expiration/test_debug_expiration.js b/toolkit/components/places/tests/expiration/test_debug_expiration.js new file mode 100644 index 0000000000..b02f55f971 --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_debug_expiration.js @@ -0,0 +1,367 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * What this is aimed to test: + * + * Expiration can be manually triggered through a debug topic, but that should + * only expire orphan entries, unless -1 is passed as limit. + */ + +var gNow = getExpirablePRTime(60); + +add_task(async function test_expire_orphans() { + // Add visits to 2 pages and force a orphan expiration. Visits should survive. + await PlacesTestUtils.addVisits({ + uri: uri("http://page1.mozilla.org/"), + visitDate: gNow++, + }); + await PlacesTestUtils.addVisits({ + uri: uri("http://page2.mozilla.org/"), + visitDate: gNow++, + }); + // Create a orphan place. + let bm = await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: "http://page3.mozilla.org/", + title: "", + }); + await PlacesUtils.bookmarks.remove(bm); + + // Expire now. + await promiseForceExpirationStep(0); + + // Check that visits survived. + Assert.equal(visits_in_database("http://page1.mozilla.org/"), 1); + Assert.equal(visits_in_database("http://page2.mozilla.org/"), 1); + Assert.ok(!page_in_database("http://page3.mozilla.org/")); + + // Clean up. + await PlacesUtils.history.clear(); +}); + +add_task(async function test_expire_orphans_optionalarg() { + // Add visits to 2 pages and force a orphan expiration. Visits should survive. + await PlacesTestUtils.addVisits({ + uri: uri("http://page1.mozilla.org/"), + visitDate: gNow++, + }); + await PlacesTestUtils.addVisits({ + uri: uri("http://page2.mozilla.org/"), + visitDate: gNow++, + }); + // Create a orphan place. + let bm = await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: "http://page3.mozilla.org/", + title: "", + }); + await PlacesUtils.bookmarks.remove(bm); + + // Expire now. + await promiseForceExpirationStep(); + + // Check that visits survived. + Assert.equal(visits_in_database("http://page1.mozilla.org/"), 1); + Assert.equal(visits_in_database("http://page2.mozilla.org/"), 1); + Assert.ok(!page_in_database("http://page3.mozilla.org/")); + + // Clean up. + await PlacesUtils.history.clear(); +}); + +add_task(async function test_expire_limited() { + await PlacesTestUtils.addVisits([ + { + // Should be expired cause it's the oldest visit + uri: "http://old.mozilla.org/", + visitDate: gNow++, + }, + { + // Should not be expired cause we limit 1 + uri: "http://new.mozilla.org/", + visitDate: gNow++, + }, + ]); + + // Expire now. + await promiseForceExpirationStep(1); + + // Check that newer visit survived. + Assert.equal(visits_in_database("http://new.mozilla.org/"), 1); + // Other visits should have been expired. + Assert.ok(!page_in_database("http://old.mozilla.org/")); + + // Clean up. + await PlacesUtils.history.clear(); +}); + +add_task(async function test_expire_limited_longurl() { + let longurl = "http://long.mozilla.org/" + "a".repeat(232); + await PlacesTestUtils.addVisits([ + { + // Should be expired cause it's the oldest visit + uri: "http://old.mozilla.org/", + visitDate: gNow++, + }, + { + // Should be expired cause it's a long url older than 60 days. + uri: longurl, + visitDate: gNow++, + }, + { + // Should not be expired cause younger than 60 days. + uri: longurl, + visitDate: getExpirablePRTime(58), + }, + ]); + + await promiseForceExpirationStep(1); + + // Check that some visits survived. + Assert.equal(visits_in_database(longurl), 1); + // Other visits should have been expired. + Assert.ok(!page_in_database("http://old.mozilla.org/")); + + // Clean up. + await PlacesUtils.history.clear(); +}); + +add_task(async function test_expire_limited_exoticurl() { + await PlacesTestUtils.addVisits([ + { + // Should be expired cause it's the oldest visit + uri: "http://old.mozilla.org/", + visitDate: gNow++, + }, + { + // Should be expired cause it's a long url older than 60 days. + uri: "http://download.mozilla.org", + visitDate: gNow++, + transition: 7, + }, + { + // Should not be expired cause younger than 60 days. + uri: "http://nonexpirable-download.mozilla.org", + visitDate: getExpirablePRTime(58), + transition: 7, + }, + ]); + + await promiseForceExpirationStep(1); + + // Check that some visits survived. + Assert.equal( + visits_in_database("http://nonexpirable-download.mozilla.org/"), + 1 + ); + // The visits are gone, the url is not yet, cause we limited the expiration + // to one entry, and we already removed http://old.mozilla.org/. + // The page normally would be expired by the next expiration run. + Assert.equal(visits_in_database("http://download.mozilla.org/"), 0); + // Other visits should have been expired. + Assert.ok(!page_in_database("http://old.mozilla.org/")); + + // Clean up. + await PlacesUtils.history.clear(); +}); + +add_task(async function test_expire_unlimited() { + let longurl = "http://long.mozilla.org/" + "a".repeat(232); + await PlacesTestUtils.addVisits([ + { + uri: "http://old.mozilla.org/", + visitDate: gNow++, + }, + { + uri: "http://new.mozilla.org/", + visitDate: gNow++, + }, + // Add expirable visits. + { + uri: "http://download.mozilla.org/", + visitDate: gNow++, + transition: PlacesUtils.history.TRANSITION_DOWNLOAD, + }, + { + uri: longurl, + visitDate: gNow++, + }, + + // Add non-expirable visits + { + uri: "http://nonexpirable.mozilla.org/", + visitDate: getExpirablePRTime(5), + }, + { + uri: "http://nonexpirable-download.mozilla.org/", + visitDate: getExpirablePRTime(5), + transition: PlacesUtils.history.TRANSITION_DOWNLOAD, + }, + { + uri: longurl, + visitDate: getExpirablePRTime(5), + }, + ]); + + await promiseForceExpirationStep(-1); + + // Check that some visits survived. + Assert.equal(visits_in_database("http://nonexpirable.mozilla.org/"), 1); + Assert.equal( + visits_in_database("http://nonexpirable-download.mozilla.org/"), + 1 + ); + Assert.equal(visits_in_database(longurl), 1); + // Other visits should have been expired. + Assert.ok(!page_in_database("http://old.mozilla.org/")); + Assert.ok(!page_in_database("http://download.mozilla.org/")); + Assert.ok(!page_in_database("http://new.mozilla.org/")); + + // Clean up. + await PlacesUtils.history.clear(); +}); + +add_task(async function test_expire_icons() { + const dataUrl = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAA" + + "AAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=="; + + const entries = [ + { + desc: "Expired because it redirects", + page: "http://source.old.org/", + icon: "http://source.old.org/test_icon.png", + expired: true, + redirect: "http://dest.old.org/", + removed: true, + }, + { + desc: "Not expired because recent", + page: "http://source.new.org/", + icon: "http://source.new.org/test_icon.png", + expired: false, + redirect: "http://dest.new.org/", + removed: false, + }, + { + desc: "Not expired because does not match, even if old", + page: "http://stay.moz.org/", + icon: "http://stay.moz.org/test_icon.png", + expired: true, + removed: false, + }, + { + desc: "Not expired because does not have a root icon, even if old", + page: "http://noroot.ref.org/#test", + icon: "http://noroot.ref.org/test_icon.png", + expired: true, + removed: false, + }, + { + desc: "Expired because has a root icon", + page: "http://root.ref.org/#test", + icon: "http://root.ref.org/test_icon.png", + root: "http://root.ref.org/favicon.ico", + expired: true, + removed: true, + }, + { + desc: "Not expired because recent", + page: "http://new.ref.org/#test", + icon: "http://new.ref.org/test_icon.png", + expired: false, + root: "http://new.ref.org/favicon.ico", + removed: false, + }, + ]; + + for (let entry of entries) { + if (entry.redirect) { + await PlacesTestUtils.addVisits(entry.page); + await PlacesTestUtils.addVisits({ + uri: entry.redirect, + transition: TRANSITION_REDIRECT_PERMANENT, + referrer: entry.page, + }); + } else { + await PlacesTestUtils.addVisits(entry.page); + } + + PlacesUtils.favicons.replaceFaviconDataFromDataURL( + Services.io.newURI(entry.icon), + dataUrl, + 0, + Services.scriptSecurityManager.getSystemPrincipal() + ); + await PlacesTestUtils.addFavicons(new Map([[entry.page, entry.icon]])); + Assert.equal( + await getFaviconUrlForPage(entry.page), + entry.icon, + "Sanity check the icon exists" + ); + + if (entry.root) { + PlacesUtils.favicons.replaceFaviconDataFromDataURL( + Services.io.newURI(entry.root), + dataUrl, + 0, + Services.scriptSecurityManager.getSystemPrincipal() + ); + await PlacesTestUtils.addFavicons(new Map([[entry.page, entry.root]])); + } + if (entry.expired) { + // Set an expired time on the icon. + await PlacesUtils.withConnectionWrapper("expireFavicon", async db => { + await db.execute( + `UPDATE moz_icons SET expire_ms = 1 WHERE icon_url = :url`, + { url: entry.icon } + ); + if (entry.root) { + await db.execute( + `UPDATE moz_icons SET expire_ms = 1 WHERE icon_url = :url`, + { url: entry.root } + ); + } + }); + } + } + + info("Run expiration"); + await promiseForceExpirationStep(-1); + + info("Check expiration"); + // Remove the root icons before checking the associated icons have been expired. + await PlacesUtils.withConnectionWrapper("test_debug_expiration.js", db => + db.execute(`DELETE FROM moz_icons WHERE root = 1`) + ); + for (let entry of entries) { + Assert.ok(page_in_database(entry.page)); + + if (entry.removed) { + await Assert.rejects( + getFaviconUrlForPage(entry.page), + /Unable to find an icon/, + entry.desc + ); + } else { + Assert.equal( + await getFaviconUrlForPage(entry.page), + entry.icon, + entry.desc + ); + } + } + + // Clean up. + await PlacesUtils.history.clear(); +}); + +function run_test() { + // Set interval to a large value so we don't expire on it. + setInterval(3600); // 1h + // Set maxPages to a low value, so it's easy to go over it. + setMaxPages(1); + + run_next_test(); +} diff --git a/toolkit/components/places/tests/expiration/test_idle_daily.js b/toolkit/components/places/tests/expiration/test_idle_daily.js new file mode 100644 index 0000000000..11547e37dc --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_idle_daily.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that expiration runs on idle-daily. + +add_task(async function test_expiration_on_idle_daily() { + // Set interval to a large value so we don't expire on it. + setInterval(3600); // 1h + + let expirationPromise = TestUtils.topicObserved( + PlacesUtils.TOPIC_EXPIRATION_FINISHED + ); + + let expire = Cc["@mozilla.org/places/expiration;1"].getService( + Ci.nsIObserver + ); + expire.observe(null, "idle-daily", null); + + await expirationPromise; +}); diff --git a/toolkit/components/places/tests/expiration/test_notifications.js b/toolkit/components/places/tests/expiration/test_notifications.js new file mode 100644 index 0000000000..d52319a9c9 --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_notifications.js @@ -0,0 +1,36 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * 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/. */ + +"use strict"; + +/** + * What this is aimed to test: + * + * Ensure that History (through category cache) notifies us just once. + */ + +var gObserver = { + notifications: 0, + observe(aSubject, aTopic, aData) { + this.notifications++; + }, +}; +Services.obs.addObserver(gObserver, PlacesUtils.TOPIC_EXPIRATION_FINISHED); + +add_task(async function test_history_expirations_notify_just_once() { + // Set interval to a large value so we don't expire on it. + setInterval(3600); // 1h + + promiseForceExpirationStep(1); + + await new Promise(resolve => { + do_timeout(2000, resolve); + }); + + Assert.equal(gObserver.notifications, 1); + + Services.obs.removeObserver(gObserver, PlacesUtils.TOPIC_EXPIRATION_FINISHED); +}); diff --git a/toolkit/components/places/tests/expiration/test_notifications_onDeleteURI.js b/toolkit/components/places/tests/expiration/test_notifications_onDeleteURI.js new file mode 100644 index 0000000000..83f6699c4c --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_notifications_onDeleteURI.js @@ -0,0 +1,111 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * 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/. */ + +/** + * What this is aimed to test: + * + * Expiring a full page should fire an onDeleteURI notification. + */ + +var hs = Cc["@mozilla.org/browser/nav-history-service;1"].getService( + Ci.nsINavHistoryService +); + +var tests = [ + { + desc: "Add 1 bookmarked page.", + addPages: 1, + addBookmarks: 1, + expectedNotifications: 0, // No expirable pages. + }, + + { + desc: "Add 2 pages, 1 bookmarked.", + addPages: 2, + addBookmarks: 1, + expectedNotifications: 1, // Only one expirable page. + }, + + { + desc: "Add 10 pages, none bookmarked.", + addPages: 10, + addBookmarks: 0, + expectedNotifications: 10, // Will expire everything. + }, + + { + desc: "Add 10 pages, all bookmarked.", + addPages: 10, + addBookmarks: 10, + expectedNotifications: 0, // No expirable pages. + }, +]; + +add_task(async function test_notifications_onDeleteURI() { + // Set interval to a large value so we don't expire on it. + setInterval(3600); // 1h + + // Expire anything that is expirable. + setMaxPages(0); + + for (let testIndex = 1; testIndex <= tests.length; testIndex++) { + let currentTest = tests[testIndex - 1]; + print("\nTEST " + testIndex + ": " + currentTest.desc); + currentTest.receivedNotifications = 0; + + // Setup visits. + let now = getExpirablePRTime(); + for (let i = 0; i < currentTest.addPages; i++) { + let page = "http://" + testIndex + "." + i + ".mozilla.org/"; + await PlacesTestUtils.addVisits({ uri: uri(page), visitDate: now++ }); + } + + // Setup bookmarks. + currentTest.bookmarks = []; + for (let i = 0; i < currentTest.addBookmarks; i++) { + let page = "http://" + testIndex + "." + i + ".mozilla.org/"; + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: null, + url: page, + }); + currentTest.bookmarks.push(page); + } + + // Observe history. + let historyObserver = { + onBeginUpdateBatch: function PEX_onBeginUpdateBatch() {}, + onEndUpdateBatch: function PEX_onEndUpdateBatch() {}, + onDeleteURI(aURI, aGUID, aReason) { + currentTest.receivedNotifications++; + // Check this uri was not bookmarked. + Assert.equal(currentTest.bookmarks.indexOf(aURI.spec), -1); + do_check_valid_places_guid(aGUID); + Assert.equal(aReason, Ci.nsINavHistoryObserver.REASON_EXPIRED); + }, + onDeleteVisits() {}, + }; + hs.addObserver(historyObserver); + + // Expire now. + await promiseForceExpirationStep(-1); + + hs.removeObserver(historyObserver, false); + + Assert.equal( + currentTest.receivedNotifications, + currentTest.expectedNotifications + ); + + // Clean up. + await PlacesUtils.bookmarks.eraseEverything(); + await PlacesUtils.history.clear(); + } + + clearMaxPages(); + await PlacesUtils.bookmarks.eraseEverything(); + await PlacesUtils.history.clear(); +}); diff --git a/toolkit/components/places/tests/expiration/test_notifications_onDeleteVisits.js b/toolkit/components/places/tests/expiration/test_notifications_onDeleteVisits.js new file mode 100644 index 0000000000..d5c0a3b6b7 --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_notifications_onDeleteVisits.js @@ -0,0 +1,154 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * 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/. */ + +/** + * What this is aimed to test: + * + * Expiring only visits for a page, but not the full page, should fire an + * onDeleteVisits notification. + */ + +var hs = Cc["@mozilla.org/browser/nav-history-service;1"].getService( + Ci.nsINavHistoryService +); + +var tests = [ + { + desc: "Add 1 bookmarked page.", + addPages: 1, + visitsPerPage: 1, + addBookmarks: 1, + limitExpiration: -1, + expectedNotifications: 1, // Will expire visits for 1 page. + expectedIsPartialRemoval: true, + }, + + { + desc: "Add 2 pages, 1 bookmarked.", + addPages: 2, + visitsPerPage: 1, + addBookmarks: 1, + limitExpiration: -1, + expectedNotifications: 1, // Will expire visits for 1 page. + expectedIsPartialRemoval: true, + }, + + { + desc: "Add 10 pages, none bookmarked.", + addPages: 10, + visitsPerPage: 1, + addBookmarks: 0, + limitExpiration: -1, + expectedNotifications: 0, // Will expire only full pages. + expectedIsPartialRemoval: false, + }, + + { + desc: "Add 10 pages, all bookmarked.", + addPages: 10, + visitsPerPage: 1, + addBookmarks: 10, + limitExpiration: -1, + expectedNotifications: 10, // Will expire visits for all pages. + expectedIsPartialRemoval: true, + }, + + { + desc: "Add 10 pages with lot of visits, none bookmarked.", + addPages: 10, + visitsPerPage: 10, + addBookmarks: 0, + limitExpiration: 10, + expectedNotifications: 10, // Will expire 1 visit for each page, but won't + // expire pages since they still have visits. + expectedIsPartialRemoval: true, + }, +]; + +add_task(async function test_notifications_onDeleteVisits() { + // Set interval to a large value so we don't expire on it. + setInterval(3600); // 1h + + // Expire anything that is expirable. + setMaxPages(0); + + for (let testIndex = 1; testIndex <= tests.length; testIndex++) { + let currentTest = tests[testIndex - 1]; + print("\nTEST " + testIndex + ": " + currentTest.desc); + currentTest.receivedNotifications = 0; + + // Setup visits. + let timeInMicroseconds = getExpirablePRTime(8); + + function newTimeInMicroseconds() { + timeInMicroseconds = timeInMicroseconds + 1000; + return timeInMicroseconds; + } + + for (let j = 0; j < currentTest.visitsPerPage; j++) { + for (let i = 0; i < currentTest.addPages; i++) { + let page = "http://" + testIndex + "." + i + ".mozilla.org/"; + await PlacesTestUtils.addVisits({ + uri: uri(page), + visitDate: newTimeInMicroseconds(), + }); + } + } + + // Setup bookmarks. + currentTest.bookmarks = []; + for (let i = 0; i < currentTest.addBookmarks; i++) { + let page = "http://" + testIndex + "." + i + ".mozilla.org/"; + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: null, + url: page, + }); + currentTest.bookmarks.push(page); + } + + // Observe history. + let historyObserver = { + onBeginUpdateBatch: function PEX_onBeginUpdateBatch() {}, + onEndUpdateBatch: function PEX_onEndUpdateBatch() {}, + onDeleteURI(aURI, aGUID, aReason) { + // Check this uri was not bookmarked. + Assert.equal(currentTest.bookmarks.indexOf(aURI.spec), -1); + do_check_valid_places_guid(aGUID); + Assert.equal(aReason, Ci.nsINavHistoryObserver.REASON_EXPIRED); + }, + onDeleteVisits(aURI, aPartialRemoval, aGUID, aReason) { + currentTest.receivedNotifications++; + do_check_guid_for_uri(aURI, aGUID); + Assert.equal( + aPartialRemoval, + currentTest.expectedIsPartialRemoval, + "Should have the correct flag setting for partial removal" + ); + Assert.equal(aReason, Ci.nsINavHistoryObserver.REASON_EXPIRED); + }, + }; + hs.addObserver(historyObserver); + + // Expire now. + await promiseForceExpirationStep(currentTest.limitExpiration); + + hs.removeObserver(historyObserver, false); + + Assert.equal( + currentTest.receivedNotifications, + currentTest.expectedNotifications + ); + + // Clean up. + await PlacesUtils.bookmarks.eraseEverything(); + await PlacesUtils.history.clear(); + } + + clearMaxPages(); + await PlacesUtils.bookmarks.eraseEverything(); + await PlacesUtils.history.clear(); +}); diff --git a/toolkit/components/places/tests/expiration/test_pref_interval.js b/toolkit/components/places/tests/expiration/test_pref_interval.js new file mode 100644 index 0000000000..5bf340e7c4 --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_pref_interval.js @@ -0,0 +1,62 @@ +/** + * What this is aimed to test: + * + * Expiration relies on an interval, that is user-preffable setting + * "places.history.expiration.interval_seconds". + * On pref change it will stop current interval timer and fire a new one, + * that will obey the new value. + * If the pref is set to a number <= 0 we will use the default value. + */ + +// Default timer value for expiration in seconds. Must have same value as +// PREF_INTERVAL_SECONDS_NOTSET in nsPlacesExpiration. +const DEFAULT_TIMER_DELAY_SECONDS = 3 * 60; + +// Sync this with the const value in the component. +const EXPIRE_AGGRESSIVITY_MULTIPLIER = 3; + +var tests = [ + { + desc: "Set interval to 1s.", + interval: 1, + expectedTimerDelay: 1 * EXPIRE_AGGRESSIVITY_MULTIPLIER, + }, + + { + desc: "Set interval to a negative value.", + interval: -1, + expectedTimerDelay: + DEFAULT_TIMER_DELAY_SECONDS * EXPIRE_AGGRESSIVITY_MULTIPLIER, + }, + + { + desc: "Set interval to 0.", + interval: 0, + expectedTimerDelay: + DEFAULT_TIMER_DELAY_SECONDS * EXPIRE_AGGRESSIVITY_MULTIPLIER, + }, + + { + desc: "Set interval to a large value.", + interval: 100, + expectedTimerDelay: 100 * EXPIRE_AGGRESSIVITY_MULTIPLIER, + }, +]; + +add_task(async function test() { + // The pref should not exist by default. + Assert.throws(() => getInterval(), /NS_ERROR_UNEXPECTED/); + + // Force the component, so it will start observing preferences. + force_expiration_start(); + + for (let currentTest of tests) { + currentTest = tests.shift(); + print(currentTest.desc); + let promise = promiseTopicObserved("test-interval-changed"); + setInterval(currentTest.interval); + let [, data] = await promise; + Assert.equal(data, currentTest.expectedTimerDelay); + } + clearInterval(); +}); diff --git a/toolkit/components/places/tests/expiration/test_pref_maxpages.js b/toolkit/components/places/tests/expiration/test_pref_maxpages.js new file mode 100644 index 0000000000..18f577ff42 --- /dev/null +++ b/toolkit/components/places/tests/expiration/test_pref_maxpages.js @@ -0,0 +1,116 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * 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/. */ + +/** + * What this is aimed to test: + * + * Expiration will obey to hardware spec, but user can set a custom maximum + * number of pages to retain, to restrict history, through + * "places.history.expiration.max_pages". + * This limit is used at next expiration run. + * If the pref is set to a number < 0 we will use the default value. + */ + +var tests = [ + { + desc: "Set max_pages to a negative value, with 1 page.", + maxPages: -1, + addPages: 1, + expectedNotifications: 0, // Will ignore and won't expire anything. + }, + + { + desc: "Set max_pages to 0.", + maxPages: 0, + addPages: 1, + expectedNotifications: 1, + }, + + { + desc: "Set max_pages to 0, with 2 pages.", + maxPages: 0, + addPages: 2, + expectedNotifications: 2, // Will expire everything. + }, + + // Notice if we are over limit we do a full step of expiration. So we ensure + // that we will expire if we are over the limit, but we don't ensure that we + // will expire exactly up to the limit. Thus in this case we expire + // everything. + { + desc: "Set max_pages to 1 with 2 pages.", + maxPages: 1, + addPages: 2, + expectedNotifications: 2, // Will expire everything (in this case). + }, + + { + desc: "Set max_pages to 10, with 9 pages.", + maxPages: 10, + addPages: 9, + expectedNotifications: 0, // We are at the limit, won't expire anything. + }, + + { + desc: "Set max_pages to 10 with 10 pages.", + maxPages: 10, + addPages: 10, + expectedNotifications: 0, // We are below the limit, won't expire anything. + }, +]; + +add_task(async function test_pref_maxpages() { + // The pref should not exist by default. + try { + getMaxPages(); + do_throw("interval pref should not exist by default"); + } catch (ex) {} + + // Set interval to a large value so we don't expire on it. + setInterval(3600); // 1h + + for (let testIndex = 1; testIndex <= tests.length; testIndex++) { + let currentTest = tests[testIndex - 1]; + print("\nTEST " + testIndex + ": " + currentTest.desc); + currentTest.receivedNotifications = 0; + + // Setup visits. + let now = getExpirablePRTime(); + for (let i = 0; i < currentTest.addPages; i++) { + let page = "http://" + testIndex + "." + i + ".mozilla.org/"; + await PlacesTestUtils.addVisits({ uri: uri(page), visitDate: now-- }); + } + + // Observe history. + let historyObserver = new NavHistoryObserver(); + historyObserver.onDeleteURI = aURI => { + print("onDeleteURI " + aURI.spec); + currentTest.receivedNotifications++; + }; + historyObserver.onDeleteVisits = (aURI, aPartialRemoval) => { + print("onDeleteVisits " + aURI.spec + " " + aPartialRemoval); + }; + PlacesUtils.history.addObserver(historyObserver); + + setMaxPages(currentTest.maxPages); + + // Expire now. + await promiseForceExpirationStep(-1); + + PlacesUtils.history.removeObserver(historyObserver, false); + + Assert.equal( + currentTest.receivedNotifications, + currentTest.expectedNotifications + ); + + // Clean up. + await PlacesUtils.history.clear(); + } + + clearMaxPages(); + await PlacesUtils.history.clear(); +}); diff --git a/toolkit/components/places/tests/expiration/xpcshell.ini b/toolkit/components/places/tests/expiration/xpcshell.ini new file mode 100644 index 0000000000..0f6ca74f62 --- /dev/null +++ b/toolkit/components/places/tests/expiration/xpcshell.ini @@ -0,0 +1,13 @@ +[DEFAULT] +head = head_expiration.js +skip-if = toolkit == 'android' + +[test_annos_expire_never.js] +[test_clearHistory.js] +[test_debug_expiration.js] +[test_idle_daily.js] +[test_notifications.js] +[test_notifications_onDeleteURI.js] +[test_notifications_onDeleteVisits.js] +[test_pref_interval.js] +[test_pref_maxpages.js] |