Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
4 "use strict";
6 Cu.import("resource://gre/modules/AddonManager.jsm");
7 Cu.import("resource://gre/modules/Preferences.jsm");
8 Cu.import("resource://gre/modules/Services.jsm");
9 Cu.import("resource://services-common/async.js");
10 Cu.import("resource://services-sync/addonsreconciler.js");
11 Cu.import("resource://services-sync/engines/addons.js");
12 Cu.import("resource://services-sync/service.js");
13 Cu.import("resource://services-sync/util.js");
14 Cu.import("resource://testing-common/services/sync/utils.js");
16 let prefs = new Preferences();
17 prefs.set("extensions.getAddons.get.url",
18 "http://localhost:8888/search/guid:%IDS%");
20 loadAddonTestFunctions();
21 startupManager();
23 let engineManager = Service.engineManager;
25 engineManager.register(AddonsEngine);
26 let engine = engineManager.get("addons");
27 let reconciler = engine._reconciler;
28 let tracker = engine._tracker;
30 function advance_test() {
31 reconciler._addons = {};
32 reconciler._changes = [];
34 let cb = Async.makeSpinningCallback();
35 reconciler.saveState(null, cb);
36 cb.wait();
38 Svc.Prefs.reset("addons.ignoreRepositoryChecking");
40 run_next_test();
41 }
43 // This is a basic sanity test for the unit test itself. If this breaks, the
44 // add-ons API likely changed upstream.
45 add_test(function test_addon_install() {
46 _("Ensure basic add-on APIs work as expected.");
48 let install = getAddonInstall("test_bootstrap1_1");
49 do_check_neq(install, null);
50 do_check_eq(install.type, "extension");
51 do_check_eq(install.name, "Test Bootstrap 1");
53 advance_test();
54 });
56 add_test(function test_find_dupe() {
57 _("Ensure the _findDupe() implementation is sane.");
59 // This gets invoked at the top of sync, which is bypassed by this
60 // test, so we do it manually.
61 engine._refreshReconcilerState();
63 let addon = installAddon("test_bootstrap1_1");
65 let record = {
66 id: Utils.makeGUID(),
67 addonID: addon.id,
68 enabled: true,
69 applicationID: Services.appinfo.ID,
70 source: "amo"
71 };
73 let dupe = engine._findDupe(record);
74 do_check_eq(addon.syncGUID, dupe);
76 record.id = addon.syncGUID;
77 dupe = engine._findDupe(record);
78 do_check_eq(null, dupe);
80 uninstallAddon(addon);
81 advance_test();
82 });
84 add_test(function test_get_changed_ids() {
85 _("Ensure getChangedIDs() has the appropriate behavior.");
87 _("Ensure getChangedIDs() returns an empty object by default.");
88 let changes = engine.getChangedIDs();
89 do_check_eq("object", typeof(changes));
90 do_check_eq(0, Object.keys(changes).length);
92 _("Ensure tracker changes are populated.");
93 let now = new Date();
94 let changeTime = now.getTime() / 1000;
95 let guid1 = Utils.makeGUID();
96 tracker.addChangedID(guid1, changeTime);
98 changes = engine.getChangedIDs();
99 do_check_eq("object", typeof(changes));
100 do_check_eq(1, Object.keys(changes).length);
101 do_check_true(guid1 in changes);
102 do_check_eq(changeTime, changes[guid1]);
104 tracker.clearChangedIDs();
106 _("Ensure reconciler changes are populated.");
107 Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
108 let addon = installAddon("test_bootstrap1_1");
109 tracker.clearChangedIDs(); // Just in case.
110 changes = engine.getChangedIDs();
111 do_check_eq("object", typeof(changes));
112 do_check_eq(1, Object.keys(changes).length);
113 do_check_true(addon.syncGUID in changes);
114 _("Change time: " + changeTime + ", addon change: " + changes[addon.syncGUID]);
115 do_check_true(changes[addon.syncGUID] >= changeTime);
117 let oldTime = changes[addon.syncGUID];
118 let guid2 = addon.syncGUID;
119 uninstallAddon(addon);
120 changes = engine.getChangedIDs();
121 do_check_eq(1, Object.keys(changes).length);
122 do_check_true(guid2 in changes);
123 do_check_true(changes[guid2] > oldTime);
125 _("Ensure non-syncable add-ons aren't picked up by reconciler changes.");
126 reconciler._addons = {};
127 reconciler._changes = [];
128 let record = {
129 id: "DUMMY",
130 guid: Utils.makeGUID(),
131 enabled: true,
132 installed: true,
133 modified: new Date(),
134 type: "UNSUPPORTED",
135 scope: 0,
136 foreignInstall: false
137 };
138 reconciler.addons["DUMMY"] = record;
139 reconciler._addChange(record.modified, CHANGE_INSTALLED, record);
141 changes = engine.getChangedIDs();
142 _(JSON.stringify(changes));
143 do_check_eq(0, Object.keys(changes).length);
145 advance_test();
146 });
148 add_test(function test_disabled_install_semantics() {
149 _("Ensure that syncing a disabled add-on preserves proper state.");
151 // This is essentially a test for bug 712542, which snuck into the original
152 // add-on sync drop. It ensures that when an add-on is installed that the
153 // disabled state and incoming syncGUID is preserved, even on the next sync.
155 Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
157 const USER = "foo";
158 const PASSWORD = "password";
159 const PASSPHRASE = "abcdeabcdeabcdeabcdeabcdea";
160 const ADDON_ID = "addon1@tests.mozilla.org";
162 let server = new SyncServer();
163 server.start();
164 new SyncTestingInfrastructure(server.server, USER, PASSWORD, PASSPHRASE);
166 generateNewKeys(Service.collectionKeys);
168 let contents = {
169 meta: {global: {engines: {addons: {version: engine.version,
170 syncID: engine.syncID}}}},
171 crypto: {},
172 addons: {}
173 };
175 server.registerUser(USER, "password");
176 server.createContents(USER, contents);
178 let amoServer = new HttpServer();
179 amoServer.registerFile("/search/guid:addon1%40tests.mozilla.org",
180 do_get_file("addon1-search.xml"));
182 let installXPI = ExtensionsTestPath("/addons/test_install1.xpi");
183 amoServer.registerFile("/addon1.xpi", do_get_file(installXPI));
184 amoServer.start(8888);
186 // Insert an existing record into the server.
187 let id = Utils.makeGUID();
188 let now = Date.now() / 1000;
190 let record = encryptPayload({
191 id: id,
192 applicationID: Services.appinfo.ID,
193 addonID: ADDON_ID,
194 enabled: false,
195 deleted: false,
196 source: "amo",
197 });
198 let wbo = new ServerWBO(id, record, now - 2);
199 server.insertWBO(USER, "addons", wbo);
201 _("Performing sync of add-ons engine.");
202 engine._sync();
204 // At this point the non-restartless extension should be staged for install.
206 // Don't need this server any more.
207 let cb = Async.makeSpinningCallback();
208 amoServer.stop(cb);
209 cb.wait();
211 // We ensure the reconciler has recorded the proper ID and enabled state.
212 let addon = reconciler.getAddonStateFromSyncGUID(id);
213 do_check_neq(null, addon);
214 do_check_eq(false, addon.enabled);
216 // We fake an app restart and perform another sync, just to make sure things
217 // are sane.
218 restartManager();
220 engine._sync();
222 // The client should not upload a new record. The old record should be
223 // retained and unmodified.
224 let collection = server.getCollection(USER, "addons");
225 do_check_eq(1, collection.count());
227 let payload = collection.payloads()[0];
228 do_check_neq(null, collection.wbo(id));
229 do_check_eq(ADDON_ID, payload.addonID);
230 do_check_false(payload.enabled);
232 server.stop(advance_test);
233 });
235 add_test(function cleanup() {
236 // There's an xpcom-shutdown hook for this, but let's give this a shot.
237 reconciler.stopListening();
238 run_next_test();
239 });
241 function run_test() {
242 initTestLogging("Trace");
243 Log.repository.getLogger("Sync.Engine.Addons").level =
244 Log.Level.Trace;
245 Log.repository.getLogger("Sync.Store.Addons").level = Log.Level.Trace;
246 Log.repository.getLogger("Sync.Tracker.Addons").level =
247 Log.Level.Trace;
248 Log.repository.getLogger("Sync.AddonsRepository").level =
249 Log.Level.Trace;
251 reconciler.startListening();
253 // Don't flush to disk in the middle of an event listener!
254 // This causes test hangs on WinXP.
255 reconciler._shouldPersist = false;
257 advance_test();
258 }