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
This commit is contained in:
Marco Bonardo 2008-10-27 18:52:21 -04:00
Родитель 51ee94d2ad
Коммит 636252beee
15 изменённых файлов: 858 добавлений и 547 удалений

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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

Просмотреть файл

@ -49,6 +49,7 @@ MODULE = test_places
XPCSHELL_TESTS = \
autocomplete \
background \
sync \
bookmarks \
queries \
unit \

Просмотреть файл

@ -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);

Просмотреть файл

@ -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 <me@shawnwilsher.com> (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();
}

Просмотреть файл

@ -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 <me@shawnwilsher.com> (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();
}

Просмотреть файл

@ -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 <me@shawnwilsher.com> (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();
}

Просмотреть файл

@ -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 <bryner@brianryner.com>
* Dietrich Ayala <dietrich@mozilla.com>
* Shawn Wilsher <me@shawnwilsher.com>
* Marco Bonardo <mak77@bonardo.net>
*
* 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);

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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();
}

Просмотреть файл

@ -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 <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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();
}

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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();

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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();
}

Просмотреть файл

@ -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 <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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();
}

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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();
}

Просмотреть файл

@ -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 <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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();
}

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
* Marco Bonardo <mak77@bonardo.net>
*
* 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;