services/sync/tests/unit/test_hmac_error.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 }

mercurial