diff options
Diffstat (limited to 'services/sync/tests/unit/test_errorhandler_1.js')
-rw-r--r-- | services/sync/tests/unit/test_errorhandler_1.js | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_errorhandler_1.js b/services/sync/tests/unit/test_errorhandler_1.js new file mode 100644 index 0000000000..baee3bb9b4 --- /dev/null +++ b/services/sync/tests/unit/test_errorhandler_1.js @@ -0,0 +1,339 @@ +/* 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 fakeServer = new SyncServer(); +fakeServer.start(); +const fakeServerUrl = "http://localhost:" + fakeServer.port; + +registerCleanupFunction(function () { + return promiseStopServer(fakeServer).finally(() => { + Svc.Prefs.resetBranch(""); + }); +}); + +let engine; +add_task(async function setup() { + await Service.engineManager.clear(); + await Service.engineManager.register(EHTestsCommon.CatapultEngine); + engine = Service.engineManager.get("catapult"); +}); + +async function clean() { + let promiseLogReset = promiseOneObserver("weave:service:reset-file-log"); + await Service.startOver(); + await promiseLogReset; + Status.resetSync(); + Status.resetBackoff(); + // Move log levels back to trace (startOver will have reversed this), sicne + syncTestLogging(); +} + +add_task(async function test_401_logout() { + enableValidationPrefs(); + + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + + // By calling sync, we ensure we're logged in. + await sync_and_validate_telem(); + Assert.equal(Status.sync, SYNC_SUCCEEDED); + Assert.ok(Service.isLoggedIn); + + let promiseErrors = new Promise(res => { + Svc.Obs.add("weave:service:sync:error", onSyncError); + function onSyncError() { + _("Got weave:service:sync:error in first sync."); + Svc.Obs.remove("weave:service:sync:error", onSyncError); + + // Wait for the automatic next sync. + Svc.Obs.add("weave:service:login:error", onLoginError); + function onLoginError() { + _("Got weave:service:login:error in second sync."); + Svc.Obs.remove("weave:service:login:error", onLoginError); + res(); + } + } + }); + + // Make sync fail due to login rejected. + await configureIdentity({ username: "janedoe" }, server); + Service._updateCachedURLs(); + + _("Starting first sync."); + await sync_and_validate_telem(ping => { + deepEqual(ping.failureReason, { name: "httperror", code: 401 }); + }); + _("First sync done."); + + await promiseErrors; + Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR); + Assert.ok(!Service.isLoggedIn); + + // Clean up. + await Service.startOver(); + await promiseStopServer(server); +}); + +add_task(async function test_credentials_changed_logout() { + enableValidationPrefs(); + + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + + // By calling sync, we ensure we're logged in. + await sync_and_validate_telem(); + Assert.equal(Status.sync, SYNC_SUCCEEDED); + Assert.ok(Service.isLoggedIn); + + await EHTestsCommon.generateCredentialsChangedFailure(); + + await sync_and_validate_telem(ping => { + equal(ping.status.sync, CREDENTIALS_CHANGED); + deepEqual(ping.failureReason, { + name: "unexpectederror", + error: "Error: Aborting sync, remote setup failed", + }); + }); + + Assert.equal(Status.sync, CREDENTIALS_CHANGED); + Assert.ok(!Service.isLoggedIn); + + // Clean up. + await Service.startOver(); + await promiseStopServer(server); +}); + +add_task(async function test_login_non_network_error() { + enableValidationPrefs(); + + // Test non-network errors are reported + // when calling sync + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + Service.identity._syncKeyBundle = null; + + await Service.sync(); + Assert.equal(Status.login, LOGIN_FAILED_NO_PASSPHRASE); + + await clean(); + await promiseStopServer(server); +}); + +add_task(async function test_sync_non_network_error() { + enableValidationPrefs(); + + // Test non-network errors are reported + // when calling sync + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + + // By calling sync, we ensure we're logged in. + await Service.sync(); + Assert.equal(Status.sync, SYNC_SUCCEEDED); + Assert.ok(Service.isLoggedIn); + + await EHTestsCommon.generateCredentialsChangedFailure(); + + await sync_and_validate_telem(ping => { + equal(ping.status.sync, CREDENTIALS_CHANGED); + deepEqual(ping.failureReason, { + name: "unexpectederror", + error: "Error: Aborting sync, remote setup failed", + }); + }); + + Assert.equal(Status.sync, CREDENTIALS_CHANGED); + // If we clean this tick, telemetry won't get the right error + await Async.promiseYield(); + await clean(); + await promiseStopServer(server); +}); + +add_task(async function test_login_sync_network_error() { + enableValidationPrefs(); + + // Test network errors are reported when calling sync. + await configureIdentity({ username: "broken.wipe" }); + Service.clusterURL = fakeServerUrl; + + await Service.sync(); + Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR); + + await clean(); +}); + +add_task(async function test_sync_network_error() { + enableValidationPrefs(); + + // Test network errors are reported when calling sync. + Services.io.offline = true; + + await Service.sync(); + Assert.equal(Status.sync, LOGIN_FAILED_NETWORK_ERROR); + + Services.io.offline = false; + await clean(); +}); + +add_task(async function test_login_non_network_error() { + enableValidationPrefs(); + + // Test non-network errors are reported + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + Service.identity._syncKeyBundle = null; + + await Service.sync(); + Assert.equal(Status.login, LOGIN_FAILED_NO_PASSPHRASE); + + await clean(); + await promiseStopServer(server); +}); + +add_task(async function test_sync_non_network_error() { + enableValidationPrefs(); + + // Test non-network errors are reported + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + + // By calling sync, we ensure we're logged in. + await Service.sync(); + Assert.equal(Status.sync, SYNC_SUCCEEDED); + Assert.ok(Service.isLoggedIn); + + await EHTestsCommon.generateCredentialsChangedFailure(); + + await Service.sync(); + Assert.equal(Status.sync, CREDENTIALS_CHANGED); + + await clean(); + await promiseStopServer(server); +}); + +add_task(async function test_login_network_error() { + enableValidationPrefs(); + + await configureIdentity({ username: "johndoe" }); + Service.clusterURL = fakeServerUrl; + + // Test network errors are not reported. + + await Service.sync(); + Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR); + + Services.io.offline = false; + await clean(); +}); + +add_task(async function test_sync_network_error() { + enableValidationPrefs(); + + // Test network errors are not reported. + Services.io.offline = true; + + await Service.sync(); + Assert.equal(Status.sync, LOGIN_FAILED_NETWORK_ERROR); + + Services.io.offline = false; + await clean(); +}); + +add_task(async function test_sync_server_maintenance_error() { + enableValidationPrefs(); + + // Test server maintenance errors are not reported. + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + + const BACKOFF = 42; + engine.enabled = true; + engine.exception = { status: 503, headers: { "retry-after": BACKOFF } }; + + Assert.equal(Status.service, STATUS_OK); + + await sync_and_validate_telem(ping => { + equal(ping.status.sync, SERVER_MAINTENANCE); + deepEqual(ping.engines.find(e => e.failureReason).failureReason, { + name: "httperror", + code: 503, + }); + }); + + Assert.equal(Status.service, SYNC_FAILED_PARTIAL); + Assert.equal(Status.sync, SERVER_MAINTENANCE); + + await clean(); + await promiseStopServer(server); +}); + +add_task(async function test_info_collections_login_server_maintenance_error() { + enableValidationPrefs(); + + // Test info/collections server maintenance errors are not reported. + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + + await configureIdentity({ username: "broken.info" }, server); + + let backoffInterval; + Svc.Obs.add( + "weave:service:backoff:interval", + function observe(subject, data) { + Svc.Obs.remove("weave:service:backoff:interval", observe); + backoffInterval = subject; + } + ); + + Assert.ok(!Status.enforceBackoff); + Assert.equal(Status.service, STATUS_OK); + + await Service.sync(); + + Assert.ok(Status.enforceBackoff); + Assert.equal(backoffInterval, 42); + Assert.equal(Status.service, LOGIN_FAILED); + Assert.equal(Status.login, SERVER_MAINTENANCE); + + await clean(); + await promiseStopServer(server); +}); + +add_task(async function test_meta_global_login_server_maintenance_error() { + enableValidationPrefs(); + + // Test meta/global server maintenance errors are not reported. + let server = await EHTestsCommon.sync_httpd_setup(); + await EHTestsCommon.setUp(server); + + await configureIdentity({ username: "broken.meta" }, server); + + let backoffInterval; + Svc.Obs.add( + "weave:service:backoff:interval", + function observe(subject, data) { + Svc.Obs.remove("weave:service:backoff:interval", observe); + backoffInterval = subject; + } + ); + + Assert.ok(!Status.enforceBackoff); + Assert.equal(Status.service, STATUS_OK); + + await Service.sync(); + + Assert.ok(Status.enforceBackoff); + Assert.equal(backoffInterval, 42); + Assert.equal(Status.service, LOGIN_FAILED); + Assert.equal(Status.login, SERVER_MAINTENANCE); + + await clean(); + await promiseStopServer(server); +}); |