diff options
Diffstat (limited to 'toolkit/components/places/tests')
53 files changed, 738 insertions, 200 deletions
diff --git a/toolkit/components/places/tests/PlacesTestUtils.sys.mjs b/toolkit/components/places/tests/PlacesTestUtils.sys.mjs index acd1152b44..4e459d2e32 100644 --- a/toolkit/components/places/tests/PlacesTestUtils.sys.mjs +++ b/toolkit/components/places/tests/PlacesTestUtils.sys.mjs @@ -64,6 +64,9 @@ export var PlacesTestUtils = Object.freeze({ let info = { url: place.uri || place.url }; let spec = info.url instanceof Ci.nsIURI ? info.url.spec : new URL(info.url).href; + info.exposableURI = Services.io.createExposableURI( + Services.io.newURI(spec) + ); info.title = "title" in place ? place.title : "test visit for " + spec; let visitDate = place.visitDate; if (visitDate) { @@ -107,7 +110,7 @@ export var PlacesTestUtils = Object.freeze({ } if (lastStoredVisit) { await lazy.TestUtils.waitForCondition( - () => lazy.PlacesUtils.history.fetch(lastStoredVisit.url), + () => lazy.PlacesUtils.history.fetch(lastStoredVisit.exposableURI), "Ensure history has been updated and is visible to read-only connections" ); } @@ -556,7 +559,9 @@ export var PlacesTestUtils = Object.freeze({ * @param {string} field - The name of the field to retrieve a value from. * @param {Object} [conditions] - An object containing the conditions to * filter the query results. The keys represent the names of the columns to - * filter by, and the values represent the filter values. + * filter by, and the values represent the filter values. It's possible to + * pass an array as value where the first element is an operator + * (e.g. "<", ">") and the second element is the actual value. * @return {Promise} A Promise that resolves to the value of the specified * field from the database table, or null if the query returns no results. * @throws If more than one result is found for the given conditions. @@ -579,9 +584,11 @@ export var PlacesTestUtils = Object.freeze({ * conditions. * @param {string} table - The name of the database table to add to. * @param {string} fields - an object with field, value pairs - * @param {Object} [conditions] - An object containing the conditions to filter - * the query results. The keys represent the names of the columns to filter - * by, and the values represent the filter values. + * @param {Object} [conditions] - An object containing the conditions to + * filter the query results. The keys represent the names of the columns to + * filter by, and the values represent the filter values. It's possible to + * pass an array as value where the first element is an operator + * (e.g. "<", ">") and the second element is the actual value. * @return {Promise} A Promise that resolves to the number of affected rows. * @throws If no rows were affected. */ @@ -636,6 +643,11 @@ export var PlacesTestUtils = Object.freeze({ } if (column == "url" && table == "moz_places") { fragments.push("url_hash = hash(:url) AND url = :url"); + } else if (Array.isArray(value)) { + // First element is the operator, second element is the value. + let [op, actualValue] = value; + fragments.push(`${column} ${op} :${column}`); + value = actualValue; } else { fragments.push(`${column} = :${column}`); } diff --git a/toolkit/components/places/tests/bookmarks/test_818584-discard-duplicate-backups.js b/toolkit/components/places/tests/bookmarks/test_818584-discard-duplicate-backups.js index be5d53f8c6..71065425fd 100644 --- a/toolkit/components/places/tests/bookmarks/test_818584-discard-duplicate-backups.js +++ b/toolkit/components/places/tests/bookmarks/test_818584-discard-duplicate-backups.js @@ -17,7 +17,7 @@ add_task(async function () { oldBackup ); Assert.ok(count > 0); - Assert.equal(hash.length, 24); + Assert.equal(hash.length, 44); oldBackupName = oldBackupName.replace( /\.json/, "_" + count + "_" + hash + ".json" diff --git a/toolkit/components/places/tests/bookmarks/test_818593-store-backup-metadata.js b/toolkit/components/places/tests/bookmarks/test_818593-store-backup-metadata.js index 6d280e8cad..265cc5621d 100644 --- a/toolkit/components/places/tests/bookmarks/test_818593-store-backup-metadata.js +++ b/toolkit/components/places/tests/bookmarks/test_818593-store-backup-metadata.js @@ -28,7 +28,7 @@ add_task(async function test_saveBookmarksToJSONFile_and_create() { PlacesBackups.filenamesRegex ); Assert.equal(matches[2], nodeCount); - Assert.equal(matches[3].length, 24); + Assert.equal(matches[3].length, 44); // Clear all backups in our backups folder. await PlacesBackups.create(0); @@ -44,7 +44,7 @@ add_task(async function test_saveBookmarksToJSONFile_and_create() { PlacesBackups.filenamesRegex ); Assert.equal(matches[2], nodeCount); - Assert.equal(matches[3].length, 24); + Assert.equal(matches[3].length, 44); // Cleanup await IOUtils.remove(backupFile); diff --git a/toolkit/components/places/tests/bookmarks/test_insert_thousands_bookmarks.js b/toolkit/components/places/tests/bookmarks/test_insert_thousands_bookmarks.js new file mode 100644 index 0000000000..9d1823449f --- /dev/null +++ b/toolkit/components/places/tests/bookmarks/test_insert_thousands_bookmarks.js @@ -0,0 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test `insertTree()` with more bookmarks than the Sqlite variables limit. + +add_task(async function () { + const NUM_BOOKMARKS = 1000; + await PlacesUtils.withConnectionWrapper("test", async db => { + db.variableLimit = NUM_BOOKMARKS - 100; + Assert.greater( + NUM_BOOKMARKS, + db.variableLimit, + "Insert more bookmarks than the Sqlite variables limit." + ); + }); + let children = []; + for (let i = 0; i < NUM_BOOKMARKS; ++i) { + children.push({ url: "http://www.mozilla.org/" + i }); + } + await PlacesUtils.bookmarks.insertTree({ + guid: PlacesUtils.bookmarks.toolbarGuid, + children, + }); +}); diff --git a/toolkit/components/places/tests/bookmarks/xpcshell.toml b/toolkit/components/places/tests/bookmarks/xpcshell.toml index 0b989e5fbf..c2e6d7ff09 100644 --- a/toolkit/components/places/tests/bookmarks/xpcshell.toml +++ b/toolkit/components/places/tests/bookmarks/xpcshell.toml @@ -70,6 +70,8 @@ support-files = ["bookmarks_long_tag.json"] ["test_bookmarks_update.js"] +["test_insert_thousands_bookmarks.js"] + ["test_insertTree_fixupOrSkipInvalidEntries.js"] ["test_keywords.js"] diff --git a/toolkit/components/places/tests/browser/browser.toml b/toolkit/components/places/tests/browser/browser.toml index 022b929240..b7d688c980 100644 --- a/toolkit/components/places/tests/browser/browser.toml +++ b/toolkit/components/places/tests/browser/browser.toml @@ -44,6 +44,8 @@ support-files = [ "redirect_twice.sjs", ] +["browser_favicon.js"] + ["browser_favicon_privatebrowsing_perwindowpb.js"] ["browser_history_post.js"] @@ -94,9 +96,11 @@ support-files = [ https_first_disabled = true support-files = [ "begin.html", + "favicon.html", "final.html", "redirect_once.sjs", "redirect_twice.sjs", + "userpass.html", ] ["browser_visituri_nohistory.js"] diff --git a/toolkit/components/places/tests/browser/browser_double_redirect.js b/toolkit/components/places/tests/browser/browser_double_redirect.js index 435bd86f19..d5b2fca1fe 100644 --- a/toolkit/components/places/tests/browser/browser_double_redirect.js +++ b/toolkit/components/places/tests/browser/browser_double_redirect.js @@ -16,7 +16,7 @@ add_task(async function () { let promiseVisits = new Promise(resolve => { let observer = { _notified: [], - onVisit(uri, id, time, referrerId, transition) { + onVisit(uri) { info("Received onVisit: " + uri); this._notified.push(uri); diff --git a/toolkit/components/places/tests/browser/browser_favicon.js b/toolkit/components/places/tests/browser/browser_favicon.js new file mode 100644 index 0000000000..9b4a1b97fe --- /dev/null +++ b/toolkit/components/places/tests/browser/browser_favicon.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const lazy = {}; +ChromeUtils.defineESModuleGetters(lazy, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +const { MockRegistrar } = ChromeUtils.importESModule( + "resource://testing-common/MockRegistrar.sys.mjs" +); + +add_task(async function test_userpass() { + // Setup the prompt to avoid showing it. + let mockPromptService = { + firstTimeCalled: false, + confirmExBC() { + if (!this.firstTimeCalled) { + this.firstTimeCalled = true; + return 0; + } + + return 1; + }, + QueryInterface: ChromeUtils.generateQI(["nsIPromptService"]), + }; + let mockPromptServiceCID = MockRegistrar.register( + "@mozilla.org/prompter;1", + mockPromptService + ); + registerCleanupFunction(() => { + MockRegistrar.unregister(mockPromptServiceCID); + }); + + const pageUrl = + "https://user:pass@example.org/tests/toolkit/components/places/tests/browser/favicon.html"; + const faviconUrl = + "https://user:pass@example.org/tests/toolkit/components/places/tests/browser/favicon-normal32.png"; + const exposableFaviconUrl = + "https://example.org/tests/toolkit/components/places/tests/browser/favicon-normal32.png"; + + let faviconPromise = lazy.PlacesTestUtils.waitForNotification( + "favicon-changed", + async () => { + let faviconForExposable = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_icons", + "icon_url", + { + icon_url: exposableFaviconUrl, + } + ); + Assert.ok(faviconForExposable, "Found the icon for exposable URL"); + + let faviconForOriginal = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_icons", + "icon_url", + { + icon_url: faviconUrl, + } + ); + Assert.ok(!faviconForOriginal, "Not found the icon for the original URL"); + return true; + } + ); + + await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl); + await faviconPromise; + + // Clean up. + await PlacesUtils.history.clear(); + gBrowser.removeCurrentTab(); +}); diff --git a/toolkit/components/places/tests/browser/browser_favicon_privatebrowsing_perwindowpb.js b/toolkit/components/places/tests/browser/browser_favicon_privatebrowsing_perwindowpb.js index ab3e0a1ef1..090fe802ab 100644 --- a/toolkit/components/places/tests/browser/browser_favicon_privatebrowsing_perwindowpb.js +++ b/toolkit/components/places/tests/browser/browser_favicon_privatebrowsing_perwindowpb.js @@ -36,7 +36,7 @@ function test() { waitForTabLoad(win, function () { PlacesUtils.favicons.getFaviconURLForPage( NetUtil.newURI(pageURI), - function (uri, dataLen, data, mimeType) { + function (uri) { is(uri, null, "No result should be found"); finish(); } diff --git a/toolkit/components/places/tests/browser/browser_history_post.js b/toolkit/components/places/tests/browser/browser_history_post.js index a62592516f..dad988a624 100644 --- a/toolkit/components/places/tests/browser/browser_history_post.js +++ b/toolkit/components/places/tests/browser/browser_history_post.js @@ -12,7 +12,7 @@ add_task(async function () { let doc = content.document; let submit = doc.getElementById("submit"); let iframe = doc.getElementById("post_iframe"); - let p = new Promise((resolve, reject) => { + let p = new Promise(resolve => { iframe.addEventListener( "load", function () { diff --git a/toolkit/components/places/tests/browser/browser_notfound.js b/toolkit/components/places/tests/browser/browser_notfound.js index 22ac67de0a..84e4f2ab9b 100644 --- a/toolkit/components/places/tests/browser/browser_notfound.js +++ b/toolkit/components/places/tests/browser/browser_notfound.js @@ -23,7 +23,7 @@ add_task(async function () { gBrowser, url, }, - async browser => { + async () => { info("awaiting for the visit"); await promiseVisited; diff --git a/toolkit/components/places/tests/browser/browser_redirect_self.js b/toolkit/components/places/tests/browser/browser_redirect_self.js index 7ed7ee0af0..3f14cf4f7c 100644 --- a/toolkit/components/places/tests/browser/browser_redirect_self.js +++ b/toolkit/components/places/tests/browser/browser_redirect_self.js @@ -37,7 +37,7 @@ add_task(async function () { gBrowser, url, }, - async browser => { + async () => { await TestUtils.waitForCondition(() => visitCount == 2); // Check that the visit is not hidden in the database. Assert.ok( diff --git a/toolkit/components/places/tests/browser/browser_visited_notfound.js b/toolkit/components/places/tests/browser/browser_visited_notfound.js index 36d1764361..ca0638481b 100644 --- a/toolkit/components/places/tests/browser/browser_visited_notfound.js +++ b/toolkit/components/places/tests/browser/browser_visited_notfound.js @@ -29,7 +29,7 @@ add_task(async function test() { gBrowser, url, }, - async browser => { + async () => { info("awaiting for the visit"); Assert.equal( diff --git a/toolkit/components/places/tests/browser/browser_visituri.js b/toolkit/components/places/tests/browser/browser_visituri.js index 6633ac188b..529c010e63 100644 --- a/toolkit/components/places/tests/browser/browser_visituri.js +++ b/toolkit/components/places/tests/browser/browser_visituri.js @@ -1,86 +1,78 @@ -/** - * One-time observer callback. - */ -function promiseObserve(name, checkFn) { - return new Promise(resolve => { - Services.obs.addObserver(function observer(subject) { - if (checkFn(subject)) { - Services.obs.removeObserver(observer, name); - resolve(); - } - }, name); - }); -} - -var conn = PlacesUtils.history.DBConnection; - -/** - * Gets a single column value from either the places or historyvisits table. - */ -function getColumn(table, column, fromColumnName, fromColumnValue) { - let sql = `SELECT ${column} - FROM ${table} - WHERE ${fromColumnName} = :val - ${fromColumnName == "url" ? "AND url_hash = hash(:val)" : ""} - LIMIT 1`; - let stmt = conn.createStatement(sql); - try { - stmt.params.val = fromColumnValue; - ok(stmt.executeStep(), "Expect to get a row"); - return stmt.row[column]; - } finally { - stmt.reset(); - } -} +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; -add_task(async function () { +const lazy = {}; +ChromeUtils.defineESModuleGetters(lazy, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", + TestUtils: "resource://testing-common/TestUtils.sys.mjs", +}); + +add_task(async function test_basic() { // Make sure places visit chains are saved correctly with a redirect // transitions. // Part 1: observe history events that fire when a visit occurs. // Make sure visits appear in order, and that the visit chain is correct. - var expectedUrls = [ + const expectedUrls = [ "http://example.com/tests/toolkit/components/places/tests/browser/begin.html", "http://example.com/tests/toolkit/components/places/tests/browser/redirect_twice.sjs", "http://example.com/tests/toolkit/components/places/tests/browser/redirect_once.sjs", "http://test1.example.com/tests/toolkit/components/places/tests/browser/final.html", ]; - var currentIndex = 0; - - function checkObserver(subject) { - var uri = subject.QueryInterface(Ci.nsIURI); - var expected = expectedUrls[currentIndex]; - is(uri.spec, expected, "Saved URL visit " + uri.spec); - - var placeId = getColumn("moz_places", "id", "url", uri.spec); - var fromVisitId = getColumn( - "moz_historyvisits", - "from_visit", - "place_id", - placeId - ); - if (currentIndex == 0) { - is(fromVisitId, 0, "First visit has no from visit"); - } else { - var lastVisitId = getColumn( - "moz_historyvisits", - "place_id", + let currentIndex = 0; + let visitUriPromise = lazy.TestUtils.topicObserved( + "uri-visit-saved", + async subject => { + let uri = subject.QueryInterface(Ci.nsIURI); + let expected = expectedUrls[currentIndex]; + is(uri.spec, expected, "Saved URL visit " + uri.spec); + + let placeId = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_places", "id", - fromVisitId + { + url: uri.spec, + } ); - var fromVisitUrl = getColumn("moz_places", "url", "id", lastVisitId); - is( - fromVisitUrl, - expectedUrls[currentIndex - 1], - "From visit was " + expectedUrls[currentIndex - 1] + let fromVisitId = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_historyvisits", + "from_visit", + { + place_id: placeId, + } ); - } - currentIndex++; - return currentIndex >= expectedUrls.length; - } - let visitUriPromise = promiseObserve("uri-visit-saved", checkObserver); + if (currentIndex == 0) { + is(fromVisitId, 0, "First visit has no from visit"); + } else { + let lastVisitId = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_historyvisits", + "place_id", + { + id: fromVisitId, + } + ); + let fromVisitUrl = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_places", + "url", + { + id: lastVisitId, + } + ); + is( + fromVisitUrl, + expectedUrls[currentIndex - 1], + "From visit was " + expectedUrls[currentIndex - 1] + ); + } + + currentIndex++; + return currentIndex >= expectedUrls.length; + } + ); const testUrl = "http://example.com/tests/toolkit/components/places/tests/browser/begin.html"; @@ -94,7 +86,119 @@ add_task(async function () { ); await visitUriPromise; + // Clean up. await PlacesUtils.history.clear(); + gBrowser.removeCurrentTab(); +}); + +add_task(async function test_userpass() { + // Avoid showing the auth prompt. + await SpecialPowers.pushPrefEnv({ + set: [["network.auth.confirmAuth.enabled", false]], + }); + + // Open a html having test links. + await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "https://example.org/tests/toolkit/components/places/tests/browser/userpass.html" + ); + + const clickedUrl = + "https://user:pass@example.org/tests/toolkit/components/places/tests/browser/favicon.html"; + const exposablePageUrl = + "https://example.org/tests/toolkit/components/places/tests/browser/favicon.html"; + + let visitUriPromise = lazy.TestUtils.topicObserved( + "uri-visit-saved", + async subject => { + let uri = subject.QueryInterface(Ci.nsIURI); + if (uri.spec !== exposablePageUrl) { + return false; + } + let placeForExposable = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_places", + "id", + { + url: exposablePageUrl, + } + ); + Assert.ok(placeForExposable, "Found the place for exposable URL"); + + let placeForOriginal = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_places", + "id", + { + url: clickedUrl, + } + ); + Assert.ok(!placeForOriginal, "Not found the place for the original URL"); + + return true; + } + ); + + // Open the target link as background. + await ContentTask.spawn(gBrowser.selectedBrowser, null, async args => { + let link = content.document.getElementById("target-userpass"); + EventUtils.synthesizeMouseAtCenter( + link, + { + ctrlKey: true, + metaKey: true, + }, + content + ); + return link.href; + }); + + // Wait for fireing visited event. + await visitUriPromise; + + // Check the title. + await BrowserTestUtils.waitForCondition(async () => { + let titleForExposable = await lazy.PlacesTestUtils.getDatabaseValue( + "moz_places", + "title", + { + url: exposablePageUrl, + } + ); + return titleForExposable == "favicon page"; + }, "Wait for the proper title is updated"); + + // Check the link status. + const expectedResults = { + "target-userpass": true, + "no-userpass": true, + "another-userpass": false, + "another-url": false, + }; + + for (const [key, value] of Object.entries(expectedResults)) { + await ContentTask.spawn( + gBrowser.selectedBrowser, + [key, value], + async ([k, v]) => { + // ElementState::VISITED + const VISITED_STATE = 1 << 18; + await ContentTaskUtils.waitForCondition(() => { + const isVisited = !!( + content.InspectorUtils.getContentState( + content.document.getElementById(k) + ) & VISITED_STATE + ); + return isVisited == v; + }); + } + ); + Assert.ok(true, `The status of ${key} is correct`); + } + + // Clean up. + await PlacesUtils.history.clear(); + // Remove the tab for userpass.html + gBrowser.removeCurrentTab(); + // Remove the tab for favicon.html gBrowser.removeCurrentTab(); }); diff --git a/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js b/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js index 746611d2ad..2d170115f6 100644 --- a/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js +++ b/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js @@ -13,7 +13,7 @@ var visitSavedPromise; add_setup(async function () { visitSavedPromise = new Promise(resolve => { observer = { - observe(subject, topic, data) { + observe(subject, topic) { // The uri-visit-saved topic should only work when on normal mode. if (topic == "uri-visit-saved") { Services.obs.removeObserver(observer, "uri-visit-saved"); diff --git a/toolkit/components/places/tests/browser/favicon.html b/toolkit/components/places/tests/browser/favicon.html index a0f5ea9594..789d0b89b8 100644 --- a/toolkit/components/places/tests/browser/favicon.html +++ b/toolkit/components/places/tests/browser/favicon.html @@ -5,9 +5,10 @@ <html> <head> - <link rel="shortcut icon" href="http://example.org/tests/toolkit/components/places/tests/browser/favicon-normal32.png"> + <link rel="shortcut icon" href="/tests/toolkit/components/places/tests/browser/favicon-normal32.png"> + <title>favicon page</title> </head> <body> - OK we're done! + <label>OK we're done!</label> </body> </html> diff --git a/toolkit/components/places/tests/browser/previews/browser.toml b/toolkit/components/places/tests/browser/previews/browser.toml index 10758a4803..f7f2c9b583 100644 --- a/toolkit/components/places/tests/browser/previews/browser.toml +++ b/toolkit/components/places/tests/browser/previews/browser.toml @@ -2,7 +2,7 @@ prefs = [ "browser.pagethumbnails.capturing_disabled=false", "places.previews.enabled=true", - "places.previews.log=true", + "places.loglevel='All'", ] ["browser_thumbnails.js"] diff --git a/toolkit/components/places/tests/browser/userpass.html b/toolkit/components/places/tests/browser/userpass.html new file mode 100644 index 0000000000..ceff388b79 --- /dev/null +++ b/toolkit/components/places/tests/browser/userpass.html @@ -0,0 +1,13 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ + --> + +<html> + <body> + <a href="https://user:pass@example.org/tests/toolkit/components/places/tests/browser/favicon.html" id="target-userpass">target userpass</a> + <a href="https://user2:pass2@example.org/tests/toolkit/components/places/tests/browser/favicon.html" id="another-userpass">another userpass</a> + <a href="https://example.org/tests/toolkit/components/places/tests/browser/favicon.html" id="no-userpass">no userpass</a> + <a href="https://example.org/" id="another-url">another url</a> + </body> +</html> diff --git a/toolkit/components/places/tests/chrome/test_371798.xhtml b/toolkit/components/places/tests/chrome/test_371798.xhtml index 33e866e51e..f66ac74aae 100644 --- a/toolkit/components/places/tests/chrome/test_371798.xhtml +++ b/toolkit/components/places/tests/chrome/test_371798.xhtml @@ -57,7 +57,7 @@ const TEST_URI = Services.io.newURI("http://foo.com"); let node = rootNode.getChild(i); // test that bm1 does not have new title if (node.bookmarkGuid == bm1.guid) - ok(node.title != "foo", + isnot(node.title, "foo", "Changing a bookmark's title did not affect the title of other bookmarks with the same URI"); } rootNode.containerOpen = false; diff --git a/toolkit/components/places/tests/expiration/test_notifications.js b/toolkit/components/places/tests/expiration/test_notifications.js index d52319a9c9..7ac7d769d6 100644 --- a/toolkit/components/places/tests/expiration/test_notifications.js +++ b/toolkit/components/places/tests/expiration/test_notifications.js @@ -14,7 +14,7 @@ var gObserver = { notifications: 0, - observe(aSubject, aTopic, aData) { + observe() { this.notifications++; }, }; diff --git a/toolkit/components/places/tests/favicons/head_favicons.js b/toolkit/components/places/tests/favicons/head_favicons.js index d8109c66e0..afd2c4924f 100644 --- a/toolkit/components/places/tests/favicons/head_favicons.js +++ b/toolkit/components/places/tests/favicons/head_favicons.js @@ -53,13 +53,10 @@ function checkFaviconDataForPage( * This function is called after the check finished. */ function checkFaviconMissingForPage(aPageURI, aCallback) { - PlacesUtils.favicons.getFaviconURLForPage( - aPageURI, - function (aURI, aDataLen, aData, aMimeType) { - Assert.ok(aURI === null); - aCallback(); - } - ); + PlacesUtils.favicons.getFaviconURLForPage(aPageURI, function (aURI) { + Assert.ok(aURI === null); + aCallback(); + }); } function promiseFaviconMissingForPage(aPageURI) { diff --git a/toolkit/components/places/tests/favicons/test_cached-favicon_mime_type.js b/toolkit/components/places/tests/favicons/test_cached-favicon_mime_type.js index 1c95d63f94..c1f6689a70 100644 --- a/toolkit/components/places/tests/favicons/test_cached-favicon_mime_type.js +++ b/toolkit/components/places/tests/favicons/test_cached-favicon_mime_type.js @@ -19,7 +19,7 @@ function streamListener(aExpectedContentType) { } streamListener.prototype = { onStartRequest() {}, - onStopRequest(aRequest, aContext, aStatusCode) { + onStopRequest(aRequest) { let channel = aRequest.QueryInterface(Ci.nsIChannel); Assert.equal( channel.contentType, @@ -28,7 +28,7 @@ streamListener.prototype = { ); this.done.resolve(); }, - onDataAvailable(aRequest, aInputStream, aOffset, aCount) { + onDataAvailable(aRequest) { aRequest.cancel(Cr.NS_ERROR_ABORT); throw Components.Exception("", Cr.NS_ERROR_ABORT); }, @@ -85,4 +85,60 @@ add_task(async function () { let listener = new streamListener("image/png"); channel.asyncOpen(listener); await listener.done.promise; + + await PlacesUtils.history.clear(); +}); + +add_task(async function test_userpass() { + info("Test whether can get favicon content regardless of user pass"); + + const PAGE_NORMAL = uri("http://mozilla.org/"); + const PAGE_USERPASS = uri("http://user:pass@mozilla.org/"); + const ICON_NORMAL = uri("http://mozilla.org/favicon.png"); + const ICON_USERPASS = uri("http://user:pass@mozilla.org/favicon.png"); + const CACHED_ICON_NORMAL = "cached-favicon:http://mozilla.org/favicon.png"; + const CACHED_ICON_USERPASS = + "cached-favicon:http://user:pass@mozilla.org/favicon.png"; + + const testData = [ + { + pageURI: PAGE_USERPASS, + iconURI: ICON_NORMAL, + }, + { + pageURI: PAGE_NORMAL, + iconURI: ICON_USERPASS, + }, + { + pageURI: PAGE_USERPASS, + iconURI: ICON_USERPASS, + }, + ]; + + for (const { pageURI, iconURI } of testData) { + for (const loadingIconURISpec of [ + CACHED_ICON_NORMAL, + CACHED_ICON_USERPASS, + ]) { + PlacesUtils.favicons.replaceFaviconDataFromDataURL( + iconURI, + testFaviconData, + 0, + systemPrincipal + ); + await PlacesTestUtils.addVisits(pageURI); + await setFaviconForPage(pageURI, iconURI); + + // Open the channel + let channel = NetUtil.newChannel({ + uri: loadingIconURISpec, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON, + }); + let listener = new streamListener("image/png"); + channel.asyncOpen(listener); + await listener.done.promise; + await PlacesUtils.history.clear(); + } + } }); diff --git a/toolkit/components/places/tests/favicons/test_page-icon_protocol.js b/toolkit/components/places/tests/favicons/test_page-icon_protocol.js index 932040bafb..287484868f 100644 --- a/toolkit/components/places/tests/favicons/test_page-icon_protocol.js +++ b/toolkit/components/places/tests/favicons/test_page-icon_protocol.js @@ -185,11 +185,11 @@ add_task(async function page_content_process() { let img = content.document.createElement("img"); img.src = url; let imgPromise = new Promise((resolve, reject) => { - img.addEventListener("error", e => { + img.addEventListener("error", () => { Assert.ok(true, "Got expected load error."); resolve(); }); - img.addEventListener("load", e => { + img.addEventListener("load", () => { Assert.ok(false, "Did not expect a successful load."); reject(); }); @@ -225,11 +225,11 @@ add_task(async function page_privileged_about_content_process() { let img = content.document.createElement("img"); img.src = url; let imgPromise = new Promise((resolve, reject) => { - img.addEventListener("error", e => { + img.addEventListener("error", () => { Assert.ok(false, "Did not expect an error. "); reject(); }); - img.addEventListener("load", e => { + img.addEventListener("load", () => { Assert.ok(true, "Got expected load event."); resolve(); }); @@ -241,3 +241,57 @@ add_task(async function page_privileged_about_content_process() { await contentPage.close(); }); + +add_task(async function test_with_user_pass() { + info("Test whether can get favicon content regardless of user pass"); + await PlacesUtils.history.clear(); + + const PAGE_NORMAL = uri("http://mozilla.org/"); + const PAGE_USERPASS = uri("http://user:pass@mozilla.org/"); + const ICON_NORMAL = uri("http://mozilla.org/favicon.png"); + const ICON_USERPASS = uri("http://user:pass@mozilla.org/favicon.png"); + const PAGE_ICON_NORMAL = "page-icon:http://mozilla.org/"; + const PAGE_ICON_USERPASS = "page-icon:http://user:pass@mozilla.org/"; + + const testData = [ + { + pageURI: PAGE_USERPASS, + iconURI: ICON_NORMAL, + }, + { + pageURI: PAGE_NORMAL, + iconURI: ICON_USERPASS, + }, + { + pageURI: PAGE_USERPASS, + iconURI: ICON_USERPASS, + }, + ]; + + for (const { pageURI, iconURI } of testData) { + for (const loadingIconURISpec of [PAGE_ICON_NORMAL, PAGE_ICON_USERPASS]) { + PlacesUtils.favicons.replaceFaviconDataFromDataURL( + iconURI, + ICON_DATAURL, + 0, + systemPrincipal + ); + await PlacesTestUtils.addVisits(pageURI); + await new Promise(resolve => { + PlacesUtils.favicons.setAndFetchFaviconForPage( + pageURI, + iconURI, + false, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + resolve, + Services.scriptSecurityManager.getSystemPrincipal() + ); + }); + + let { data, contentType } = await fetchIconForSpec(loadingIconURISpec); + Assert.equal(contentType, gFavicon.contentType); + Assert.deepEqual(data, gFavicon.data, "Got the favicon data"); + await PlacesUtils.history.clear(); + } + } +}); diff --git a/toolkit/components/places/tests/favicons/test_setAndFetchFaviconForPage.js b/toolkit/components/places/tests/favicons/test_setAndFetchFaviconForPage.js index 1b4ea87ec0..b2d82e65b0 100644 --- a/toolkit/components/places/tests/favicons/test_setAndFetchFaviconForPage.js +++ b/toolkit/components/places/tests/favicons/test_setAndFetchFaviconForPage.js @@ -53,6 +53,17 @@ let gTests = [ Services.prefs.setBoolPref("places.history.enabled", true); }, }, + { + desc: "Visit URL with login info", + href: "http://user:pass@example.com/with_login_info", + loadType: PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + async setup() { + await PlacesTestUtils.addVisits({ + uri: this.href, + transition: TRANSITION_TYPED, + }); + }, + }, ]; add_task(async function () { @@ -67,6 +78,7 @@ add_task(async function () { for (let test of gTests) { info(test.desc); let pageURI = PlacesUtils.toURI(test.href); + let exposableURI = Services.io.createExposableURI(pageURI); await test.setup(); @@ -75,7 +87,7 @@ add_task(async function () { "favicon-changed", events => events.some(e => { - if (e.url == pageURI.spec && e.faviconUrl == faviconURI.spec) { + if (e.url == exposableURI.spec && e.faviconUrl == faviconURI.spec) { pageGuid = e.pageGuid; return true; } @@ -97,7 +109,7 @@ add_task(async function () { Assert.equal( pageGuid, await PlacesTestUtils.getDatabaseValue("moz_places", "guid", { - url: pageURI, + url: exposableURI, }), "Page guid is correct" ); diff --git a/toolkit/components/places/tests/history/test_async_history_api.js b/toolkit/components/places/tests/history/test_async_history_api.js index ce0d96b306..cc645baaec 100644 --- a/toolkit/components/places/tests/history/test_async_history_api.js +++ b/toolkit/components/places/tests/history/test_async_history_api.js @@ -32,7 +32,7 @@ function VisitInfo(aTransitionType, aVisitTime) { } function promiseUpdatePlaces(aPlaces, aOptions = {}) { - return new Promise((resolve, reject) => { + return new Promise(resolve => { asyncHistory.updatePlaces( aPlaces, Object.assign( @@ -974,7 +974,7 @@ add_task(async function test_title_change_notifies() { place.title = "title 1"; let expectedNotification = false; let titleChangeObserver; - let titleChangePromise = new Promise((resolve, reject) => { + let titleChangePromise = new Promise(resolve => { titleChangeObserver = new TitleChangedObserver( place.uri, place.title, @@ -1032,8 +1032,8 @@ add_task(async function test_visit_notifies() { }; Assert.equal(false, await PlacesUtils.history.hasVisits(place.uri)); - function promiseVisitObserver(aPlace) { - return new Promise((resolve, reject) => { + function promiseVisitObserver() { + return new Promise(resolve => { let callbackCount = 0; let finisher = function () { if (++callbackCount == 2) { @@ -1137,7 +1137,7 @@ add_task(async function test_omit_frecency_notifications() { // we won't get a ranking changed notification until recalculation happens. await PlacesUtils.history.clear(); let notified = false; - let listener = events => { + let listener = () => { notified = true; PlacesUtils.observers.removeListener(["pages-rank-changed"], listener); }; diff --git a/toolkit/components/places/tests/history/test_insertMany.js b/toolkit/components/places/tests/history/test_insertMany.js index b2cf60ed91..3d0774cbf2 100644 --- a/toolkit/components/places/tests/history/test_insertMany.js +++ b/toolkit/components/places/tests/history/test_insertMany.js @@ -189,7 +189,7 @@ add_task(async function test_transitions() { await PlacesUtils.history.insertMany(places); // Check callbacks. let count = 0; - await PlacesUtils.history.insertMany(places, pageInfo => { + await PlacesUtils.history.insertMany(places, () => { ++count; }); Assert.equal(count, Object.keys(PlacesUtils.history.TRANSITIONS).length); @@ -246,3 +246,22 @@ add_task(async function test_guid() { "Record C is fetchable after insertMany" ); }); + +add_task(async function test_withUserPass() { + await PlacesUtils.history.insertMany([ + { + url: "http://user:pass@example.com/userpass", + visits: [{ date: new Date() }], + }, + ]); + + Assert.ok( + !(await PlacesUtils.history.fetch("http://user:pass@example.com/userpass")), + "The url with user and pass is not stored" + ); + + Assert.ok( + await PlacesUtils.history.fetch("http://example.com/userpass"), + "The url without user and pass is stored" + ); +}); diff --git a/toolkit/components/places/tests/history/test_removeByFilter.js b/toolkit/components/places/tests/history/test_removeByFilter.js index fb18bf8e74..fe90977bfd 100644 --- a/toolkit/components/places/tests/history/test_removeByFilter.js +++ b/toolkit/components/places/tests/history/test_removeByFilter.js @@ -174,13 +174,13 @@ add_task(async function test_removeByFilter() { for (let callbackUse of [true, false]) { // Case A Positives for (let bookmarkUse of [true, false]) { - let bookmarkedUri = arr => undefined; + let bookmarkedUri = () => undefined; let checkableArray = arr => arr; let checkClosure = assertNotInDB; if (bookmarkUse) { bookmarkedUri = arr => arr[0]; checkableArray = arr => arr.slice(1); - checkClosure = function (aUri) {}; + checkClosure = function () {}; } // Case A 1: Dates await removeByFilterTester( diff --git a/toolkit/components/places/tests/history/test_removeVisitsByFilter.js b/toolkit/components/places/tests/history/test_removeVisitsByFilter.js index 5681ab22bc..be01fcb901 100644 --- a/toolkit/components/places/tests/history/test_removeVisitsByFilter.js +++ b/toolkit/components/places/tests/history/test_removeVisitsByFilter.js @@ -117,7 +117,7 @@ add_task(async function test_removeVisitsByFilter() { } endIndex = Math.min( endIndex, - removedItems.findIndex((v, index) => v.uri.spec != rawURL) - 1 + removedItems.findIndex(v => v.uri.spec != rawURL) - 1 ); } removedItems.splice(endIndex + 1); diff --git a/toolkit/components/places/tests/history/test_updatePlaces_embed.js b/toolkit/components/places/tests/history/test_updatePlaces_embed.js index a2831f2f58..84efd11b2d 100644 --- a/toolkit/components/places/tests/history/test_updatePlaces_embed.js +++ b/toolkit/components/places/tests/history/test_updatePlaces_embed.js @@ -28,10 +28,10 @@ add_task(async function test_embed_visit() { asyncHistory.updatePlaces(place, { ignoreErrors: true, ignoreResults: true, - handleError(aResultCode, aPlace) { + handleError() { errors++; }, - handleResult(aPlace) { + handleResult() { results++; }, handleCompletion(resultCount) { @@ -64,10 +64,10 @@ add_task(async function test_misc_visits() { asyncHistory.updatePlaces(place, { ignoreErrors: true, ignoreResults: true, - handleError(aResultCode, aPlace) { + handleError() { errors++; }, - handleResult(aPlace) { + handleResult() { results++; }, handleCompletion(resultCount) { diff --git a/toolkit/components/places/tests/migration/places_v75.sqlite b/toolkit/components/places/tests/migration/places_v77.sqlite Binary files differindex 2dd624b945..d77d8233b0 100644 --- a/toolkit/components/places/tests/migration/places_v75.sqlite +++ b/toolkit/components/places/tests/migration/places_v77.sqlite diff --git a/toolkit/components/places/tests/migration/test_current_from_v74.js b/toolkit/components/places/tests/migration/test_current_from_v74.js index 82c535f78f..eeb862daf5 100644 --- a/toolkit/components/places/tests/migration/test_current_from_v74.js +++ b/toolkit/components/places/tests/migration/test_current_from_v74.js @@ -4,7 +4,16 @@ "use strict"; add_task(async function setup() { - await setupPlacesDatabase("places_v74.sqlite"); + let path = await setupPlacesDatabase("places_v74.sqlite"); + let db = await Sqlite.openConnection({ path }); + await db.execute(` + INSERT INTO moz_origins (id, prefix, host, frecency, recalc_frecency) + VALUES + (100, 'https://', 'test1.com', 0, 0), + (101, 'https://', 'test2.com', 0, 0), + (102, 'https://', 'test3.com', 0, 0) + `); + await db.close(); }); add_task(async function database_is_valid() { @@ -20,3 +29,18 @@ add_task(async function database_is_valid() { await db.execute("SELECT * FROM moz_places_extra"); await db.execute("SELECT * from moz_historyvisits_extra"); }); + +add_task(async function recalc_origins_frecency() { + const db = await PlacesUtils.promiseDBConnection(); + Assert.equal(await db.getSchemaVersion(), CURRENT_SCHEMA_VERSION); + + Assert.equal( + ( + await db.execute( + "SELECT count(*) FROM moz_origins WHERE recalc_frecency = 0" + ) + )[0].getResultByIndex(0), + 0, + "All entries should be set for recalculation" + ); +}); diff --git a/toolkit/components/places/tests/migration/xpcshell.toml b/toolkit/components/places/tests/migration/xpcshell.toml index b127fa501f..06dbb67fce 100644 --- a/toolkit/components/places/tests/migration/xpcshell.toml +++ b/toolkit/components/places/tests/migration/xpcshell.toml @@ -14,7 +14,7 @@ support-files = [ "places_v70.sqlite", "places_v72.sqlite", "places_v74.sqlite", - "places_v75.sqlite", + "places_v77.sqlite", ] ["test_current_from_downgraded.js"] diff --git a/toolkit/components/places/tests/moz.build b/toolkit/components/places/tests/moz.build index 60c57f53b8..a93b86a134 100644 --- a/toolkit/components/places/tests/moz.build +++ b/toolkit/components/places/tests/moz.build @@ -65,6 +65,7 @@ TEST_HARNESS_FILES.testing.mochitest.tests.toolkit.components.places.tests.brows "browser/redirect_twice_perma.sjs", "browser/title1.html", "browser/title2.html", + "browser/userpass.html", ] TEST_HARNESS_FILES.testing.mochitest.tests.toolkit.components.places.tests.chrome += [ diff --git a/toolkit/components/places/tests/queries/test_async.js b/toolkit/components/places/tests/queries/test_async.js index 8e895748ab..32a5c1a691 100644 --- a/toolkit/components/places/tests/queries/test_async.js +++ b/toolkit/components/places/tests/queries/test_async.js @@ -85,7 +85,7 @@ var tests = [ node.containerOpen = false; }, - opened(node, newState, oldState) { + opened() { do_throw("opened should not be called"); }, diff --git a/toolkit/components/places/tests/queries/test_containersQueries_sorting.js b/toolkit/components/places/tests/queries/test_containersQueries_sorting.js index 9cdc0f2a52..ff4bbe67bf 100644 --- a/toolkit/components/places/tests/queries/test_containersQueries_sorting.js +++ b/toolkit/components/places/tests/queries/test_containersQueries_sorting.js @@ -113,7 +113,7 @@ function cartProd(aSequences, aCallback) { // For each sequence in aSequences, we maintain a pointer (an array index, // really) to the element we're currently enumerating in that sequence - var seqEltPtrs = aSequences.map(i => 0); + var seqEltPtrs = aSequences.map(() => 0); var numProds = 0; var done = false; @@ -407,7 +407,7 @@ function check_children_sorting(aRootNode, aExpectedSortingMode) { var comparator; switch (aExpectedSortingMode) { case Ci.nsINavHistoryQueryOptions.SORT_BY_NONE: - comparator = function (a, b) { + comparator = function () { return 0; }; break; diff --git a/toolkit/components/places/tests/queries/test_querySerialization.js b/toolkit/components/places/tests/queries/test_querySerialization.js index 4c33854718..64a4c5a6e7 100644 --- a/toolkit/components/places/tests/queries/test_querySerialization.js +++ b/toolkit/components/places/tests/queries/test_querySerialization.js @@ -86,11 +86,11 @@ const querySwitches = [ desc: "nsINavHistoryQuery.hasBeginTime", matches: flagSwitchMatches, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.beginTime = Date.now() * 1000; aQuery.beginTimeReference = Ci.nsINavHistoryQuery.TIME_RELATIVE_EPOCH; }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.beginTime = Date.now() * 1000; aQuery.beginTimeReference = Ci.nsINavHistoryQuery.TIME_RELATIVE_TODAY; }, @@ -103,11 +103,11 @@ const querySwitches = [ desc: "nsINavHistoryQuery.hasEndTime", matches: flagSwitchMatches, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.endTime = Date.now() * 1000; aQuery.endTimeReference = Ci.nsINavHistoryQuery.TIME_RELATIVE_EPOCH; }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.endTime = Date.now() * 1000; aQuery.endTimeReference = Ci.nsINavHistoryQuery.TIME_RELATIVE_TODAY; }, @@ -120,10 +120,10 @@ const querySwitches = [ desc: "nsINavHistoryQuery.hasSearchTerms", matches: flagSwitchMatches, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.searchTerms = "shrimp and white wine"; }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.searchTerms = ""; }, ], @@ -135,15 +135,15 @@ const querySwitches = [ desc: "nsINavHistoryQuery.hasDomain", matches: flagSwitchMatches, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.domain = "mozilla.com"; aQuery.domainIsHost = false; }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.domain = "www.mozilla.com"; aQuery.domainIsHost = true; }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.domain = ""; }, ], @@ -155,7 +155,7 @@ const querySwitches = [ desc: "nsINavHistoryQuery.hasUri", matches: flagSwitchMatches, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.uri = uri("http://mozilla.com"); }, ], @@ -167,7 +167,7 @@ const querySwitches = [ desc: "nsINavHistoryQuery.minVisits", matches: simplePropertyMatches, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.minVisits = 0x7fffffff; // 2^31 - 1 }, ], @@ -178,7 +178,7 @@ const querySwitches = [ desc: "nsINavHistoryQuery.maxVisits", matches: simplePropertyMatches, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.maxVisits = 0x7fffffff; // 2^31 - 1 }, ], @@ -205,13 +205,13 @@ const querySwitches = [ return true; }, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.setParents([]); }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.setParents([PlacesUtils.bookmarks.rootGuid]); }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.setParents([ PlacesUtils.bookmarks.rootGuid, PlacesUtils.bookmarks.tagsGuid, @@ -244,13 +244,13 @@ const querySwitches = [ return true; }, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.tags = []; }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.tags = [""]; }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.tags = [ "foo", "七難", @@ -263,7 +263,7 @@ const querySwitches = [ "あいうえお", ]; }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.tags = [ "foo", "七難", @@ -301,13 +301,13 @@ const querySwitches = [ return true; }, runs: [ - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.setTransitions([]); }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.setTransitions([Ci.nsINavHistoryService.TRANSITION_DOWNLOAD]); }, - function (aQuery, aQueryOptions) { + function (aQuery) { aQuery.setTransitions([ Ci.nsINavHistoryService.TRANSITION_TYPED, Ci.nsINavHistoryService.TRANSITION_BOOKMARK, @@ -455,7 +455,7 @@ function cartProd(aSequences, aCallback) { // For each sequence in aSequences, we maintain a pointer (an array index, // really) to the element we're currently enumerating in that sequence - var seqEltPtrs = aSequences.map(i => 0); + var seqEltPtrs = aSequences.map(() => 0); var numProds = 0; var done = false; diff --git a/toolkit/components/places/tests/queries/test_redirects.js b/toolkit/components/places/tests/queries/test_redirects.js index b0e7c9b421..6b122e3180 100644 --- a/toolkit/components/places/tests/queries/test_redirects.js +++ b/toolkit/components/places/tests/queries/test_redirects.js @@ -42,7 +42,7 @@ function check_results_callback(aSequence) { } // Build expectedData array. - let expectedData = visits.filter(function (aVisit, aIndex, aArray) { + let expectedData = visits.filter(function (aVisit) { // Embed visits never appear in results. if (aVisit.transType == Ci.nsINavHistoryService.TRANSITION_EMBED) { return false; @@ -154,7 +154,7 @@ function cartProd(aSequences, aCallback) { // For each sequence in aSequences, we maintain a pointer (an array index, // really) to the element we're currently enumerating in that sequence - let seqEltPtrs = aSequences.map(i => 0); + let seqEltPtrs = aSequences.map(() => 0); let numProds = 0; let done = false; diff --git a/toolkit/components/places/tests/queries/test_tags.js b/toolkit/components/places/tests/queries/test_tags.js index 17ad3478ce..23a332f20b 100644 --- a/toolkit/components/places/tests/queries/test_tags.js +++ b/toolkit/components/places/tests/queries/test_tags.js @@ -190,7 +190,7 @@ add_task(async function many_tags_no_bookmark() { "Querying on many tags associated with a URI and tags not associated " + "with that URI should not return that URI" ); - await task_doWithBookmark(["foo", "bar", "baz"], function (aURI) { + await task_doWithBookmark(["foo", "bar", "baz"], function () { var [query, opts] = makeQuery(["foo", "bogus"]); executeAndCheckQueryResults(query, opts, []); [query, opts] = makeQuery(["foo", "bar", "bogus"]); @@ -202,7 +202,7 @@ add_task(async function many_tags_no_bookmark() { add_task(async function nonexistent_tags() { info("Querying on nonexistent tag should return no results"); - await task_doWithBookmark(["foo", "bar", "baz"], function (aURI) { + await task_doWithBookmark(["foo", "bar", "baz"], function () { var [query, opts] = makeQuery(["bogus"]); executeAndCheckQueryResults(query, opts, []); [query, opts] = makeQuery(["bogus", "gnarly"]); @@ -449,7 +449,7 @@ function addBookmark(aURI) { /** * Asynchronous task that removes all pages from history and bookmarks. */ -async function task_cleanDatabase(aCallback) { +async function task_cleanDatabase() { await PlacesUtils.bookmarks.eraseEverything(); await PlacesUtils.history.clear(); } diff --git a/toolkit/components/places/tests/sync/head_sync.js b/toolkit/components/places/tests/sync/head_sync.js index 7dd69e275b..68221ce93f 100644 --- a/toolkit/components/places/tests/sync/head_sync.js +++ b/toolkit/components/places/tests/sync/head_sync.js @@ -116,7 +116,7 @@ function makeRecord(cleartext) { return new Proxy( { cleartext }, { - get(target, property, receiver) { + get(target, property) { if (property == "cleartext") { return target.cleartext; } @@ -125,7 +125,7 @@ function makeRecord(cleartext) { } return target.cleartext[property]; }, - set(target, property, value, receiver) { + set(target, property, value) { if (property == "cleartext") { target.cleartext = value; } else if (property != "cleartextToString") { @@ -135,7 +135,7 @@ function makeRecord(cleartext) { has(target, property) { return property == "cleartext" || property in target.cleartext; }, - deleteProperty(target, property) {}, + deleteProperty() {}, ownKeys(target) { return ["cleartext", ...Reflect.ownKeys(target)]; }, diff --git a/toolkit/components/places/tests/sync/test_bookmark_abort_merging.js b/toolkit/components/places/tests/sync/test_bookmark_abort_merging.js index 877feb99f4..f7a871e3cb 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_abort_merging.js +++ b/toolkit/components/places/tests/sync/test_bookmark_abort_merging.js @@ -95,8 +95,8 @@ add_task(async function test_blocker_state() { let buf = await SyncedBookmarksMirror.open({ path: "blocker_state_buf.sqlite", finalizeAt: barrier.client, - recordStepTelemetry(...args) {}, - recordValidationTelemetry(...args) {}, + recordStepTelemetry() {}, + recordValidationTelemetry() {}, }); await storeRecords(buf, [ { diff --git a/toolkit/components/places/tests/sync/test_bookmark_observer_recorder.js b/toolkit/components/places/tests/sync/test_bookmark_observer_recorder.js index 16d8ed746c..b4f3d4bd0b 100644 --- a/toolkit/components/places/tests/sync/test_bookmark_observer_recorder.js +++ b/toolkit/components/places/tests/sync/test_bookmark_observer_recorder.js @@ -185,7 +185,7 @@ add_task(async function test_update_frecencies() { let frecencies = await promiseAllURLFrecencies(); let urlsWithFrecency = mapFilterIterator( frecencies.entries(), - ([href, { frecency, recalc }]) => (recalc == 0 ? href : null) + ([href, { recalc }]) => (recalc == 0 ? href : null) ); // A is unchanged, and we should recalculate frecency for three more @@ -236,7 +236,7 @@ add_task(async function test_update_frecencies() { let frecencies = await promiseAllURLFrecencies(); let urlsWithoutFrecency = mapFilterIterator( frecencies.entries(), - ([href, { frecency, recalc }]) => (recalc == 1 ? href : null) + ([href, { recalc }]) => (recalc == 1 ? href : null) ); deepEqual( urlsWithoutFrecency, diff --git a/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js b/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js index 084415fb37..02577f159e 100644 --- a/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js +++ b/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js @@ -30,7 +30,7 @@ add_task(async function test_history_query() { "Async execution error (" + aError.result + "): " + aError.message ); }, - handleCompletion(aReason) { + handleCompletion() { cleanupTest().then(resolve); }, }); @@ -69,7 +69,7 @@ add_task(async function test_bookmarks_query() { "Async execution error (" + aError.result + "): " + aError.message ); }, - handleCompletion(aReason) { + handleCompletion() { cleanupTest().then(resolve); }, }); diff --git a/toolkit/components/places/tests/unit/test_async_transactions.js b/toolkit/components/places/tests/unit/test_async_transactions.js index b0e9b292f3..9f96a9c040 100644 --- a/toolkit/components/places/tests/unit/test_async_transactions.js +++ b/toolkit/components/places/tests/unit/test_async_transactions.js @@ -1485,7 +1485,7 @@ add_task(async function test_edit_specific_keyword() { url: "http://test.edit.keyword/", }; bm_info.guid = await PT.NewBookmark(bm_info).transact(); - function ensureKeywordChange(aCurrentKeyword = "", aPreviousKeyword = "") { + function ensureKeywordChange(aCurrentKeyword = "") { ensureItemsKeywordChanged({ guid: bm_info.guid, keyword: aCurrentKeyword, diff --git a/toolkit/components/places/tests/unit/test_bookmark_list.js b/toolkit/components/places/tests/unit/test_bookmark_list.js new file mode 100644 index 0000000000..b743a1281d --- /dev/null +++ b/toolkit/components/places/tests/unit/test_bookmark_list.js @@ -0,0 +1,115 @@ +/* Any copyright is dedicated to the Public Domain. +http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { sinon } = ChromeUtils.importESModule( + "resource://testing-common/Sinon.sys.mjs" +); +const { BookmarkList } = ChromeUtils.importESModule( + "resource://gre/modules/BookmarkList.sys.mjs" +); + +registerCleanupFunction( + async () => await PlacesUtils.bookmarks.eraseEverything() +); + +add_task(async function test_url_tracking() { + const firstBookmark = await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + url: "https://www.example.com/", + }); + const secondBookmark = await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + url: "https://www.reddit.com/", + }); + + let deferredUpdate; + const bookmarkList = new BookmarkList( + [ + "https://www.example.com/", + "https://www.reddit.com/", + "https://www.youtube.com/", + ], + () => deferredUpdate?.resolve() + ); + + async function waitForUpdateBookmarksTask(updateTask) { + deferredUpdate = Promise.withResolvers(); + await updateTask(); + return deferredUpdate.promise; + } + + info("Check bookmark status of tracked URLs."); + equal(await bookmarkList.isBookmark("https://www.example.com/"), true); + equal(await bookmarkList.isBookmark("https://www.reddit.com/"), true); + equal(await bookmarkList.isBookmark("https://www.youtube.com/"), false); + + info("Add a bookmark."); + await waitForUpdateBookmarksTask(() => + PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + url: "https://www.youtube.com/", + }) + ); + equal(await bookmarkList.isBookmark("https://www.youtube.com/"), true); + + info("Remove a bookmark."); + await waitForUpdateBookmarksTask(() => + PlacesUtils.bookmarks.remove(firstBookmark.guid) + ); + equal(await bookmarkList.isBookmark("https://www.example.com/"), false); + + info("Update a bookmark's URL."); + await waitForUpdateBookmarksTask(() => + PlacesUtils.bookmarks.update({ + guid: secondBookmark.guid, + url: "https://www.wikipedia.org/", + }) + ); + equal(await bookmarkList.isBookmark("https://www.reddit.com/"), false); + + info("Add a bookmark after removing listeners."); + bookmarkList.removeListeners(); + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + url: "https://www.example.com/", + }); + + info("Reinitialize the list and validate bookmark status."); + bookmarkList.setTrackedUrls(["https://www.example.com/"]); + bookmarkList.addListeners(); + equal(await bookmarkList.isBookmark("https://www.example.com/"), true); + + info("Cleanup."); + bookmarkList.removeListeners(); + await PlacesUtils.bookmarks.eraseEverything(); +}); + +add_task(async function test_no_unnecessary_observer_notifications() { + const spy = sinon.spy(); + const bookmarkList = new BookmarkList( + ["https://www.example.com/"], + spy, + 0, + 0 + ); + + info("Add a bookmark with an untracked URL."); + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + url: "https://www.reddit.com/", + }); + await new Promise(resolve => ChromeUtils.idleDispatch(resolve)); + ok(spy.notCalled, "Observer was not notified."); + equal(await bookmarkList.isBookmark("https://www.reddit.com"), undefined); + + info("Add a bookmark after removing listeners."); + bookmarkList.removeListeners(); + await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + url: "https://www.example.com/", + }); + await new Promise(resolve => ChromeUtils.idleDispatch(resolve)); + ok(spy.notCalled, "Observer was not notified."); +}); diff --git a/toolkit/components/places/tests/unit/test_bookmarks_html.js b/toolkit/components/places/tests/unit/test_bookmarks_html.js index 4b3f04b444..f1f8caa354 100644 --- a/toolkit/components/places/tests/unit/test_bookmarks_html.js +++ b/toolkit/components/places/tests/unit/test_bookmarks_html.js @@ -246,7 +246,7 @@ add_task(async function test_import_chromefavicon() { let data = await new Promise(resolve => { PlacesUtils.favicons.getFaviconDataForPage( PAGE_URI, - (uri, dataLen, faviconData, mimeType) => resolve(faviconData) + (uri, dataLen, faviconData) => resolve(faviconData) ); }); diff --git a/toolkit/components/places/tests/unit/test_bookmarks_html_corrupt.js b/toolkit/components/places/tests/unit/test_bookmarks_html_corrupt.js index 061c8c0c5f..f7b366b309 100644 --- a/toolkit/components/places/tests/unit/test_bookmarks_html_corrupt.js +++ b/toolkit/components/places/tests/unit/test_bookmarks_html_corrupt.js @@ -112,7 +112,7 @@ var database_check = async function () { await new Promise(resolve => { PlacesUtils.favicons.getFaviconDataForPage( uri(TEST_FAVICON_PAGE_URL), - (aURI, aDataLen, aData, aMimeType) => { + (aURI, aDataLen) => { // aURI should never be null when aDataLen > 0. Assert.notEqual(aURI, null); // Favicon data is stored in the bookmarks file as a "data:" URI. For diff --git a/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js b/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js index 892b2d1d04..75b52aafc7 100644 --- a/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js +++ b/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js @@ -115,7 +115,7 @@ async function checkObservers(expectPromises, expectedData) { /** * Run after every test cases. */ -async function teardown(file, begin, success, fail) { +async function teardown(file) { // On restore failed, file may not exist, so wrap in try-catch. await IOUtils.remove(file, { ignoreAbsent: true }); diff --git a/toolkit/components/places/tests/unit/test_frecency_decay.js b/toolkit/components/places/tests/unit/test_frecency_decay.js index 8fbb08aecc..a9762209c1 100644 --- a/toolkit/components/places/tests/unit/test_frecency_decay.js +++ b/toolkit/components/places/tests/unit/test_frecency_decay.js @@ -78,5 +78,5 @@ add_task(async function test_frecency_decay() { ); let snapshot = histogram.snapshot(); - Assert.greater(snapshot.sum, 0); + Assert.greater(Object.values(snapshot.values).length, 0); }); diff --git a/toolkit/components/places/tests/unit/test_nsINavHistoryViewer.js b/toolkit/components/places/tests/unit/test_nsINavHistoryViewer.js index e98cdbac79..2cdcba60aa 100644 --- a/toolkit/components/places/tests/unit/test_nsINavHistoryViewer.js +++ b/toolkit/components/places/tests/unit/test_nsINavHistoryViewer.js @@ -6,11 +6,11 @@ var resultObserver = { insertedNode: null, - nodeInserted(parent, node, newIndex) { + nodeInserted(parent, node) { this.insertedNode = node; }, removedNode: null, - nodeRemoved(parent, node, oldIndex) { + nodeRemoved(parent, node) { this.removedNode = node; }, @@ -24,14 +24,14 @@ var resultObserver = { newAccessCount: 0, newTime: 0, nodeChangedByHistoryDetails: null, - nodeHistoryDetailsChanged(node, oldVisitDate, oldVisitCount) { + nodeHistoryDetailsChanged(node) { this.nodeChangedByHistoryDetails = node; this.newTime = node.time; this.newAccessCount = node.accessCount; }, movedNode: null, - nodeMoved(node, oldParent, oldIndex, newParent, newIndex) { + nodeMoved(node) { this.movedNode = node; }, openedContainer: null, diff --git a/toolkit/components/places/tests/unit/test_origins.js b/toolkit/components/places/tests/unit/test_origins.js index 67b6d59c7d..f74313a125 100644 --- a/toolkit/components/places/tests/unit/test_origins.js +++ b/toolkit/components/places/tests/unit/test_origins.js @@ -1005,6 +1005,33 @@ add_task(async function moreOriginFrecencyStats() { await cleanUp(); }); +add_task(async function test_cutoff() { + // Add first page with visit. + await PlacesTestUtils.addVisits([{ uri: "http://example.com/0" }]); + // Add a second page last visited before the cutoff, it should be ignored. + let visitDate = PlacesUtils.toPRTime( + new Date( + new Date().setDate( + -Services.prefs.getIntPref("places.frecency.originsCutOffDays", 90) + ) + ) + ); + await PlacesTestUtils.addVisits([{ uri: "http://example.com/1", visitDate }]); + // Add a third page with visit both before and after the cutoff, should count. + await PlacesTestUtils.addVisits([ + { uri: "http://example.com/2" }, + { uri: "http://example.com/2", visitDate }, + ]); + await checkDB([ + [ + "http://", + "example.com", + ["http://example.com/0", "http://example.com/2"], + ], + ]); + await cleanUp(); +}); + /** * Returns the expected frecency of the origin of the given URLs, i.e., the sum * of their frecencies. Each URL is expected to have the same origin. @@ -1017,12 +1044,15 @@ async function expectedOriginFrecency(urls) { let value = 0; for (let url of urls) { let v = Math.max( - await PlacesTestUtils.getDatabaseValue("moz_places", "frecency", { url }), + (await PlacesTestUtils.getDatabaseValue("moz_places", "frecency", { + url, + last_visit_date: [">", 0], + })) ?? 0, 0 ); value += v; } - return value; + return value || 1.0; } /** @@ -1064,49 +1094,34 @@ async function checkDB(expectedOrigins) { } Assert.deepEqual(actualOrigins, expected); if (checkFrecencies) { - await checkStats(expected.map(o => o[2]).filter(o => o > 0)); + info("Checking threshold"); + await PlacesTestUtils.dumpTable({ db, table: "moz_origins" }); + await checkThreshold(expected.map(o => o[2])); } } /** - * Asserts that the origin frecency stats are correct. + * Asserts that the origin frecency threshold is correct. * * @param expectedOriginFrecencies * An array of expected origin frecencies. */ -async function checkStats(expectedOriginFrecencies) { - let stats = await promiseStats(); - Assert.equal(stats.count, expectedOriginFrecencies.length); - Assert.equal( - stats.sum, - expectedOriginFrecencies.reduce((sum, f) => sum + f, 0) +async function checkThreshold(expectedOriginFrecencies) { + const DEFAULT_THRESHOLD = 2.0; + let threshold = await PlacesUtils.metadata.get( + "origin_frecency_threshold", + DEFAULT_THRESHOLD ); + Assert.equal( - stats.squares, - expectedOriginFrecencies.reduce((squares, f) => squares + f * f, 0) + threshold, + expectedOriginFrecencies.length + ? expectedOriginFrecencies.reduce((a, b) => a + b, 0) / + expectedOriginFrecencies.length + : DEFAULT_THRESHOLD ); } -/** - * Returns the origin frecency stats. - * - * @return An object: { count, sum, squares } - */ -async function promiseStats() { - let db = await PlacesUtils.promiseDBConnection(); - let rows = await db.execute(` - SELECT - IFNULL((SELECT value FROM moz_meta WHERE key = 'origin_frecency_count'), 0), - IFNULL((SELECT value FROM moz_meta WHERE key = 'origin_frecency_sum'), 0), - IFNULL((SELECT value FROM moz_meta WHERE key = 'origin_frecency_sum_of_squares'), 0) - `); - return { - count: rows[0].getResultByIndex(0), - sum: rows[0].getResultByIndex(1), - squares: rows[0].getResultByIndex(2), - }; -} - async function cleanUp() { await PlacesUtils.bookmarks.eraseEverything(); await PlacesUtils.history.clear(); diff --git a/toolkit/components/places/tests/unit/test_origins_parsing.js b/toolkit/components/places/tests/unit/test_origins_parsing.js index 35ba8bdd0d..bdeabce271 100644 --- a/toolkit/components/places/tests/unit/test_origins_parsing.js +++ b/toolkit/components/places/tests/unit/test_origins_parsing.js @@ -65,7 +65,16 @@ add_task(async function parsing() { // in the database are correct. for (let i = 0; i < uris.length; i++) { await PlacesUtils.history.remove(uris[i]); - await checkDB(expectedOrigins.slice(i + 1, expectedOrigins.length)); + + let uri = Services.io.newURI(uris[i]); + if (uri.hasUserPass) { + // The history cannot be deleted at a URL with a user path. + } else { + expectedOrigins = expectedOrigins.filter( + ([prefix, hostPort]) => !prefix.startsWith(uri.scheme + ":") + ); + } + await checkDB(expectedOrigins); } await cleanUp(); } diff --git a/toolkit/components/places/tests/unit/test_tag_autocomplete_search.js b/toolkit/components/places/tests/unit/test_tag_autocomplete_search.js index 43f899c237..06182b6dd3 100644 --- a/toolkit/components/places/tests/unit/test_tag_autocomplete_search.js +++ b/toolkit/components/places/tests/unit/test_tag_autocomplete_search.js @@ -33,7 +33,7 @@ AutoCompleteInput.prototype = { popupOpen: false, popup: { - setSelectedIndex(aIndex) {}, + setSelectedIndex() {}, invalidate() {}, // nsISupports implementation diff --git a/toolkit/components/places/tests/unit/xpcshell.toml b/toolkit/components/places/tests/unit/xpcshell.toml index 750e8ad9ea..8a56fcc370 100644 --- a/toolkit/components/places/tests/unit/xpcshell.toml +++ b/toolkit/components/places/tests/unit/xpcshell.toml @@ -78,6 +78,8 @@ skip-if = ["os == 'linux'"] # Bug 821781 ["test_bookmark-tags-changed_frequency.js"] +["test_bookmark_list.js"] + ["test_bookmarks_html.js"] ["test_bookmarks_html_corrupt.js"] |