1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // These constants should match the ones in renderer_webidbcursor_impl.h 6 // to make sure the test hits the right code paths. 7 var kPrefetchThreshold = 2; 8 var kMinPrefetchAmount = 5; 9 10 var kNumberOfItems = 200; 11 12 function test() { 13 indexedDBTest(setVersionSuccess, fillObjectStore); 14 } 15 16 function setVersionSuccess() { 17 debug("setVersionSuccess():"); 18 window.db = event.target.result; 19 window.trans = event.target.transaction; 20 shouldBeTrue("trans !== null"); 21 var store = db.createObjectStore('store'); 22 store.createIndex('index', ''); 23 } 24 25 function fillObjectStore() { 26 debug("fillObjectStore()"); 27 var trans = db.transaction(['store'], 'readwrite'); 28 trans.onabort = unexpectedAbortCallback; 29 trans.oncomplete = firstTest; 30 31 var store = trans.objectStore('store'); 32 debug("Storing " + kNumberOfItems + " object in the object store."); 33 for (var i = 0; i < kNumberOfItems; ++i) { 34 var req = store.put(i, i); 35 req.onerror = unexpectedErrorCallback; 36 } 37 38 // Let the transaction finish. 39 } 40 41 function firstTest() { 42 debug("firstTest()"); 43 44 // Test iterating straight through the object store. 45 46 var trans = db.transaction(['store'], 'readwrite'); 47 trans.onabort = unexpectedAbortCallback; 48 trans.oncomplete = secondTest; 49 50 var store = trans.objectStore('store'); 51 var cursorReq = store.openCursor(); 52 cursorReq.onerror = unexpectedErrorCallback; 53 54 count = 0; 55 cursorReq.onsuccess = function() { 56 cursor = event.target.result; 57 if (cursor === null) { 58 shouldBe("count", "kNumberOfItems"); 59 return; // Let the transaction finish. 60 } 61 62 if (cursor.key !== count) 63 shouldBe("cursor.key", "count"); 64 if (cursor.value !== count) 65 shouldBe("cursor.value", "count"); 66 67 ++count; 68 69 cursor.continue(); 70 } 71 } 72 73 function secondTest() { 74 debug("secondTest()"); 75 76 // Test iterating through the object store, intermixed with 77 // continue calls to specific keys. 78 79 var trans = db.transaction(['store'], 'readwrite'); 80 trans.onabort = unexpectedAbortCallback; 81 trans.oncomplete = thirdTest; 82 83 var store = trans.objectStore('store'); 84 var cursorReq = store.openCursor(); 85 cursorReq.onerror = unexpectedErrorCallback; 86 87 var jumpTable = [{from: 5, to: 17}, 88 {from: 25, to: 30}, 89 {from: 31, to: 35}, 90 {from: 70, to: 80}, 91 {from: 98, to: 99}]; 92 93 count = 0; 94 expectedKey = 0; 95 96 cursorReq.onsuccess = function() { 97 cursor = event.target.result; 98 if (cursor === null) { 99 debug("Finished iterating after " + count + " steps."); 100 return; // Let the transaction finish. 101 } 102 103 if (cursor.key !== expectedKey) 104 shouldBe("cursor.key", "expectedKey"); 105 if (cursor.value !== expectedKey) 106 shouldBe("cursor.value", "expectedKey"); 107 108 ++count; 109 110 for (var i = 0; i < jumpTable.length; ++i) { 111 if (jumpTable[i].from === cursor.key) { 112 expectedKey = jumpTable[i].to; 113 debug("Jumping from "+ cursor.key + " to " + expectedKey); 114 cursor.continue(expectedKey); 115 return; 116 } 117 } 118 119 ++expectedKey; 120 cursor.continue(); 121 } 122 } 123 124 function thirdTest() { 125 debug("thirdTest()"); 126 127 // Test iterating straight through the object store in reverse. 128 129 var trans = db.transaction(['store'], 'readwrite'); 130 trans.onabort = unexpectedAbortCallback; 131 trans.oncomplete = fourthTest; 132 133 var store = trans.objectStore('store'); 134 var cursorReq = store.openCursor( 135 IDBKeyRange.upperBound(kNumberOfItems-1), 'prev'); 136 cursorReq.onerror = unexpectedErrorCallback; 137 138 count = 0; 139 cursorReq.onsuccess = function() { 140 cursor = event.target.result; 141 if (cursor === null) { 142 shouldBe("count", "kNumberOfItems"); 143 return; // Let the transaction finish. 144 } 145 146 expectedKey = kNumberOfItems - count - 1; 147 148 if (cursor.key !== expectedKey) 149 shouldBe("cursor.key", "expectedKey"); 150 if (cursor.value !== expectedKey) 151 shouldBe("cursor.value", "expectedKey"); 152 153 ++count; 154 155 cursor.continue(); 156 } 157 } 158 159 function fourthTest() { 160 debug("fourthTest()"); 161 162 // Test iterating, and then stopping before reaching the end. 163 // Make sure transaction terminates anyway. 164 165 var trans = db.transaction(['store'], 'readwrite'); 166 trans.onabort = unexpectedAbortCallback; 167 trans.oncomplete = function() { 168 debug("fourthTest() transaction completed"); 169 fifthTest(); 170 } 171 172 var store = trans.objectStore('store'); 173 var cursorReq = store.openCursor(); 174 cursorReq.onerror = unexpectedErrorCallback; 175 176 count = 0; 177 cursorReq.onsuccess = function() { 178 cursor = event.target.result; 179 180 if (cursor.key !== count) 181 shouldBe("cursor.key", "count"); 182 if (cursor.value !== count) 183 shouldBe("cursor.value", "count"); 184 185 ++count; 186 187 if (count === 25) { 188 // Schedule some other request. 189 var otherReq = store.get(42); 190 otherReq.onerror = unexpectedErrorCallback; 191 otherReq.onsuccess = function() { 192 if (count === 25) { 193 debug("Other request fired before continue, as expected."); 194 } else { 195 debug("Other request fired out-of-order!"); 196 fail(); 197 } 198 } 199 200 cursor.continue(); 201 return; 202 } 203 204 if (count === 30) { 205 // Do a continue first, then another request. 206 cursor.continue(); 207 208 var otherReq = store.get(42); 209 otherReq.onerror = unexpectedErrorCallback; 210 otherReq.onsuccess = function() { 211 if (count === 31) { 212 debug("Other request fired right after continue as expected."); 213 } else { 214 debug("Other request didn't fire right after continue as expected."); 215 fail(); 216 } 217 } 218 219 return; 220 } 221 222 if (count === 75) { 223 return; // Sudden stop. 224 } 225 226 cursor.continue(); 227 } 228 } 229 230 function fifthTest() { 231 debug("fifthTest()"); 232 233 // Test iterating over the pre-fetch threshold, but make sure the 234 // cursor is positioned so that it is actually at the last element 235 // in the range when pre-fetch fires, and make sure a null cursor 236 // is the result as expected. 237 238 var trans = db.transaction(['store'], 'readwrite'); 239 trans.onabort = unexpectedAbortCallback; 240 trans.oncomplete = sixthTest; 241 242 var store = trans.objectStore('store'); 243 244 var startKey = kNumberOfItems - 1 - kPrefetchThreshold; 245 var cursorReq = store.openCursor(IDBKeyRange.lowerBound(startKey)); 246 cursorReq.onerror = unexpectedErrorCallback; 247 248 count = 0; 249 cursorReq.onsuccess = function() { 250 cursor = event.target.result; 251 252 if (cursor === null) { 253 debug("cursor is null"); 254 shouldBe("count", "kPrefetchThreshold + 1"); 255 return; 256 } 257 258 debug("count: " + count); 259 ++count; 260 cursor.continue(); 261 } 262 } 263 264 function sixthTest() { 265 debug("sixthTest()"); 266 267 // Test stepping two cursors simultaneously. First cursor1 steps 268 // for a while, then cursor2, then back to cursor1, etc. 269 270 var trans = db.transaction(['store'], 'readwrite'); 271 trans.onabort = unexpectedAbortCallback; 272 trans.oncomplete = seventhTest; 273 var store = trans.objectStore('store'); 274 275 cursor1 = null; 276 cursor2 = null; 277 278 count1 = 0; 279 count2 = 0; 280 281 var cursor1func = function() { 282 var cursor = event.target.result; 283 if (cursor === null) { 284 shouldBe("count1", "kNumberOfItems"); 285 cursor2.continue(); 286 return; 287 } 288 289 if (cursor1 === null) { 290 cursor1 = cursor; 291 } 292 293 if (cursor1.key !== count1) 294 shouldBe("cursor1.key", "count1"); 295 if (cursor1.value !== count1) 296 shouldBe("cursor1.value", "count1"); 297 298 ++count1; 299 300 if (count1 % 20 === 0) { 301 if (cursor2 !== null) { 302 cursor2.continue(); 303 } else { 304 var req = store.openCursor(); 305 req.onerror = unexpectedErrorCallback; 306 req.onsuccess = cursor2func; 307 } 308 } else { 309 cursor1.continue(); 310 } 311 } 312 313 var cursor2func = function() { 314 var cursor = event.target.result; 315 if (cursor === null) { 316 shouldBe("count2", "kNumberOfItems"); 317 return; 318 } 319 320 if (cursor2 === null) { 321 cursor2 = cursor; 322 } 323 324 if (cursor2.key !== count2) 325 shouldBe("cursor2.key", "count2"); 326 if (cursor2.value !== count2) 327 shouldBe("cursor2.value", "count2"); 328 329 ++count2; 330 331 if (count2 % 20 === 0) { 332 cursor1.continue(); 333 } else { 334 cursor2.continue(); 335 } 336 } 337 338 var req = store.openCursor(); 339 req.onerror = unexpectedErrorCallback; 340 req.onsuccess = cursor1func; 341 } 342 343 function seventhTest() { 344 debug("seventhTest()"); 345 346 // Test iterating straight through an index. 347 348 var trans = db.transaction(['store'], 'readwrite'); 349 trans.onabort = unexpectedAbortCallback; 350 trans.oncomplete = eighthTest; 351 352 var store = trans.objectStore('store'); 353 var index = store.index('index'); 354 355 var cursorReq = index.openCursor(); 356 cursorReq.onerror = unexpectedErrorCallback; 357 count = 0; 358 359 cursorReq.onsuccess = function() { 360 cursor = event.target.result; 361 if (cursor === null) { 362 shouldBe("count", "kNumberOfItems"); 363 return; 364 } 365 366 if (cursor.key !== count) 367 shouldBe("cursor.key", "count"); 368 if (cursor.primaryKey !== count) 369 shouldBe("cursor.primaryKey", "count"); 370 if (cursor.value !== count) 371 shouldBe("cursor.value", "count"); 372 373 ++count; 374 cursor.continue(); 375 } 376 } 377 378 function eighthTest() { 379 debug("eighthTest()"); 380 381 // Run a key cursor over an index. 382 383 var trans = db.transaction(['store'], 'readwrite'); 384 trans.onabort = unexpectedAbortCallback; 385 trans.oncomplete = done; 386 387 var store = trans.objectStore('store'); 388 var index = store.index('index'); 389 390 var cursorReq = index.openKeyCursor(); 391 cursorReq.onerror = unexpectedErrorCallback; 392 count = 0; 393 394 cursorReq.onsuccess = function() { 395 cursor = event.target.result; 396 if (cursor === null) { 397 shouldBe("count", "kNumberOfItems"); 398 return; 399 } 400 401 if (cursor.key !== count) 402 shouldBe("cursor.key", "count"); 403 if (cursor.primaryKey !== count) 404 shouldBe("cursor.primaryKey", "count"); 405 406 ++count; 407 cursor.continue(); 408 } 409 } 410