diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /services/sync/tests/unit/test_history_store.js | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'services/sync/tests/unit/test_history_store.js')
-rw-r--r-- | services/sync/tests/unit/test_history_store.js | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_history_store.js b/services/sync/tests/unit/test_history_store.js new file mode 100644 index 000000000..207b621e0 --- /dev/null +++ b/services/sync/tests/unit/test_history_store.js @@ -0,0 +1,297 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +Cu.import("resource://gre/modules/PlacesUtils.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://services-common/async.js"); +Cu.import("resource://services-sync/engines/history.js"); +Cu.import("resource://services-sync/service.js"); +Cu.import("resource://services-sync/util.js"); + +const TIMESTAMP1 = (Date.now() - 103406528) * 1000; +const TIMESTAMP2 = (Date.now() - 6592903) * 1000; +const TIMESTAMP3 = (Date.now() - 123894) * 1000; + +function queryPlaces(uri, options) { + let query = PlacesUtils.history.getNewQuery(); + query.uri = uri; + let res = PlacesUtils.history.executeQuery(query, options); + res.root.containerOpen = true; + + let results = []; + for (let i = 0; i < res.root.childCount; i++) + results.push(res.root.getChild(i)); + res.root.containerOpen = false; + return results; +} + +function queryHistoryVisits(uri) { + let options = PlacesUtils.history.getNewQueryOptions(); + options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY; + options.resultType = Ci.nsINavHistoryQueryOptions.RESULTS_AS_VISIT; + options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_ASCENDING; + return queryPlaces(uri, options); +} + +function onNextTitleChanged(callback) { + PlacesUtils.history.addObserver({ + onBeginUpdateBatch: function onBeginUpdateBatch() {}, + onEndUpdateBatch: function onEndUpdateBatch() {}, + onPageChanged: function onPageChanged() {}, + onTitleChanged: function onTitleChanged() { + PlacesUtils.history.removeObserver(this); + Utils.nextTick(callback); + }, + onVisit: function onVisit() {}, + onDeleteVisits: function onDeleteVisits() {}, + onPageExpired: function onPageExpired() {}, + onDeleteURI: function onDeleteURI() {}, + onClearHistory: function onClearHistory() {}, + QueryInterface: XPCOMUtils.generateQI([ + Ci.nsINavHistoryObserver, + Ci.nsINavHistoryObserver_MOZILLA_1_9_1_ADDITIONS, + Ci.nsISupportsWeakReference + ]) + }, true); +} + +// Ensure exceptions from inside callbacks leads to test failures while +// we still clean up properly. +function ensureThrows(func) { + return function() { + try { + func.apply(this, arguments); + } catch (ex) { + PlacesTestUtils.clearHistory(); + do_throw(ex); + } + }; +} + +var store = new HistoryEngine(Service)._store; +function applyEnsureNoFailures(records) { + do_check_eq(store.applyIncomingBatch(records).length, 0); +} + +var fxuri, fxguid, tburi, tbguid; + +function run_test() { + initTestLogging("Trace"); + run_next_test(); +} + +add_test(function test_store() { + _("Verify that we've got an empty store to work with."); + do_check_empty(store.getAllIDs()); + + _("Let's create an entry in the database."); + fxuri = Utils.makeURI("http://getfirefox.com/"); + + let place = { + uri: fxuri, + title: "Get Firefox!", + visits: [{ + visitDate: TIMESTAMP1, + transitionType: Ci.nsINavHistoryService.TRANSITION_LINK + }] + }; + PlacesUtils.asyncHistory.updatePlaces(place, { + handleError: function handleError() { + do_throw("Unexpected error in adding visit."); + }, + handleResult: function handleResult() {}, + handleCompletion: onVisitAdded + }); + + function onVisitAdded() { + _("Verify that the entry exists."); + let ids = Object.keys(store.getAllIDs()); + do_check_eq(ids.length, 1); + fxguid = ids[0]; + do_check_true(store.itemExists(fxguid)); + + _("If we query a non-existent record, it's marked as deleted."); + let record = store.createRecord("non-existent"); + do_check_true(record.deleted); + + _("Verify createRecord() returns a complete record."); + record = store.createRecord(fxguid); + do_check_eq(record.histUri, fxuri.spec); + do_check_eq(record.title, "Get Firefox!"); + do_check_eq(record.visits.length, 1); + do_check_eq(record.visits[0].date, TIMESTAMP1); + do_check_eq(record.visits[0].type, Ci.nsINavHistoryService.TRANSITION_LINK); + + _("Let's modify the record and have the store update the database."); + let secondvisit = {date: TIMESTAMP2, + type: Ci.nsINavHistoryService.TRANSITION_TYPED}; + onNextTitleChanged(ensureThrows(function() { + let queryres = queryHistoryVisits(fxuri); + do_check_eq(queryres.length, 2); + do_check_eq(queryres[0].time, TIMESTAMP1); + do_check_eq(queryres[0].title, "Hol Dir Firefox!"); + do_check_eq(queryres[1].time, TIMESTAMP2); + do_check_eq(queryres[1].title, "Hol Dir Firefox!"); + run_next_test(); + })); + applyEnsureNoFailures([ + {id: fxguid, + histUri: record.histUri, + title: "Hol Dir Firefox!", + visits: [record.visits[0], secondvisit]} + ]); + } +}); + +add_test(function test_store_create() { + _("Create a brand new record through the store."); + tbguid = Utils.makeGUID(); + tburi = Utils.makeURI("http://getthunderbird.com"); + onNextTitleChanged(ensureThrows(function() { + do_check_attribute_count(store.getAllIDs(), 2); + let queryres = queryHistoryVisits(tburi); + do_check_eq(queryres.length, 1); + do_check_eq(queryres[0].time, TIMESTAMP3); + do_check_eq(queryres[0].title, "The bird is the word!"); + run_next_test(); + })); + applyEnsureNoFailures([ + {id: tbguid, + histUri: tburi.spec, + title: "The bird is the word!", + visits: [{date: TIMESTAMP3, + type: Ci.nsINavHistoryService.TRANSITION_TYPED}]} + ]); +}); + +add_test(function test_null_title() { + _("Make sure we handle a null title gracefully (it can happen in some cases, e.g. for resource:// URLs)"); + let resguid = Utils.makeGUID(); + let resuri = Utils.makeURI("unknown://title"); + applyEnsureNoFailures([ + {id: resguid, + histUri: resuri.spec, + title: null, + visits: [{date: TIMESTAMP3, + type: Ci.nsINavHistoryService.TRANSITION_TYPED}]} + ]); + do_check_attribute_count(store.getAllIDs(), 3); + let queryres = queryHistoryVisits(resuri); + do_check_eq(queryres.length, 1); + do_check_eq(queryres[0].time, TIMESTAMP3); + run_next_test(); +}); + +add_test(function test_invalid_records() { + _("Make sure we handle invalid URLs in places databases gracefully."); + let connection = PlacesUtils.history + .QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + let stmt = connection.createAsyncStatement( + "INSERT INTO moz_places " + + "(url, url_hash, title, rev_host, visit_count, last_visit_date) " + + "VALUES ('invalid-uri', hash('invalid-uri'), 'Invalid URI', '.', 1, " + TIMESTAMP3 + ")" + ); + Async.querySpinningly(stmt); + stmt.finalize(); + // Add the corresponding visit to retain database coherence. + stmt = connection.createAsyncStatement( + "INSERT INTO moz_historyvisits " + + "(place_id, visit_date, visit_type, session) " + + "VALUES ((SELECT id FROM moz_places WHERE url_hash = hash('invalid-uri') AND url = 'invalid-uri'), " + + TIMESTAMP3 + ", " + Ci.nsINavHistoryService.TRANSITION_TYPED + ", 1)" + ); + Async.querySpinningly(stmt); + stmt.finalize(); + do_check_attribute_count(store.getAllIDs(), 4); + + _("Make sure we report records with invalid URIs."); + let invalid_uri_guid = Utils.makeGUID(); + let failed = store.applyIncomingBatch([{ + id: invalid_uri_guid, + histUri: ":::::::::::::::", + title: "Doesn't have a valid URI", + visits: [{date: TIMESTAMP3, + type: Ci.nsINavHistoryService.TRANSITION_EMBED}]} + ]); + do_check_eq(failed.length, 1); + do_check_eq(failed[0], invalid_uri_guid); + + _("Make sure we handle records with invalid GUIDs gracefully (ignore)."); + applyEnsureNoFailures([ + {id: "invalid", + histUri: "http://invalid.guid/", + title: "Doesn't have a valid GUID", + visits: [{date: TIMESTAMP3, + type: Ci.nsINavHistoryService.TRANSITION_EMBED}]} + ]); + + _("Make sure we handle records with invalid visit codes or visit dates, gracefully ignoring those visits."); + let no_date_visit_guid = Utils.makeGUID(); + let no_type_visit_guid = Utils.makeGUID(); + let invalid_type_visit_guid = Utils.makeGUID(); + let non_integer_visit_guid = Utils.makeGUID(); + failed = store.applyIncomingBatch([ + {id: no_date_visit_guid, + histUri: "http://no.date.visit/", + title: "Visit has no date", + visits: [{type: Ci.nsINavHistoryService.TRANSITION_EMBED}]}, + {id: no_type_visit_guid, + histUri: "http://no.type.visit/", + title: "Visit has no type", + visits: [{date: TIMESTAMP3}]}, + {id: invalid_type_visit_guid, + histUri: "http://invalid.type.visit/", + title: "Visit has invalid type", + visits: [{date: TIMESTAMP3, + type: Ci.nsINavHistoryService.TRANSITION_LINK - 1}]}, + {id: non_integer_visit_guid, + histUri: "http://non.integer.visit/", + title: "Visit has non-integer date", + visits: [{date: 1234.567, + type: Ci.nsINavHistoryService.TRANSITION_EMBED}]} + ]); + do_check_eq(failed.length, 0); + + _("Make sure we handle records with javascript: URLs gracefully."); + applyEnsureNoFailures([ + {id: Utils.makeGUID(), + histUri: "javascript:''", + title: "javascript:''", + visits: [{date: TIMESTAMP3, + type: Ci.nsINavHistoryService.TRANSITION_EMBED}]} + ]); + + _("Make sure we handle records without any visits gracefully."); + applyEnsureNoFailures([ + {id: Utils.makeGUID(), + histUri: "http://getfirebug.com", + title: "Get Firebug!", + visits: []} + ]); + + run_next_test(); +}); + +add_test(function test_remove() { + _("Remove an existent record and a non-existent from the store."); + applyEnsureNoFailures([{id: fxguid, deleted: true}, + {id: Utils.makeGUID(), deleted: true}]); + do_check_false(store.itemExists(fxguid)); + let queryres = queryHistoryVisits(fxuri); + do_check_eq(queryres.length, 0); + + _("Make sure wipe works."); + store.wipe(); + do_check_empty(store.getAllIDs()); + queryres = queryHistoryVisits(fxuri); + do_check_eq(queryres.length, 0); + queryres = queryHistoryVisits(tburi); + do_check_eq(queryres.length, 0); + run_next_test(); +}); + +add_test(function cleanup() { + _("Clean up."); + PlacesTestUtils.clearHistory().then(run_next_test); +}); |