Home | History | Annotate | Download | only in indexeddb
      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