test_SessionStoreBackupResource_mockSessionStore.js (8231B)
1 /* Any copyright is dedicated to the Public Domain. 2 https://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 /** 7 * This tests that SessionStore backups contain the info that we want and do 8 * not contain info we don't want. This is separate from 9 * test_SessionStoreBackupResource because that uses the real SessionStore 10 * service and can only check what that includes. This test adds things that 11 * are not usually testable in xpcshell tests, like window session state 12 * serialization. It is based on test_SessionStoreBackupResource.js. 13 */ 14 15 const { SessionStoreBackupResource } = ChromeUtils.importESModule( 16 "resource:///modules/backup/SessionStoreBackupResource.sys.mjs" 17 ); 18 19 const mockSessionStore = { 20 getCurrentState: _ignored => { 21 return { 22 cookies: [], 23 windows: [ 24 { 25 tabs: [ 26 { 27 someData: "hi I am data, I will get serialized", 28 moreData: -3.7, 29 storage: { 30 message: "I don't get serialized!", 31 }, 32 }, 33 { 34 stillMoreData: -3.71, 35 storage: { 36 message: "I don't get serialized either!", 37 }, 38 }, 39 ], 40 _closedTabs: [ 41 { 42 state: { 43 closedTabData: "hi I am a closed tab", 44 moreData: -3.7, 45 storage: { 46 message: "I don't get serialized!", 47 }, 48 }, 49 etc: { 50 dataNotInState: true, 51 }, 52 }, 53 { 54 state: { 55 storage: { 56 message: "I don't get serialized either!", 57 }, 58 }, 59 }, 60 ], 61 }, 62 { 63 tabs: [ 64 { 65 someData: "hi I am window #2's data, I will get serialized", 66 moreData: -3.7, 67 storage: { 68 message: "I don't get serialized!", 69 }, 70 }, 71 ], 72 _closedTabs: [ 73 { 74 state: { 75 storage: { 76 message: "I don't get serialized either!", 77 }, 78 }, 79 notState: { 80 notStateData: "not state data", 81 }, 82 }, 83 ], 84 }, 85 { 86 tabs: [ 87 { 88 someData: "hi I am the private window's data", 89 storage: { 90 message: "I don't get serialized!", 91 }, 92 }, 93 ], 94 isPrivate: true, 95 _closedTabs: [], 96 }, 97 { 98 tabs: [ 99 { 100 someData: "hi I am the private window #2's data", 101 storage: { 102 message: "I don't get serialized!", 103 }, 104 }, 105 ], 106 isPrivate: true, 107 _closedTabs: [], 108 }, 109 ], 110 savedGroups: [ 111 { 112 tabs: [ 113 { 114 state: { 115 savedGroupData: -3.7, 116 storage: { 117 message: "I don't get serialized!", 118 }, 119 }, 120 }, 121 { 122 state: { 123 someData: "hi I am window #2's data", 124 moreData: -3.71, 125 // tab has no storage 126 }, 127 }, 128 ], 129 notTabData: "notTabData", 130 }, 131 ], 132 }; 133 }, 134 }; 135 136 // This is mockSessionStore but with the data that should not be saved removed. 137 let filteredMockSessionData; 138 let sessionStoreBackupResource; 139 140 add_setup(() => { 141 // let's use the SessionStoreBackupResource's filtering 142 sessionStoreBackupResource = new SessionStoreBackupResource(mockSessionStore); 143 144 filteredMockSessionData = 145 sessionStoreBackupResource.filteredSessionStoreState; 146 }); 147 148 /** 149 * Test that the backup method properly serializes window session state. This 150 * includes checking that it does NOT serialize window storage state. 151 */ 152 add_task(async function test_backups_have_correct_window_state() { 153 let sandbox = sinon.createSandbox(); 154 155 let sourcePath = await IOUtils.createUniqueDirectory( 156 PathUtils.tempDir, 157 "SessionStoreBackupResource-src" 158 ); 159 let stagingPath = await IOUtils.createUniqueDirectory( 160 PathUtils.tempDir, 161 "SessionStoreBackupResource-stage" 162 ); 163 164 // This "filtered" session store state is what we expect to write. It should 165 // not include any WebStorage items. 166 // Quick sanity-check that the filtering was done correctly and we will still 167 // serialize windows. 168 Assert.equal( 169 filteredMockSessionData.windows.length, 170 2, 171 "will serialize only 2 windows, since we don't backup private window sessions" 172 ); 173 Assert.equal( 174 filteredMockSessionData.windows[0].tabs.length, 175 2, 176 "will serialize 2 tabs for 1st window" 177 ); 178 Assert.equal( 179 filteredMockSessionData.windows[0].tabs[0].storage, 180 undefined, 181 "does not contain win 0 tab storage" 182 ); 183 Assert.equal( 184 filteredMockSessionData.windows[0]._closedTabs[0].storage, 185 undefined, 186 "does not contain win 0 closed tab storage" 187 ); 188 Assert.equal( 189 filteredMockSessionData.savedGroups.length, 190 1, 191 "will serialize 1 savedGroup" 192 ); 193 Assert.equal( 194 filteredMockSessionData.savedGroups[0].tabs.length, 195 2, 196 "will serialize 2 savedGroup tabs" 197 ); 198 199 let manifestEntry = await sessionStoreBackupResource.backup( 200 stagingPath, 201 sourcePath, 202 false /* isEncrypted */ 203 ); 204 Assert.equal( 205 manifestEntry, 206 null, 207 "SessionStoreBackupResource.backup should return null as its ManifestEntry" 208 ); 209 210 /** 211 * We don't expect the actual file sessionstore.jsonlz4 to exist in the profile directory before calling the backup method. 212 * Instead, verify that it is created by the backup method and exists in the staging folder right after. 213 */ 214 await assertFilesExist(stagingPath, [{ path: "sessionstore.jsonlz4" }]); 215 216 /** 217 * Do a deep comparison between the filtered session state before backup 218 * and contents of the file made in the staging folder, to verify that 219 * information about session state was correctly written for backup. 220 */ 221 let sessionStoreStateStaged = await IOUtils.readJSON( 222 PathUtils.join(stagingPath, "sessionstore.jsonlz4"), 223 { decompress: true } 224 ); 225 226 Assert.deepEqual( 227 sessionStoreStateStaged, 228 filteredMockSessionData, 229 "sessionstore.jsonlz4 in the staging folder matches the recorded session state" 230 ); 231 232 await maybeRemovePath(stagingPath); 233 await maybeRemovePath(sourcePath); 234 235 sandbox.restore(); 236 }); 237 238 /** 239 * Minor test that the recover method correctly copies the session store from 240 * the recovery directory into the destination profile directory. 241 */ 242 add_task(async function test_recover() { 243 let recoveryPath = await IOUtils.createUniqueDirectory( 244 PathUtils.tempDir, 245 "SessionStoreBackupResource-recover" 246 ); 247 let destProfilePath = await IOUtils.createUniqueDirectory( 248 PathUtils.tempDir, 249 "SessionStoreBackupResource-restored-profile" 250 ); 251 252 // We backup a copy of sessionstore.jsonlz4, so ensure it exists in the recovery path 253 let sessionStoreBackupPath = PathUtils.join( 254 recoveryPath, 255 "sessionstore.jsonlz4" 256 ); 257 await IOUtils.writeJSON(sessionStoreBackupPath, filteredMockSessionData, { 258 compress: true, 259 }); 260 261 // The backup method is expected to have returned a null ManifestEntry 262 let postRecoveryEntry = await sessionStoreBackupResource.recover( 263 null /* manifestEntry */, 264 recoveryPath, 265 destProfilePath 266 ); 267 Assert.equal( 268 postRecoveryEntry, 269 null, 270 "SessionStoreBackupResource.recover should return null as its post recovery entry" 271 ); 272 273 await assertFilesExist(destProfilePath, [{ path: "sessionstore.jsonlz4" }]); 274 275 let sessionStateCopied = await IOUtils.readJSON( 276 PathUtils.join(destProfilePath, "sessionstore.jsonlz4"), 277 { decompress: true } 278 ); 279 280 Assert.deepEqual( 281 sessionStateCopied, 282 filteredMockSessionData, 283 "sessionstore.jsonlz4 in the destination profile folder matches the backed up session state" 284 ); 285 286 await maybeRemovePath(recoveryPath); 287 await maybeRemovePath(destProfilePath); 288 });