summaryrefslogtreecommitdiffstats
path: root/services/sync/tests/unit/test_bookmark_validator.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/sync/tests/unit/test_bookmark_validator.js')
-rw-r--r--services/sync/tests/unit/test_bookmark_validator.js347
1 files changed, 347 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_bookmark_validator.js b/services/sync/tests/unit/test_bookmark_validator.js
new file mode 100644
index 000000000..cc0b3b08f
--- /dev/null
+++ b/services/sync/tests/unit/test_bookmark_validator.js
@@ -0,0 +1,347 @@
+/* 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();
+}