Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
4 Cu.import("resource://services-sync/engines.js");
5 Cu.import("resource://services-sync/service.js");
6 Cu.import("resource://services-sync/util.js");
7 Cu.import("resource://testing-common/services/sync/rotaryengine.js");
8 Cu.import("resource://testing-common/services/sync/utils.js");
10 // Track HMAC error counts.
11 let hmacErrorCount = 0;
12 (function () {
13 let hHE = Service.handleHMACEvent;
14 Service.handleHMACEvent = function () {
15 hmacErrorCount++;
16 return hHE.call(Service);
17 };
18 })();
20 function shared_setup() {
21 hmacErrorCount = 0;
23 // Do not instantiate SyncTestingInfrastructure; we need real crypto.
24 ensureLegacyIdentityManager();
25 setBasicCredentials("foo", "foo", "aabcdeabcdeabcdeabcdeabcde");
27 // Make sure RotaryEngine is the only one we sync.
28 Service.engineManager._engines = {};
29 Service.engineManager.register(RotaryEngine);
30 let engine = Service.engineManager.get("rotary");
31 engine.enabled = true;
32 engine.lastSync = 123; // Needs to be non-zero so that tracker is queried.
33 engine._store.items = {flying: "LNER Class A3 4472",
34 scotsman: "Flying Scotsman"};
35 engine._tracker.addChangedID('scotsman', 0);
36 do_check_eq(1, Service.engineManager.getEnabled().length);
38 let engines = {rotary: {version: engine.version,
39 syncID: engine.syncID},
40 clients: {version: Service.clientsEngine.version,
41 syncID: Service.clientsEngine.syncID}};
43 // Common server objects.
44 let global = new ServerWBO("global", {engines: engines});
45 let keysWBO = new ServerWBO("keys");
46 let rotaryColl = new ServerCollection({}, true);
47 let clientsColl = new ServerCollection({}, true);
49 return [engine, rotaryColl, clientsColl, keysWBO, global];
50 }
52 add_test(function hmac_error_during_404() {
53 _("Attempt to replicate the HMAC error setup.");
54 let [engine, rotaryColl, clientsColl, keysWBO, global] = shared_setup();
56 // Hand out 404s for crypto/keys.
57 let keysHandler = keysWBO.handler();
58 let key404Counter = 0;
59 let keys404Handler = function (request, response) {
60 if (key404Counter > 0) {
61 let body = "Not Found";
62 response.setStatusLine(request.httpVersion, 404, body);
63 response.bodyOutputStream.write(body, body.length);
64 key404Counter--;
65 return;
66 }
67 keysHandler(request, response);
68 };
70 let collectionsHelper = track_collections_helper();
71 let upd = collectionsHelper.with_updated_collection;
72 let collections = collectionsHelper.collections;
73 let handlers = {
74 "/1.1/foo/info/collections": collectionsHelper.handler,
75 "/1.1/foo/storage/meta/global": upd("meta", global.handler()),
76 "/1.1/foo/storage/crypto/keys": upd("crypto", keys404Handler),
77 "/1.1/foo/storage/clients": upd("clients", clientsColl.handler()),
78 "/1.1/foo/storage/rotary": upd("rotary", rotaryColl.handler())
79 };
81 let server = sync_httpd_setup(handlers);
82 Service.serverURL = server.baseURI;
84 try {
85 _("Syncing.");
86 Service.sync();
87 _("Partially resetting client, as if after a restart, and forcing redownload.");
88 Service.collectionKeys.clear();
89 engine.lastSync = 0; // So that we redownload records.
90 key404Counter = 1;
91 _("---------------------------");
92 Service.sync();
93 _("---------------------------");
95 // Two rotary items, one client record... no errors.
96 do_check_eq(hmacErrorCount, 0)
97 } finally {
98 Svc.Prefs.resetBranch("");
99 Service.recordManager.clearCache();
100 server.stop(run_next_test);
101 }
102 });
104 add_test(function hmac_error_during_node_reassignment() {
105 _("Attempt to replicate an HMAC error during node reassignment.");
106 let [engine, rotaryColl, clientsColl, keysWBO, global] = shared_setup();
108 let collectionsHelper = track_collections_helper();
109 let upd = collectionsHelper.with_updated_collection;
111 // We'll provide a 401 mid-way through the sync. This function
112 // simulates shifting to a node which has no data.
113 function on401() {
114 _("Deleting server data...");
115 global.delete();
116 rotaryColl.delete();
117 keysWBO.delete();
118 clientsColl.delete();
119 delete collectionsHelper.collections.rotary;
120 delete collectionsHelper.collections.crypto;
121 delete collectionsHelper.collections.clients;
122 _("Deleted server data.");
123 }
125 let should401 = false;
126 function upd401(coll, handler) {
127 return function (request, response) {
128 if (should401 && (request.method != "DELETE")) {
129 on401();
130 should401 = false;
131 let body = "\"reassigned!\"";
132 response.setStatusLine(request.httpVersion, 401, "Node reassignment.");
133 response.bodyOutputStream.write(body, body.length);
134 return;
135 }
136 handler(request, response);
137 };
138 }
140 function sameNodeHandler(request, response) {
141 // Set this so that _setCluster will think we've really changed.
142 let url = Service.serverURL.replace("localhost", "LOCALHOST");
143 _("Client requesting reassignment; pointing them to " + url);
144 response.setStatusLine(request.httpVersion, 200, "OK");
145 response.bodyOutputStream.write(url, url.length);
146 }
148 let handlers = {
149 "/user/1.0/foo/node/weave": sameNodeHandler,
150 "/1.1/foo/info/collections": collectionsHelper.handler,
151 "/1.1/foo/storage/meta/global": upd("meta", global.handler()),
152 "/1.1/foo/storage/crypto/keys": upd("crypto", keysWBO.handler()),
153 "/1.1/foo/storage/clients": upd401("clients", clientsColl.handler()),
154 "/1.1/foo/storage/rotary": upd("rotary", rotaryColl.handler())
155 };
157 let server = sync_httpd_setup(handlers);
158 Service.serverURL = server.baseURI;
159 _("Syncing.");
160 // First hit of clients will 401. This will happen after meta/global and
161 // keys -- i.e., in the middle of the sync, but before RotaryEngine.
162 should401 = true;
164 // Use observers to perform actions when our sync finishes.
165 // This allows us to observe the automatic next-tick sync that occurs after
166 // an abort.
167 function onSyncError() {
168 do_throw("Should not get a sync error!");
169 }
170 function onSyncFinished() {}
171 let obs = {
172 observe: function observe(subject, topic, data) {
173 switch (topic) {
174 case "weave:service:sync:error":
175 onSyncError();
176 break;
177 case "weave:service:sync:finish":
178 onSyncFinished();
179 break;
180 }
181 }
182 };
184 Svc.Obs.add("weave:service:sync:finish", obs);
185 Svc.Obs.add("weave:service:sync:error", obs);
187 // This kicks off the actual test. Split into a function here to allow this
188 // source file to broadly follow actual execution order.
189 function onwards() {
190 _("== Invoking first sync.");
191 Service.sync();
192 _("We should not simultaneously have data but no keys on the server.");
193 let hasData = rotaryColl.wbo("flying") ||
194 rotaryColl.wbo("scotsman");
195 let hasKeys = keysWBO.modified;
197 _("We correctly handle 401s by aborting the sync and starting again.");
198 do_check_true(!hasData == !hasKeys);
200 _("Be prepared for the second (automatic) sync...");
201 }
203 _("Make sure that syncing again causes recovery.");
204 onSyncFinished = function() {
205 _("== First sync done.");
206 _("---------------------------");
207 onSyncFinished = function() {
208 _("== Second (automatic) sync done.");
209 hasData = rotaryColl.wbo("flying") ||
210 rotaryColl.wbo("scotsman");
211 hasKeys = keysWBO.modified;
212 do_check_true(!hasData == !hasKeys);
214 // Kick off another sync. Can't just call it, because we're inside the
215 // lock...
216 Utils.nextTick(function() {
217 _("Now a fresh sync will get no HMAC errors.");
218 _("Partially resetting client, as if after a restart, and forcing redownload.");
219 Service.collectionKeys.clear();
220 engine.lastSync = 0;
221 hmacErrorCount = 0;
223 onSyncFinished = function() {
224 // Two rotary items, one client record... no errors.
225 do_check_eq(hmacErrorCount, 0)
227 Svc.Obs.remove("weave:service:sync:finish", obs);
228 Svc.Obs.remove("weave:service:sync:error", obs);
230 Svc.Prefs.resetBranch("");
231 Service.recordManager.clearCache();
232 server.stop(run_next_test);
233 };
235 Service.sync();
236 },
237 this);
238 };
239 };
241 onwards();
242 });
244 function run_test() {
245 initTestLogging("Trace");
246 run_next_test();
247 }