test_final_write_cleanup.js (3821B)
1 "use strict"; 2 3 /** 4 * This test ensures that we correctly clean up the session state when 5 * writing with isFinalWrite, which is used on shutdown. It tests that each 6 * tab's shistory is capped to a maximum number of preceding and succeeding 7 * entries. 8 */ 9 10 const { SessionWriter } = ChromeUtils.importESModule( 11 "resource:///modules/sessionstore/SessionWriter.sys.mjs" 12 ); 13 14 // Make sure that we have a profile before initializing SessionFile. 15 do_get_profile(); 16 const { 17 SessionFile: { Paths }, 18 } = ChromeUtils.importESModule( 19 "resource:///modules/sessionstore/SessionFile.sys.mjs" 20 ); 21 22 const MAX_ENTRIES = 9; 23 const URL = "http://example.com/#"; 24 25 async function prepareWithLimit(back, fwd) { 26 SessionWriter.init("empty", false, Paths, { 27 maxSerializeBack: back, 28 maxSerializeForward: fwd, 29 maxUpgradeBackups: 3, 30 }); 31 await SessionWriter.wipe(); 32 } 33 34 add_setup(async function () { 35 registerCleanupFunction(() => SessionWriter.wipe()); 36 }); 37 38 function createSessionState(index) { 39 // Generate the tab state entries and set the one-based 40 // tab-state index to the middle session history entry. 41 let tabState = { entries: [], index }; 42 for (let i = 0; i < MAX_ENTRIES; i++) { 43 tabState.entries.push({ url: URL + i }); 44 } 45 46 return { windows: [{ tabs: [tabState] }] }; 47 } 48 49 async function writeAndParse(state, path, options = {}) { 50 // We clone here because `write` can change the data passed. 51 let data = structuredClone(state); 52 await SessionWriter.write(data, options); 53 return IOUtils.readJSON(path, { decompress: true }); 54 } 55 56 add_task(async function test_shistory_cap_none() { 57 let state = createSessionState(5); 58 59 // Don't limit the number of shistory entries. 60 await prepareWithLimit(-1, -1); 61 62 // Check that no caps are applied. 63 let diskState = await writeAndParse(state, Paths.clean, { 64 isFinalWrite: true, 65 }); 66 Assert.deepEqual(state, diskState, "no cap applied"); 67 }); 68 69 add_task(async function test_shistory_cap_middle() { 70 let state = createSessionState(5); 71 await prepareWithLimit(2, 3); 72 73 // Cap is only applied on clean shutdown. 74 let diskState = await writeAndParse(state, Paths.recovery); 75 Assert.deepEqual(state, diskState, "no cap applied"); 76 77 // Check that the right number of shistory entries was discarded 78 // and the shistory index updated accordingly. 79 diskState = await writeAndParse(state, Paths.clean, { isFinalWrite: true }); 80 let tabState = state.windows[0].tabs[0]; 81 tabState.entries = tabState.entries.slice(2, 8); 82 tabState.index = 3; 83 Assert.deepEqual(state, diskState, "cap applied"); 84 }); 85 86 add_task(async function test_shistory_cap_lower_bound() { 87 let state = createSessionState(1); 88 await prepareWithLimit(5, 5); 89 90 // Cap is only applied on clean shutdown. 91 let diskState = await writeAndParse(state, Paths.recovery); 92 Assert.deepEqual(state, diskState, "no cap applied"); 93 94 // Check that the right number of shistory entries was discarded. 95 diskState = await writeAndParse(state, Paths.clean, { isFinalWrite: true }); 96 let tabState = state.windows[0].tabs[0]; 97 tabState.entries = tabState.entries.slice(0, 6); 98 Assert.deepEqual(state, diskState, "cap applied"); 99 }); 100 101 add_task(async function test_shistory_cap_upper_bound() { 102 let state = createSessionState(MAX_ENTRIES); 103 await prepareWithLimit(5, 5); 104 105 // Cap is only applied on clean shutdown. 106 let diskState = await writeAndParse(state, Paths.recovery); 107 Assert.deepEqual(state, diskState, "no cap applied"); 108 109 // Check that the right number of shistory entries was discarded 110 // and the shistory index updated accordingly. 111 diskState = await writeAndParse(state, Paths.clean, { isFinalWrite: true }); 112 let tabState = state.windows[0].tabs[0]; 113 tabState.entries = tabState.entries.slice(3); 114 tabState.index = 6; 115 Assert.deepEqual(state, diskState, "cap applied"); 116 });