test_shutdown_handling.js (3673B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 add_setup(() => { 7 Services.prefs.setStringPref("services.settings.loglevel", "debug"); 8 registerCleanupFunction(() => { 9 Services.prefs.clearUserPref("services.settings.loglevel"); 10 }); 11 }); 12 13 add_task(async function test_shutdown_abort_after_start() { 14 // Start a forever transaction: 15 let counter = 0; 16 let transactionStarted; 17 let startedPromise = new Promise(r => { 18 transactionStarted = r; 19 }); 20 let promise = Database._executeIDB( 21 "records", 22 store => { 23 // Signal we've started. 24 transactionStarted(); 25 function makeRequest() { 26 if (++counter > 1000) { 27 Assert.ok( 28 false, 29 "We ran 1000 requests and didn't get aborted, what?" 30 ); 31 return; 32 } 33 dump("Making request " + counter + "\n"); 34 const request = store 35 .index("cid") 36 .openCursor(IDBKeyRange.only("foopydoo/foo")); 37 request.onsuccess = () => { 38 makeRequest(); 39 }; 40 } 41 makeRequest(); 42 }, 43 { mode: "readonly" } 44 ); 45 46 // Wait for the transaction to start. 47 await startedPromise; 48 49 Database._shutdownHandler(); // should abort the readonly transaction. 50 51 let rejection; 52 await promise.catch(e => { 53 rejection = e; 54 }); 55 ok(rejection, "Promise should have rejected."); 56 57 // Now clear the shutdown flag and rejection error: 58 Database._cancelShutdown(); 59 rejection = null; 60 }); 61 62 add_task(async function test_shutdown_immediate_abort() { 63 // Now abort directly from the successful request. 64 let promise = Database._executeIDB( 65 "records", 66 store => { 67 let request = store 68 .index("cid") 69 .openCursor(IDBKeyRange.only("foopydoo/foo")); 70 request.onsuccess = () => { 71 // Abort immediately. 72 Database._shutdownHandler(); 73 request = store 74 .index("cid") 75 .openCursor(IDBKeyRange.only("foopydoo/foo")); 76 Assert.ok(false, "IndexedDB allowed opening a cursor after aborting?!"); 77 }; 78 }, 79 { mode: "readonly" } 80 ); 81 82 let rejection; 83 // Wait for the abort 84 await promise.catch(e => { 85 rejection = e; 86 }); 87 ok(rejection, "Directly aborted promise should also have rejected."); 88 // Now clear the shutdown flag and rejection error: 89 Database._cancelShutdown(); 90 }); 91 92 add_task(async function test_shutdown_worker() { 93 let client = new RemoteSettingsClient("language-dictionaries"); 94 const before = await client.db.getLastModified(); 95 Assert.equal(before, null); 96 97 let records = [{}]; 98 let importPromise = RemoteSettingsWorker._execute( 99 "_test_only_import", 100 ["main", "language-dictionaries", records, 0], 101 { mustComplete: true } 102 ); 103 let stringifyPromise = RemoteSettingsWorker.canonicalStringify( 104 [], 105 [], 106 Date.now() 107 ); 108 // Change the idle time so we shut the worker down even though we can't 109 // set gShutdown from outside of the worker management code. 110 Services.prefs.setIntPref( 111 "services.settings.worker_idle_max_milliseconds", 112 1 113 ); 114 RemoteSettingsWorker._abortCancelableRequests(); 115 await Assert.rejects( 116 stringifyPromise, 117 /Shutdown/, 118 "Should have aborted the stringify request at shutdown." 119 ); 120 await Assert.rejects( 121 importPromise, 122 /shutting down/, 123 "Ensure imports get aborted during shutdown" 124 ); 125 const after = await client.db.getLastModified(); 126 Assert.equal(after, null); 127 await TestUtils.waitForCondition(() => !RemoteSettingsWorker.worker); 128 Assert.ok( 129 !RemoteSettingsWorker.worker, 130 "Worker should have been terminated." 131 ); 132 });