mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1058435 - Add removeAllDomainsSince to ContentPrefService2. r=adw
This commit is contained in:
parent
ef065ba355
commit
00cc687159
@ -67,7 +67,7 @@ interface nsIContentPref;
|
||||
* See nsIContentPrefCallback2 below for more information about callbacks.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(f2507add-dc39-48e0-9147-e0270376148b)]
|
||||
[scriptable, uuid(bed98666-d995-470f-bebd-62476d318576)]
|
||||
interface nsIContentPrefService2 : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -299,6 +299,17 @@ interface nsIContentPrefService2 : nsISupports
|
||||
void removeAllDomains(in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes all non-global preferences created after and including |since|.
|
||||
*
|
||||
* @param since Timestamp in milliseconds.
|
||||
* @param context The private-browsing context, if any.
|
||||
* @param callback handleCompletion is called when the operation completes.
|
||||
*/
|
||||
void removeAllDomainsSince(in unsigned long long since,
|
||||
in nsILoadContext context,
|
||||
[optional] in nsIContentPrefCallback2 callback);
|
||||
|
||||
/**
|
||||
* Removes all global preferences -- in other words, all preferences that have
|
||||
* no domain.
|
||||
|
@ -286,7 +286,7 @@ ContentPrefService2.prototype = {
|
||||
// Finally create or update the pref.
|
||||
if (group) {
|
||||
stmt = this._stmt(`
|
||||
INSERT OR REPLACE INTO prefs (id, groupID, settingID, value)
|
||||
INSERT OR REPLACE INTO prefs (id, groupID, settingID, value, timestamp)
|
||||
VALUES(
|
||||
(SELECT prefs.id
|
||||
FROM prefs
|
||||
@ -295,14 +295,15 @@ ContentPrefService2.prototype = {
|
||||
WHERE groups.name = :group AND settings.name = :name),
|
||||
(SELECT id FROM groups WHERE name = :group),
|
||||
(SELECT id FROM settings WHERE name = :name),
|
||||
:value
|
||||
:value,
|
||||
:now
|
||||
)
|
||||
`);
|
||||
stmt.params.group = group;
|
||||
}
|
||||
else {
|
||||
stmt = this._stmt(`
|
||||
INSERT OR REPLACE INTO prefs (id, groupID, settingID, value)
|
||||
INSERT OR REPLACE INTO prefs (id, groupID, settingID, value, timestamp)
|
||||
VALUES(
|
||||
(SELECT prefs.id
|
||||
FROM prefs
|
||||
@ -310,12 +311,14 @@ ContentPrefService2.prototype = {
|
||||
WHERE prefs.groupID IS NULL AND settings.name = :name),
|
||||
NULL,
|
||||
(SELECT id FROM settings WHERE name = :name),
|
||||
:value
|
||||
:value,
|
||||
:now
|
||||
)
|
||||
`);
|
||||
}
|
||||
stmt.params.name = name;
|
||||
stmt.params.value = value;
|
||||
stmt.params.now = Date.now() / 1000;
|
||||
stmts.push(stmt);
|
||||
|
||||
this._execStmts(stmts, {
|
||||
@ -379,18 +382,7 @@ ContentPrefService2.prototype = {
|
||||
stmt.params.name = name;
|
||||
stmts.push(stmt);
|
||||
|
||||
// Delete settings and groups that are no longer used. The NOTNULL term in
|
||||
// the subquery of the second statment is needed because of SQLite's weird
|
||||
// IN behavior vis-a-vis NULLs. See http://sqlite.org/lang_expr.html.
|
||||
stmts.push(this._stmt(`
|
||||
DELETE FROM settings
|
||||
WHERE id NOT IN (SELECT DISTINCT settingID FROM prefs)
|
||||
`));
|
||||
stmts.push(this._stmt(`
|
||||
DELETE FROM groups WHERE id NOT IN (
|
||||
SELECT DISTINCT groupID FROM prefs WHERE groupID NOTNULL
|
||||
)
|
||||
`));
|
||||
stmts = stmts.concat(this._settingsAndGroupsCleanupStmts());
|
||||
|
||||
let prefs = new ContentPrefStore();
|
||||
|
||||
@ -424,6 +416,23 @@ ContentPrefService2.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
// Deletes settings and groups that are no longer used.
|
||||
_settingsAndGroupsCleanupStmts: function() {
|
||||
// The NOTNULL term in the subquery of the second statment is needed because of
|
||||
// SQLite's weird IN behavior vis-a-vis NULLs. See http://sqlite.org/lang_expr.html.
|
||||
return [
|
||||
this._stmt(`
|
||||
DELETE FROM settings
|
||||
WHERE id NOT IN (SELECT DISTINCT settingID FROM prefs)
|
||||
`),
|
||||
this._stmt(`
|
||||
DELETE FROM groups WHERE id NOT IN (
|
||||
SELECT DISTINCT groupID FROM prefs WHERE groupID NOTNULL
|
||||
)
|
||||
`)
|
||||
];
|
||||
},
|
||||
|
||||
removeByDomain: function CPS2_removeByDomain(group, context, callback) {
|
||||
checkGroupArg(group);
|
||||
this._removeByDomain(group, false, context, callback);
|
||||
@ -516,36 +525,40 @@ ContentPrefService2.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
removeAllDomains: function CPS2_removeAllDomains(context, callback) {
|
||||
_removeAllDomainsSince: function CPS2__removeAllDomainsSince(since, context, callback) {
|
||||
checkCallbackArg(callback, false);
|
||||
|
||||
since /= 1000;
|
||||
|
||||
// Invalidate the cached values so consumers accessing the cache between now
|
||||
// and when the operation finishes don't get old data.
|
||||
// Invalidate all the group cache because we don't know which groups will be removed.
|
||||
this._cache.removeAllGroups();
|
||||
|
||||
let stmts = [];
|
||||
|
||||
// First get the matching prefs.
|
||||
stmts.push(this._stmt(`
|
||||
// Get prefs that are about to be removed to notify about their removal.
|
||||
let stmt = this._stmt(`
|
||||
SELECT groups.name AS grp, settings.name AS name
|
||||
FROM prefs
|
||||
JOIN settings ON settings.id = prefs.settingID
|
||||
JOIN groups ON groups.id = prefs.groupID
|
||||
`));
|
||||
WHERE timestamp >= :since
|
||||
`);
|
||||
stmt.params.since = since;
|
||||
stmts.push(stmt);
|
||||
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM prefs WHERE groupID NOTNULL"
|
||||
));
|
||||
stmts.push(this._stmt(
|
||||
"DELETE FROM groups"
|
||||
));
|
||||
stmts.push(this._stmt(`
|
||||
DELETE FROM settings
|
||||
WHERE id NOT IN (SELECT DISTINCT settingID FROM prefs)
|
||||
`));
|
||||
// Do the actual remove.
|
||||
stmt = this._stmt(`
|
||||
DELETE FROM prefs WHERE groupID NOTNULL AND timestamp >= :since
|
||||
`);
|
||||
stmt.params.since = since;
|
||||
stmts.push(stmt);
|
||||
|
||||
// Cleanup no longer used values.
|
||||
stmts = stmts.concat(this._settingsAndGroupsCleanupStmts());
|
||||
|
||||
let prefs = new ContentPrefStore();
|
||||
|
||||
this._execStmts(stmts, {
|
||||
onRow: function onRow(row) {
|
||||
let grp = row.getResultByName("grp");
|
||||
@ -554,6 +567,8 @@ ContentPrefService2.prototype = {
|
||||
this._cache.set(grp, name, undefined);
|
||||
},
|
||||
onDone: function onDone(reason, ok) {
|
||||
// This nukes all the groups in _pbStore since we don't have their timestamp
|
||||
// information.
|
||||
if (ok && context && context.usePrivateBrowsing) {
|
||||
for (let [sgroup, sname, ] in this._pbStore) {
|
||||
prefs.set(sgroup, sname, undefined);
|
||||
@ -573,6 +588,14 @@ ContentPrefService2.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
removeAllDomainsSince: function CPS2_removeAllDomainsSince(since, context, callback) {
|
||||
this._removeAllDomainsSince(since, context, callback);
|
||||
},
|
||||
|
||||
removeAllDomains: function CPS2_removeAllDomains(context, callback) {
|
||||
this._removeAllDomainsSince(0, context, callback);
|
||||
},
|
||||
|
||||
removeByName: function CPS2_removeByName(name, context, callback) {
|
||||
checkNameArg(name);
|
||||
checkCallbackArg(callback, false);
|
||||
|
@ -998,20 +998,21 @@ ContentPrefService.prototype = {
|
||||
//**************************************************************************//
|
||||
// Database Creation & Access
|
||||
|
||||
_dbVersion: 3,
|
||||
_dbVersion: 4,
|
||||
|
||||
_dbSchema: {
|
||||
tables: {
|
||||
groups: "id INTEGER PRIMARY KEY, \
|
||||
name TEXT NOT NULL",
|
||||
|
||||
|
||||
settings: "id INTEGER PRIMARY KEY, \
|
||||
name TEXT NOT NULL",
|
||||
|
||||
|
||||
prefs: "id INTEGER PRIMARY KEY, \
|
||||
groupID INTEGER REFERENCES groups(id), \
|
||||
settingID INTEGER NOT NULL REFERENCES settings(id), \
|
||||
value BLOB"
|
||||
value BLOB, \
|
||||
timestamp INTEGER NOT NULL DEFAULT 0" // Storage in seconds, API in ms. 0 for migrated values.
|
||||
},
|
||||
indices: {
|
||||
groups_idx: {
|
||||
@ -1024,7 +1025,7 @@ ContentPrefService.prototype = {
|
||||
},
|
||||
prefs_idx: {
|
||||
table: "prefs",
|
||||
columns: ["groupID", "settingID"]
|
||||
columns: ["timestamp", "groupID", "settingID"]
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1166,35 +1167,36 @@ ContentPrefService.prototype = {
|
||||
},
|
||||
|
||||
_dbMigrate: function ContentPrefService__dbMigrate(aDBConnection, aOldVersion, aNewVersion) {
|
||||
if (this["_dbMigrate" + aOldVersion + "To" + aNewVersion]) {
|
||||
aDBConnection.beginTransaction();
|
||||
try {
|
||||
this["_dbMigrate" + aOldVersion + "To" + aNewVersion](aDBConnection);
|
||||
aDBConnection.schemaVersion = aNewVersion;
|
||||
aDBConnection.commitTransaction();
|
||||
}
|
||||
catch(ex) {
|
||||
aDBConnection.rollbackTransaction();
|
||||
throw ex;
|
||||
aDBConnection.beginTransaction();
|
||||
|
||||
try {
|
||||
/**
|
||||
* If the schema version is 0, that means it was never set, which means
|
||||
* the database was somehow created without the schema being applied, perhaps
|
||||
* because the system ran out of disk space (although we check for this
|
||||
* in _createDB) or because some other code created the database file without
|
||||
* applying the schema. In any case, recover by simply reapplying the schema.
|
||||
*/
|
||||
if (aOldVersion == 0) {
|
||||
this._dbCreateSchema(aDBConnection);
|
||||
} else {
|
||||
for (let i = aOldVersion; i < aNewVersion; i++) {
|
||||
let migrationName = "_dbMigrate" + i + "To" + (i + 1);
|
||||
if (typeof this[migrationName] != 'function') {
|
||||
throw("no migrator function from version " + aOldVersion + " to version " + aNewVersion);
|
||||
}
|
||||
this[migrationName](aDBConnection);
|
||||
}
|
||||
}
|
||||
aDBConnection.schemaVersion = aNewVersion;
|
||||
aDBConnection.commitTransaction();
|
||||
} catch (ex) {
|
||||
aDBConnection.rollbackTransaction();
|
||||
throw ex;
|
||||
}
|
||||
else
|
||||
throw("no migrator function from version " + aOldVersion +
|
||||
" to version " + aNewVersion);
|
||||
},
|
||||
|
||||
/**
|
||||
* If the schema version is 0, that means it was never set, which means
|
||||
* the database was somehow created without the schema being applied, perhaps
|
||||
* because the system ran out of disk space (although we check for this
|
||||
* in _createDB) or because some other code created the database file without
|
||||
* applying the schema. In any case, recover by simply reapplying the schema.
|
||||
*/
|
||||
_dbMigrate0To3: function ContentPrefService___dbMigrate0To3(aDBConnection) {
|
||||
this._dbCreateSchema(aDBConnection);
|
||||
},
|
||||
|
||||
_dbMigrate1To3: function ContentPrefService___dbMigrate1To3(aDBConnection) {
|
||||
_dbMigrate1To2: function ContentPrefService___dbMigrate1To2(aDBConnection) {
|
||||
aDBConnection.executeSimpleSQL("ALTER TABLE groups RENAME TO groupsOld");
|
||||
aDBConnection.createTable("groups", this._dbSchema.tables.groups);
|
||||
aDBConnection.executeSimpleSQL(`
|
||||
@ -1204,14 +1206,19 @@ ContentPrefService.prototype = {
|
||||
|
||||
aDBConnection.executeSimpleSQL("DROP TABLE groupers");
|
||||
aDBConnection.executeSimpleSQL("DROP TABLE groupsOld");
|
||||
|
||||
this._dbCreateIndices(aDBConnection);
|
||||
},
|
||||
|
||||
_dbMigrate2To3: function ContentPrefService__dbMigrate2To3(aDBConnection) {
|
||||
this._dbCreateIndices(aDBConnection);
|
||||
},
|
||||
|
||||
_dbMigrate3To4: function ContentPrefService__dbMigrate3To4(aDBConnection) {
|
||||
aDBConnection.executeSimpleSQL("ALTER TABLE prefs ADD COLUMN timestamp INTEGER NOT NULL DEFAULT 0");
|
||||
// To modify prefs_idx drop it and create again.
|
||||
aDBConnection.executeSimpleSQL("DROP INDEX IF EXISTS prefs_idx");
|
||||
this._dbCreateIndices(aDBConnection);
|
||||
},
|
||||
|
||||
_parseGroupParam: function ContentPrefService__parseGroupParam(aGroup) {
|
||||
if (aGroup == null)
|
||||
return null;
|
||||
|
@ -15,7 +15,7 @@ var next;
|
||||
do_get_profile();
|
||||
})();
|
||||
|
||||
function runAsyncTests(tests) {
|
||||
function runAsyncTests(tests, dontResetBefore = false) {
|
||||
do_test_pending();
|
||||
|
||||
cps = Cc["@mozilla.org/content-pref/service;1"].
|
||||
@ -31,7 +31,7 @@ function runAsyncTests(tests) {
|
||||
asyncRunner = new s.AsyncRunner({
|
||||
done: do_test_finished,
|
||||
error: function (err) {
|
||||
// xpcshell test functions like do_check_eq throw NS_ERROR_ABORT on
|
||||
// xpcshell test functions like equal throw NS_ERROR_ABORT on
|
||||
// failure. Ignore those and catch only uncaught exceptions.
|
||||
if (err !== Cr.NS_ERROR_ABORT) {
|
||||
if (err.stack) {
|
||||
@ -76,21 +76,33 @@ function runAsyncTests(tests) {
|
||||
});
|
||||
|
||||
// reset() ends up calling asyncRunner.next(), starting the tests.
|
||||
reset();
|
||||
if (dontResetBefore) {
|
||||
next();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
function makeCallback(callbacks) {
|
||||
function makeCallback(callbacks, success = null) {
|
||||
callbacks = callbacks || {};
|
||||
["handleResult", "handleError"].forEach(function (meth) {
|
||||
if (!callbacks[meth])
|
||||
callbacks[meth] = function () {
|
||||
do_throw(meth + " shouldn't be called.");
|
||||
};
|
||||
});
|
||||
if (!callbacks.handleError) {
|
||||
callbacks.handleError = function (error) {
|
||||
do_throw("handleError call was not expected, error: " + error);
|
||||
};
|
||||
}
|
||||
if (!callbacks.handleResult) {
|
||||
callbacks.handleResult = function() {
|
||||
do_throw("handleResult call was not expected");
|
||||
};
|
||||
}
|
||||
if (!callbacks.handleCompletion)
|
||||
callbacks.handleCompletion = function (reason) {
|
||||
do_check_eq(reason, Ci.nsIContentPrefCallback2.COMPLETE_OK);
|
||||
next();
|
||||
equal(reason, Ci.nsIContentPrefCallback2.COMPLETE_OK);
|
||||
if (success) {
|
||||
success();
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
return callbacks;
|
||||
}
|
||||
@ -103,7 +115,7 @@ function do_check_throws(fn) {
|
||||
catch (err) {
|
||||
threw = true;
|
||||
}
|
||||
do_check_true(threw);
|
||||
ok(threw);
|
||||
}
|
||||
|
||||
function sendMessage(msg, callback) {
|
||||
@ -117,6 +129,60 @@ function reset() {
|
||||
sendMessage("reset", next);
|
||||
}
|
||||
|
||||
function setWithDate(group, name, val, timestamp, context) {
|
||||
function updateDate() {
|
||||
let db = sendMessage("db");
|
||||
let stmt = db.createAsyncStatement(`
|
||||
UPDATE prefs SET timestamp = :timestamp
|
||||
WHERE
|
||||
settingID = (SELECT id FROM settings WHERE name = :name)
|
||||
AND groupID = (SELECT id FROM groups WHERE name = :group)
|
||||
`);
|
||||
stmt.params.timestamp = timestamp / 1000;
|
||||
stmt.params.name = name;
|
||||
stmt.params.group = group;
|
||||
|
||||
stmt.executeAsync({
|
||||
handleCompletion: function (reason) {
|
||||
next();
|
||||
},
|
||||
handleError: function (err) {
|
||||
do_throw(err);
|
||||
}
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
cps.set(group, name, val, context, makeCallback(null, updateDate));
|
||||
}
|
||||
|
||||
function getDate(group, name, context) {
|
||||
let db = sendMessage("db");
|
||||
let stmt = db.createAsyncStatement(`
|
||||
SELECT timestamp FROM prefs
|
||||
WHERE
|
||||
settingID = (SELECT id FROM settings WHERE name = :name)
|
||||
AND groupID = (SELECT id FROM groups WHERE name = :group)
|
||||
`);
|
||||
stmt.params.name = name;
|
||||
stmt.params.group = group;
|
||||
|
||||
let res;
|
||||
stmt.executeAsync({
|
||||
handleResult: function (results) {
|
||||
let row = results.getNextRow();
|
||||
res = row.getResultByName("timestamp");
|
||||
},
|
||||
handleCompletion: function (reason) {
|
||||
next(res * 1000);
|
||||
},
|
||||
handleError: function (err) {
|
||||
do_throw(err);
|
||||
}
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function set(group, name, val, context) {
|
||||
cps.set(group, name, val, context, makeCallback());
|
||||
}
|
||||
@ -126,13 +192,13 @@ function setGlobal(name, val, context) {
|
||||
}
|
||||
|
||||
function prefOK(actual, expected, strict) {
|
||||
do_check_true(actual instanceof Ci.nsIContentPref);
|
||||
do_check_eq(actual.domain, expected.domain);
|
||||
do_check_eq(actual.name, expected.name);
|
||||
ok(actual instanceof Ci.nsIContentPref);
|
||||
equal(actual.domain, expected.domain);
|
||||
equal(actual.name, expected.name);
|
||||
if (strict)
|
||||
do_check_true(actual.value === expected.value);
|
||||
strictEqual(actual.value, expected.value);
|
||||
else
|
||||
do_check_eq(actual.value, expected.value);
|
||||
equal(actual.value, expected.value);
|
||||
}
|
||||
|
||||
function getOK(args, expectedVal, expectedGroup, strict) {
|
||||
@ -194,7 +260,7 @@ function getCachedSubdomainsOK(args, expectedGroupValPairs) {
|
||||
actualPrefs = actualPrefs.sort(function (a, b) {
|
||||
return a.domain.localeCompare(b.domain);
|
||||
});
|
||||
do_check_eq(actualPrefs.length, len.value);
|
||||
equal(actualPrefs.length, len.value);
|
||||
let expectedPrefs = expectedGroupValPairs.map(function ([group, val]) {
|
||||
return { domain: group, name: args[1], value: val };
|
||||
});
|
||||
@ -217,19 +283,24 @@ function getCachedOKEx(methodName, args, expectedPref, strict) {
|
||||
if (expectedPref)
|
||||
prefOK(actualPref, expectedPref, strict);
|
||||
else
|
||||
do_check_true(actualPref === null);
|
||||
strictEqual(actualPref, null);
|
||||
}
|
||||
|
||||
function arraysOK(actual, expected, cmp) {
|
||||
if (actual.length != expected.length) {
|
||||
do_throw("Length is not equal: " + JSON.stringify(actual) + "==" + JSON.stringify(expected));
|
||||
} else {
|
||||
actual.forEach(function (actualElt, j) {
|
||||
let expectedElt = expected[j];
|
||||
cmp(actualElt, expectedElt);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function arraysOfArraysOK(actual, expected, cmp) {
|
||||
cmp = cmp || function (a, b) do_check_eq(a, b);
|
||||
do_check_eq(actual.length, expected.length);
|
||||
actual.forEach(function (actualChildArr, i) {
|
||||
let expectedChildArr = expected[i];
|
||||
do_check_eq(actualChildArr.length, expectedChildArr.length);
|
||||
actualChildArr.forEach(function (actualElt, j) {
|
||||
let expectedElt = expectedChildArr[j];
|
||||
cmp(actualElt, expectedElt);
|
||||
});
|
||||
cmp = cmp || equal;
|
||||
arraysOK(actual, expected, function (act, exp) {
|
||||
arraysOK(act, exp, cmp)
|
||||
});
|
||||
}
|
||||
|
||||
@ -320,11 +391,16 @@ function on(event, names, dontRemove) {
|
||||
});
|
||||
}
|
||||
|
||||
function schemaVersionIs(expectedVersion) {
|
||||
let db = sendMessage("db");
|
||||
equal(db.schemaVersion, expectedVersion);
|
||||
}
|
||||
|
||||
function wait() {
|
||||
do_execute_soon(next);
|
||||
}
|
||||
|
||||
function observerArgsOK(actualArgs, expectedArgs) {
|
||||
do_check_neq(actualArgs, undefined);
|
||||
notEqual(actualArgs, undefined);
|
||||
arraysOfArraysOK(actualArgs, expectedArgs);
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Dump of version we migrate from
|
||||
let schema_version3 = `
|
||||
PRAGMA foreign_keys=OFF;
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE groups (id INTEGER PRIMARY KEY, name TEXT NOT NULL);
|
||||
INSERT INTO "groups" VALUES(1,'foo.com');
|
||||
INSERT INTO "groups" VALUES(2,'bar.com');
|
||||
|
||||
CREATE TABLE settings (id INTEGER PRIMARY KEY, name TEXT NOT NULL);
|
||||
INSERT INTO "settings" VALUES(1,'zoom-setting');
|
||||
INSERT INTO "settings" VALUES(2,'dir-setting');
|
||||
|
||||
CREATE TABLE prefs (id INTEGER PRIMARY KEY, groupID INTEGER REFERENCES groups(id), settingID INTEGER NOT NULL REFERENCES settings(id), value BLOB);
|
||||
INSERT INTO "prefs" VALUES(1,1,1,0.5);
|
||||
INSERT INTO "prefs" VALUES(2,1,2,'/download/dir');
|
||||
INSERT INTO "prefs" VALUES(3,2,1,0.3);
|
||||
INSERT INTO "prefs" VALUES(4,NULL,1,0.1);
|
||||
|
||||
CREATE INDEX groups_idx ON groups(name);
|
||||
CREATE INDEX settings_idx ON settings(name);
|
||||
CREATE INDEX prefs_idx ON prefs(groupID, settingID);
|
||||
COMMIT;`;
|
||||
|
||||
function prepareVersion3Schema(callback) {
|
||||
var dirService = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
|
||||
var dbFile = dirService.get("ProfD", Ci.nsIFile);
|
||||
dbFile.append("content-prefs.sqlite");
|
||||
|
||||
var dbService = Cc["@mozilla.org/storage/service;1"].
|
||||
getService(Ci.mozIStorageService);
|
||||
ok(!dbFile.exists(), "Db should not exist yet.");
|
||||
|
||||
var dbConnection = dbService.openDatabase(dbFile);
|
||||
equal(dbConnection.schemaVersion, 0);
|
||||
|
||||
dbConnection.executeSimpleSQL(schema_version3);
|
||||
dbConnection.schemaVersion = 3;
|
||||
|
||||
dbConnection.close();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
prepareVersion3Schema();
|
||||
runAsyncTests(tests, true);
|
||||
}
|
||||
|
||||
|
||||
// WARNING: Database will reset after every test. This limitation comes from
|
||||
// the fact that we ContentPrefService constructor is run only once per test file
|
||||
// and so migration will be run only once.
|
||||
let tests = [
|
||||
function testMigration() {
|
||||
// Test migrated db content.
|
||||
schemaVersionIs(4);
|
||||
let dbExpectedState = [
|
||||
[null, "zoom-setting", 0.1],
|
||||
["bar.com", "zoom-setting", 0.3],
|
||||
["foo.com", "zoom-setting", 0.5],
|
||||
["foo.com", "dir-setting", "/download/dir"],
|
||||
];
|
||||
yield dbOK(dbExpectedState);
|
||||
|
||||
// Migrated fields should have timestamp set to 0.
|
||||
yield cps.removeAllDomainsSince(1000, null, makeCallback());
|
||||
yield dbOK(dbExpectedState);
|
||||
|
||||
yield cps.removeAllDomainsSince(0, null, makeCallback());
|
||||
yield dbOK([[null, "zoom-setting", 0.1]]);
|
||||
|
||||
// Test that dates are present after migration (column is added).
|
||||
const timestamp = 1234;
|
||||
yield setWithDate("a.com", "pref-name", "val", timestamp);
|
||||
let actualTimestamp = yield getDate("a.com", "pref-name");
|
||||
equal(actualTimestamp, timestamp);
|
||||
}
|
||||
];
|
@ -69,6 +69,25 @@ let tests = [
|
||||
observerArgsOK(args.bar, []);
|
||||
},
|
||||
|
||||
function observerForName_removeAllDomainsSince() {
|
||||
yield setWithDate("a.com", "foo", 1, 100);
|
||||
yield setWithDate("b.com", "foo", 2, 200);
|
||||
yield setWithDate("c.com", "foo", 3, 300);
|
||||
|
||||
yield setWithDate("a.com", "bar", 1, 000);
|
||||
yield setWithDate("b.com", "bar", 2, 100);
|
||||
yield setWithDate("c.com", "bar", 3, 200);
|
||||
yield setGlobal("foo", 2);
|
||||
|
||||
yield cps.removeAllDomainsSince(200, null, makeCallback());
|
||||
|
||||
let args = yield on("Removed", ["foo", "bar", null]);
|
||||
|
||||
observerArgsOK(args.foo, [["b.com", "foo"], ["c.com", "foo"]]);
|
||||
observerArgsOK(args.bar, [["c.com", "bar"]]);
|
||||
observerArgsOK(args.null, [["b.com", "foo"], ["c.com", "bar"], ["c.com", "foo"]]);
|
||||
},
|
||||
|
||||
function observerForName_removeAllDomains() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield setGlobal("foo", 2);
|
||||
|
@ -0,0 +1,111 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function run_test() {
|
||||
runAsyncTests(tests);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
|
||||
function nonexistent() {
|
||||
yield setGlobal("foo", 1);
|
||||
yield cps.removeAllDomainsSince(0, null, makeCallback());
|
||||
yield getGlobalOK(["foo"], 1);
|
||||
},
|
||||
|
||||
function domainsAll() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
yield set("b.com", "bar", 6);
|
||||
|
||||
yield cps.removeAllDomainsSince(0, null, makeCallback());
|
||||
yield dbOK([
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
]);
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
yield getOK(["b.com", "foo"], undefined);
|
||||
yield getOK(["b.com", "bar"], undefined);
|
||||
},
|
||||
|
||||
function domainsWithDate() {
|
||||
yield setWithDate("a.com", "foobar", 0, 0);
|
||||
yield setWithDate("a.com", "foo", 1, 1000);
|
||||
yield setWithDate("a.com", "bar", 2, 4000);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield setWithDate("b.com", "foo", 5, 2000);
|
||||
yield setWithDate("b.com", "bar", 6, 3000);
|
||||
yield setWithDate("b.com", "foobar", 7, 1000);
|
||||
|
||||
yield cps.removeAllDomainsSince(2000, null, makeCallback());
|
||||
yield dbOK([
|
||||
["a.com", "foobar", 0],
|
||||
["a.com", "foo", 1],
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
["b.com", "foobar", 7],
|
||||
]);
|
||||
},
|
||||
|
||||
function privateBrowsing() {
|
||||
yield set("a.com", "foo", 1);
|
||||
yield set("a.com", "bar", 2);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield set("b.com", "foo", 5);
|
||||
|
||||
let context = { usePrivateBrowsing: true };
|
||||
yield set("a.com", "foo", 6, context);
|
||||
yield setGlobal("foo", 7, context);
|
||||
yield cps.removeAllDomainsSince(0, context, makeCallback());
|
||||
yield dbOK([
|
||||
[null, "foo", 3],
|
||||
[null, "bar", 4],
|
||||
]);
|
||||
yield getOK(["a.com", "foo", context], undefined);
|
||||
yield getOK(["a.com", "bar", context], undefined);
|
||||
yield getGlobalOK(["foo", context], 7);
|
||||
yield getGlobalOK(["bar", context], 4);
|
||||
yield getOK(["b.com", "foo", context], undefined);
|
||||
|
||||
yield getOK(["a.com", "foo"], undefined);
|
||||
yield getOK(["a.com", "bar"], undefined);
|
||||
yield getGlobalOK(["foo"], 3);
|
||||
yield getGlobalOK(["bar"], 4);
|
||||
yield getOK(["b.com", "foo"], undefined);
|
||||
},
|
||||
|
||||
function erroneous() {
|
||||
do_check_throws(function () cps.removeAllDomainsSince(null, "bogus"));
|
||||
yield true;
|
||||
},
|
||||
|
||||
function invalidateCache() {
|
||||
yield setWithDate("a.com", "foobar", 0, 0);
|
||||
yield setWithDate("a.com", "foo", 1, 1000);
|
||||
yield setWithDate("a.com", "bar", 2, 4000);
|
||||
yield setGlobal("foo", 3);
|
||||
yield setGlobal("bar", 4);
|
||||
yield setWithDate("b.com", "foo", 5, 2000);
|
||||
yield setWithDate("b.com", "bar", 6, 3000);
|
||||
yield setWithDate("b.com", "foobar", 7, 1000);
|
||||
cps.removeAllDomainsSince(0, null, makeCallback());
|
||||
getCachedOK(["a.com", "foobar"], false);
|
||||
getCachedOK(["a.com", "foo"], false);
|
||||
getCachedOK(["a.com", "bar"], false);
|
||||
getCachedGlobalOK(["foo"], true, 3);
|
||||
getCachedGlobalOK(["bar"], true, 4);
|
||||
getCachedOK(["b.com", "foo"], false);
|
||||
getCachedOK(["b.com", "bar"], false);
|
||||
getCachedOK(["b.com", "foobar"], false);
|
||||
yield true;
|
||||
},
|
||||
];
|
@ -191,5 +191,18 @@ let tests = [
|
||||
{"domain": null, "name": "foo", "value": 4},
|
||||
{"domain": "b.com", "name": "foo", "value": 5}
|
||||
]);
|
||||
}
|
||||
},
|
||||
|
||||
function setSetsCurrentDate() {
|
||||
// Because Date.now() is not guaranteed to be monotonically increasing
|
||||
// we just do here rough sanity check with one minute tolerance.
|
||||
const MINUTE = 60 * 1000;
|
||||
let now = Date.now();
|
||||
let start = now - MINUTE;
|
||||
let end = now + MINUTE;
|
||||
yield set("a.com", "foo", 1);
|
||||
let timestamp = yield getDate("a.com", "foo");
|
||||
ok(start <= timestamp, "Timestamp is not too early (" + start + "<=" + timestamp + ").");
|
||||
ok(timestamp <= end, "Timestamp is not too late (" + timestamp + "<=" + end + ").");
|
||||
},
|
||||
];
|
||||
|
@ -14,3 +14,5 @@ support-files = AsyncRunner.jsm
|
||||
[test_getCachedSubdomains.js]
|
||||
[test_observers.js]
|
||||
[test_extractDomain.js]
|
||||
[test_migrationToSchema4.js]
|
||||
[test_removeAllDomainsSince.js]
|
||||
|
Loading…
Reference in New Issue
Block a user