From 636252beee261815bb57e1f35d0efe9d7379732d Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Mon, 27 Oct 2008 18:52:21 -0400 Subject: [PATCH] Bug 459491 - nsPlacesDBFlush could use async queries instead of background thread r=sdwilsh --HG-- rename : toolkit/components/places/tests/background/head_background.js => toolkit/components/places/tests/sync/head_sync.js rename : toolkit/components/places/tests/background/test_database_sync_after_addBookmark.js => toolkit/components/places/tests/sync/test_database_sync_after_addBookmark.js rename : toolkit/components/places/tests/background/test_database_sync_after_addBookmark_batched.js => toolkit/components/places/tests/sync/test_database_sync_after_addBookmark_batched.js rename : toolkit/components/places/tests/background/test_database_sync_after_addVisit.js => toolkit/components/places/tests/sync/test_database_sync_after_addVisit.js rename : toolkit/components/places/tests/background/test_database_sync_after_addVisit_batched.js => toolkit/components/places/tests/sync/test_database_sync_after_addVisit_batched.js rename : toolkit/components/places/tests/background/test_database_sync_after_modifyBookmark.js => toolkit/components/places/tests/sync/test_database_sync_after_modifyBookmark.js rename : toolkit/components/places/tests/background/test_database_sync_after_quit_application.js => toolkit/components/places/tests/sync/test_database_sync_after_quit_application.js rename : toolkit/components/places/tests/background/test_multiple_bookmarks_around_sync.js => toolkit/components/places/tests/sync/test_multiple_bookmarks_around_sync.js rename : toolkit/components/places/tests/background/test_multiple_visits_around_sync.js => toolkit/components/places/tests/sync/test_multiple_visits_around_sync.js --- .../components/places/src/nsPlacesDBFlush.js | 151 +++++----- toolkit/components/places/tests/Makefile.in | 1 + .../tests/background/head_background.js | 173 ------------ .../test_database_sync_after_addBookmark.js | 55 ---- ...test_database_sync_after_modifyBookmark.js | 64 ----- .../test_multiple_bookmarks_around_sync.js | 103 ------- .../components/places/tests/sync/head_sync.js | 258 ++++++++++++++++++ .../test_database_sync_after_addBookmark.js} | 56 ++-- ...database_sync_after_addBookmark_batched.js | 110 ++++++++ .../test_database_sync_after_addVisit.js | 18 +- ...st_database_sync_after_addVisit_batched.js | 71 ++++- ...test_database_sync_after_modifyBookmark.js | 108 ++++++++ ...t_database_sync_after_quit_application.js} | 63 +++-- .../test_multiple_bookmarks_around_sync.js | 150 ++++++++++ .../test_multiple_visits_around_sync.js | 24 +- 15 files changed, 858 insertions(+), 547 deletions(-) delete mode 100644 toolkit/components/places/tests/background/test_database_sync_after_addBookmark.js delete mode 100644 toolkit/components/places/tests/background/test_database_sync_after_modifyBookmark.js delete mode 100644 toolkit/components/places/tests/background/test_multiple_bookmarks_around_sync.js create mode 100644 toolkit/components/places/tests/sync/head_sync.js rename toolkit/components/places/tests/{background/test_database_sync_after_quit_application.js => sync/test_database_sync_after_addBookmark.js} (63%) create mode 100644 toolkit/components/places/tests/sync/test_database_sync_after_addBookmark_batched.js rename toolkit/components/places/tests/{background => sync}/test_database_sync_after_addVisit.js (84%) rename toolkit/components/places/tests/{background => sync}/test_database_sync_after_addVisit_batched.js (55%) create mode 100644 toolkit/components/places/tests/sync/test_database_sync_after_modifyBookmark.js rename toolkit/components/places/tests/{background/test_database_sync_after_addBookmark_batched.js => sync/test_database_sync_after_quit_application.js} (54%) create mode 100644 toolkit/components/places/tests/sync/test_multiple_bookmarks_around_sync.js rename toolkit/components/places/tests/{background => sync}/test_multiple_visits_around_sync.js (85%) diff --git a/toolkit/components/places/src/nsPlacesDBFlush.js b/toolkit/components/places/src/nsPlacesDBFlush.js index eaeeb2134b28..44d58f896016 100644 --- a/toolkit/components/places/src/nsPlacesDBFlush.js +++ b/toolkit/components/places/src/nsPlacesDBFlush.js @@ -22,6 +22,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * Marco Bonardo * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -38,7 +39,6 @@ * ***** END LICENSE BLOCK ***** */ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); //////////////////////////////////////////////////////////////////////////////// //// Constants @@ -47,7 +47,8 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; -const kPlacesBackgroundShutdown = "places-background-shutdown"; +const kQuitApplication = "quit-application"; +const kSyncFinished = "places-sync-finished"; const kSyncPrefName = "syncDBTableIntervalInSecs"; const kDefaultSyncInterval = 120; @@ -57,27 +58,11 @@ const kDefaultSyncInterval = 120; function nsPlacesDBFlush() { - ////////////////////////////////////////////////////////////////////////////// - //// Smart Getters - - this.__defineGetter__("_db", function() { - delete this._db; - return this._db = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsPIPlacesDatabase). - DBConnection; - }); - - this.__defineGetter__("_bh", function() { - delete this._bh; - return this._bh = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - }); - + this._prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch("places."); // Get our sync interval - this._prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService). - getBranch("places."); try { // We want to silently fail if the preference does not exist, and use a // default to fallback to. @@ -91,13 +76,16 @@ function nsPlacesDBFlush() } // Register observers - this._bh.addObserver(this, false); + this._bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. + getService(Ci.nsINavBookmarksService); + this._bs.addObserver(this, false); - this._prefs.QueryInterface(Ci.nsIPrefBranch2).addObserver("", this, false); + this._os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); + this._os.addObserver(this, kQuitApplication, false); - let os = Cc["@mozilla.org/observer-service;1"]. - getService(Ci.nsIObserverService); - os.addObserver(this, kPlacesBackgroundShutdown, false); + this._prefs.QueryInterface(Ci.nsIPrefBranch2) + .addObserver("", this, false); // Create our timer to update everything this._timer = this._newTimer(); @@ -109,11 +97,13 @@ nsPlacesDBFlush.prototype = { observe: function DBFlush_observe(aSubject, aTopic, aData) { - if (aTopic == kPlacesBackgroundShutdown) { - this._bh.removeObserver(this); + if (aTopic == kQuitApplication) { + this._bs.removeObserver(this); + this._os.removeObserver(this, kQuitApplication); + this._prefs.QueryInterface(Ci.nsIPrefBranch2).removeObserver("", this); this._timer.cancel(); this._timer = null; - this._syncAll(); + this._syncTables(["places", "historyvisits"]); } else if (aTopic == "nsPref:changed" && aData == kSyncPrefName) { // Get the new pref value, and then update our timer @@ -148,18 +138,18 @@ nsPlacesDBFlush.prototype = { this._inBatchMode = false; // We need to sync and restore our timer now. - this._syncAll(); + this._syncTables(["places", "historyvisits"]); this._timer = this._newTimer(); }, - onItemAdded: function() this._syncMozPlaces(), + onItemAdded: function() this._syncTables(["places"]), onItemChanged: function DBFlush_onItemChanged(aItemId, aProperty, aIsAnnotationProperty, aValue) { if (aProperty == "uri") - this._syncMozPlaces(); + this._syncTables(["places"]); }, onItemRemoved: function() { }, @@ -169,78 +159,63 @@ nsPlacesDBFlush.prototype = { ////////////////////////////////////////////////////////////////////////////// //// nsITimerCallback - notify: function() this._syncAll(), + notify: function() this._syncTables(["places", "historyvisits"]), + + ////////////////////////////////////////////////////////////////////////////// + //// mozIStorageStatementCallback + + handleCompletion: function DBFlush_handleCompletion(aReason) + { + if (aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED) { + // Dispatch a notification that sync has finished. + this._os.notifyObservers(null, kSyncFinished, null); + } + }, ////////////////////////////////////////////////////////////////////////////// //// nsPlacesDBFlush + _syncInterval: kDefaultSyncInterval, /** - * Dispatches an event to the background thread to run _doSyncMozX("places"). + * Execute async statements to sync temporary places table. + * @param aTableNames + * array of table names that should be synced, as moz_{TableName}_temp. */ - _syncMozPlaces: function DBFlush_syncMozPlaces() + _syncTables: function DBFlush_syncTables(aTableNames) { // No need to do extra work if we are in batch mode if (this._inBatchMode) return; - let self = this; - PlacesBackground.dispatch({ - run: function() self._doSyncMozX("places") - }, Ci.nsIEventTarget.DISPATCH_NORMAL); + let statements = []; + for (let i = 0; i < aTableNames.length; i++) + statements.push(this._getSyncTableStatement(aTableNames[i])); + + // Execute sync statements async in a transaction + this._db.executeAsync(statements, statements.length, this); }, /** - * Dispatches an event to the background thread to sync all temporary tables. + * Generate the statement to synchronizes the moz_{aTableName} and + * moz_{aTableName}_temp by copying all the data from the temporary table + * into the permanent one. + * Most of the work is done through triggers defined in nsPlacesTriggers.h, + * they sync back to disk, then delete the data in the temporary table. + * @param aTableName + * name of the table to build statement for, as moz_{TableName}_temp. */ - _syncAll: function DBFlush_syncAll() - { - let self = this; - PlacesBackground.dispatch({ - run: function() { - // We try to get a transaction, but if we can't don't worry - let ourTransaction = false; - try { - this._db.beginTransaction(); - ourTransaction = true; - } - catch (e) { } - - try { - // This needs to also sync moz_places in order to maintain data - // integrity - self._doSyncMozX("places"); - self._doSyncMozX("historyvisits"); - } - catch (e) { - if (ourTransaction) - this._db.rollbackTransaction(); - throw e; - } - - if (ourTransaction) - this._db.commitTransaction(); - } - }, Ci.nsIEventTarget.DISPATCH_NORMAL); - }, - - /** - * Synchronizes the moz_{aName} and moz_{aName}_temp by copying all the data - * from the temporary table into the permanent one. It then deletes the data - * in the temporary table. All of this is done in a transaction that is - * rolled back upon failure at any point. - */ - _doSyncMozX: function DBFlush_doSyncMozX(aName) + _getSyncTableStatement: function DBFlush_getSyncTableStatement(aTableName) { // Delete all the data in the temp table. - // We have triggers setup that ensure that the data is transfered over - // upon deletion. - this._db.executeSimpleSQL("DELETE FROM moz_" + aName + "_temp"); + // We have triggers setup that ensure that the data is transferred over + // upon deletion. + return this._db.createStatement("DELETE FROM moz_" + aTableName + "_temp"); }, /** - * Creates a new timer bases on this._timerInterval. + * Creates a new timer based on this._syncInterval. * - * @returns a REPEATING_SLACK nsITimer that runs every this._timerInterval. + * @returns a REPEATING_SLACK nsITimer that runs every this._syncInterval. */ _newTimer: function DBFlush_newTimer() { @@ -267,6 +242,16 @@ nsPlacesDBFlush.prototype = { ]) }; +////////////////////////////////////////////////////////////////////////////// +//// Smart Getters + +nsPlacesDBFlush.prototype.__defineGetter__("_db", function() { + delete nsPlacesDBFlush._db; + return nsPlacesDBFlush._db = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsPIPlacesDatabase). + DBConnection; +}); + //////////////////////////////////////////////////////////////////////////////// //// Module Registration diff --git a/toolkit/components/places/tests/Makefile.in b/toolkit/components/places/tests/Makefile.in index 97a2dc108f23..c9dc3c16b995 100644 --- a/toolkit/components/places/tests/Makefile.in +++ b/toolkit/components/places/tests/Makefile.in @@ -49,6 +49,7 @@ MODULE = test_places XPCSHELL_TESTS = \ autocomplete \ background \ + sync \ bookmarks \ queries \ unit \ diff --git a/toolkit/components/places/tests/background/head_background.js b/toolkit/components/places/tests/background/head_background.js index 91a9e3f03690..4b070422be84 100644 --- a/toolkit/components/places/tests/background/head_background.js +++ b/toolkit/components/places/tests/background/head_background.js @@ -100,176 +100,3 @@ function clearDB() { } catch(ex) { dump("Exception: " + ex); } } clearDB(); - -/** - * Dumps the rows of a table out to the console. - * - * @param aName - * The name of the table or view to output. - */ -function dump_table(aName) -{ - let db = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsPIPlacesDatabase). - DBConnection; - let stmt = db.createStatement("SELECT * FROM " + aName); - - dump("\n*** Printing data from " + aName + ":\n"); - let count = 0; - while (stmt.executeStep()) { - let columns = stmt.numEntries; - - if (count == 0) { - // print the column names - for (let i = 0; i < columns; i++) - dump(stmt.getColumnName(i) + "\t"); - dump("\n"); - } - - // print the row - for (let i = 0; i < columns; i++) { - switch (stmt.getTypeOfIndex(i)) { - case Ci.mozIStorageValueArray.VALUE_TYPE_NULL: - dump("NULL\t"); - break; - case Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER: - dump(stmt.getInt64(i) + "\t"); - break; - case Ci.mozIStorageValueArray.VALUE_TYPE_FLOAT: - dump(stmt.getDouble(i) + "\t"); - break; - case Ci.mozIStorageValueArray.VALUE_TYPE_TEXT: - dump(stmt.getString(i) + "\t"); - break; - } - } - dump("\n"); - - count++; - } - dump("*** There were a total of " + count + " rows of data.\n\n"); - - stmt.reset(); - stmt.finalize(); - stmt = null; -} - -/** - * This dispatches the observer topic "quit-application" to clean up the - * background thread. - */ -function finish_test() -{ - // This next bit needs to run on the main thread - let tm = Cc["@mozilla.org/thread-manager;1"]. - getService(Ci.nsIThreadManager); - tm.mainThread.dispatch({ - run: function() - { - // xpcshell doesn't dispatch shutdown-application - let os = Cc["@mozilla.org/observer-service;1"]. - getService(Ci.nsIObserverService); - os.notifyObservers(null, "quit-application", null); - do_test_finished(); - } - }, Ci.nsIEventTarget.DISPATCH_NORMAL); -} - -/** - * Function tests to see if the place associated with the bookmark with id - * aBookmarkId has the uri aExpectedURI. The event will call finish_test() if - * aFinish is true. - * - * @param aBookmarkId - * The bookmark to check against. - * @param aExpectedURI - * The URI we expect to be in moz_places. - * @param aExpected - * Indicates if we expect to get a result or not. - * @param [optional] aFinish - * Indicates if the test should be completed or not. - */ -function new_test_bookmark_uri_event(aBookmarkId, aExpectedURI, aExpected, aFinish) -{ - return { - run: function() - { - let db = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsPIPlacesDatabase). - DBConnection; - let stmt = db.createStatement( - "SELECT moz_places.url " + - "FROM moz_bookmarks INNER JOIN moz_places " + - "ON moz_bookmarks.fk = moz_places.id " + - "WHERE moz_bookmarks.id = ?1" - ); - stmt.bindInt64Parameter(0, aBookmarkId); - - if (aExpected) { - do_check_true(stmt.executeStep()); - do_check_eq(stmt.getUTF8String(0), aExpectedURI); - } - else { - do_check_false(stmt.executeStep()); - } - stmt.reset(); - stmt.finalize(); - stmt = null; - - if (aFinish) - finish_test(); - } - }; -} - -/** - * Function tests to see if the place associated with the visit with id aVisitId - * has the uri aExpectedURI. The event will call finish_test() if aFinish is - * true. - * - * @param aVisitId - * The visit to check against. - * @param aExpectedURI - * The URI we expect to be in moz_places. - * @param aExpected - * Indicates if we expect to get a result or not. - * @param [optional] aFinish - * Indicates if the test should be completed or not. - */ -function new_test_visit_uri_event(aVisitId, aExpectedURI, aExpected, aFinish) -{ - return { - run: function() - { - let db = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsPIPlacesDatabase). - DBConnection; - let stmt = db.createStatement( - "SELECT moz_places.url " + - "FROM moz_historyvisits INNER JOIN moz_places " + - "ON moz_historyvisits.place_id = moz_places.id " + - "WHERE moz_historyvisits.id = ?1" - ); - stmt.bindInt64Parameter(0, aVisitId); - - if (aExpected) { - do_check_true(stmt.executeStep()); - do_check_eq(stmt.getUTF8String(0), aExpectedURI); - } - else { - do_check_false(stmt.executeStep()); - } - stmt.reset(); - stmt.finalize(); - stmt = null; - - if (aFinish) - finish_test(); - } - }; -} - -// profile-after-change doesn't create components in xpcshell, so we have to do -// it ourselves -Cc["@mozilla.org/places/sync;1"].getService(Ci.nsISupports); - diff --git a/toolkit/components/places/tests/background/test_database_sync_after_addBookmark.js b/toolkit/components/places/tests/background/test_database_sync_after_addBookmark.js deleted file mode 100644 index 1bc18ebec777..000000000000 --- a/toolkit/components/places/tests/background/test_database_sync_after_addBookmark.js +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Shawn Wilsher (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); - -const TEST_URI = "http://test.com/"; - -function run_test() -{ - // First insert it - let bh = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - let id = bh.insertBookmark(bh.unfiledBookmarksFolder, uri(TEST_URI), - bh.DEFAULT_INDEX, "test"); - - PlacesBackground.dispatch(new_test_bookmark_uri_event(id, TEST_URI, true, true), - Ci.nsIEventTarget.DISPATCH_NORMAL); - do_test_pending(); -} diff --git a/toolkit/components/places/tests/background/test_database_sync_after_modifyBookmark.js b/toolkit/components/places/tests/background/test_database_sync_after_modifyBookmark.js deleted file mode 100644 index 70034ea09837..000000000000 --- a/toolkit/components/places/tests/background/test_database_sync_after_modifyBookmark.js +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Shawn Wilsher (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); - -const TEST_URI = "http://test.com/"; -const MODIFIED_URI = "http://test.com/index.html"; - -function run_test() -{ - // First insert it - let bh = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - let id = bh.insertBookmark(bh.unfiledBookmarksFolder, uri(TEST_URI), - bh.DEFAULT_INDEX, "test"); - - // Dispatch the check synchronously so we don't modify the data before this - // test runs - PlacesBackground.dispatch(new_test_bookmark_uri_event(id, TEST_URI, true), - Ci.nsIEventTarget.DISPATCH_SYNC); - - // Now modify the bookmark - bh.changeBookmarkURI(id, uri(MODIFIED_URI)); - - PlacesBackground.dispatch(new_test_bookmark_uri_event(id, MODIFIED_URI, true, true), - Ci.nsIEventTarget.DISPATCH_NORMAL); - do_test_pending(); -} diff --git a/toolkit/components/places/tests/background/test_multiple_bookmarks_around_sync.js b/toolkit/components/places/tests/background/test_multiple_bookmarks_around_sync.js deleted file mode 100644 index 444a0ddc9764..000000000000 --- a/toolkit/components/places/tests/background/test_multiple_bookmarks_around_sync.js +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Shawn Wilsher (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * This test ensures that adding a bookmark (which has an implicit sync), then - * adding another one that has the same place, we end up with only one entry in - * moz_places. - */ - -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); - -const TEST_URI = "http://test.com/"; - -let db = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsPIPlacesDatabase). - DBConnection; - -function run_test() -{ - // Add the first bookmark - let bh = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - let id1 = bh.insertBookmark(bh.unfiledBookmarksFolder, uri(TEST_URI), - bh.DEFAULT_INDEX, "test"); - - // Ensure it was added - PlacesBackground.dispatch(new_test_bookmark_uri_event(id1, TEST_URI, true), - Ci.nsIEventTarget.DISPATCH_SYNC); - - // Get the place_id - let stmt = db.createStatement( - "SELECT fk " + - "FROM moz_bookmarks " + - "WHERE id = ?" - ); - stmt.bindInt64Parameter(0, id1); - do_check_true(stmt.executeStep()); - let place_id = stmt.getInt64(0); - stmt.finalize(); - stmt = null; - - // Now we add another bookmark to a different folder - let id2 = bh.insertBookmark(bh.toolbarFolder, uri(TEST_URI), - bh.DEFAULT_INDEX, "test"); - do_check_neq(id1, id2); - - // Ensure it was added - PlacesBackground.dispatch(new_test_bookmark_uri_event(id2, TEST_URI, true), - Ci.nsIEventTarget.DISPATCH_SYNC); - - // Check to make sure we have the same place_id - stmt = db.createStatement( - "SELECT * " + - "FROM moz_bookmarks " + - "WHERE id = ?1 " + - "AND fk = ?2" - ); - stmt.bindInt64Parameter(0, id2); - stmt.bindInt64Parameter(1, place_id); - do_check_true(stmt.executeStep()); - stmt.finalize(); - stmt = null; - - // finish_test() calls do_test_finished, so we call do_test_pending()... - do_test_pending(); - finish_test(); -} diff --git a/toolkit/components/places/tests/sync/head_sync.js b/toolkit/components/places/tests/sync/head_sync.js new file mode 100644 index 000000000000..a2a02fa40ce5 --- /dev/null +++ b/toolkit/components/places/tests/sync/head_sync.js @@ -0,0 +1,258 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Places. + * + * The Initial Developer of the Original Code is + * Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner + * Dietrich Ayala + * Shawn Wilsher + * Marco Bonardo + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const NS_APP_USER_PROFILE_50_DIR = "ProfD"; +const NS_APP_HISTORY_50_FILE = "UHist"; + +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; + +function LOG(aMsg) { + aMsg = ("*** PLACES TESTS: " + aMsg); + Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService). + logStringMessage(aMsg); + print(aMsg); +} + +// If there's no location registered for the profile direcotry, register one now. +var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties); +var profileDir = null; +try { + profileDir = dirSvc.get(NS_APP_USER_PROFILE_50_DIR, Ci.nsIFile); +} catch (e) {} +if (!profileDir) { + // Register our own provider for the profile directory. + // It will simply return the current directory. + var provider = { + getFile: function(prop, persistent) { + persistent.value = true; + if (prop == NS_APP_USER_PROFILE_50_DIR) { + return dirSvc.get("CurProcD", Ci.nsIFile); + } + if (prop == NS_APP_HISTORY_50_FILE) { + var histFile = dirSvc.get("CurProcD", Ci.nsIFile); + histFile.append("history.dat"); + return histFile; + } + throw Cr.NS_ERROR_FAILURE; + }, + QueryInterface: function(iid) { + if (iid.equals(Ci.nsIDirectoryServiceProvider) || + iid.equals(Ci.nsISupports)) { + return this; + } + throw Cr.NS_ERROR_NO_INTERFACE; + } + }; + dirSvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider); +} + +var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); + +function uri(spec) { + return iosvc.newURI(spec, null, null); +} + +// Delete a previously created sqlite file +function clearDB() { + try { + var file = dirSvc.get('ProfD', Ci.nsIFile); + file.append("places.sqlite"); + if (file.exists()) + file.remove(false); + } catch(ex) { dump("Exception: " + ex); } +} +clearDB(); + +/** + * Dumps the rows of a table out to the console. + * + * @param aName + * The name of the table or view to output. + */ +function dump_table(aName) +{ + let db = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsPIPlacesDatabase). + DBConnection; + let stmt = db.createStatement("SELECT * FROM " + aName); + + dump("\n*** Printing data from " + aName + ":\n"); + let count = 0; + while (stmt.executeStep()) { + let columns = stmt.numEntries; + + if (count == 0) { + // print the column names + for (let i = 0; i < columns; i++) + dump(stmt.getColumnName(i) + "\t"); + dump("\n"); + } + + // print the row + for (let i = 0; i < columns; i++) { + switch (stmt.getTypeOfIndex(i)) { + case Ci.mozIStorageValueArray.VALUE_TYPE_NULL: + dump("NULL\t"); + break; + case Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER: + dump(stmt.getInt64(i) + "\t"); + break; + case Ci.mozIStorageValueArray.VALUE_TYPE_FLOAT: + dump(stmt.getDouble(i) + "\t"); + break; + case Ci.mozIStorageValueArray.VALUE_TYPE_TEXT: + dump(stmt.getString(i) + "\t"); + break; + } + } + dump("\n"); + + count++; + } + dump("*** There were a total of " + count + " rows of data.\n\n"); + + stmt.reset(); + stmt.finalize(); + stmt = null; +} + +/** + * This dispatches the observer topic "quit-application" to clean up the sync + * component. + */ +function finish_test() +{ + // xpcshell doesn't dispatch shutdown-application + let os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); + os.notifyObservers(null, "quit-application", null); + do_test_finished(); +} + +/** + * Function tests to see if the place associated with the bookmark with id + * aBookmarkId has the uri aExpectedURI. The event will call finish_test() if + * aFinish is true. + * + * @param aBookmarkId + * The bookmark to check against. + * @param aExpectedURI + * The URI we expect to be in moz_places. + * @param aExpected + * Indicates if we expect to get a result or not. + * @param [optional] aFinish + * Indicates if the test should be completed or not. + */ +function new_test_bookmark_uri_event(aBookmarkId, aExpectedURI, aExpected, aFinish) +{ + let db = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsPIPlacesDatabase). + DBConnection; + let stmt = db.createStatement( + "SELECT moz_places.url " + + "FROM moz_bookmarks INNER JOIN moz_places " + + "ON moz_bookmarks.fk = moz_places.id " + + "WHERE moz_bookmarks.id = ?1" + ); + stmt.bindInt64Parameter(0, aBookmarkId); + + if (aExpected) { + do_check_true(stmt.executeStep()); + do_check_eq(stmt.getUTF8String(0), aExpectedURI); + } + else { + do_check_false(stmt.executeStep()); + } + stmt.reset(); + stmt.finalize(); + stmt = null; + + if (aFinish) + finish_test(); +} + +/** + * Function tests to see if the place associated with the visit with id aVisitId + * has the uri aExpectedURI. The event will call finish_test() if aFinish is + * true. + * + * @param aVisitId + * The visit to check against. + * @param aExpectedURI + * The URI we expect to be in moz_places. + * @param aExpected + * Indicates if we expect to get a result or not. + * @param [optional] aFinish + * Indicates if the test should be completed or not. + */ +function new_test_visit_uri_event(aVisitId, aExpectedURI, aExpected, aFinish) +{ + let db = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsPIPlacesDatabase). + DBConnection; + let stmt = db.createStatement( + "SELECT moz_places.url " + + "FROM moz_historyvisits INNER JOIN moz_places " + + "ON moz_historyvisits.place_id = moz_places.id " + + "WHERE moz_historyvisits.id = ?1" + ); + stmt.bindInt64Parameter(0, aVisitId); + + if (aExpected) { + do_check_true(stmt.executeStep()); + do_check_eq(stmt.getUTF8String(0), aExpectedURI); + } + else { + do_check_false(stmt.executeStep()); + } + stmt.reset(); + stmt.finalize(); + stmt = null; + + if (aFinish) + finish_test(); +} + +// profile-after-change doesn't create components in xpcshell, so we have to do +// it ourselves +Cc["@mozilla.org/places/sync;1"].getService(Ci.nsISupports); diff --git a/toolkit/components/places/tests/background/test_database_sync_after_quit_application.js b/toolkit/components/places/tests/sync/test_database_sync_after_addBookmark.js similarity index 63% rename from toolkit/components/places/tests/background/test_database_sync_after_quit_application.js rename to toolkit/components/places/tests/sync/test_database_sync_after_addBookmark.js index cdf39d157ce9..85033c5f683d 100644 --- a/toolkit/components/places/tests/background/test_database_sync_after_quit_application.js +++ b/toolkit/components/places/tests/sync/test_database_sync_after_addBookmark.js @@ -22,6 +22,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * Marco Bonardo * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,33 +38,52 @@ * * ***** END LICENSE BLOCK ***** */ -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); +var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. + getService(Ci.nsINavBookmarksService); +var os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch("places."); const TEST_URI = "http://test.com/"; -const kSyncPrefName = "syncDBTableIntervalInSecs"; + const SYNC_INTERVAL = 600; // ten minutes +const kSyncPrefName = "syncDBTableIntervalInSecs"; +const kSyncFinished = "places-sync-finished"; + +// Used to update observer itemId +var bookmarksObserver = { + onItemAdded: function(aItemId, aNewParent, aNewIndex) { + observer.itemId = aItemId; + } +} +bs.addObserver(bookmarksObserver, false); + +var observer = { + itemId: -1, + observe: function(aSubject, aTopic, aData) { + if (aTopic == kSyncFinished) { + do_check_neq(this.itemId, -1); + // remove the observer, we don't need to observe sync on quit + os.removeObserver(this, kSyncFinished); + bs.removeObserver(bookmarksObserver); + // Check that moz_places table has been correctly synced + new_test_bookmark_uri_event(this.itemId, TEST_URI, true, true); + } + } +} +os.addObserver(observer, kSyncFinished, false); function run_test() { // First set the preference for the timer to a really large value so it won't // run before the test finishes. - let prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService). - getBranch("places."); prefs.setIntPref(kSyncPrefName, SYNC_INTERVAL); - // Now add the visit - let hs = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); - let id = hs.addVisit(uri(TEST_URI), Date.now() * 1000, null, - hs.TRANSITION_TYPED, false, 0); + // Insert a new bookmark + bs.insertBookmark(bs.unfiledBookmarksFolder, uri(TEST_URI), + bs.DEFAULT_INDEX, "test"); - // Notify that we are quitting the app - we should sync! - let os = Cc["@mozilla.org/observer-service;1"]. - getService(Ci.nsIObserverService); - os.notifyObservers(null, "quit-application", null); - - // Check the visit. The background thread should have joined with the main - // thread by now if everything is working correctly. - new_test_visit_uri_event(id, TEST_URI, true, false).run(); + do_test_pending(); } diff --git a/toolkit/components/places/tests/sync/test_database_sync_after_addBookmark_batched.js b/toolkit/components/places/tests/sync/test_database_sync_after_addBookmark_batched.js new file mode 100644 index 000000000000..f95227bd01b5 --- /dev/null +++ b/toolkit/components/places/tests/sync/test_database_sync_after_addBookmark_batched.js @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 sts=2 expandtab + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Shawn Wilsher (Original Author) + * Marco Bonardo + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. + getService(Ci.nsINavBookmarksService); +var os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch("places."); + +const TEST_URI = "http://test.com/"; + +const SYNC_INTERVAL = 600; // ten minutes +const kSyncPrefName = "syncDBTableIntervalInSecs"; +const kSyncFinished = "places-sync-finished"; + +// Used to check if we are batching and to update observer itemId +var bookmarksObserver = { + _batching: false, + onBeginUpdateBatch: function() { + this._batching = true; + }, + onEndUpdateBatch: function() { + this._batching = false; + }, + onItemAdded: function(aItemId, aNewParent, aNewIndex) { + observer.itemId = aItemId; + } +} +bs.addObserver(bookmarksObserver, false); + +var observer = { + itemId: -1, + observe: function(aSubject, aTopic, aData) { + if (aTopic == kSyncFinished) { + dump(this.itemId); + // item id must be valid + do_check_neq(this.itemId, -1); + // Check that we are not in a batch + do_check_false(bookmarksObserver._batching); + // remove the observer, we don't need to observe sync on quit + os.removeObserver(this, kSyncFinished); + bs.removeObserver(bookmarksObserver); + // Check that tables have been correctly synced + new_test_bookmark_uri_event(this.itemId, TEST_URI, true, true); + } + } +} +os.addObserver(observer, kSyncFinished, false); + +function run_test() +{ + // Set the preference for the timer to a really large value, so it won't + // run before the test finishes. + prefs.setIntPref(kSyncPrefName, SYNC_INTERVAL); + + // Add a bookmark in batch mode + let id = -1; + bs.runInBatchMode({ + runBatched: function(aUserData) + { + id = bs.insertBookmark(bs.unfiledBookmarksFolder, uri(TEST_URI), + bs.DEFAULT_INDEX, "test"); + // We should not sync during a batch + new_test_bookmark_uri_event(id, TEST_URI, false); + } + }, null); + // Ensure the bookmark has been added + do_check_neq(id, -1); + + do_test_pending(); +} diff --git a/toolkit/components/places/tests/background/test_database_sync_after_addVisit.js b/toolkit/components/places/tests/sync/test_database_sync_after_addVisit.js similarity index 84% rename from toolkit/components/places/tests/background/test_database_sync_after_addVisit.js rename to toolkit/components/places/tests/sync/test_database_sync_after_addVisit.js index 60add32c9f47..431324cf46a8 100644 --- a/toolkit/components/places/tests/background/test_database_sync_after_addVisit.js +++ b/toolkit/components/places/tests/sync/test_database_sync_after_addVisit.js @@ -22,6 +22,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * Marco Bonardo * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,23 +38,25 @@ * * ***** END LICENSE BLOCK ***** */ -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); +var hs = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsINavHistoryService); +var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. + getService(Ci.nsINavBookmarksService); +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch("places."); const TEST_URI = "http://test.com/"; + const kSyncPrefName = "syncDBTableIntervalInSecs"; const SYNC_INTERVAL = 1; function run_test() { // First set the preference for the timer to a small value - let prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService). - getBranch("places."); prefs.setIntPref(kSyncPrefName, SYNC_INTERVAL); // Now add the visit - let hs = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); let id = hs.addVisit(uri(TEST_URI), Date.now() * 1000, null, hs.TRANSITION_TYPED, false, 0); @@ -63,8 +66,7 @@ function run_test() timer.initWithCallback({ notify: function(aTimer) { - PlacesBackground.dispatch(new_test_visit_uri_event(id, TEST_URI, true, true), - Ci.nsIEventTarget.DISPATCH_NORMAL); + new_test_visit_uri_event(id, TEST_URI, true, true); } }, (SYNC_INTERVAL * 1000) * 2, Ci.nsITimer.TYPE_ONE_SHOT); do_test_pending(); diff --git a/toolkit/components/places/tests/background/test_database_sync_after_addVisit_batched.js b/toolkit/components/places/tests/sync/test_database_sync_after_addVisit_batched.js similarity index 55% rename from toolkit/components/places/tests/background/test_database_sync_after_addVisit_batched.js rename to toolkit/components/places/tests/sync/test_database_sync_after_addVisit_batched.js index 920f93734f44..6c9055594692 100644 --- a/toolkit/components/places/tests/background/test_database_sync_after_addVisit_batched.js +++ b/toolkit/components/places/tests/sync/test_database_sync_after_addVisit_batched.js @@ -22,6 +22,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * Marco Bonardo * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,30 +38,72 @@ * * ***** END LICENSE BLOCK ***** */ -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); + var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. + getService(Ci.nsINavBookmarksService); + var hs = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsINavHistoryService); + var os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); const TEST_URI = "http://test.com/"; +const kSyncFinished = "places-sync-finished"; + +// Used to check if we are batching +var bookmarksObserver = { + _batching: false, + onBeginUpdateBatch: function() { + this._batching = true; + }, + onEndUpdateBatch: function() { + this._batching = false; + } +} +bs.addObserver(bookmarksObserver, false); + +// Used to update observer visitId +var historyObserver = { + onVisit: function(aURI, aVisitId, aTime, aSessionId, aReferringId, + aTransitionType, aAdded) { + observer.visitId = aVisitId; + } +} +hs.addObserver(historyObserver, false); + +var observer = { + visitId: -1, + observe: function(aSubject, aTopic, aData) { + if (aTopic == kSyncFinished) { + // visit id must be valid + do_check_neq(this.visitId, -1); + // Check that we are not in a batch + do_check_false(bookmarksObserver._batching); + // remove the observer, we don't need to observe sync on quit + os.removeObserver(this, kSyncFinished); + bs.removeObserver(bookmarksObserver); + hs.removeObserver(historyObserver); + // Check that tables have been correctly synced + new_test_visit_uri_event(this.visitId, TEST_URI, true, true); + } + } +} +os.addObserver(observer, kSyncFinished, false); + function run_test() { - // Now add the visit in batch mode - let bh = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - let id = null; - bh.runInBatchMode({ + // Add a visit in batch mode + let id = -1; + bs.runInBatchMode({ runBatched: function(aUserData) { - let hs = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); - id = hs.addVisit(uri(TEST_URI), Date.now() * 1000, null, hs.TRANSITION_TYPED, false, 0); - PlacesBackground.dispatch(new_test_visit_uri_event(id, TEST_URI, false), - Ci.nsIEventTarget.DISPATCH_SYNC); + // We should not sync during a batch + new_test_visit_uri_event(id, TEST_URI, false); } }, null); - do_check_neq(id, null); - PlacesBackground.dispatch(new_test_visit_uri_event(id, TEST_URI, true, true), - Ci.nsIEventTarget.DISPATCH_NORMAL); + // Ensure the visit has been added + do_check_neq(id, -1); + do_test_pending(); } diff --git a/toolkit/components/places/tests/sync/test_database_sync_after_modifyBookmark.js b/toolkit/components/places/tests/sync/test_database_sync_after_modifyBookmark.js new file mode 100644 index 000000000000..4ec54d836a21 --- /dev/null +++ b/toolkit/components/places/tests/sync/test_database_sync_after_modifyBookmark.js @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 sts=2 expandtab + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Shawn Wilsher (Original Author) + * Marco Bonardo + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. + getService(Ci.nsINavBookmarksService); +var os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch("places."); + +const TEST_URI = "http://test.com/"; +const MODIFIED_URI = "http://test.com/index.html"; + +const SYNC_INTERVAL = 600; // ten minutes +const kSyncPrefName = "syncDBTableIntervalInSecs"; +const kSyncFinished = "places-sync-finished"; + +// Used to update observer itemId +var bookmarksObserver = { + onItemAdded: function(aItemId, aNewParent, aNewIndex) { + observer.itemId = aItemId; + }, + onItemChanged: function(aItemId, aProperty, aValue) { + if (aProperty == "uri") + do_check_eq(observer.itemId, aItemId); + } +} +bs.addObserver(bookmarksObserver, false); + +var observer = { + itemId: -1, + _runCount: 0, + observe: function(aSubject, aTopic, aData) { + if (aTopic == kSyncFinished) { + // item id must be valid + do_check_neq(this.itemId, -1); + if (++this._runCount == 1) { + // First sync is fired by adding the bookmark + // Check that tables have been synced after insertBookmark + new_test_bookmark_uri_event(this.itemId, TEST_URI, true); + // Now modify the bookmark + bs.changeBookmarkURI(this.itemId, uri(MODIFIED_URI)); + } + else if (this._runCount == 2) { + // Second sync is fired by changing the bookmark's uri + // remove the observer, we don't need to observe sync on quit + os.removeObserver(this, kSyncFinished); + bs.removeObserver(bookmarksObserver); + // Check that tables have been synced after changeBookmarkURI + new_test_bookmark_uri_event(this.itemId, MODIFIED_URI, true, true); + } + else + do_throw("Too many places sync calls"); + } + } +} +os.addObserver(observer, kSyncFinished, false); + +function run_test() +{ + // Set the preference for the timer to a really large value, so it won't + // run before the test finishes. + prefs.setIntPref(kSyncPrefName, SYNC_INTERVAL); + + // Insert a new bookmark + bs.insertBookmark(bs.unfiledBookmarksFolder, uri(TEST_URI), + bs.DEFAULT_INDEX, "test"); + + do_test_pending(); +} diff --git a/toolkit/components/places/tests/background/test_database_sync_after_addBookmark_batched.js b/toolkit/components/places/tests/sync/test_database_sync_after_quit_application.js similarity index 54% rename from toolkit/components/places/tests/background/test_database_sync_after_addBookmark_batched.js rename to toolkit/components/places/tests/sync/test_database_sync_after_quit_application.js index 3efb861f1630..9fa61bf0b9e6 100644 --- a/toolkit/components/places/tests/background/test_database_sync_after_addBookmark_batched.js +++ b/toolkit/components/places/tests/sync/test_database_sync_after_quit_application.js @@ -22,6 +22,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * Marco Bonardo * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,28 +38,56 @@ * * ***** END LICENSE BLOCK ***** */ -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); +var os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch("places."); +var hs = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsINavHistoryService); const TEST_URI = "http://test.com/"; +const kSyncPrefName = "syncDBTableIntervalInSecs"; +const SYNC_INTERVAL = 600; // ten minutes +const kSyncFinished = "places-sync-finished"; + +var historyObserver = { + onVisit: function(aURI, aVisitId, aTime, aSessionId, aReferringId, + aTransitionType, aAdded) { + observer.visitId = aVisitId; + } +} +hs.addObserver(historyObserver, false); + +var observer = { + visitId: -1, + observe: function(aSubject, aTopic, aData) { + if (aTopic == kSyncFinished) { + // visit id must be valid + do_check_neq(this.visitId, -1); + // remove the observer, we don't need to observe sync on quit + os.removeObserver(this, kSyncFinished); + hs.removeObserver(historyObserver); + // Check that tables have been correctly synced + new_test_visit_uri_event(this.visitId, TEST_URI, true, true); + } + } +} +os.addObserver(observer, kSyncFinished, false); + function run_test() { - // First insert it - let bh = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - let id = null; - bh.runInBatchMode({ - runBatched: function(aUserData) - { - id = bh.insertBookmark(bh.unfiledBookmarksFolder, uri(TEST_URI), - bh.DEFAULT_INDEX, "test"); + // Set the preference for the timer to a really large value, so it won't + // run before the test finishes. + prefs.setIntPref(kSyncPrefName, SYNC_INTERVAL); + + // Now add a visit + hs.addVisit(uri(TEST_URI), Date.now() * 1000, null, + hs.TRANSITION_TYPED, false, 0); + + // Notify that we are quitting the app - we should sync! + os.notifyObservers(null, "quit-application", null); - PlacesBackground.dispatch(new_test_bookmark_uri_event(id, TEST_URI, false), - Ci.nsIEventTarget.DISPATCH_SYNC); - } - }, null); - do_check_neq(id, null); - PlacesBackground.dispatch(new_test_bookmark_uri_event(id, TEST_URI, true, true), - Ci.nsIEventTarget.DISPATCH_NORMAL); do_test_pending(); } diff --git a/toolkit/components/places/tests/sync/test_multiple_bookmarks_around_sync.js b/toolkit/components/places/tests/sync/test_multiple_bookmarks_around_sync.js new file mode 100644 index 000000000000..222e08c0526b --- /dev/null +++ b/toolkit/components/places/tests/sync/test_multiple_bookmarks_around_sync.js @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 sts=2 expandtab + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Shawn Wilsher (Original Author) + * Marco Bonardo + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * This test ensures that adding a bookmark (which has an implicit sync), then + * adding another one that has the same place, we end up with only one entry in + * moz_places. + */ + +var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. + getService(Ci.nsINavBookmarksService); +var hs = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsINavHistoryService); +var db = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsPIPlacesDatabase). + DBConnection; +var os = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch("places."); + +const TEST_URI = "http://test.com/"; + +const SYNC_INTERVAL = 600; // ten minutes +const kSyncPrefName = "syncDBTableIntervalInSecs"; +const kSyncFinished = "places-sync-finished"; + +// Used to update observer itemId +var bookmarksObserver = { + onItemAdded: function(aItemId, aNewParent, aNewIndex) { + observer.itemIds.push(aItemId); + } +} +bs.addObserver(bookmarksObserver, false); + +var observer = { + itemIds: [], + _placeId: -1, + _runCount: 0, + observe: function(aSubject, aTopic, aData) { + if (aTopic == kSyncFinished) { + if (++this._runCount == 1) { + let itemId = this.itemIds[this._runCount - 1]; + // item id must be valid + do_check_neq(itemId, null); + // Ensure tables have been synced + new_test_bookmark_uri_event(itemId, TEST_URI, true); + + // Get the place_id + let stmt = db.createStatement( + "SELECT fk " + + "FROM moz_bookmarks " + + "WHERE id = ?" + ); + stmt.bindInt64Parameter(0, itemId); + do_check_true(stmt.executeStep()); + this._placeId = stmt.getInt64(0); + stmt.finalize(); + stmt = null; + // place id must be valid + do_check_true(this._placeId > 0); + } + else if (this._runCount == 2) { + let itemId = this.itemIds[this._runCount - 1]; + // item id must be valid + do_check_neq(itemId, null); + // Ensure it was added + new_test_bookmark_uri_event(itemId, TEST_URI, true); + + // Check to make sure we have the same place_id + stmt = db.createStatement( + "SELECT * " + + "FROM moz_bookmarks " + + "WHERE id = ?1 " + + "AND fk = ?2" + ); + stmt.bindInt64Parameter(0, itemId); + stmt.bindInt64Parameter(1, this._placeId); + do_check_true(stmt.executeStep()); + stmt.finalize(); + stmt = null; + + // remove the observer, we don't need to observe sync on quit + os.removeObserver(this, kSyncFinished); + bs.removeObserver(bookmarksObserver); + // test ends here + finish_test(); + } + else + do_throw("Too many places sync calls"); + } + } +} +os.addObserver(observer, kSyncFinished, false); + +function run_test() +{ + // Set the preference for the timer to a really large value, so it won't + // run before the test finishes. + prefs.setIntPref(kSyncPrefName, SYNC_INTERVAL); + + // Add the first bookmark + let id1 = bs.insertBookmark(bs.unfiledBookmarksFolder, uri(TEST_URI), + bs.DEFAULT_INDEX, "test"); + + // Now we add another bookmark to a different folder + let id2 = bs.insertBookmark(bs.toolbarFolder, uri(TEST_URI), + bs.DEFAULT_INDEX, "test"); + do_check_neq(id1, id2); + + do_test_pending(); +} diff --git a/toolkit/components/places/tests/background/test_multiple_visits_around_sync.js b/toolkit/components/places/tests/sync/test_multiple_visits_around_sync.js similarity index 85% rename from toolkit/components/places/tests/background/test_multiple_visits_around_sync.js rename to toolkit/components/places/tests/sync/test_multiple_visits_around_sync.js index 9420c0c9ab53..3796c24cf8e5 100644 --- a/toolkit/components/places/tests/background/test_multiple_visits_around_sync.js +++ b/toolkit/components/places/tests/sync/test_multiple_visits_around_sync.js @@ -22,6 +22,7 @@ * * Contributor(s): * Shawn Wilsher (Original Author) + * Marco Bonardo * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -43,23 +44,26 @@ * entry in moz_places. */ -Components.utils.import("resource://gre/modules/PlacesBackground.jsm"); +var hs = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsINavHistoryService); +var db = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsPIPlacesDatabase). + DBConnection; +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService). + getBranch("places."); const TEST_URI = "http://test.com/"; + const kSyncPrefName = "syncDBTableIntervalInSecs"; const SYNC_INTERVAL = 1; function run_test() { // First set the preference for the timer to a small value - let prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService). - getBranch("places."); prefs.setIntPref(kSyncPrefName, SYNC_INTERVAL); // Now add the first visit - let hs = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); let id = hs.addVisit(uri(TEST_URI), Date.now() * 1000, null, hs.TRANSITION_TYPED, false, 0); @@ -69,8 +73,7 @@ function run_test() timer.initWithCallback({ notify: function(aTimer) { - PlacesBackground.dispatch(new_test_visit_uri_event(id, TEST_URI, true), - Ci.nsIEventTarget.DISPATCH_SYNC); + new_test_visit_uri_event(id, TEST_URI, true); // Get the place_id and pass it on let db = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection; @@ -92,8 +95,6 @@ function run_test() function continue_test(aLastVisitId, aPlaceId) { // Now we add another visit - let hs = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); let id = hs.addVisit(uri(TEST_URI), Date.now() * 1000, null, hs.TRANSITION_TYPED, false, 0); do_check_neq(aLastVisitId, id); @@ -104,8 +105,7 @@ function continue_test(aLastVisitId, aPlaceId) timer.initWithCallback({ notify: function(aTimer) { - PlacesBackground.dispatch(new_test_visit_uri_event(id, TEST_URI, true), - Ci.nsIEventTarget.DISPATCH_SYNC); + new_test_visit_uri_event(id, TEST_URI, true); // Check to make sure we have the same place_id let db = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;