tor-browser

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

idb-explicit-commit.any.js (10999B)


      1 // META: script=resources/support-promises.js
      2 'use strict';
      3 
      4 promise_test(async testCase => {
      5  const db = await createDatabase(testCase, db => {
      6    createBooksStore(testCase, db);
      7  });
      8  const txn = db.transaction(['books'], 'readwrite');
      9  const objectStore = txn.objectStore('books');
     10  objectStore.put({isbn: 'one', title: 'title1'});
     11  objectStore.put({isbn: 'two', title: 'title2'});
     12  objectStore.put({isbn: 'three', title: 'title3'});
     13  txn.commit();
     14  await promiseForTransaction(testCase, txn);
     15 
     16  const txn2 = db.transaction(['books'], 'readonly');
     17  const objectStore2 = txn2.objectStore('books');
     18  const getRequestitle1 = objectStore2.get('one');
     19  const getRequestitle2 = objectStore2.get('two');
     20  const getRequestitle3 = objectStore2.get('three');
     21  txn2.commit();
     22  await promiseForTransaction(testCase, txn2);
     23  assert_array_equals(
     24      [getRequestitle1.result.title,
     25          getRequestitle2.result.title,
     26          getRequestitle3.result.title],
     27      ['title1', 'title2', 'title3'],
     28      'All three retrieved titles should match those that were put.');
     29  db.close();
     30 }, 'Explicitly committed data can be read back out.');
     31 
     32 
     33 promise_test(async testCase => {
     34  let db = await createDatabase(testCase, () => {});
     35  assert_equals(1, db.version, 'A database should be created as version 1');
     36  db.close();
     37 
     38  // Upgrade the versionDB database and explicitly commit its versionchange
     39  // transaction.
     40  db = await migrateDatabase(testCase, 2, (db, txn) => {
     41    txn.commit();
     42  });
     43  assert_equals(2, db.version,
     44      'The database version should have been incremented regardless of '
     45      + 'whether the versionchange transaction was explicitly or implicitly '
     46      + 'committed.');
     47  db.close();
     48 }, 'commit() on a version change transaction does not cause errors.');
     49 
     50 
     51 promise_test(async testCase => {
     52  const db = await createDatabase(testCase, db => {
     53    createBooksStore(testCase, db);
     54  });
     55  const txn = db.transaction(['books'], 'readwrite');
     56  const objectStore = txn.objectStore('books');
     57  txn.commit();
     58  assert_throws_dom('TransactionInactiveError',
     59      () => { objectStore.put({isbn: 'one', title: 'title1'}); },
     60      'After commit is called, the transaction should be inactive.');
     61  db.close();
     62 }, 'A committed transaction becomes inactive immediately.');
     63 
     64 
     65 promise_test(async testCase => {
     66  const db = await createDatabase(testCase, db => {
     67    createBooksStore(testCase, db);
     68  });
     69  const txn = db.transaction(['books'], 'readwrite');
     70  const objectStore = txn.objectStore('books');
     71  const putRequest = objectStore.put({isbn: 'one', title: 'title1'});
     72  putRequest.onsuccess = testCase.step_func(() => {
     73    assert_throws_dom('TransactionInactiveError',
     74      () => { objectStore.put({isbn:'two', title:'title2'}); },
     75      'The transaction should not be active in the callback of a request after '
     76      + 'commit() is called.');
     77  });
     78  txn.commit();
     79  await promiseForTransaction(testCase, txn);
     80  db.close();
     81 }, 'A committed transaction is inactive in future request callbacks.');
     82 
     83 
     84 promise_test(async testCase => {
     85  const db = await createDatabase(testCase, db => {
     86    createBooksStore(testCase, db);
     87  });
     88  const txn = db.transaction(['books'], 'readwrite');
     89  const objectStore = txn.objectStore('books');
     90  txn.commit();
     91 
     92  assert_throws_dom('TransactionInactiveError',
     93      () => { objectStore.put({isbn:'one', title:'title1'}); },
     94      'After commit is called, the transaction should be inactive.');
     95 
     96  const txn2 = db.transaction(['books'], 'readonly');
     97  const objectStore2 = txn2.objectStore('books');
     98  const getRequest = objectStore2.get('one');
     99  await promiseForTransaction(testCase, txn2);
    100  assert_equals(getRequest.result, undefined);
    101 
    102  db.close();
    103 }, 'Puts issued after commit are not fulfilled.');
    104 
    105 
    106 promise_test(async testCase => {
    107  const db = await createDatabase(testCase, db => {
    108    createBooksStore(testCase, db);
    109  });
    110  const txn = db.transaction(['books'], 'readwrite');
    111  const objectStore = txn.objectStore('books');
    112  txn.abort();
    113  assert_throws_dom('InvalidStateError',
    114      () => { txn.commit(); },
    115      'The transaction should have been aborted.');
    116  db.close();
    117 }, 'Calling commit on an aborted transaction throws.');
    118 
    119 
    120 promise_test(async testCase => {
    121  const db = await createDatabase(testCase, db => {
    122    createBooksStore(testCase, db);
    123  });
    124  const txn = db.transaction(['books'], 'readwrite');
    125  const objectStore = txn.objectStore('books');
    126  txn.commit();
    127  assert_throws_dom('InvalidStateError',
    128      () => { txn.commit(); },
    129      'The transaction should have already committed.');
    130  db.close();
    131 }, 'Calling commit on a committed transaction throws.');
    132 
    133 
    134 promise_test(async testCase => {
    135  const db = await createDatabase(testCase, db => {
    136    createBooksStore(testCase, db);
    137  });
    138  const txn = db.transaction(['books'], 'readwrite');
    139  const objectStore = txn.objectStore('books');
    140  const putRequest = objectStore.put({isbn:'one', title:'title1'});
    141  txn.commit();
    142  assert_throws_dom('InvalidStateError',
    143      () => { txn.abort(); },
    144      'The transaction should already have committed.');
    145  const txn2 = db.transaction(['books'], 'readwrite');
    146  const objectStore2 = txn2.objectStore('books');
    147  const getRequest = objectStore2.get('one');
    148  await promiseForTransaction(testCase, txn2);
    149  assert_equals(
    150      getRequest.result.title,
    151      'title1',
    152      'Explicitly committed data should be gettable.');
    153  db.close();
    154 }, 'Calling abort on a committed transaction throws and does not prevent '
    155   + 'persisting the data.');
    156 
    157 
    158 promise_test(async testCase => {
    159  const db = await createDatabase(testCase, db => {
    160    createBooksStore(testCase, db);
    161  });
    162  const txn = db.transaction(['books'], 'readwrite');
    163  const objectStore = txn.objectStore('books');
    164  const releaseTxnFunction = keepAlive(testCase, txn, 'books');
    165 
    166  // Break up the scope of execution to force the transaction into an inactive
    167  // state.
    168  await timeoutPromise(0);
    169 
    170  assert_throws_dom('InvalidStateError',
    171      () => { txn.commit(); },
    172      'The transaction should be inactive so calling commit should throw.');
    173  releaseTxnFunction();
    174  db.close();
    175 }, 'Calling txn.commit() when txn is inactive should throw.');
    176 
    177 
    178 promise_test(async testCase => {
    179  const db = await createDatabase(testCase, db => {
    180    createBooksStore(testCase, db);
    181    createNotBooksStore(testCase, db);
    182  });
    183  // Txn1 should commit before txn2, even though txn2 uses commit().
    184  const txn1 = db.transaction(['books'], 'readwrite');
    185  txn1.objectStore('books').put({isbn: 'one', title: 'title1'});
    186  const releaseTxnFunction = keepAlive(testCase, txn1, 'books');
    187 
    188  const txn2 = db.transaction(['books'], 'readwrite');
    189  txn2.objectStore('books').put({isbn:'one', title:'title2'});
    190  txn2.commit();
    191 
    192  // Exercise the IndexedDB transaction ordering by executing one with a
    193  // different scope. A readonly transaction is used here because
    194  // implementations are not required to run non-overlapping readwrite
    195  // transactions in parallel, and some implementations (ex: Firefox)
    196  // will not.
    197  const txn3 = db.transaction(['not_books'], 'readonly');
    198  txn3.objectStore('not_books').getAllKeys();
    199  txn3.oncomplete = function() {
    200    releaseTxnFunction();
    201  }
    202  await Promise.all([promiseForTransaction(testCase, txn1),
    203                     promiseForTransaction(testCase, txn2)]);
    204 
    205  // Read the data back to verify that txn2 executed last.
    206  const txn4 = db.transaction(['books'], 'readonly');
    207  const getRequest4 = txn4.objectStore('books').get('one');
    208  await promiseForTransaction(testCase, txn4);
    209  assert_equals(getRequest4.result.title, 'title2');
    210  db.close();
    211 }, 'Transactions with same scope should stay in program order, even if one '
    212   + 'calls commit.');
    213 
    214 
    215 promise_test(async testCase => {
    216  const db = await createDatabase(testCase, db => {
    217    createBooksStore(testCase, db);
    218  });
    219  // Txn1 creates the book 'one' so the 'add()' below fails.
    220  const txn1 = db.transaction(['books'], 'readwrite');
    221  txn1.objectStore('books').add({isbn:'one', title:'title1'});
    222  txn1.commit();
    223  await promiseForTransaction(testCase, txn1);
    224 
    225  // Txn2 should abort, because the 'add' call is invalid, and commit() was
    226  // called.
    227  const txn2 = db.transaction(['books'], 'readwrite');
    228  const objectStore2 = txn2.objectStore('books');
    229  objectStore2.put({isbn:'two', title:'title2'});
    230  const addRequest = objectStore2.add({isbn:'one', title:'title2'});
    231  txn2.commit();
    232  txn2.oncomplete = () => { assert_unreached(
    233    'Transaction with invalid "add" call should not be completed.'); };
    234 
    235  // Wait for the transaction to complete. We have to explicitly wait for the
    236  // error signal on the transaction because of the nature of the test tooling.
    237  await Promise.all([
    238      requestWatcher(testCase, addRequest).wait_for('error'),
    239      transactionWatcher(testCase, txn2).wait_for(['error', 'abort'])
    240  ]);
    241 
    242  // Read the data back to verify that txn2 was aborted.
    243  const txn3 = db.transaction(['books'], 'readonly');
    244  const objectStore3 = txn3.objectStore('books');
    245  const getRequest1 = objectStore3.get('one');
    246  const getRequest2 = objectStore3.count('two');
    247  await promiseForTransaction(testCase, txn3);
    248  assert_equals(getRequest1.result.title, 'title1');
    249  assert_equals(getRequest2.result, 0);
    250  db.close();
    251 }, 'Transactions that explicitly commit and have errors should abort.');
    252 
    253 
    254 promise_test(async testCase => {
    255  const db = await createDatabase(testCase, db => {
    256    createBooksStore(testCase, db);
    257  });
    258  const txn1 = db.transaction(['books'], 'readwrite');
    259  txn1.objectStore('books').add({isbn: 'one', title: 'title1'});
    260  txn1.commit();
    261  await promiseForTransaction(testCase, txn1);
    262 
    263  // The second add request will throw an error, but the onerror handler will
    264  // appropriately catch the error allowing the valid put request on the
    265  // transaction to commit.
    266  const txn2 = db.transaction(['books'], 'readwrite');
    267  const objectStore2 = txn2.objectStore('books');
    268  objectStore2.put({isbn: 'two', title:'title2'});
    269  const addRequest = objectStore2.add({isbn: 'one', title:'unreached_title'});
    270  addRequest.onerror = (event) => {
    271    event.preventDefault();
    272    addRequest.transaction.commit();
    273  };
    274 
    275  // Wait for the transaction to complete. We have to explicitly wait for the
    276  // error signal on the transaction because of the nature of the test tooling.
    277  await transactionWatcher(testCase,txn2).wait_for(['error', 'complete'])
    278 
    279  // Read the data back to verify that txn2 was committed.
    280  const txn3 = db.transaction(['books'], 'readonly');
    281  const objectStore3 = txn3.objectStore('books');
    282  const getRequest1 = objectStore3.get('one');
    283  const getRequest2 = objectStore3.get('two');
    284  await promiseForTransaction(testCase, txn3);
    285  assert_equals(getRequest1.result.title, 'title1');
    286  assert_equals(getRequest2.result.title, 'title2');
    287  db.close();
    288 }, 'Transactions that handle all errors properly should behave as ' +
    289   'expected when an explicit commit is called in an onerror handler.');