/** * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Test repeatedly setting values that are just under the LocalStorage quota * limit without yielding control flow in order to verify that the write * optimizer is present / works. If there was no write optimizer present, the * IPC message size limit would be exceeded, resulting in a crash. */ add_task(async function testSteps() { const globalLimitKB = 5 * 1024; // 18 and more iterations would produce an IPC message with size greater than // 256 MB if write optimizer was not present. This number was determined // experimentally by running the test with disabled write optimizer. const numberOfIterations = 18; const randomStringBlockSize = 65536; // We need to use a random string because LS internally tries to compress // values. function getRandomString(size) { let crypto = this.window ? this.window.crypto : this.crypto; let decoder = new TextDecoder("ISO-8859-2"); function getRandomStringBlock(array) { crypto.getRandomValues(array); return decoder.decode(array); } let string = ""; let quotient = size / randomStringBlockSize; if (quotient) { let array = new Uint8Array(randomStringBlockSize); for (let i = 1; i <= quotient; i++) { string += getRandomStringBlock(array); } } let remainder = size % randomStringBlockSize; if (remainder) { let array = new Uint8Array(remainder); string += getRandomStringBlock(array); } return string; } const data = {}; data.key = "foo"; data.value = getRandomString( globalLimitKB * 1024 - data.key.length - numberOfIterations.toString().length ); info("Setting pref"); // By disabling snapshot reusing, we guarantee that the snapshot will be // checkpointed once control returns to the event loop. if (this.window) { await SpecialPowers.pushPrefEnv({ set: [["dom.storage.snapshot_reusing", false]], }); } else { Services.prefs.setBoolPref("dom.storage.snapshot_reusing", false); } info("Getting storage"); let storage = getLocalStorage(); info("Adding/updating item"); for (var i = 0; i < numberOfIterations; i++) { storage.setItem(data.key, data.value + i); } info("Returning to event loop"); await returnToEventLoop(); ok(!storage.hasSnapshot, "Snapshot successfully finished"); });