/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ Components.utils.import("resource://services-sync/bookmark_validator.js"); Components.utils.import("resource://services-sync/util.js"); function inspectServerRecords(data) { return new BookmarkValidator().inspectServerRecords(data); } add_test(function test_isr_rootOnServer() { let c = inspectServerRecords([{ id: 'places', type: 'folder', children: [], }]); ok(c.problemData.rootOnServer); run_next_test(); }); add_test(function test_isr_empty() { let c = inspectServerRecords([]); ok(!c.problemData.rootOnServer); notEqual(c.root, null); run_next_test(); }); add_test(function test_isr_cycles() { let c = inspectServerRecords([ {id: 'C', type: 'folder', children: ['A', 'B'], parentid: 'places'}, {id: 'A', type: 'folder', children: ['B'], parentid: 'B'}, {id: 'B', type: 'folder', children: ['A'], parentid: 'A'}, ]).problemData; equal(c.cycles.length, 1); ok(c.cycles[0].indexOf('A') >= 0); ok(c.cycles[0].indexOf('B') >= 0); run_next_test(); }); add_test(function test_isr_orphansMultiParents() { let c = inspectServerRecords([ { id: 'A', type: 'bookmark', parentid: 'D' }, { id: 'B', type: 'folder', parentid: 'places', children: ['A']}, { id: 'C', type: 'folder', parentid: 'places', children: ['A']}, ]).problemData; deepEqual(c.orphans, [{ id: "A", parent: "D" }]); equal(c.multipleParents.length, 1) ok(c.multipleParents[0].parents.indexOf('B') >= 0); ok(c.multipleParents[0].parents.indexOf('C') >= 0); run_next_test(); }); add_test(function test_isr_orphansMultiParents2() { let c = inspectServerRecords([ { id: 'A', type: 'bookmark', parentid: 'D' }, { id: 'B', type: 'folder', parentid: 'places', children: ['A']}, ]).problemData; equal(c.orphans.length, 1); equal(c.orphans[0].id, 'A'); equal(c.multipleParents.length, 0); run_next_test(); }); add_test(function test_isr_deletedParents() { let c = inspectServerRecords([ { id: 'A', type: 'bookmark', parentid: 'B' }, { id: 'B', type: 'folder', parentid: 'places', children: ['A']}, { id: 'B', type: 'item', deleted: true}, ]).problemData; deepEqual(c.deletedParents, ['A']) run_next_test(); }); add_test(function test_isr_badChildren() { let c = inspectServerRecords([ { id: 'A', type: 'bookmark', parentid: 'places', children: ['B', 'C'] }, { id: 'C', type: 'bookmark', parentid: 'A' } ]).problemData; deepEqual(c.childrenOnNonFolder, ['A']) deepEqual(c.missingChildren, [{parent: 'A', child: 'B'}]); deepEqual(c.parentNotFolder, ['C']); run_next_test(); }); add_test(function test_isr_parentChildMismatches() { let c = inspectServerRecords([ { id: 'A', type: 'folder', parentid: 'places', children: [] }, { id: 'B', type: 'bookmark', parentid: 'A' } ]).problemData; deepEqual(c.parentChildMismatches, [{parent: 'A', child: 'B'}]); run_next_test(); }); add_test(function test_isr_duplicatesAndMissingIDs() { let c = inspectServerRecords([ {id: 'A', type: 'folder', parentid: 'places', children: []}, {id: 'A', type: 'folder', parentid: 'places', children: []}, {type: 'folder', parentid: 'places', children: []} ]).problemData; equal(c.missingIDs, 1); deepEqual(c.duplicates, ['A']); run_next_test(); }); add_test(function test_isr_duplicateChildren() { let c = inspectServerRecords([ {id: 'A', type: 'folder', parentid: 'places', children: ['B', 'B']}, {id: 'B', type: 'bookmark', parentid: 'A'}, ]).problemData; deepEqual(c.duplicateChildren, ['A']); run_next_test(); }); // Each compareServerWithClient test mutates these, so we can't just keep them // global function getDummyServerAndClient() { let server = [ { id: 'menu', parentid: 'places', type: 'folder', parentName: '', title: 'foo', children: ['bbbbbbbbbbbb', 'cccccccccccc'] }, { id: 'bbbbbbbbbbbb', type: 'bookmark', parentid: 'menu', parentName: 'foo', title: 'bar', bmkUri: 'http://baz.com' }, { id: 'cccccccccccc', parentid: 'menu', parentName: 'foo', title: '', type: 'query', bmkUri: 'place:type=6&sort=14&maxResults=10' } ]; let client = { "guid": "root________", "title": "", "id": 1, "type": "text/x-moz-place-container", "children": [ { "guid": "menu________", "title": "foo", "id": 1000, "type": "text/x-moz-place-container", "children": [ { "guid": "bbbbbbbbbbbb", "title": "bar", "id": 1001, "type": "text/x-moz-place", "uri": "http://baz.com" }, { "guid": "cccccccccccc", "title": "", "id": 1002, "annos": [{ "name": "Places/SmartBookmark", "flags": 0, "expires": 4, "value": "RecentTags" }], "type": "text/x-moz-place", "uri": "place:type=6&sort=14&maxResults=10" } ] } ] }; return {server, client}; } add_test(function test_cswc_valid() { let {server, client} = getDummyServerAndClient(); let c = new BookmarkValidator().compareServerWithClient(server, client).problemData; equal(c.clientMissing.length, 0); equal(c.serverMissing.length, 0); equal(c.differences.length, 0); run_next_test(); }); add_test(function test_cswc_serverMissing() { let {server, client} = getDummyServerAndClient(); // remove c server.pop(); server[0].children.pop(); let c = new BookmarkValidator().compareServerWithClient(server, client).problemData; deepEqual(c.serverMissing, ['cccccccccccc']); equal(c.clientMissing.length, 0); deepEqual(c.structuralDifferences, [{id: 'menu', differences: ['childGUIDs']}]); run_next_test(); }); add_test(function test_cswc_clientMissing() { let {server, client} = getDummyServerAndClient(); client.children[0].children.pop(); let c = new BookmarkValidator().compareServerWithClient(server, client).problemData; deepEqual(c.clientMissing, ['cccccccccccc']); equal(c.serverMissing.length, 0); deepEqual(c.structuralDifferences, [{id: 'menu', differences: ['childGUIDs']}]); run_next_test(); }); add_test(function test_cswc_differences() { { let {server, client} = getDummyServerAndClient(); client.children[0].children[0].title = 'asdf'; let c = new BookmarkValidator().compareServerWithClient(server, client).problemData; equal(c.clientMissing.length, 0); equal(c.serverMissing.length, 0); deepEqual(c.differences, [{id: 'bbbbbbbbbbbb', differences: ['title']}]); } { let {server, client} = getDummyServerAndClient(); server[2].type = 'bookmark'; let c = new BookmarkValidator().compareServerWithClient(server, client).problemData; equal(c.clientMissing.length, 0); equal(c.serverMissing.length, 0); deepEqual(c.differences, [{id: 'cccccccccccc', differences: ['type']}]); } run_next_test(); }); add_test(function test_cswc_serverUnexpected() { let {server, client} = getDummyServerAndClient(); client.children.push({ "guid": "dddddddddddd", "title": "", "id": 2000, "annos": [{ "name": "places/excludeFromBackup", "flags": 0, "expires": 4, "value": 1 }, { "name": "PlacesOrganizer/OrganizerFolder", "flags": 0, "expires": 4, "value": 7 }], "type": "text/x-moz-place-container", "children": [{ "guid": "eeeeeeeeeeee", "title": "History", "annos": [{ "name": "places/excludeFromBackup", "flags": 0, "expires": 4, "value": 1 }, { "name": "PlacesOrganizer/OrganizerQuery", "flags": 0, "expires": 4, "value": "History" }], "type": "text/x-moz-place", "uri": "place:type=3&sort=4" }] }); server.push({ id: 'dddddddddddd', parentid: 'places', parentName: '', title: '', type: 'folder', children: ['eeeeeeeeeeee'] }, { id: 'eeeeeeeeeeee', parentid: 'dddddddddddd', parentName: '', title: 'History', type: 'query', bmkUri: 'place:type=3&sort=4' }); let c = new BookmarkValidator().compareServerWithClient(server, client).problemData; equal(c.clientMissing.length, 0); equal(c.serverMissing.length, 0); equal(c.serverUnexpected.length, 2); deepEqual(c.serverUnexpected, ["dddddddddddd", "eeeeeeeeeeee"]); run_next_test(); }); function validationPing(server, client, duration) { return wait_for_ping(function() { // fake this entirely Svc.Obs.notify("weave:service:sync:start"); Svc.Obs.notify("weave:engine:sync:start", null, "bookmarks"); Svc.Obs.notify("weave:engine:sync:finish", null, "bookmarks"); let validator = new BookmarkValidator(); let data = { // We fake duration and version just so that we can verify they're passed through. duration, version: validator.version, recordCount: server.length, problems: validator.compareServerWithClient(server, client).problemData, }; Svc.Obs.notify("weave:engine:validate:finish", data, "bookmarks"); Svc.Obs.notify("weave:service:sync:finish"); }, true); // Allow "failing" pings, since having validation info indicates failure. } add_task(function *test_telemetry_integration() { let {server, client} = getDummyServerAndClient(); // remove "c" server.pop(); server[0].children.pop(); const duration = 50; let ping = yield validationPing(server, client, duration); ok(ping.engines); let bme = ping.engines.find(e => e.name === "bookmarks"); ok(bme); ok(bme.validation); ok(bme.validation.problems) equal(bme.validation.checked, server.length); equal(bme.validation.took, duration); bme.validation.problems.sort((a, b) => String.localeCompare(a.name, b.name)); equal(bme.validation.version, new BookmarkValidator().version); deepEqual(bme.validation.problems, [ { name: "badClientRoots", count: 3 }, { name: "sdiff:childGUIDs", count: 1 }, { name: "serverMissing", count: 1 }, { name: "structuralDifferences", count: 1 }, ]); }); function run_test() { run_next_test(); }