From 39cab5722d1a9d8582ac50aeea7c7a648618c6c8 Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Tue, 19 Apr 2011 12:56:46 -0700 Subject: [PATCH] Bug 650208: add test for freshStart behavior, improve collection tracking in tests. r=philiKON --- services/sync/modules/service.js | 1 + services/sync/tests/unit/head_http_server.js | 28 +++++-- .../tests/unit/test_collections_recovery.js | 78 +++++++++++++++++++ 3 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 services/sync/tests/unit/test_collections_recovery.js diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index df047755d4be..1bee3b8a4424 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -970,6 +970,7 @@ WeaveSvc.prototype = { } this._log.info("Got status " + uploadRes.status + " uploading keys."); let serverModified = uploadRes.obj; // Modified timestamp according to server. + this._log.debug("Server reports crypto modified: " + serverModified); // Now verify that info/collections shows them! this._log.debug("Verifying server collection records."); diff --git a/services/sync/tests/unit/head_http_server.js b/services/sync/tests/unit/head_http_server.js index 3669e2ae0ca7..0c9e62f4882a 100644 --- a/services/sync/tests/unit/head_http_server.js +++ b/services/sync/tests/unit/head_http_server.js @@ -87,6 +87,9 @@ ServerWBO.prototype = { delete this.modified; }, + // This handler sets `newModified` on the response body if the collection + // timestamp has changed. This allows wrapper handlers to extract information + // that otherwise would exist only in the body stream. handler: function() { let self = this; @@ -109,11 +112,14 @@ ServerWBO.prototype = { case "PUT": self.put(readBytesFromInputStream(request.bodyInputStream)); body = JSON.stringify(self.modified); + response.newModified = self.modified; break; case "DELETE": self.delete(); - body = JSON.stringify(new_timestamp()); + let ts = new_timestamp(); + body = JSON.stringify(ts); + response.newModified = ts; break; } response.setHeader("X-Weave-Timestamp", "" + new_timestamp(), false); @@ -217,6 +223,8 @@ ServerCollection.prototype = { } }, + // This handler sets `newModified` on the response body if the collection + // timestamp has changed. handler: function() { let self = this; @@ -256,11 +264,14 @@ ServerCollection.prototype = { case "POST": let res = self.post(readBytesFromInputStream(request.bodyInputStream)); body = JSON.stringify(res); + response.newModified = res.modified; break; case "DELETE": self.delete(options); - body = JSON.stringify(new_timestamp()); + let ts = new_timestamp(); + body = JSON.stringify(ts); + response.newModified = ts; break; } response.setHeader("X-Weave-Timestamp", @@ -295,8 +306,9 @@ function track_collections_helper() { /* * Update the timestamp of a collection. */ - function update_collection(coll) { - let timestamp = new_timestamp(); + function update_collection(coll, ts) { + _("Updating collection " + coll + " to " + ts); + let timestamp = ts || new_timestamp(); collections[coll] = timestamp; } @@ -306,9 +318,13 @@ function track_collections_helper() { */ function with_updated_collection(coll, f) { return function(request, response) { - if (request.method != "GET") - update_collection(coll); f.call(this, request, response); + + // Update the collection timestamp to the appropriate modified time. + // This is either a value set by the handler, or the current time. + if (request.method != "GET") { + update_collection(coll, response.newModified) + } }; } diff --git a/services/sync/tests/unit/test_collections_recovery.js b/services/sync/tests/unit/test_collections_recovery.js new file mode 100644 index 000000000000..14eba948608f --- /dev/null +++ b/services/sync/tests/unit/test_collections_recovery.js @@ -0,0 +1,78 @@ +// Verify that we wipe the server if we have to regenerate keys. +Cu.import("resource://services-sync/service.js"); + +add_test(function test_missing_crypto_collection() { + let johnHelper = track_collections_helper(); + let johnU = johnHelper.with_updated_collection; + let johnColls = johnHelper.collections; + + let empty = false; + function maybe_empty(handler) { + return function (request, response) { + if (empty) { + let body = "{}"; + response.setStatusLine(request.httpVersion, 200, "OK"); + response.bodyOutputStream.write(body, body.length); + } else { + handler(request, response); + } + }; + } + + Service.serverURL = "http://localhost:8080/"; + Service.clusterURL = "http://localhost:8080/"; + Service.username = "johndoe"; + Service.password = "ilovejane"; + Service.passphrase = "a-aaaaa-aaaaa-aaaaa-aaaaa-aaaaa"; + + let handlers = { + "/1.1/johndoe/info/collections": maybe_empty(johnHelper.handler), + "/1.1/johndoe/storage/crypto/keys": johnU("crypto", new ServerWBO("keys").handler()), + "/1.1/johndoe/storage/meta/global": johnU("meta", new ServerWBO("global").handler()) + }; + let collections = ["clients", "bookmarks", "forms", "history", + "passwords", "prefs", "tabs"]; + for each (let coll in collections) { + handlers["/1.1/johndoe/storage/" + coll] = + johnU(coll, new ServerCollection({}, true).handler()); + } + let server = httpd_setup(handlers); + + try { + let fresh = 0; + let orig = Service._freshStart; + Service._freshStart = function() { + _("Called _freshStart."); + orig.call(Service); + fresh++; + }; + + _("Startup, no meta/global: freshStart called once."); + Service.sync(); + do_check_eq(fresh, 1); + fresh = 0; + + _("Regular sync: no need to freshStart."); + Service.sync(); + do_check_eq(fresh, 0); + + _("Simulate a bad info/collections."); + delete johnColls.crypto; + Service.sync(); + do_check_eq(fresh, 1); + fresh = 0; + + _("Regular sync: no need to freshStart."); + Service.sync(); + do_check_eq(fresh, 0); + + } finally { + Svc.Prefs.resetBranch(""); + server.stop(run_next_test); + } +}); + +function run_test() { + initTestLogging("Trace"); + run_next_test(); +}