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