Blame services/sync/tests/unit/test_errorhandler_sync_checkServerError.js

Packit f0b94e
/* Any copyright is dedicated to the Public Domain.
Packit f0b94e
   http://creativecommons.org/publicdomain/zero/1.0/ */
Packit f0b94e
Packit f0b94e
ChromeUtils.import("resource://services-sync/constants.js");
Packit f0b94e
ChromeUtils.import("resource://services-sync/engines.js");
Packit f0b94e
ChromeUtils.import("resource://services-sync/policies.js");
Packit f0b94e
ChromeUtils.import("resource://services-sync/record.js");
Packit f0b94e
ChromeUtils.import("resource://services-sync/service.js");
Packit f0b94e
ChromeUtils.import("resource://services-sync/status.js");
Packit f0b94e
ChromeUtils.import("resource://services-sync/util.js");
Packit f0b94e
ChromeUtils.import("resource://testing-common/services/sync/fakeservices.js");
Packit f0b94e
Packit f0b94e
var engineManager = Service.engineManager;
Packit f0b94e
Packit f0b94e
function CatapultEngine() {
Packit f0b94e
  SyncEngine.call(this, "Catapult", Service);
Packit f0b94e
}
Packit f0b94e
CatapultEngine.prototype = {
Packit f0b94e
  __proto__: SyncEngine.prototype,
Packit f0b94e
  exception: null, // tests fill this in
Packit f0b94e
  async _sync() {
Packit f0b94e
    throw this.exception;
Packit f0b94e
  }
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
async function sync_httpd_setup() {
Packit f0b94e
  let collectionsHelper = track_collections_helper();
Packit f0b94e
  let upd = collectionsHelper.with_updated_collection;
Packit f0b94e
Packit f0b94e
  let catapultEngine = engineManager.get("catapult");
Packit f0b94e
  let engines        = {catapult: {version: catapultEngine.version,
Packit f0b94e
                                   syncID:  catapultEngine.syncID}};
Packit f0b94e
Packit f0b94e
  // Track these using the collections helper, which keeps modified times
Packit f0b94e
  // up-to-date.
Packit f0b94e
  let clientsColl = new ServerCollection({}, true);
Packit f0b94e
  let keysWBO     = new ServerWBO("keys");
Packit f0b94e
  let globalWBO   = new ServerWBO("global", {storageVersion: STORAGE_VERSION,
Packit f0b94e
                                             syncID: Utils.makeGUID(),
Packit f0b94e
                                             engines});
Packit f0b94e
Packit f0b94e
  let handlers = {
Packit f0b94e
    "/1.1/johndoe/info/collections":    collectionsHelper.handler,
Packit f0b94e
    "/1.1/johndoe/storage/meta/global": upd("meta", globalWBO.handler()),
Packit f0b94e
    "/1.1/johndoe/storage/clients":     upd("clients", clientsColl.handler()),
Packit f0b94e
    "/1.1/johndoe/storage/crypto/keys": upd("crypto", keysWBO.handler())
Packit f0b94e
  };
Packit f0b94e
  return httpd_setup(handlers);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
async function setUp(server) {
Packit f0b94e
  await configureIdentity({username: "johndoe"}, server);
Packit f0b94e
  new FakeCryptoService();
Packit f0b94e
  syncTestLogging();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
async function generateAndUploadKeys(server) {
Packit f0b94e
  await generateNewKeys(Service.collectionKeys);
Packit f0b94e
  let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
Packit f0b94e
  await serverKeys.encrypt(Service.identity.syncKeyBundle);
Packit f0b94e
  let res = Service.resource(server.baseURI + "/1.1/johndoe/storage/crypto/keys");
Packit f0b94e
  return (await serverKeys.upload(res)).success;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
add_task(async function setup() {
Packit f0b94e
  await engineManager.clear();
Packit f0b94e
  validate_all_future_pings();
Packit f0b94e
  await engineManager.register(CatapultEngine);
Packit f0b94e
});
Packit f0b94e
Packit f0b94e
add_task(async function test_backoff500() {
Packit f0b94e
  enableValidationPrefs();
Packit f0b94e
Packit f0b94e
  _("Test: HTTP 500 sets backoff status.");
Packit f0b94e
  let server = await sync_httpd_setup();
Packit f0b94e
  await setUp(server);
Packit f0b94e
Packit f0b94e
  let engine = engineManager.get("catapult");
Packit f0b94e
  engine.enabled = true;
Packit f0b94e
  engine.exception = {status: 500};
Packit f0b94e
Packit f0b94e
  try {
Packit f0b94e
    Assert.ok(!Status.enforceBackoff);
Packit f0b94e
Packit f0b94e
    // Forcibly create and upload keys here -- otherwise we don't get to the 500!
Packit f0b94e
    Assert.ok(await generateAndUploadKeys(server));
Packit f0b94e
Packit f0b94e
    await Service.login();
Packit f0b94e
    await Service.sync();
Packit f0b94e
    Assert.ok(Status.enforceBackoff);
Packit f0b94e
    Assert.equal(Status.sync, SYNC_SUCCEEDED);
Packit f0b94e
    Assert.equal(Status.service, SYNC_FAILED_PARTIAL);
Packit f0b94e
  } finally {
Packit f0b94e
    Status.resetBackoff();
Packit f0b94e
    await Service.startOver();
Packit f0b94e
  }
Packit f0b94e
  await promiseStopServer(server);
Packit f0b94e
});
Packit f0b94e
Packit f0b94e
add_task(async function test_backoff503() {
Packit f0b94e
  enableValidationPrefs();
Packit f0b94e
Packit f0b94e
  _("Test: HTTP 503 with Retry-After header leads to backoff notification and sets backoff status.");
Packit f0b94e
  let server = await sync_httpd_setup();
Packit f0b94e
  await setUp(server);
Packit f0b94e
Packit f0b94e
  const BACKOFF = 42;
Packit f0b94e
  let engine = engineManager.get("catapult");
Packit f0b94e
  engine.enabled = true;
Packit f0b94e
  engine.exception = {status: 503,
Packit f0b94e
                      headers: {"retry-after": BACKOFF}};
Packit f0b94e
Packit f0b94e
  let backoffInterval;
Packit f0b94e
  Svc.Obs.add("weave:service:backoff:interval", function(subject) {
Packit f0b94e
    backoffInterval = subject;
Packit f0b94e
  });
Packit f0b94e
Packit f0b94e
  try {
Packit f0b94e
    Assert.ok(!Status.enforceBackoff);
Packit f0b94e
Packit f0b94e
    Assert.ok(await generateAndUploadKeys(server));
Packit f0b94e
Packit f0b94e
    await Service.login();
Packit f0b94e
    await Service.sync();
Packit f0b94e
Packit f0b94e
    Assert.ok(Status.enforceBackoff);
Packit f0b94e
    Assert.equal(backoffInterval, BACKOFF);
Packit f0b94e
    Assert.equal(Status.service, SYNC_FAILED_PARTIAL);
Packit f0b94e
    Assert.equal(Status.sync, SERVER_MAINTENANCE);
Packit f0b94e
  } finally {
Packit f0b94e
    Status.resetBackoff();
Packit f0b94e
    Status.resetSync();
Packit f0b94e
    await Service.startOver();
Packit f0b94e
  }
Packit f0b94e
  await promiseStopServer(server);
Packit f0b94e
});
Packit f0b94e
Packit f0b94e
add_task(async function test_overQuota() {
Packit f0b94e
  enableValidationPrefs();
Packit f0b94e
Packit f0b94e
  _("Test: HTTP 400 with body error code 14 means over quota.");
Packit f0b94e
  let server = await sync_httpd_setup();
Packit f0b94e
  await setUp(server);
Packit f0b94e
Packit f0b94e
  let engine = engineManager.get("catapult");
Packit f0b94e
  engine.enabled = true;
Packit f0b94e
  engine.exception = {status: 400,
Packit f0b94e
                      toString() {
Packit f0b94e
                        return "14";
Packit f0b94e
                      }};
Packit f0b94e
Packit f0b94e
  try {
Packit f0b94e
    Assert.equal(Status.sync, SYNC_SUCCEEDED);
Packit f0b94e
Packit f0b94e
    Assert.ok(await generateAndUploadKeys(server));
Packit f0b94e
Packit f0b94e
    await Service.login();
Packit f0b94e
    await Service.sync();
Packit f0b94e
Packit f0b94e
    Assert.equal(Status.sync, OVER_QUOTA);
Packit f0b94e
    Assert.equal(Status.service, SYNC_FAILED_PARTIAL);
Packit f0b94e
  } finally {
Packit f0b94e
    Status.resetSync();
Packit f0b94e
    await Service.startOver();
Packit f0b94e
  }
Packit f0b94e
  await promiseStopServer(server);
Packit f0b94e
});
Packit f0b94e
Packit f0b94e
add_task(async function test_service_networkError() {
Packit f0b94e
  enableValidationPrefs();
Packit f0b94e
Packit f0b94e
  _("Test: Connection refused error from Service.sync() leads to the right status code.");
Packit f0b94e
  let server = await sync_httpd_setup();
Packit f0b94e
  await setUp(server);
Packit f0b94e
  await promiseStopServer(server);
Packit f0b94e
  // Provoke connection refused.
Packit f0b94e
  Service.clusterURL = "http://localhost:12345/";
Packit f0b94e
Packit f0b94e
  try {
Packit f0b94e
    Assert.equal(Status.sync, SYNC_SUCCEEDED);
Packit f0b94e
Packit f0b94e
    Service._loggedIn = true;
Packit f0b94e
    await Service.sync();
Packit f0b94e
Packit f0b94e
    Assert.equal(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
Packit f0b94e
    Assert.equal(Status.service, SYNC_FAILED);
Packit f0b94e
  } finally {
Packit f0b94e
    Status.resetSync();
Packit f0b94e
    await Service.startOver();
Packit f0b94e
  }
Packit f0b94e
});
Packit f0b94e
Packit f0b94e
add_task(async function test_service_offline() {
Packit f0b94e
  enableValidationPrefs();
Packit f0b94e
Packit f0b94e
  _("Test: Wanting to sync in offline mode leads to the right status code but does not increment the ignorable error count.");
Packit f0b94e
  let server = await sync_httpd_setup();
Packit f0b94e
  await setUp(server);
Packit f0b94e
Packit f0b94e
  await promiseStopServer(server);
Packit f0b94e
  Services.io.offline = true;
Packit f0b94e
  Services.prefs.setBoolPref("network.dns.offline-localhost", false);
Packit f0b94e
Packit f0b94e
  try {
Packit f0b94e
    Assert.equal(Status.sync, SYNC_SUCCEEDED);
Packit f0b94e
Packit f0b94e
    Service._loggedIn = true;
Packit f0b94e
    await Service.sync();
Packit f0b94e
Packit f0b94e
    Assert.equal(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
Packit f0b94e
    Assert.equal(Status.service, SYNC_FAILED);
Packit f0b94e
  } finally {
Packit f0b94e
    Status.resetSync();
Packit f0b94e
    await Service.startOver();
Packit f0b94e
  }
Packit f0b94e
  Services.io.offline = false;
Packit f0b94e
  Services.prefs.clearUserPref("network.dns.offline-localhost");
Packit f0b94e
});
Packit f0b94e
Packit f0b94e
add_task(async function test_engine_networkError() {
Packit f0b94e
  enableValidationPrefs();
Packit f0b94e
Packit f0b94e
  _("Test: Network related exceptions from engine.sync() lead to the right status code.");
Packit f0b94e
  let server = await sync_httpd_setup();
Packit f0b94e
  await setUp(server);
Packit f0b94e
Packit f0b94e
  let engine = engineManager.get("catapult");
Packit f0b94e
  engine.enabled = true;
Packit f0b94e
  engine.exception = Components.Exception("NS_ERROR_UNKNOWN_HOST",
Packit f0b94e
                                          Cr.NS_ERROR_UNKNOWN_HOST);
Packit f0b94e
Packit f0b94e
  try {
Packit f0b94e
    Assert.equal(Status.sync, SYNC_SUCCEEDED);
Packit f0b94e
Packit f0b94e
    Assert.ok(await generateAndUploadKeys(server));
Packit f0b94e
Packit f0b94e
    await Service.login();
Packit f0b94e
    await Service.sync();
Packit f0b94e
Packit f0b94e
    Assert.equal(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
Packit f0b94e
    Assert.equal(Status.service, SYNC_FAILED_PARTIAL);
Packit f0b94e
  } finally {
Packit f0b94e
    Status.resetSync();
Packit f0b94e
    await Service.startOver();
Packit f0b94e
  }
Packit f0b94e
  await promiseStopServer(server);
Packit f0b94e
});
Packit f0b94e
Packit f0b94e
add_task(async function test_resource_timeout() {
Packit f0b94e
  enableValidationPrefs();
Packit f0b94e
Packit f0b94e
  let server = await sync_httpd_setup();
Packit f0b94e
  await setUp(server);
Packit f0b94e
Packit f0b94e
  let engine = engineManager.get("catapult");
Packit f0b94e
  engine.enabled = true;
Packit f0b94e
  // Resource throws this when it encounters a timeout.
Packit f0b94e
  engine.exception = Components.Exception("Aborting due to channel inactivity.",
Packit f0b94e
                                          Cr.NS_ERROR_NET_TIMEOUT);
Packit f0b94e
Packit f0b94e
  try {
Packit f0b94e
    Assert.equal(Status.sync, SYNC_SUCCEEDED);
Packit f0b94e
Packit f0b94e
    Assert.ok(await generateAndUploadKeys(server));
Packit f0b94e
Packit f0b94e
    await Service.login();
Packit f0b94e
    await Service.sync();
Packit f0b94e
Packit f0b94e
    Assert.equal(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
Packit f0b94e
    Assert.equal(Status.service, SYNC_FAILED_PARTIAL);
Packit f0b94e
  } finally {
Packit f0b94e
    Status.resetSync();
Packit f0b94e
    await Service.startOver();
Packit f0b94e
  }
Packit f0b94e
  await promiseStopServer(server);
Packit f0b94e
});