Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/**
* Any copyright is dedicated to the Public Domain.
*/
/* eslint-disable mozilla/no-arbitrary-setTimeout */
/**
* This test verifies that writes of a failed flush are not lost and are
* persisted by the next flush or when the connection is closed. See bug
* 2058495.
*/
const { QuotaUtils } = ChromeUtils.importESModule(
);
const flushSleepTimeSec = 6;
function waitForFlush() {
info("Sleeping for " + flushSleepTimeSec + " seconds to let the flush run");
return new Promise(function (resolve) {
setTimeout(resolve, flushSleepTimeSec * 1000);
});
}
// The usage journal is written before the commit and only removed once the
// commit succeeds, so it is left behind by a failed flush.
function getUsageJournalFile() {
return getRelativeFile("storage/default/http+++example.com/ls/usage-journal");
}
async function addItemAndFlush(storage, item) {
info("Adding item");
storage.setItem(item.key, item.value);
await returnToEventLoop();
await waitForFlush();
}
async function addItemWithFailingFlush(storage, item) {
info("Making the next flush fail");
await QuotaUtils.withArtificialFailures(
Ci.nsIQuotaArtificialFailure.CATEGORY_LOCAL_STORAGE_FLUSH,
/* probability */ 100,
Cr.NS_ERROR_FAILURE,
addItemAndFlush.bind(null, storage, item)
);
ok(getUsageJournalFile().exists(), "Flush failed");
}
async function checkPersistedItems(principal, items) {
info("Resetting");
let request = reset();
await requestFinished(request);
ok(!getUsageJournalFile().exists(), "No pending flush failure");
info("Getting usage");
request = getOriginUsage(principal);
await requestFinished(request);
const expectedUsage = items.reduce(
(usage, item) => usage + item.key.length + item.value.length,
0
);
is(request.result.usage, expectedUsage, "Correct usage");
info("Getting storage");
const storage = getLocalStorage(principal);
for (const item of items) {
is(storage.getItem(item.key), item.value, "Correct value");
}
info("Clearing");
request = clear();
await requestFinished(request);
}
add_task(async function testRetryOnNextFlush() {
const items = [
{ key: "key1", value: "value1" },
{ key: "key2", value: "value2" },
];
const principal = getDefaultPrincipal();
info("Getting storage");
const storage = getLocalStorage(principal);
await addItemWithFailingFlush(storage, items[0]);
info("Adding second item");
await addItemAndFlush(storage, items[1]);
ok(!getUsageJournalFile().exists(), "Retry flush succeeded");
await checkPersistedItems(principal, items);
});
add_task(async function testRetryOnClose() {
const items = [{ key: "key1", value: "value1" }];
const principal = getDefaultPrincipal();
info("Getting storage");
const storage = getLocalStorage(principal);
await addItemWithFailingFlush(storage, items[0]);
// No other write, so the failed writes are only flushed when the reset
// closes the connection.
await checkPersistedItems(principal, items);
});