1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/services/sync/tests/unit/test_addons_engine.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,258 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +"use strict"; 1.8 + 1.9 +Cu.import("resource://gre/modules/AddonManager.jsm"); 1.10 +Cu.import("resource://gre/modules/Preferences.jsm"); 1.11 +Cu.import("resource://gre/modules/Services.jsm"); 1.12 +Cu.import("resource://services-common/async.js"); 1.13 +Cu.import("resource://services-sync/addonsreconciler.js"); 1.14 +Cu.import("resource://services-sync/engines/addons.js"); 1.15 +Cu.import("resource://services-sync/service.js"); 1.16 +Cu.import("resource://services-sync/util.js"); 1.17 +Cu.import("resource://testing-common/services/sync/utils.js"); 1.18 + 1.19 +let prefs = new Preferences(); 1.20 +prefs.set("extensions.getAddons.get.url", 1.21 + "http://localhost:8888/search/guid:%IDS%"); 1.22 + 1.23 +loadAddonTestFunctions(); 1.24 +startupManager(); 1.25 + 1.26 +let engineManager = Service.engineManager; 1.27 + 1.28 +engineManager.register(AddonsEngine); 1.29 +let engine = engineManager.get("addons"); 1.30 +let reconciler = engine._reconciler; 1.31 +let tracker = engine._tracker; 1.32 + 1.33 +function advance_test() { 1.34 + reconciler._addons = {}; 1.35 + reconciler._changes = []; 1.36 + 1.37 + let cb = Async.makeSpinningCallback(); 1.38 + reconciler.saveState(null, cb); 1.39 + cb.wait(); 1.40 + 1.41 + Svc.Prefs.reset("addons.ignoreRepositoryChecking"); 1.42 + 1.43 + run_next_test(); 1.44 +} 1.45 + 1.46 +// This is a basic sanity test for the unit test itself. If this breaks, the 1.47 +// add-ons API likely changed upstream. 1.48 +add_test(function test_addon_install() { 1.49 + _("Ensure basic add-on APIs work as expected."); 1.50 + 1.51 + let install = getAddonInstall("test_bootstrap1_1"); 1.52 + do_check_neq(install, null); 1.53 + do_check_eq(install.type, "extension"); 1.54 + do_check_eq(install.name, "Test Bootstrap 1"); 1.55 + 1.56 + advance_test(); 1.57 +}); 1.58 + 1.59 +add_test(function test_find_dupe() { 1.60 + _("Ensure the _findDupe() implementation is sane."); 1.61 + 1.62 + // This gets invoked at the top of sync, which is bypassed by this 1.63 + // test, so we do it manually. 1.64 + engine._refreshReconcilerState(); 1.65 + 1.66 + let addon = installAddon("test_bootstrap1_1"); 1.67 + 1.68 + let record = { 1.69 + id: Utils.makeGUID(), 1.70 + addonID: addon.id, 1.71 + enabled: true, 1.72 + applicationID: Services.appinfo.ID, 1.73 + source: "amo" 1.74 + }; 1.75 + 1.76 + let dupe = engine._findDupe(record); 1.77 + do_check_eq(addon.syncGUID, dupe); 1.78 + 1.79 + record.id = addon.syncGUID; 1.80 + dupe = engine._findDupe(record); 1.81 + do_check_eq(null, dupe); 1.82 + 1.83 + uninstallAddon(addon); 1.84 + advance_test(); 1.85 +}); 1.86 + 1.87 +add_test(function test_get_changed_ids() { 1.88 + _("Ensure getChangedIDs() has the appropriate behavior."); 1.89 + 1.90 + _("Ensure getChangedIDs() returns an empty object by default."); 1.91 + let changes = engine.getChangedIDs(); 1.92 + do_check_eq("object", typeof(changes)); 1.93 + do_check_eq(0, Object.keys(changes).length); 1.94 + 1.95 + _("Ensure tracker changes are populated."); 1.96 + let now = new Date(); 1.97 + let changeTime = now.getTime() / 1000; 1.98 + let guid1 = Utils.makeGUID(); 1.99 + tracker.addChangedID(guid1, changeTime); 1.100 + 1.101 + changes = engine.getChangedIDs(); 1.102 + do_check_eq("object", typeof(changes)); 1.103 + do_check_eq(1, Object.keys(changes).length); 1.104 + do_check_true(guid1 in changes); 1.105 + do_check_eq(changeTime, changes[guid1]); 1.106 + 1.107 + tracker.clearChangedIDs(); 1.108 + 1.109 + _("Ensure reconciler changes are populated."); 1.110 + Svc.Prefs.set("addons.ignoreRepositoryChecking", true); 1.111 + let addon = installAddon("test_bootstrap1_1"); 1.112 + tracker.clearChangedIDs(); // Just in case. 1.113 + changes = engine.getChangedIDs(); 1.114 + do_check_eq("object", typeof(changes)); 1.115 + do_check_eq(1, Object.keys(changes).length); 1.116 + do_check_true(addon.syncGUID in changes); 1.117 + _("Change time: " + changeTime + ", addon change: " + changes[addon.syncGUID]); 1.118 + do_check_true(changes[addon.syncGUID] >= changeTime); 1.119 + 1.120 + let oldTime = changes[addon.syncGUID]; 1.121 + let guid2 = addon.syncGUID; 1.122 + uninstallAddon(addon); 1.123 + changes = engine.getChangedIDs(); 1.124 + do_check_eq(1, Object.keys(changes).length); 1.125 + do_check_true(guid2 in changes); 1.126 + do_check_true(changes[guid2] > oldTime); 1.127 + 1.128 + _("Ensure non-syncable add-ons aren't picked up by reconciler changes."); 1.129 + reconciler._addons = {}; 1.130 + reconciler._changes = []; 1.131 + let record = { 1.132 + id: "DUMMY", 1.133 + guid: Utils.makeGUID(), 1.134 + enabled: true, 1.135 + installed: true, 1.136 + modified: new Date(), 1.137 + type: "UNSUPPORTED", 1.138 + scope: 0, 1.139 + foreignInstall: false 1.140 + }; 1.141 + reconciler.addons["DUMMY"] = record; 1.142 + reconciler._addChange(record.modified, CHANGE_INSTALLED, record); 1.143 + 1.144 + changes = engine.getChangedIDs(); 1.145 + _(JSON.stringify(changes)); 1.146 + do_check_eq(0, Object.keys(changes).length); 1.147 + 1.148 + advance_test(); 1.149 +}); 1.150 + 1.151 +add_test(function test_disabled_install_semantics() { 1.152 + _("Ensure that syncing a disabled add-on preserves proper state."); 1.153 + 1.154 + // This is essentially a test for bug 712542, which snuck into the original 1.155 + // add-on sync drop. It ensures that when an add-on is installed that the 1.156 + // disabled state and incoming syncGUID is preserved, even on the next sync. 1.157 + 1.158 + Svc.Prefs.set("addons.ignoreRepositoryChecking", true); 1.159 + 1.160 + const USER = "foo"; 1.161 + const PASSWORD = "password"; 1.162 + const PASSPHRASE = "abcdeabcdeabcdeabcdeabcdea"; 1.163 + const ADDON_ID = "addon1@tests.mozilla.org"; 1.164 + 1.165 + let server = new SyncServer(); 1.166 + server.start(); 1.167 + new SyncTestingInfrastructure(server.server, USER, PASSWORD, PASSPHRASE); 1.168 + 1.169 + generateNewKeys(Service.collectionKeys); 1.170 + 1.171 + let contents = { 1.172 + meta: {global: {engines: {addons: {version: engine.version, 1.173 + syncID: engine.syncID}}}}, 1.174 + crypto: {}, 1.175 + addons: {} 1.176 + }; 1.177 + 1.178 + server.registerUser(USER, "password"); 1.179 + server.createContents(USER, contents); 1.180 + 1.181 + let amoServer = new HttpServer(); 1.182 + amoServer.registerFile("/search/guid:addon1%40tests.mozilla.org", 1.183 + do_get_file("addon1-search.xml")); 1.184 + 1.185 + let installXPI = ExtensionsTestPath("/addons/test_install1.xpi"); 1.186 + amoServer.registerFile("/addon1.xpi", do_get_file(installXPI)); 1.187 + amoServer.start(8888); 1.188 + 1.189 + // Insert an existing record into the server. 1.190 + let id = Utils.makeGUID(); 1.191 + let now = Date.now() / 1000; 1.192 + 1.193 + let record = encryptPayload({ 1.194 + id: id, 1.195 + applicationID: Services.appinfo.ID, 1.196 + addonID: ADDON_ID, 1.197 + enabled: false, 1.198 + deleted: false, 1.199 + source: "amo", 1.200 + }); 1.201 + let wbo = new ServerWBO(id, record, now - 2); 1.202 + server.insertWBO(USER, "addons", wbo); 1.203 + 1.204 + _("Performing sync of add-ons engine."); 1.205 + engine._sync(); 1.206 + 1.207 + // At this point the non-restartless extension should be staged for install. 1.208 + 1.209 + // Don't need this server any more. 1.210 + let cb = Async.makeSpinningCallback(); 1.211 + amoServer.stop(cb); 1.212 + cb.wait(); 1.213 + 1.214 + // We ensure the reconciler has recorded the proper ID and enabled state. 1.215 + let addon = reconciler.getAddonStateFromSyncGUID(id); 1.216 + do_check_neq(null, addon); 1.217 + do_check_eq(false, addon.enabled); 1.218 + 1.219 + // We fake an app restart and perform another sync, just to make sure things 1.220 + // are sane. 1.221 + restartManager(); 1.222 + 1.223 + engine._sync(); 1.224 + 1.225 + // The client should not upload a new record. The old record should be 1.226 + // retained and unmodified. 1.227 + let collection = server.getCollection(USER, "addons"); 1.228 + do_check_eq(1, collection.count()); 1.229 + 1.230 + let payload = collection.payloads()[0]; 1.231 + do_check_neq(null, collection.wbo(id)); 1.232 + do_check_eq(ADDON_ID, payload.addonID); 1.233 + do_check_false(payload.enabled); 1.234 + 1.235 + server.stop(advance_test); 1.236 +}); 1.237 + 1.238 +add_test(function cleanup() { 1.239 + // There's an xpcom-shutdown hook for this, but let's give this a shot. 1.240 + reconciler.stopListening(); 1.241 + run_next_test(); 1.242 +}); 1.243 + 1.244 +function run_test() { 1.245 + initTestLogging("Trace"); 1.246 + Log.repository.getLogger("Sync.Engine.Addons").level = 1.247 + Log.Level.Trace; 1.248 + Log.repository.getLogger("Sync.Store.Addons").level = Log.Level.Trace; 1.249 + Log.repository.getLogger("Sync.Tracker.Addons").level = 1.250 + Log.Level.Trace; 1.251 + Log.repository.getLogger("Sync.AddonsRepository").level = 1.252 + Log.Level.Trace; 1.253 + 1.254 + reconciler.startListening(); 1.255 + 1.256 + // Don't flush to disk in the middle of an event listener! 1.257 + // This causes test hangs on WinXP. 1.258 + reconciler._shouldPersist = false; 1.259 + 1.260 + advance_test(); 1.261 +}