test_shutdownDuringAllTemporaryOriginsInitialization.js (6470B)
1 /** 2 * Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/publicdomain/zero/1.0/ 4 */ 5 6 const { FileUtils } = ChromeUtils.importESModule( 7 "resource://testing-common/dom/quota/test/modules/FileUtils.sys.mjs" 8 ); 9 const { PrincipalUtils } = ChromeUtils.importESModule( 10 "resource://testing-common/dom/quota/test/modules/PrincipalUtils.sys.mjs" 11 ); 12 const { QuotaUtils } = ChromeUtils.importESModule( 13 "resource://testing-common/dom/quota/test/modules/QuotaUtils.sys.mjs" 14 ); 15 const { TestUtils } = ChromeUtils.importESModule( 16 "resource://testing-common/TestUtils.sys.mjs" 17 ); 18 19 /** 20 * This test verifies the behavior when a shutdown occurs during the 21 * initialization of all temporary origins in the background. 22 * 23 * Test Setup & Procedure: 24 * 1. Lazy Origin Initialization Enabled 25 * - The test runs with lazy origin initialization enabled, meaning that 26 * calling `Services.qms.initTemporaryStorage` does not initialize 27 * individual origins. 28 * 29 * 2. Preparation of Existing Profile 30 * - Two origins belonging to the same eTLD+1 group are created. 31 * 32 * 3. Removal of Metadata Files 33 * - Metadata files are removed to force restoration, providing a way 34 * to check whether origin initialization has occurred. 35 * 36 * 4. Triggering Initialization of All Temporary Origins 37 * - The test explicitly triggers the initialization of all temporary 38 * origins by calling `Services.qms.initializeAllTemporaryOrigins`. 39 * 40 * 5. Inducing a Controlled Shutdown 41 * - The test waits for the first origin to begin initialization. 42 * - Once initialization starts, shutdown is triggered. 43 * - A 2-second delay is introduced in origin initialization to ensure 44 * the shutdown signal has time to propagate. 45 * 46 * 6. Expected Behavior & Verification 47 * - Due to the shutdown, the second origin does not initialize. 48 * - Since active operations are not available during shutdown, the test 49 * verifies initialization by checking whether the metadata file has 50 * been restored for the given origin. 51 * 52 * Notes & Justification: 53 * - This approach has been successfully used in other tests to handle 54 * shutdown scenarios. 55 * - See also: 56 * https://searchfox.org/mozilla-central/rev/d5baa11e35e0186c3c867f4948010f0742198467/modules/libpref/init/StaticPrefList.yaml#3789-3846 57 */ 58 async function testShutdownDuringAllTemporaryOriginsInitialization() { 59 // This test creates two origins belonging to the same eTLD+1 group on 60 // purpose to test specific shutdown check. 61 const principal1 = PrincipalUtils.createPrincipal("https://1.example.com"); 62 const principal2 = PrincipalUtils.createPrincipal("https://2.example.com"); 63 const metadata1 = FileUtils.getFile( 64 "storage/default/https+++1.example.com/.metadata-v2" 65 ); 66 const metadata2 = FileUtils.getFile( 67 "storage/default/https+++2.example.com/.metadata-v2" 68 ); 69 70 // Preparation phase: simulating an existing profile with pre-existing 71 // storage. At least two temporary origins must already exist. 72 info("Clearing storage"); 73 74 { 75 const request = Services.qms.clear(); 76 await QuotaUtils.requestFinished(request); 77 } 78 79 info("Initializing storage"); 80 81 { 82 const request = Services.qms.init(); 83 await QuotaUtils.requestFinished(request); 84 } 85 86 info("Initializing temporary storage"); 87 88 { 89 const request = Services.qms.initTemporaryStorage(); 90 await QuotaUtils.requestFinished(request); 91 } 92 93 info("Initializing temporary origin"); 94 95 { 96 const request = Services.qms.initializeTemporaryOrigin( 97 "default", 98 principal1, 99 /* aCreateIfNonExistent */ true 100 ); 101 await QuotaUtils.requestFinished(request); 102 } 103 104 info("Initializing temporary origin"); 105 106 { 107 const request = Services.qms.initializeTemporaryOrigin( 108 "default", 109 principal2, 110 /* aCreateIfNonExistent */ true 111 ); 112 await QuotaUtils.requestFinished(request); 113 } 114 115 // Restore the original uninitialized state to force reinitialization of both 116 // storage and temporary storage. 117 info("Shutting down storage"); 118 119 { 120 const request = Services.qms.reset(); 121 await QuotaUtils.requestFinished(request); 122 } 123 124 // Reinitialize storage and temporary storage. 125 info("Initializing storage"); 126 127 { 128 const request = Services.qms.init(); 129 await QuotaUtils.requestFinished(request); 130 } 131 132 info("Initializing temporary storage"); 133 134 { 135 const request = Services.qms.initTemporaryStorage(); 136 await QuotaUtils.requestFinished(request); 137 } 138 139 info("Removing origin metadata"); 140 141 metadata1.remove(false); 142 143 info("Removing origin metadata"); 144 145 metadata2.remove(false); 146 147 // Now trigger the initialization of all temporary origins, which normally 148 // happens automatically when incremental origin initialization is enabled 149 // and temporary storage initialization is complete. 150 info("Starting all temporary origins initialization"); 151 152 const initPromise = (async function () { 153 const request = Services.qms.initializeAllTemporaryOrigins(); 154 const promise = QuotaUtils.requestFinished(request); 155 return promise; 156 })(); 157 158 info("Waiting for origin initialization to start"); 159 160 await TestUtils.topicObserved("QuotaManager::OriginInitializationStarted"); 161 162 info("Starting shutdown"); 163 164 QuotaUtils.startShutdown(); 165 166 info("Waiting for all temoporary origins initialization to finish"); 167 168 await initPromise; 169 170 info("Metadata file for first origin exists: " + metadata1.exists()); 171 172 info("Metadata file for second origin exists: " + metadata2.exists()); 173 174 // Once shutdown has started, we can no longer use the Quota Manager Service 175 // to check the initialization status of origins, as any new operation will 176 // fail. However, we can determine if the initialization of all origins was 177 // aborted due to shutdown by checking for the existence of origin metadata 178 // files, which were artificially removed earlier. 179 Assert.notEqual( 180 metadata1.exists(), 181 metadata2.exists(), 182 "Metadata for the second origin is not restored" 183 ); 184 } 185 186 /* exported testSteps */ 187 async function testSteps() { 188 add_task( 189 { 190 pref_set: [ 191 ["dom.quotaManager.temporaryStorage.lazyOriginInitialization", true], 192 ["dom.quotaManager.loadQuotaFromCache", false], 193 ["dom.quotaManager.loadQuotaFromSecondaryCache", false], 194 ["dom.quotaManager.originInitialization.pauseOnIOThreadMs", 2000], 195 ], 196 }, 197 testShutdownDuringAllTemporaryOriginsInitialization 198 ); 199 }