gecko-dev/services/sync/tests/unit/test_addons_store.js

464 строки
13 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://services-common/preferences.js");
Cu.import("resource://services-sync/addonutils.js");
Cu.import("resource://services-sync/engines/addons.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
const HTTP_PORT = 8888;
let prefs = new Preferences();
prefs.set("extensions.getAddons.get.url", "http://localhost:8888/search/guid:%IDS%");
loadAddonTestFunctions();
startupManager();
Service.engineManager.register(AddonsEngine);
let engine = Service.engineManager.get("addons");
let tracker = engine._tracker;
let store = engine._store;
let reconciler = engine._reconciler;
/**
* Create a AddonsRec for this application with the fields specified.
*
* @param id Sync GUID of record
* @param addonId ID of add-on
* @param enabled Boolean whether record is enabled
* @param deleted Boolean whether record was deleted
*/
function createRecordForThisApp(id, addonId, enabled, deleted) {
return {
id: id,
addonID: addonId,
enabled: enabled,
deleted: !!deleted,
applicationID: Services.appinfo.ID,
source: "amo"
};
}
function createAndStartHTTPServer(port) {
try {
let server = new HttpServer();
let bootstrap1XPI = ExtensionsTestPath("/addons/test_bootstrap1_1.xpi");
server.registerFile("/search/guid:bootstrap1%40tests.mozilla.org",
do_get_file("bootstrap1-search.xml"));
server.registerFile("/bootstrap1.xpi", do_get_file(bootstrap1XPI));
server.registerFile("/search/guid:missing-xpi%40tests.mozilla.org",
do_get_file("missing-xpi-search.xml"));
server.start(port);
return server;
} catch (ex) {
_("Got exception starting HTTP server on port " + port);
_("Error: " + Utils.exceptionStr(ex));
do_throw(ex);
}
}
function run_test() {
initTestLogging("Trace");
Log4Moz.repository.getLogger("Sync.Engine.Addons").level = Log4Moz.Level.Trace;
Log4Moz.repository.getLogger("Sync.AddonsRepository").level =
Log4Moz.Level.Trace;
reconciler.startListening();
run_next_test();
}
add_test(function test_remove() {
_("Ensure removing add-ons from deleted records works.");
let addon = installAddon("test_bootstrap1_1");
let record = createRecordForThisApp(addon.syncGUID, addon.id, true, true);
let failed = store.applyIncomingBatch([record]);
do_check_eq(0, failed.length);
let newAddon = getAddonFromAddonManagerByID(addon.id);
do_check_eq(null, newAddon);
run_next_test();
});
add_test(function test_apply_enabled() {
_("Ensures that changes to the userEnabled flag apply.");
let addon = installAddon("test_bootstrap1_1");
do_check_true(addon.isActive);
do_check_false(addon.userDisabled);
_("Ensure application of a disable record works as expected.");
let records = [];
records.push(createRecordForThisApp(addon.syncGUID, addon.id, false, false));
let failed = store.applyIncomingBatch(records);
do_check_eq(0, failed.length);
addon = getAddonFromAddonManagerByID(addon.id);
do_check_true(addon.userDisabled);
records = [];
_("Ensure enable record works as expected.");
records.push(createRecordForThisApp(addon.syncGUID, addon.id, true, false));
failed = store.applyIncomingBatch(records);
do_check_eq(0, failed.length);
addon = getAddonFromAddonManagerByID(addon.id);
do_check_false(addon.userDisabled);
records = [];
_("Ensure enabled state updates don't apply if the ignore pref is set.");
records.push(createRecordForThisApp(addon.syncGUID, addon.id, false, false));
Svc.Prefs.set("addons.ignoreUserEnabledChanges", true);
failed = store.applyIncomingBatch(records);
do_check_eq(0, failed.length);
addon = getAddonFromAddonManagerByID(addon.id);
do_check_false(addon.userDisabled);
records = [];
uninstallAddon(addon);
Svc.Prefs.reset("addons.ignoreUserEnabledChanges");
run_next_test();
});
add_test(function test_ignore_different_appid() {
_("Ensure that incoming records with a different application ID are ignored.");
// We test by creating a record that should result in an update.
let addon = installAddon("test_bootstrap1_1");
do_check_false(addon.userDisabled);
let record = createRecordForThisApp(addon.syncGUID, addon.id, false, false);
record.applicationID = "FAKE_ID";
let failed = store.applyIncomingBatch([record]);
do_check_eq(0, failed.length);
let newAddon = getAddonFromAddonManagerByID(addon.id);
do_check_false(addon.userDisabled);
uninstallAddon(addon);
run_next_test();
});
add_test(function test_ignore_unknown_source() {
_("Ensure incoming records with unknown source are ignored.");
let addon = installAddon("test_bootstrap1_1");
let record = createRecordForThisApp(addon.syncGUID, addon.id, false, false);
record.source = "DUMMY_SOURCE";
let failed = store.applyIncomingBatch([record]);
do_check_eq(0, failed.length);
let newAddon = getAddonFromAddonManagerByID(addon.id);
do_check_false(addon.userDisabled);
uninstallAddon(addon);
run_next_test();
});
add_test(function test_apply_uninstall() {
_("Ensures that uninstalling an add-on from a record works.");
let addon = installAddon("test_bootstrap1_1");
let records = [];
records.push(createRecordForThisApp(addon.syncGUID, addon.id, true, true));
let failed = store.applyIncomingBatch(records);
do_check_eq(0, failed.length);
addon = getAddonFromAddonManagerByID(addon.id);
do_check_eq(null, addon);
run_next_test();
});
add_test(function test_addon_syncability() {
_("Ensure isAddonSyncable functions properly.");
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
Svc.Prefs.set("addons.trustedSourceHostnames",
"addons.mozilla.org,other.example.com");
do_check_false(store.isAddonSyncable(null));
let addon = installAddon("test_bootstrap1_1");
do_check_true(store.isAddonSyncable(addon));
let dummy = {};
const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"];
for each (let k in KEYS) {
dummy[k] = addon[k];
}
do_check_true(store.isAddonSyncable(dummy));
dummy.type = "UNSUPPORTED";
do_check_false(store.isAddonSyncable(dummy));
dummy.type = addon.type;
dummy.scope = 0;
do_check_false(store.isAddonSyncable(dummy));
dummy.scope = addon.scope;
dummy.foreignInstall = true;
do_check_false(store.isAddonSyncable(dummy));
dummy.foreignInstall = false;
uninstallAddon(addon);
do_check_false(store.isSourceURITrusted(null));
function createURI(s) {
let service = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
return service.newURI(s, null, null);
}
let trusted = [
"https://addons.mozilla.org/foo",
"https://other.example.com/foo"
];
let untrusted = [
"http://addons.mozilla.org/foo", // non-https
"ftps://addons.mozilla.org/foo", // non-https
"https://untrusted.example.com/foo", // non-trusted hostname`
];
for each (let uri in trusted) {
do_check_true(store.isSourceURITrusted(createURI(uri)));
}
for each (let uri in untrusted) {
do_check_false(store.isSourceURITrusted(createURI(uri)));
}
Svc.Prefs.set("addons.trustedSourceHostnames", "");
for each (let uri in trusted) {
do_check_false(store.isSourceURITrusted(createURI(uri)));
}
Svc.Prefs.set("addons.trustedSourceHostnames", "addons.mozilla.org");
do_check_true(store.isSourceURITrusted(createURI("https://addons.mozilla.org/foo")));
Svc.Prefs.reset("addons.trustedSourceHostnames");
run_next_test();
});
add_test(function test_ignore_hotfixes() {
_("Ensure that hotfix extensions are ignored.");
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
// A hotfix extension is one that has the id the same as the
// extensions.hotfix.id pref.
let prefs = new Preferences("extensions.");
let addon = installAddon("test_bootstrap1_1");
do_check_true(store.isAddonSyncable(addon));
let dummy = {};
const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"];
for each (let k in KEYS) {
dummy[k] = addon[k];
}
// Basic sanity check.
do_check_true(store.isAddonSyncable(dummy));
prefs.set("hotfix.id", dummy.id);
do_check_false(store.isAddonSyncable(dummy));
// Verify that int values don't throw off checking.
let prefSvc = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.getBranch("extensions.");
// Need to delete pref before changing type.
prefSvc.deleteBranch("hotfix.id");
prefSvc.setIntPref("hotfix.id", 0xdeadbeef);
do_check_true(store.isAddonSyncable(dummy));
uninstallAddon(addon);
Svc.Prefs.reset("addons.ignoreRepositoryChecking");
prefs.reset("hotfix.id");
run_next_test();
});
add_test(function test_get_all_ids() {
_("Ensures that getAllIDs() returns an appropriate set.");
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
_("Installing two addons.");
let addon1 = installAddon("test_install1");
let addon2 = installAddon("test_bootstrap1_1");
_("Ensure they're syncable.");
do_check_true(store.isAddonSyncable(addon1));
do_check_true(store.isAddonSyncable(addon2));
let ids = store.getAllIDs();
do_check_eq("object", typeof(ids));
do_check_eq(2, Object.keys(ids).length);
do_check_true(addon1.syncGUID in ids);
do_check_true(addon2.syncGUID in ids);
addon1.install.cancel();
uninstallAddon(addon2);
Svc.Prefs.reset("addons.ignoreRepositoryChecking");
run_next_test();
});
add_test(function test_change_item_id() {
_("Ensures that changeItemID() works properly.");
let addon = installAddon("test_bootstrap1_1");
let oldID = addon.syncGUID;
let newID = Utils.makeGUID();
store.changeItemID(oldID, newID);
let newAddon = getAddonFromAddonManagerByID(addon.id);
do_check_neq(null, newAddon);
do_check_eq(newID, newAddon.syncGUID);
uninstallAddon(newAddon);
run_next_test();
});
add_test(function test_create() {
_("Ensure creating/installing an add-on from a record works.");
// Set this so that getInstallFromSearchResult doesn't end up
// failing the install due to an insecure source URI scheme.
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
let server = createAndStartHTTPServer(HTTP_PORT);
let addon = installAddon("test_bootstrap1_1");
let id = addon.id;
uninstallAddon(addon);
let guid = Utils.makeGUID();
let record = createRecordForThisApp(guid, id, true, false);
let failed = store.applyIncomingBatch([record]);
do_check_eq(0, failed.length);
let newAddon = getAddonFromAddonManagerByID(id);
do_check_neq(null, newAddon);
do_check_eq(guid, newAddon.syncGUID);
do_check_false(newAddon.userDisabled);
uninstallAddon(newAddon);
Svc.Prefs.reset("addons.ignoreRepositoryChecking");
server.stop(run_next_test);
});
add_test(function test_create_missing_search() {
_("Ensures that failed add-on searches are handled gracefully.");
let server = createAndStartHTTPServer(HTTP_PORT);
// The handler for this ID is not installed, so a search should 404.
const id = "missing@tests.mozilla.org";
let guid = Utils.makeGUID();
let record = createRecordForThisApp(guid, id, true, false);
let failed = store.applyIncomingBatch([record]);
do_check_eq(1, failed.length);
do_check_eq(guid, failed[0]);
let addon = getAddonFromAddonManagerByID(id);
do_check_eq(null, addon);
server.stop(run_next_test);
});
add_test(function test_create_bad_install() {
_("Ensures that add-ons without a valid install are handled gracefully.");
let server = createAndStartHTTPServer(HTTP_PORT);
// The handler returns a search result but the XPI will 404.
const id = "missing-xpi@tests.mozilla.org";
let guid = Utils.makeGUID();
let record = createRecordForThisApp(guid, id, true, false);
let failed = store.applyIncomingBatch([record]);
do_check_eq(1, failed.length);
do_check_eq(guid, failed[0]);
let addon = getAddonFromAddonManagerByID(id);
do_check_eq(null, addon);
server.stop(run_next_test);
});
add_test(function test_wipe() {
_("Ensures that wiping causes add-ons to be uninstalled.");
let addon1 = installAddon("test_bootstrap1_1");
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
store.wipe();
let addon = getAddonFromAddonManagerByID(addon1.id);
do_check_eq(null, addon);
Svc.Prefs.reset("addons.ignoreRepositoryChecking");
run_next_test();
});
add_test(function test_wipe_and_install() {
_("Ensure wipe followed by install works.");
// This tests the reset sync flow where remote data is replaced by local. The
// receiving client will see a wipe followed by a record which should undo
// the wipe.
let installed = installAddon("test_bootstrap1_1");
let record = createRecordForThisApp(installed.syncGUID, installed.id, true,
false);
Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
store.wipe();
let deleted = getAddonFromAddonManagerByID(installed.id);
do_check_null(deleted);
// Re-applying the record can require re-fetching the XPI.
let server = createAndStartHTTPServer(HTTP_PORT);
store.applyIncoming(record);
let fetched = getAddonFromAddonManagerByID(record.addonID);
do_check_true(!!fetched);
Svc.Prefs.reset("addons.ignoreRepositoryChecking");
server.stop(run_next_test);
});