diff options
Diffstat (limited to 'toolkit/components/places/tests/sync/test_bookmark_chunking.js')
-rw-r--r-- | toolkit/components/places/tests/sync/test_bookmark_chunking.js | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/sync/test_bookmark_chunking.js b/toolkit/components/places/tests/sync/test_bookmark_chunking.js new file mode 100644 index 0000000000..3652502a3d --- /dev/null +++ b/toolkit/components/places/tests/sync/test_bookmark_chunking.js @@ -0,0 +1,165 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// These tests ensure we correctly chunk statements that exceed SQLite's +// binding parameter limit. + +// Inserts 1500 unfiled bookmarks. Using `PlacesUtils.bookmarks.insertTree` +// is an order of magnitude slower, so we write bookmarks directly into the +// database. +async function insertManyUnfiledBookmarks(db, url) { + await db.executeCached( + ` + INSERT OR IGNORE INTO moz_places(id, url, url_hash, rev_host, hidden, + frecency, guid) + VALUES((SELECT id FROM moz_places + WHERE url_hash = hash(:url) AND + url = :url), :url, hash(:url), :revHost, 0, -1, + generate_guid())`, + { url: url.href, revHost: PlacesUtils.getReversedHost(url) } + ); + + let guids = []; + + for (let position = 0; position < 1500; ++position) { + let title = position.toString(10); + let guid = title.padStart(12, "A"); + await db.executeCached( + ` + INSERT INTO moz_bookmarks(guid, parent, fk, position, type, title, + syncStatus, syncChangeCounter) + VALUES(:guid, (SELECT id FROM moz_bookmarks WHERE guid = :parentGuid), + (SELECT id FROM moz_places WHERE url_hash = hash(:url) AND + url = :url), + :position, :type, :title, :syncStatus, 1)`, + { + guid, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + position, + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + title, + syncStatus: PlacesUtils.bookmarks.SYNC_STATUS.NEW, + } + ); + guids.push(guid); + } + + return guids; +} + +add_task(async function test_merged_item_chunking() { + let buf = await openMirror("merged_item_chunking"); + + info("Set up local tree with 1500 bookmarks"); + let localGuids = await buf.db.executeTransaction(function () { + let url = new URL("http://example.com/a"); + return insertManyUnfiledBookmarks(buf.db, url); + }); + await PlacesTestUtils.markBookmarksAsSynced(); + + info("Set up remote tree with 1500 bookmarks"); + let toolbarRecord = makeRecord({ + id: "toolbar", + parentid: "places", + type: "folder", + children: [], + }); + let records = [toolbarRecord]; + for (let i = 0; i < 1500; ++i) { + let title = i.toString(10); + let guid = title.padStart(12, "B"); + toolbarRecord.children.push(guid); + records.push( + makeRecord({ + id: guid, + parentid: "toolbar", + type: "bookmark", + title, + bmkUri: "http://example.com/b", + }) + ); + } + await buf.store(shuffle(records)); + + info("Apply remote"); + let changesToUpload = await buf.apply(); + deepEqual( + await buf.fetchUnmergedGuids(), + [PlacesUtils.bookmarks.unfiledGuid], + "Should leave unfiled with new remote structure unmerged" + ); + + let localChildRecordIds = await PlacesSyncUtils.bookmarks.fetchChildRecordIds( + "toolbar" + ); + deepEqual( + localChildRecordIds, + toolbarRecord.children, + "Should apply all remote toolbar children" + ); + + let guidsToUpload = Object.keys(changesToUpload); + deepEqual( + guidsToUpload.sort(), + ["unfiled", ...localGuids].sort(), + "Should upload unfiled and all new local children" + ); + + await storeChangesInMirror(buf, changesToUpload); + deepEqual(await buf.fetchUnmergedGuids(), [], "Should merge all items"); + + await buf.finalize(); + await PlacesUtils.bookmarks.eraseEverything(); + await PlacesSyncUtils.bookmarks.reset(); +}); + +add_task(async function test_deletion_chunking() { + let buf = await openMirror("deletion_chunking"); + + info("Set up local tree with 1500 bookmarks"); + let guids = await buf.db.executeTransaction(function () { + let url = new URL("http://example.com/a"); + return insertManyUnfiledBookmarks(buf.db, url); + }); + await PlacesTestUtils.markBookmarksAsSynced(); + + info("Delete them all on the server"); + let records = [ + makeRecord({ + id: "unfiled", + parentid: "places", + type: "folder", + children: [], + }), + ]; + for (let guid of guids) { + records.push( + makeRecord({ + id: guid, + deleted: true, + }) + ); + } + await buf.store(shuffle(records)); + + info("Apply remote"); + let changesToUpload = await buf.apply(); + deepEqual(await buf.fetchUnmergedGuids(), [], "Should merge all items"); + deepEqual(changesToUpload, {}, "Should take all remote deletions"); + + let tombstones = await PlacesTestUtils.fetchSyncTombstones(); + deepEqual(tombstones, [], "Shouldn't store tombstones for remote deletions"); + + let localChildRecordIds = await PlacesSyncUtils.bookmarks.fetchChildRecordIds( + "unfiled" + ); + deepEqual( + localChildRecordIds, + [], + "Should delete all unfiled children locally" + ); + + await buf.finalize(); + await PlacesUtils.bookmarks.eraseEverything(); + await PlacesSyncUtils.bookmarks.reset(); +}); |