test_clear_object_store_with_indexes.js (5820B)
1 /** 2 * Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/publicdomain/zero/1.0/ 4 */ 5 6 // Reduce the amount of data on slow platforms. 7 const getDataBlockSize = () => { 8 if (mozinfo.os == "android") { 9 // Android is much slower than desktop. 10 if (mozinfo.verify) { 11 return 54; // Chaos mode on android 12 } 13 14 return 3333; 15 } 16 17 if (isInChaosMode()) { 18 return 333; 19 } 20 21 return 33333; 22 }; 23 24 /* exported testSteps */ 25 async function testSteps() { 26 const name = this.window ? window.location.pathname : "Splendid Test"; 27 const request = indexedDB.open(name, 1); 28 29 (ev => { 30 const os = ev.target.result.createObjectStore("testObjectStore", { 31 keyPath: "id", 32 autoIncrement: false, 33 }); 34 35 os.createIndex("testObjectStoreIndexA", "indexA", { unique: true }); 36 os.createIndex("testObjectStoreIndexB", "indexB", { unique: false }); 37 os.createIndex("testObjectStoreIndexC", "indexC", { unique: false }); 38 })(await expectingUpgrade(request)); 39 40 const db = (await expectingSuccess(request)).target.result; 41 42 const objectStore = db 43 .transaction(["testObjectStore"], "readwrite") 44 .objectStore("testObjectStore"); 45 46 const dataBlock = getDataBlockSize(); 47 const lastIndex = 3 * dataBlock; 48 49 info("We will now add " + lastIndex + " blobs to our object store"); 50 51 const addSegment = async (from, dataValue) => { 52 for (let i = from; i <= from + dataBlock - 1; ++i) { 53 await objectStore.add({ 54 id: i, 55 indexA: i, 56 indexB: lastIndex + 1 - i, 57 indexC: i % 3, 58 value: dataValue, 59 }); 60 } 61 }; 62 63 const expectedBegin = getRandomView(512); 64 const expectedMiddle = getRandomView(512); 65 const expectedEnd = getRandomView(512); 66 ok( 67 !compareBuffers(expectedBegin, expectedMiddle), 68 "Are all buffers different?" 69 ); 70 ok(!compareBuffers(expectedBegin, expectedEnd), "Are all buffers different?"); 71 ok( 72 !compareBuffers(expectedMiddle, expectedEnd), 73 "Are all buffers different?" 74 ); 75 76 const dataValueBegin = getBlob(expectedBegin); 77 await addSegment(1, dataValueBegin); 78 79 const dataValueMiddle = getBlob(expectedMiddle); 80 await addSegment(dataBlock + 1, dataValueMiddle); 81 82 const dataValueEnd = getBlob(expectedEnd); 83 await addSegment(2 * dataBlock + 1, dataValueEnd); 84 85 // Performance issue of 1860486 occurs here 86 await new Promise((res, rej) => { 87 let isDone = false; 88 const deleteReq = objectStore.delete( 89 IDBKeyRange.bound(6, lastIndex - 5, false, false) 90 ); 91 deleteReq.onsuccess = () => { 92 isDone = true; 93 res(); 94 }; 95 deleteReq.onerror = err => { 96 isDone = true; 97 rej(err); 98 }; 99 100 /** 101 * The deletion should be over in 20 seconds or less on desktop. With the 102 * regression, the operation can take more than 30 minutes. We use one 103 * minute to reduce intermittent failures due to the CI environment. 104 * 105 * Note that this is not a magical timeout for the completion of an 106 * asynchronous request: we are testing a hang and using an explicit timeout 107 * will avoid the much longer default timeout which is way too long to be 108 * acceptable in real use cases. 109 * 110 * Maintenance plan: If disk contention and slow hardware lead to too many 111 * intermittent failures, the regression cutoff could be increased to 2-3 112 * minutes or the test could be turned into a raptor performance test. 113 */ 114 const minutes = 60 * 1000; 115 const performance_regression_cutoff = 1 * minutes; 116 do_timeout(performance_regression_cutoff, () => { 117 if (!isDone) { 118 rej(Error("Performance regression detected")); 119 } 120 }); 121 }); 122 123 const getIndexedItems = async indexName => { 124 let actuals = []; 125 return new Promise(res => { 126 db 127 .transaction(["testObjectStore"], "readonly") 128 .objectStore("testObjectStore") 129 .index(indexName) 130 .openCursor().onsuccess = ev => { 131 const cursor = ev.target.result; 132 if (!cursor) { 133 res(actuals); 134 } else { 135 actuals.push(cursor.value.value); 136 cursor.continue(); 137 } 138 }; 139 }); 140 }; 141 142 const checkValuesEqualTo = async (actuals, from, to, expected) => { 143 for (let i = from; i < to; ++i) { 144 const actual = new Uint8Array(await actuals[i].arrayBuffer()); 145 if (!compareBuffers(actual, expected)) { 146 return i; 147 } 148 } 149 return undefined; 150 }; 151 152 const itemsA = await getIndexedItems("testObjectStoreIndexA"); 153 equal(itemsA.length, 10); 154 155 const mismatchABegin = await checkValuesEqualTo(itemsA, 0, 5, expectedBegin); 156 equal( 157 mismatchABegin, 158 undefined, 159 "First index with value mismatch is " + mismatchABegin 160 ); 161 const mismatchAEnd = await checkValuesEqualTo(itemsA, 5, 10, expectedEnd); 162 equal( 163 mismatchAEnd, 164 undefined, 165 "First index with value mismatch is " + mismatchAEnd 166 ); 167 168 const itemsB = await getIndexedItems("testObjectStoreIndexB"); 169 170 equal(itemsB.length, 10); 171 const mismatchBEnd = await checkValuesEqualTo(itemsB, 0, 5, expectedEnd); 172 equal( 173 mismatchBEnd, 174 undefined, 175 "First index with value mismatch is " + mismatchBEnd 176 ); 177 const mismatchBBegin = await checkValuesEqualTo(itemsB, 5, 10, expectedBegin); 178 equal( 179 mismatchBBegin, 180 undefined, 181 "First index with value mismatch is " + mismatchBBegin 182 ); 183 184 const actualsC = await getIndexedItems("testObjectStoreIndexC"); 185 186 equal(actualsC.length, 10); 187 let countBegin = 0; 188 let countEnd = 0; 189 for (let i = 0; i < 10; ++i) { 190 const actual = new Uint8Array(await actualsC[i].arrayBuffer()); 191 if (compareBuffers(actual, expectedBegin)) { 192 ++countBegin; 193 } else if (compareBuffers(actual, expectedEnd)) { 194 ++countEnd; 195 } 196 } 197 198 equal(countBegin, 5); 199 equal(countEnd, 5); 200 201 await db.close(); 202 }