test_errorhandler_1.js (9412B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const { Service } = ChromeUtils.importESModule( 5 "resource://services-sync/service.sys.mjs" 6 ); 7 const { Status } = ChromeUtils.importESModule( 8 "resource://services-sync/status.sys.mjs" 9 ); 10 11 const fakeServer = new SyncServer(); 12 fakeServer.start(); 13 const fakeServerUrl = "http://localhost:" + fakeServer.port; 14 15 registerCleanupFunction(function () { 16 return promiseStopServer(fakeServer).finally(() => { 17 for (const pref of Svc.PrefBranch.getChildList("")) { 18 Svc.PrefBranch.clearUserPref(pref); 19 } 20 }); 21 }); 22 23 let engine; 24 add_task(async function setup() { 25 await Service.engineManager.clear(); 26 await Service.engineManager.register(EHTestsCommon.CatapultEngine); 27 engine = Service.engineManager.get("catapult"); 28 }); 29 30 async function clean() { 31 let promiseLogReset = promiseOneObserver("weave:service:reset-file-log"); 32 await Service.startOver(); 33 await promiseLogReset; 34 Status.resetSync(); 35 Status.resetBackoff(); 36 // Move log levels back to trace (startOver will have reversed this), sicne 37 syncTestLogging(); 38 } 39 40 add_task(async function test_401_logout() { 41 enableValidationPrefs(); 42 43 let server = await EHTestsCommon.sync_httpd_setup(); 44 await EHTestsCommon.setUp(server); 45 46 // By calling sync, we ensure we're logged in. 47 await sync_and_validate_telem(); 48 Assert.equal(Status.sync, SYNC_SUCCEEDED); 49 Assert.ok(Service.isLoggedIn); 50 51 let promiseErrors = new Promise(res => { 52 Svc.Obs.add("weave:service:sync:error", onSyncError); 53 function onSyncError() { 54 _("Got weave:service:sync:error in first sync."); 55 Svc.Obs.remove("weave:service:sync:error", onSyncError); 56 57 // Wait for the automatic next sync. 58 Svc.Obs.add("weave:service:login:error", onLoginError); 59 function onLoginError() { 60 _("Got weave:service:login:error in second sync."); 61 Svc.Obs.remove("weave:service:login:error", onLoginError); 62 res(); 63 } 64 } 65 }); 66 67 // Make sync fail due to login rejected. 68 await configureIdentity({ username: "janedoe" }, server); 69 Service._updateCachedURLs(); 70 71 _("Starting first sync."); 72 await sync_and_validate_telem(ping => { 73 deepEqual(ping.failureReason, { name: "httperror", code: 401 }); 74 }); 75 _("First sync done."); 76 77 await promiseErrors; 78 Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR); 79 Assert.ok(!Service.isLoggedIn); 80 81 // Clean up. 82 await Service.startOver(); 83 await promiseStopServer(server); 84 }); 85 86 add_task(async function test_credentials_changed_logout() { 87 enableValidationPrefs(); 88 89 let server = await EHTestsCommon.sync_httpd_setup(); 90 await EHTestsCommon.setUp(server); 91 92 // By calling sync, we ensure we're logged in. 93 await sync_and_validate_telem(); 94 Assert.equal(Status.sync, SYNC_SUCCEEDED); 95 Assert.ok(Service.isLoggedIn); 96 97 await EHTestsCommon.generateCredentialsChangedFailure(); 98 99 await sync_and_validate_telem(ping => { 100 equal(ping.status.sync, CREDENTIALS_CHANGED); 101 deepEqual(ping.failureReason, { 102 name: "unexpectederror", 103 error: "Error: Aborting sync, remote setup failed", 104 }); 105 }); 106 107 Assert.equal(Status.sync, CREDENTIALS_CHANGED); 108 Assert.ok(!Service.isLoggedIn); 109 110 // Clean up. 111 await Service.startOver(); 112 await promiseStopServer(server); 113 }); 114 115 add_task(async function test_login_non_network_error() { 116 enableValidationPrefs(); 117 118 // Test non-network errors are reported 119 // when calling sync 120 let server = await EHTestsCommon.sync_httpd_setup(); 121 await EHTestsCommon.setUp(server); 122 Service.identity._syncKeyBundle = null; 123 124 await Service.sync(); 125 Assert.equal(Status.login, LOGIN_FAILED_NO_PASSPHRASE); 126 127 await clean(); 128 await promiseStopServer(server); 129 }); 130 131 add_task(async function test_sync_non_network_error() { 132 enableValidationPrefs(); 133 134 // Test non-network errors are reported 135 // when calling sync 136 let server = await EHTestsCommon.sync_httpd_setup(); 137 await EHTestsCommon.setUp(server); 138 139 // By calling sync, we ensure we're logged in. 140 await Service.sync(); 141 Assert.equal(Status.sync, SYNC_SUCCEEDED); 142 Assert.ok(Service.isLoggedIn); 143 144 await EHTestsCommon.generateCredentialsChangedFailure(); 145 146 await sync_and_validate_telem(ping => { 147 equal(ping.status.sync, CREDENTIALS_CHANGED); 148 deepEqual(ping.failureReason, { 149 name: "unexpectederror", 150 error: "Error: Aborting sync, remote setup failed", 151 }); 152 }); 153 154 Assert.equal(Status.sync, CREDENTIALS_CHANGED); 155 // If we clean this tick, telemetry won't get the right error 156 await Async.promiseYield(); 157 await clean(); 158 await promiseStopServer(server); 159 }); 160 161 add_task(async function test_login_sync_network_error() { 162 enableValidationPrefs(); 163 164 // Test network errors are reported when calling sync. 165 await configureIdentity({ username: "broken.wipe" }); 166 Service.clusterURL = fakeServerUrl; 167 168 await Service.sync(); 169 Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR); 170 171 await clean(); 172 }); 173 174 add_task(async function test_sync_network_error() { 175 enableValidationPrefs(); 176 177 // Test network errors are reported when calling sync. 178 Services.io.offline = true; 179 180 await Service.sync(); 181 Assert.equal(Status.sync, LOGIN_FAILED_NETWORK_ERROR); 182 183 Services.io.offline = false; 184 await clean(); 185 }); 186 187 add_task(async function test_login_non_network_error() { 188 enableValidationPrefs(); 189 190 // Test non-network errors are reported 191 let server = await EHTestsCommon.sync_httpd_setup(); 192 await EHTestsCommon.setUp(server); 193 Service.identity._syncKeyBundle = null; 194 195 await Service.sync(); 196 Assert.equal(Status.login, LOGIN_FAILED_NO_PASSPHRASE); 197 198 await clean(); 199 await promiseStopServer(server); 200 }); 201 202 add_task(async function test_sync_non_network_error() { 203 enableValidationPrefs(); 204 205 // Test non-network errors are reported 206 let server = await EHTestsCommon.sync_httpd_setup(); 207 await EHTestsCommon.setUp(server); 208 209 // By calling sync, we ensure we're logged in. 210 await Service.sync(); 211 Assert.equal(Status.sync, SYNC_SUCCEEDED); 212 Assert.ok(Service.isLoggedIn); 213 214 await EHTestsCommon.generateCredentialsChangedFailure(); 215 216 await Service.sync(); 217 Assert.equal(Status.sync, CREDENTIALS_CHANGED); 218 219 await clean(); 220 await promiseStopServer(server); 221 }); 222 223 add_task(async function test_login_network_error() { 224 enableValidationPrefs(); 225 226 await configureIdentity({ username: "johndoe" }); 227 Service.clusterURL = fakeServerUrl; 228 229 // Test network errors are not reported. 230 231 await Service.sync(); 232 Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR); 233 234 Services.io.offline = false; 235 await clean(); 236 }); 237 238 add_task(async function test_sync_network_error() { 239 enableValidationPrefs(); 240 241 // Test network errors are not reported. 242 Services.io.offline = true; 243 244 await Service.sync(); 245 Assert.equal(Status.sync, LOGIN_FAILED_NETWORK_ERROR); 246 247 Services.io.offline = false; 248 await clean(); 249 }); 250 251 add_task(async function test_sync_server_maintenance_error() { 252 enableValidationPrefs(); 253 254 // Test server maintenance errors are not reported. 255 let server = await EHTestsCommon.sync_httpd_setup(); 256 await EHTestsCommon.setUp(server); 257 258 const BACKOFF = 42; 259 engine.enabled = true; 260 engine.exception = { status: 503, headers: { "retry-after": BACKOFF } }; 261 262 Assert.equal(Status.service, STATUS_OK); 263 264 await sync_and_validate_telem(ping => { 265 equal(ping.status.sync, SERVER_MAINTENANCE); 266 deepEqual(ping.engines.find(e => e.failureReason).failureReason, { 267 name: "httperror", 268 code: 503, 269 }); 270 }); 271 272 Assert.equal(Status.service, SYNC_FAILED_PARTIAL); 273 Assert.equal(Status.sync, SERVER_MAINTENANCE); 274 275 await clean(); 276 await promiseStopServer(server); 277 }); 278 279 add_task(async function test_info_collections_login_server_maintenance_error() { 280 enableValidationPrefs(); 281 282 // Test info/collections server maintenance errors are not reported. 283 let server = await EHTestsCommon.sync_httpd_setup(); 284 await EHTestsCommon.setUp(server); 285 286 await configureIdentity({ username: "broken.info" }, server); 287 288 let backoffInterval; 289 Svc.Obs.add("weave:service:backoff:interval", function observe(subject) { 290 Svc.Obs.remove("weave:service:backoff:interval", observe); 291 backoffInterval = subject; 292 }); 293 294 Assert.ok(!Status.enforceBackoff); 295 Assert.equal(Status.service, STATUS_OK); 296 297 await Service.sync(); 298 299 Assert.ok(Status.enforceBackoff); 300 Assert.equal(backoffInterval, 42); 301 Assert.equal(Status.service, LOGIN_FAILED); 302 Assert.equal(Status.login, SERVER_MAINTENANCE); 303 304 await clean(); 305 await promiseStopServer(server); 306 }); 307 308 add_task(async function test_meta_global_login_server_maintenance_error() { 309 enableValidationPrefs(); 310 311 // Test meta/global server maintenance errors are not reported. 312 let server = await EHTestsCommon.sync_httpd_setup(); 313 await EHTestsCommon.setUp(server); 314 315 await configureIdentity({ username: "broken.meta" }, server); 316 317 let backoffInterval; 318 Svc.Obs.add("weave:service:backoff:interval", function observe(subject) { 319 Svc.Obs.remove("weave:service:backoff:interval", observe); 320 backoffInterval = subject; 321 }); 322 323 Assert.ok(!Status.enforceBackoff); 324 Assert.equal(Status.service, STATUS_OK); 325 326 await Service.sync(); 327 328 Assert.ok(Status.enforceBackoff); 329 Assert.equal(backoffInterval, 42); 330 Assert.equal(Status.service, LOGIN_FAILED); 331 Assert.equal(Status.login, SERVER_MAINTENANCE); 332 333 await clean(); 334 await promiseStopServer(server); 335 });