tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

idbcursor_continue_delete_objectstore.any.js (3843B)


      1 // META: title=IDBObjectStore.delete() and IDBCursor.continue()
      2 // META: global=window,worker
      3 // META: script=resources/support.js
      4 
      5 'use strict';
      6 
      7 async_test(t => {
      8  /* The goal here is to test that any prefetching of cursor values performs
      9   * correct invalidation of prefetched data.  This test is motivated by the
     10   * particularities of the Firefox implementation of preloading, and is
     11   * specifically motivated by an edge case when prefetching prefetches at
     12   * least 2 extra records and at most determines whether a mutation is
     13   * potentially relevant based on current cursor position and direction and
     14   * does not test for key equivalence.  Future implementations may want to
     15   * help refine this test if their cursors are more clever.
     16   *
     17   * Step-wise we:
     18   * - Open a cursor, returning key 0.
     19   * - When the cursor request completes, without yielding control:
     20   *   - Issue a delete() call that won't actually delete anything but looks
     21   *     relevant.  This should purge prefetched records 1 and 2.
     22   *   - Issue a continue() which should result in record 1 being fetched
     23   *     again and record 2 being prefetched again.
     24   *   - Delete record 2.  Unless there's a synchronously available source
     25   *     of truth, the data from continue() above will not be present and
     26   *     we'll expect the implementation to need to set a flag to invalidate
     27   *     the prefetched data when it arrives.
     28   * - When the cursor request completes, validate we got record 1 and issue
     29   *   a continue.
     30   * - When the request completes, we should have a null cursor result value
     31   *   because 2 was deleted.
     32   */
     33  let db;
     34  let count = 0;
     35  const records =
     36      [{pKey: 'primaryKey_0'}, {pKey: 'primaryKey_1'}, {pKey: 'primaryKey_2'}];
     37 
     38  // This is a key that is not present in the database, but that is known to
     39  // be relevant to a forward iteration of the above keys by comparing to be
     40  // greater than all of them.
     41  const plausibleFutureKey = 'primaryKey_9';
     42 
     43  let open_rq = createdb(t);
     44  open_rq.onupgradeneeded = function(e) {
     45    db = e.target.result;
     46 
     47    let objStore = db.createObjectStore('test', {keyPath: 'pKey'});
     48 
     49    for (let i = 0; i < records.length; i++)
     50      objStore.add(records[i]);
     51  };
     52 
     53  open_rq.onsuccess = t.step_func(CursorDeleteRecord);
     54 
     55 
     56  function CursorDeleteRecord(e) {
     57    let txn = db.transaction('test', 'readwrite');
     58    let object_store = txn.objectStore('test');
     59    let cursor_rq = object_store.openCursor();
     60    let iteration = 0;
     61 
     62    cursor_rq.onsuccess = t.step_func(function(e) {
     63      let cursor = e.target.result;
     64 
     65      switch (iteration) {
     66        case 0:
     67          object_store.delete(plausibleFutureKey);
     68          assert_true(cursor != null, 'cursor valid');
     69          assert_equals(cursor.value.pKey, records[iteration].pKey);
     70          cursor.continue();
     71          object_store.delete(records[2].pKey);
     72          break;
     73        case 1:
     74          assert_true(cursor != null, 'cursor valid');
     75          assert_equals(cursor.value.pKey, records[iteration].pKey);
     76          cursor.continue();
     77          break;
     78        case 2:
     79          assert_equals(cursor, null, 'cursor no longer valid');
     80          break;
     81      };
     82      iteration++;
     83    });
     84 
     85    txn.oncomplete = t.step_func(VerifyRecordWasDeleted);
     86  }
     87 
     88 
     89  function VerifyRecordWasDeleted(e) {
     90    let cursor_rq = db.transaction('test', 'readonly')
     91                        .objectStore('test')
     92                        .openCursor();
     93 
     94    cursor_rq.onsuccess = t.step_func(function(e) {
     95      let cursor = e.target.result;
     96 
     97      if (!cursor) {
     98        assert_equals(count, 2, 'count');
     99        t.done();
    100      }
    101 
    102      assert_equals(cursor.value.pKey, records[count].pKey);
    103      count++;
    104      cursor.continue();
    105    });
    106  }
    107 }, 'Object store - remove a record from the object store while iterating cursor');