Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: tsan
- Manifest: dom/indexedDB/test/unit/xpcshell-parent-process.toml
/**
* Any copyright is dedicated to the Public Domain.
*/
// Reduce the amount of data on slow platforms.
const getDataBlockSize = () => {
if (mozinfo.os == "android") {
// Android is much slower than desktop.
if (mozinfo.verify) {
return 54; // Chaos mode on android
}
return 3333;
}
if (isInChaosMode()) {
return 333;
}
return 33333;
};
/* exported testSteps */
async function testSteps() {
const name = this.window ? window.location.pathname : "Splendid Test";
const request = indexedDB.open(name, 1);
(ev => {
const os = ev.target.result.createObjectStore("testObjectStore", {
keyPath: "id",
autoIncrement: false,
});
os.createIndex("testObjectStoreIndexA", "indexA", { unique: true });
os.createIndex("testObjectStoreIndexB", "indexB", { unique: false });
os.createIndex("testObjectStoreIndexC", "indexC", { unique: false });
})(await expectingUpgrade(request));
const db = (await expectingSuccess(request)).target.result;
const objectStore = db
.transaction(["testObjectStore"], "readwrite")
.objectStore("testObjectStore");
const dataBlock = getDataBlockSize();
const lastIndex = 3 * dataBlock;
info("We will now add " + lastIndex + " blobs to our object store");
const addSegment = async (from, dataValue) => {
for (let i = from; i <= from + dataBlock - 1; ++i) {
await objectStore.add({
id: i,
indexA: i,
indexB: lastIndex + 1 - i,
indexC: i % 3,
value: dataValue,
});
}
};
const expectedBegin = getRandomView(512);
const expectedMiddle = getRandomView(512);
const expectedEnd = getRandomView(512);
ok(
!compareBuffers(expectedBegin, expectedMiddle),
"Are all buffers different?"
);
ok(!compareBuffers(expectedBegin, expectedEnd), "Are all buffers different?");
ok(
!compareBuffers(expectedMiddle, expectedEnd),
"Are all buffers different?"
);
const dataValueBegin = getBlob(expectedBegin);
await addSegment(1, dataValueBegin);
const dataValueMiddle = getBlob(expectedMiddle);
await addSegment(dataBlock + 1, dataValueMiddle);
const dataValueEnd = getBlob(expectedEnd);
await addSegment(2 * dataBlock + 1, dataValueEnd);
// Performance issue of 1860486 occurs here
await new Promise((res, rej) => {
let isDone = false;
const deleteReq = objectStore.delete(
IDBKeyRange.bound(6, lastIndex - 5, false, false)
);
deleteReq.onsuccess = () => {
isDone = true;
res();
};
deleteReq.onerror = err => {
isDone = true;
rej(err);
};
/**
* The deletion should be over in 20 seconds or less on desktop. With the
* regression, the operation can take more than 30 minutes. We use one
* minute to reduce intermittent failures due to the CI environment.
*
* Note that this is not a magical timeout for the completion of an
* asynchronous request: we are testing a hang and using an explicit timeout
* will avoid the much longer default timeout which is way too long to be
* acceptable in real use cases.
*
* Maintenance plan: If disk contention and slow hardware lead to too many
* intermittent failures, the regression cutoff could be increased to 2-3
* minutes or the test could be turned into a raptor performance test.
*/
const minutes = 60 * 1000;
const performance_regression_cutoff = 1 * minutes;
do_timeout(performance_regression_cutoff, () => {
if (!isDone) {
rej(Error("Performance regression detected"));
}
});
});
const getIndexedItems = async indexName => {
let actuals = [];
return new Promise(res => {
db
.transaction(["testObjectStore"], "readonly")
.objectStore("testObjectStore")
.index(indexName)
.openCursor().onsuccess = ev => {
const cursor = ev.target.result;
if (!cursor) {
res(actuals);
} else {
actuals.push(cursor.value.value);
cursor.continue();
}
};
});
};
const checkValuesEqualTo = async (actuals, from, to, expected) => {
for (let i = from; i < to; ++i) {
const actual = new Uint8Array(await actuals[i].arrayBuffer());
if (!compareBuffers(actual, expected)) {
return i;
}
}
return undefined;
};
const itemsA = await getIndexedItems("testObjectStoreIndexA");
equal(itemsA.length, 10);
const mismatchABegin = await checkValuesEqualTo(itemsA, 0, 5, expectedBegin);
equal(
mismatchABegin,
undefined,
"First index with value mismatch is " + mismatchABegin
);
const mismatchAEnd = await checkValuesEqualTo(itemsA, 5, 10, expectedEnd);
equal(
mismatchAEnd,
undefined,
"First index with value mismatch is " + mismatchAEnd
);
const itemsB = await getIndexedItems("testObjectStoreIndexB");
equal(itemsB.length, 10);
const mismatchBEnd = await checkValuesEqualTo(itemsB, 0, 5, expectedEnd);
equal(
mismatchBEnd,
undefined,
"First index with value mismatch is " + mismatchBEnd
);
const mismatchBBegin = await checkValuesEqualTo(itemsB, 5, 10, expectedBegin);
equal(
mismatchBBegin,
undefined,
"First index with value mismatch is " + mismatchBBegin
);
const actualsC = await getIndexedItems("testObjectStoreIndexC");
equal(actualsC.length, 10);
let countBegin = 0;
let countEnd = 0;
for (let i = 0; i < 10; ++i) {
const actual = new Uint8Array(await actualsC[i].arrayBuffer());
if (compareBuffers(actual, expectedBegin)) {
++countBegin;
} else if (compareBuffers(actual, expectedEnd)) {
++countEnd;
}
}
equal(countBegin, 5);
equal(countEnd, 5);
await db.close();
}