summaryrefslogtreecommitdiffstats
path: root/dom/indexedDB/test/unit/test_clear_object_store_with_indexes.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/indexedDB/test/unit/test_clear_object_store_with_indexes.js')
-rw-r--r--dom/indexedDB/test/unit/test_clear_object_store_with_indexes.js206
1 files changed, 206 insertions, 0 deletions
diff --git a/dom/indexedDB/test/unit/test_clear_object_store_with_indexes.js b/dom/indexedDB/test/unit/test_clear_object_store_with_indexes.js
new file mode 100644
index 0000000000..a6e15cc15c
--- /dev/null
+++ b/dom/indexedDB/test/unit/test_clear_object_store_with_indexes.js
@@ -0,0 +1,206 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const isInChaosMode = () => {
+ return !!parseInt(Services.env.get("MOZ_CHAOSMODE"), 16);
+};
+
+// 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();
+}