services/sync/tests/unit/test_service_login.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/services/sync/tests/unit/test_service_login.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,245 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 +   http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +Cu.import("resource://gre/modules/Log.jsm");
     1.8 +Cu.import("resource://services-sync/constants.js");
     1.9 +Cu.import("resource://services-sync/service.js");
    1.10 +Cu.import("resource://services-sync/policies.js");
    1.11 +Cu.import("resource://services-sync/util.js");
    1.12 +Cu.import("resource://testing-common/services/sync/utils.js");
    1.13 +
    1.14 +function login_handling(handler) {
    1.15 +  return function (request, response) {
    1.16 +    if (basic_auth_matches(request, "johndoe", "ilovejane") ||
    1.17 +        basic_auth_matches(request, "janedoe", "ilovejohn")) {
    1.18 +      handler(request, response);
    1.19 +    } else {
    1.20 +      let body = "Unauthorized";
    1.21 +      response.setStatusLine(request.httpVersion, 401, "Unauthorized");
    1.22 +      response.setHeader("Content-Type", "text/plain");
    1.23 +      response.bodyOutputStream.write(body, body.length);
    1.24 +    }
    1.25 +  };
    1.26 +}
    1.27 +
    1.28 +function run_test() {
    1.29 +  let logger = Log.repository.rootLogger;
    1.30 +  Log.repository.rootLogger.addAppender(new Log.DumpAppender());
    1.31 +
    1.32 +  run_next_test();
    1.33 +}
    1.34 +
    1.35 +add_test(function test_offline() {
    1.36 +  try {
    1.37 +    _("The right bits are set when we're offline.");
    1.38 +    Services.io.offline = true;
    1.39 +    do_check_false(!!Service.login());
    1.40 +    do_check_eq(Service.status.login, LOGIN_FAILED_NETWORK_ERROR);
    1.41 +    Services.io.offline = false;
    1.42 +  } finally {
    1.43 +    Svc.Prefs.resetBranch("");
    1.44 +    run_next_test();
    1.45 +  }
    1.46 +});
    1.47 +
    1.48 +function setup() {
    1.49 +  let janeHelper = track_collections_helper();
    1.50 +  let janeU      = janeHelper.with_updated_collection;
    1.51 +  let janeColls  = janeHelper.collections;
    1.52 +  let johnHelper = track_collections_helper();
    1.53 +  let johnU      = johnHelper.with_updated_collection;
    1.54 +  let johnColls  = johnHelper.collections;
    1.55 +
    1.56 +  let server = httpd_setup({
    1.57 +    "/1.1/johndoe/info/collections": login_handling(johnHelper.handler),
    1.58 +    "/1.1/janedoe/info/collections": login_handling(janeHelper.handler),
    1.59 +
    1.60 +    // We need these handlers because we test login, and login
    1.61 +    // is where keys are generated or fetched.
    1.62 +    // TODO: have Jane fetch her keys, not generate them...
    1.63 +    "/1.1/johndoe/storage/crypto/keys": johnU("crypto", new ServerWBO("keys").handler()),
    1.64 +    "/1.1/johndoe/storage/meta/global": johnU("meta",   new ServerWBO("global").handler()),
    1.65 +    "/1.1/janedoe/storage/crypto/keys": janeU("crypto", new ServerWBO("keys").handler()),
    1.66 +    "/1.1/janedoe/storage/meta/global": janeU("meta",   new ServerWBO("global").handler())
    1.67 +  });
    1.68 +
    1.69 +  Service.serverURL = server.baseURI;
    1.70 +  return server;
    1.71 +}
    1.72 +
    1.73 +add_test(function test_login_logout() {
    1.74 +  let server = setup();
    1.75 +
    1.76 +  try {
    1.77 +    _("Force the initial state.");
    1.78 +    ensureLegacyIdentityManager();
    1.79 +    Service.status.service = STATUS_OK;
    1.80 +    do_check_eq(Service.status.service, STATUS_OK);
    1.81 +
    1.82 +    _("Try logging in. It won't work because we're not configured yet.");
    1.83 +    Service.login();
    1.84 +    do_check_eq(Service.status.service, CLIENT_NOT_CONFIGURED);
    1.85 +    do_check_eq(Service.status.login, LOGIN_FAILED_NO_USERNAME);
    1.86 +    do_check_false(Service.isLoggedIn);
    1.87 +
    1.88 +    _("Try again with username and password set.");
    1.89 +    Service.identity.account = "johndoe";
    1.90 +    Service.identity.basicPassword = "ilovejane";
    1.91 +    Service.login();
    1.92 +    do_check_eq(Service.status.service, CLIENT_NOT_CONFIGURED);
    1.93 +    do_check_eq(Service.status.login, LOGIN_FAILED_NO_PASSPHRASE);
    1.94 +    do_check_false(Service.isLoggedIn);
    1.95 +
    1.96 +    _("Success if passphrase is set.");
    1.97 +    Service.identity.syncKey = "foo";
    1.98 +    Service.login();
    1.99 +    do_check_eq(Service.status.service, STATUS_OK);
   1.100 +    do_check_eq(Service.status.login, LOGIN_SUCCEEDED);
   1.101 +    do_check_true(Service.isLoggedIn);
   1.102 +
   1.103 +    _("We can also pass username, password and passphrase to login().");
   1.104 +    Service.login("janedoe", "incorrectpassword", "bar");
   1.105 +    setBasicCredentials("janedoe", "incorrectpassword", "bar");
   1.106 +    do_check_eq(Service.status.service, LOGIN_FAILED);
   1.107 +    do_check_eq(Service.status.login, LOGIN_FAILED_LOGIN_REJECTED);
   1.108 +    do_check_false(Service.isLoggedIn);
   1.109 +
   1.110 +    _("Try again with correct password.");
   1.111 +    Service.login("janedoe", "ilovejohn");
   1.112 +    do_check_eq(Service.status.service, STATUS_OK);
   1.113 +    do_check_eq(Service.status.login, LOGIN_SUCCEEDED);
   1.114 +    do_check_true(Service.isLoggedIn);
   1.115 +
   1.116 +    _("Calling login() with parameters when the client is unconfigured sends notification.");
   1.117 +    let notified = false;
   1.118 +    Svc.Obs.add("weave:service:setup-complete", function() {
   1.119 +      notified = true;
   1.120 +    });
   1.121 +    setBasicCredentials(null, null, null);
   1.122 +    Service.login("janedoe", "ilovejohn", "bar");
   1.123 +    do_check_true(notified);
   1.124 +    do_check_eq(Service.status.service, STATUS_OK);
   1.125 +    do_check_eq(Service.status.login, LOGIN_SUCCEEDED);
   1.126 +    do_check_true(Service.isLoggedIn);
   1.127 +
   1.128 +    _("Logout.");
   1.129 +    Service.logout();
   1.130 +    do_check_false(Service.isLoggedIn);
   1.131 +
   1.132 +    _("Logging out again won't do any harm.");
   1.133 +    Service.logout();
   1.134 +    do_check_false(Service.isLoggedIn);
   1.135 +
   1.136 +  } finally {
   1.137 +    Svc.Prefs.resetBranch("");
   1.138 +    server.stop(run_next_test);
   1.139 +  }
   1.140 +});
   1.141 +
   1.142 +add_test(function test_login_on_sync() {
   1.143 +  let server = setup();
   1.144 +  setBasicCredentials("johndoe", "ilovejane", "bar");
   1.145 +
   1.146 +  try {
   1.147 +    _("Sync calls login.");
   1.148 +    let oldLogin = Service.login;
   1.149 +    let loginCalled = false;
   1.150 +    Service.login = function() {
   1.151 +      loginCalled = true;
   1.152 +      Service.status.login = LOGIN_SUCCEEDED;
   1.153 +      this._loggedIn = false;           // So that sync aborts.
   1.154 +      return true;
   1.155 +    };
   1.156 +
   1.157 +    Service.sync();
   1.158 +
   1.159 +    do_check_true(loginCalled);
   1.160 +    Service.login = oldLogin;
   1.161 +
   1.162 +    // Stub mpLocked.
   1.163 +    let mpLockedF = Utils.mpLocked;
   1.164 +    let mpLocked = true;
   1.165 +    Utils.mpLocked = function() mpLocked;
   1.166 +
   1.167 +    // Stub scheduleNextSync. This gets called within checkSyncStatus if we're
   1.168 +    // ready to sync, so use it as an indicator.
   1.169 +    let scheduleNextSyncF = Service.scheduler.scheduleNextSync;
   1.170 +    let scheduleCalled = false;
   1.171 +    Service.scheduler.scheduleNextSync = function(wait) {
   1.172 +      scheduleCalled = true;
   1.173 +      scheduleNextSyncF.call(this, wait);
   1.174 +    };
   1.175 +
   1.176 +    // Autoconnect still tries to connect in the background (useful behavior:
   1.177 +    // for non-MP users and unlocked MPs, this will detect version expiry
   1.178 +    // earlier).
   1.179 +    //
   1.180 +    // Consequently, non-MP users will be logged in as in the pre-Bug 543784 world,
   1.181 +    // and checkSyncStatus reflects that by waiting for login.
   1.182 +    //
   1.183 +    // This process doesn't apply if your MP is still locked, so we make
   1.184 +    // checkSyncStatus accept a locked MP in place of being logged in.
   1.185 +    //
   1.186 +    // This test exercises these two branches.
   1.187 +
   1.188 +    _("We're ready to sync if locked.");
   1.189 +    Service.enabled = true;
   1.190 +    Services.io.offline = false;
   1.191 +    Service.scheduler.checkSyncStatus();
   1.192 +    do_check_true(scheduleCalled);
   1.193 +
   1.194 +    _("... and also if we're not locked.");
   1.195 +    scheduleCalled = false;
   1.196 +    mpLocked = false;
   1.197 +    Service.scheduler.checkSyncStatus();
   1.198 +    do_check_true(scheduleCalled);
   1.199 +    Service.scheduler.scheduleNextSync = scheduleNextSyncF;
   1.200 +
   1.201 +    // TODO: need better tests around master password prompting. See Bug 620583.
   1.202 +
   1.203 +    mpLocked = true;
   1.204 +
   1.205 +    // Testing exception handling if master password dialog is canceled.
   1.206 +    // Do this by monkeypatching.
   1.207 +    let oldGetter = Service.identity.__lookupGetter__("syncKey");
   1.208 +    let oldSetter = Service.identity.__lookupSetter__("syncKey");
   1.209 +    _("Old passphrase function is " + oldGetter);
   1.210 +    Service.identity.__defineGetter__("syncKey",
   1.211 +                           function() {
   1.212 +                             throw "User canceled Master Password entry";
   1.213 +                           });
   1.214 +
   1.215 +    let oldClearSyncTriggers = Service.scheduler.clearSyncTriggers;
   1.216 +    let oldLockedSync = Service._lockedSync;
   1.217 +
   1.218 +    let cSTCalled = false;
   1.219 +    let lockedSyncCalled = false;
   1.220 +
   1.221 +    Service.scheduler.clearSyncTriggers = function() { cSTCalled = true; };
   1.222 +    Service._lockedSync = function() { lockedSyncCalled = true; };
   1.223 +
   1.224 +    _("If master password is canceled, login fails and we report lockage.");
   1.225 +    do_check_false(!!Service.login());
   1.226 +    do_check_eq(Service.status.login, MASTER_PASSWORD_LOCKED);
   1.227 +    do_check_eq(Service.status.service, LOGIN_FAILED);
   1.228 +    _("Locked? " + Utils.mpLocked());
   1.229 +    _("checkSync reports the correct term.");
   1.230 +    do_check_eq(Service._checkSync(), kSyncMasterPasswordLocked);
   1.231 +
   1.232 +    _("Sync doesn't proceed and clears triggers if MP is still locked.");
   1.233 +    Service.sync();
   1.234 +
   1.235 +    do_check_true(cSTCalled);
   1.236 +    do_check_false(lockedSyncCalled);
   1.237 +
   1.238 +    Service.identity.__defineGetter__("syncKey", oldGetter);
   1.239 +    Service.identity.__defineSetter__("syncKey", oldSetter);
   1.240 +
   1.241 +    // N.B., a bunch of methods are stubbed at this point. Be careful putting
   1.242 +    // new tests after this point!
   1.243 +
   1.244 +  } finally {
   1.245 +    Svc.Prefs.resetBranch("");
   1.246 +    server.stop(run_next_test);
   1.247 +  }
   1.248 +});

mercurial