Bug 828223 - Write nsSearchService cache with OS.File + nsSearchService cache tests. r=gavin

This commit is contained in:
David Rajchenbach-Teller 2013-02-25 09:07:16 -05:00
parent ead362c499
commit bb5d0c6915
4 changed files with 141 additions and 19 deletions

View File

@ -2664,29 +2664,20 @@ SearchService.prototype = {
cache.directories[cacheKey].engines.push(engine._serializeToJSON(true));
}
let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Ci.nsIScriptableUnicodeConverter);
let cacheFile = getDir(NS_APP_USER_PROFILE_50_DIR);
cacheFile.append("search.json");
try {
LOG("_buildCache: Writing to cache file.");
ostream.init(cacheFile, (MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE), PERMS_FILE, ostream.DEFER_OPEN);
converter.charset = "UTF-8";
let data = converter.convertToInputStream(JSON.stringify(cache));
let path = OS.Path.join(OS.Constants.Path.profileDir, "search.json");
let data = gEncoder.encode(JSON.stringify(cache));
let promise = OS.File.writeAtomic(path, data, { tmpPath: path + ".tmp"});
// Write to the cache file asynchronously
NetUtil.asyncCopy(data, ostream, function(rv) {
if (Components.isSuccessCode(rv)) {
Services.obs.notifyObservers(null,
SEARCH_SERVICE_TOPIC,
SEARCH_SERVICE_CACHE_WRITTEN);
} else {
LOG("_buildCache: failure during asyncCopy: " + rv);
promise.then(
function onSuccess() {
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, SEARCH_SERVICE_CACHE_WRITTEN);
},
function onError(e) {
LOG("_buildCache: failure during writeAtomic: " + e);
}
});
);
} catch (ex) {
LOG("_buildCache: Could not write to cache file: " + ex);
}

View File

@ -51,6 +51,19 @@ function removeCacheFile()
}
}
/**
* Clean the profile of any cache file left from a previous run.
*/
function removeCache()
{
let file = gProfD.clone();
file.append("search.json");
if (file.exists()) {
file.remove(false);
}
}
/**
* Run some callback once metadata has been committed to disk.
*/
@ -67,6 +80,23 @@ function afterCommit(callback)
Services.obs.addObserver(obs, "browser-search-service", false);
}
/**
* Run some callback once cache has been built.
*/
function afterCache(callback)
{
let obs = function(result, topic, verb) {
do_print("afterCache: " + verb);
if (verb == "write-cache-to-disk-complete") {
Services.obs.removeObserver(obs, topic);
callback(result);
} else {
dump("TOPIC: " + topic+ "\n");
}
}
Services.obs.addObserver(obs, "browser-search-service", false);
}
function parseJsonFromStream(aInputStream) {
const json = Cc["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON);
const data = json.decodeFromStream(aInputStream, aInputStream.available());

View File

@ -0,0 +1,100 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let Cu = Components.utils;
let Ci = Components.interfaces;
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://testing-common/httpd.js");
/*
* test_nocache: Start search engine
* - without search.json
*
* Ensure that :
* - nothing explodes;
* - search.json is created.
*/
function run_test()
{
removeCache();
updateAppInfo();
do_load_manifest("data/chrome.manifest");
let httpServer = new HttpServer();
httpServer.start(4444);
httpServer.registerDirectory("/", do_get_cwd());
let search = Services.search;
do_test_pending();
// Check that cache is created at startup
afterCache(function cacheCreated() {
// Check that search.json has been created.
let cache = gProfD.clone();
cache.append("search.json");
do_check_true(cache.exists());
});
// Perform initialization
search.init(function ss_initialized(rv) {
do_check_true(Components.isSuccessCode(rv));
do_print("Setting up observer");
function observer(aSubject, aTopic, aData) {
do_print("Observing topic " + aTopic);
if ("engine-added" == aData) {
let engine = search.getEngineByName("Test search engine");
if (!engine) {
return;
}
Services.obs.removeObserver(observer, "browser-search-engine-modified");
do_print("Engine has been added, let's wait for the cache to be built");
afterCache(function() {
do_print("Success");
Task.spawn(function task() {
do_print("Searching test engine in cache");
try {
let path = OS.Path.join(OS.Constants.Path.profileDir, "search.json");
let data = yield OS.File.read(path);
let text = new TextDecoder().decode(data);
let cache = JSON.parse(text);
let found = false;
for (let dirName in cache.directories) {
for (let engine of cache.directories[dirName].engines) {
if (engine._id == "[app]/test-search-engine.xml") {
found = true;
break;
}
}
if (found) {
break;
}
}
do_check_true(found);
} catch (ex) {
do_throw(ex);
} finally {
removeCache();
httpServer.stop(function() {
// httpServer doesn't seem to stop cleanly if there is no callback
});
do_test_finished();
}
});
});
}
};
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
// Add an engine, check if it appears in the cache
search.addEngine("http://localhost:4444/data/engine.xml",
Ci.nsISearchEngine.DATA_XML,
null, false);
});
}

View File

@ -3,6 +3,7 @@ head = head_search.js
tail =
firefox-appdir = browser
[test_nocache.js]
[test_645970.js]
[test_init_async_multiple.js]
[test_init_async_multiple_then_sync.js]