tor-browser

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

test_transaction_abort.js (10834B)


      1 /**
      2 * Any copyright is dedicated to the Public Domain.
      3 * http://creativecommons.org/publicdomain/zero/1.0/
      4 */
      5 
      6 var testGenerator = testSteps();
      7 
      8 var abortFired = false;
      9 
     10 function abortListener(evt) {
     11  abortFired = true;
     12  is(evt.target.error, null, "Expect a null error for an aborted transaction");
     13 }
     14 
     15 function* testSteps() {
     16  const name = this.window ? window.location.pathname : "Splendid Test";
     17 
     18  let request = indexedDB.open(name, 1);
     19  request.onerror = errorHandler;
     20  request.onupgradeneeded = grabEventAndContinueHandler;
     21  request.onsuccess = grabEventAndContinueHandler;
     22  let event = yield undefined;
     23 
     24  let db = event.target.result;
     25  db.onabort = abortListener;
     26 
     27  let transaction;
     28  let objectStore;
     29  let index;
     30 
     31  transaction = event.target.transaction;
     32 
     33  is(transaction.error, null, "Expect a null error");
     34 
     35  objectStore = db.createObjectStore("foo", { autoIncrement: true });
     36  index = objectStore.createIndex("fooindex", "indexKey", { unique: true });
     37 
     38  is(transaction.db, db, "Correct database");
     39  is(transaction.mode, "versionchange", "Correct mode");
     40  is(transaction.objectStoreNames.length, 1, "Correct names length");
     41  is(transaction.objectStoreNames.item(0), "foo", "Correct name");
     42  is(transaction.objectStore("foo"), objectStore, "Can get stores");
     43  is(transaction.oncomplete, null, "No complete listener");
     44  is(transaction.onabort, null, "No abort listener");
     45 
     46  is(objectStore.name, "foo", "Correct name");
     47  is(objectStore.keyPath, null, "Correct keyPath");
     48 
     49  is(objectStore.indexNames.length, 1, "Correct indexNames length");
     50  is(objectStore.indexNames[0], "fooindex", "Correct indexNames name");
     51  is(objectStore.index("fooindex"), index, "Can get index");
     52 
     53  // Wait until it's complete!
     54  transaction.oncomplete = grabEventAndContinueHandler;
     55  event = yield undefined;
     56 
     57  is(transaction.db, db, "Correct database");
     58  is(transaction.mode, "versionchange", "Correct mode");
     59  is(transaction.objectStoreNames.length, 1, "Correct names length");
     60  is(transaction.objectStoreNames.item(0), "foo", "Correct name");
     61  is(transaction.onabort, null, "No abort listener");
     62 
     63  try {
     64    is(transaction.objectStore("foo").name, "foo", "Can't get stores");
     65    ok(false, "Should have thrown");
     66  } catch (e) {
     67    ok(true, "Out of scope transaction can't make stores");
     68  }
     69 
     70  is(objectStore.name, "foo", "Correct name");
     71  is(objectStore.keyPath, null, "Correct keyPath");
     72 
     73  is(objectStore.indexNames.length, 1, "Correct indexNames length");
     74  is(objectStore.indexNames[0], "fooindex", "Correct indexNames name");
     75 
     76  try {
     77    objectStore.add({});
     78    ok(false, "Should have thrown");
     79  } catch (e) {
     80    ok(true, "Add threw");
     81  }
     82 
     83  try {
     84    objectStore.put({}, 1);
     85    ok(false, "Should have thrown");
     86  } catch (e) {
     87    ok(true, "Put threw");
     88  }
     89 
     90  try {
     91    objectStore.put({}, 1);
     92    ok(false, "Should have thrown");
     93  } catch (e) {
     94    ok(true, "Put threw");
     95  }
     96 
     97  try {
     98    objectStore.delete(1);
     99    ok(false, "Should have thrown");
    100  } catch (e) {
    101    ok(true, "Remove threw");
    102  }
    103 
    104  try {
    105    objectStore.get(1);
    106    ok(false, "Should have thrown");
    107  } catch (e) {
    108    ok(true, "Get threw");
    109  }
    110 
    111  try {
    112    objectStore.getAll(null);
    113    ok(false, "Should have thrown");
    114  } catch (e) {
    115    ok(true, "GetAll threw");
    116  }
    117 
    118  try {
    119    objectStore.openCursor();
    120    ok(false, "Should have thrown");
    121  } catch (e) {
    122    ok(true, "OpenCursor threw");
    123  }
    124 
    125  try {
    126    objectStore.createIndex("bar", "id");
    127    ok(false, "Should have thrown");
    128  } catch (e) {
    129    ok(true, "CreateIndex threw");
    130  }
    131 
    132  try {
    133    objectStore.index("bar");
    134    ok(false, "Should have thrown");
    135  } catch (e) {
    136    ok(true, "Index threw");
    137  }
    138 
    139  try {
    140    objectStore.deleteIndex("bar");
    141    ok(false, "Should have thrown");
    142  } catch (e) {
    143    ok(true, "RemoveIndex threw");
    144  }
    145 
    146  yield undefined;
    147 
    148  request = db.transaction("foo", "readwrite").objectStore("foo").add({});
    149  request.onerror = errorHandler;
    150  request.onsuccess = grabEventAndContinueHandler;
    151  event = yield undefined;
    152 
    153  event.target.transaction.onabort = function () {
    154    ok(false, "Shouldn't see an abort event!");
    155  };
    156  event.target.transaction.oncomplete = grabEventAndContinueHandler;
    157  event = yield undefined;
    158 
    159  is(event.type, "complete", "Right kind of event");
    160 
    161  let key;
    162 
    163  request = db.transaction("foo", "readwrite").objectStore("foo").add({});
    164  request.onerror = errorHandler;
    165  request.onsuccess = grabEventAndContinueHandler;
    166  event = yield undefined;
    167 
    168  key = event.target.result;
    169 
    170  event.target.transaction.onabort = grabEventAndContinueHandler;
    171  event.target.transaction.oncomplete = function () {
    172    ok(false, "Shouldn't see a complete event here!");
    173  };
    174 
    175  event.target.transaction.abort();
    176 
    177  event = yield undefined;
    178 
    179  is(event.type, "abort", "Right kind of event");
    180 
    181  request = db.transaction("foo").objectStore("foo").get(key);
    182  request.onerror = errorHandler;
    183  request.onsuccess = grabEventAndContinueHandler;
    184  event = yield undefined;
    185 
    186  is(event.target.result, undefined, "Object was removed");
    187 
    188  executeSoon(function () {
    189    testGenerator.next();
    190  });
    191  yield undefined;
    192 
    193  let keys = [];
    194  let abortEventCount = 0;
    195  function abortErrorHandler(event) {
    196    is(event.target.error.name, "AbortError", "Good error");
    197    abortEventCount++;
    198    event.preventDefault();
    199  }
    200  objectStore = db.transaction("foo", "readwrite").objectStore("foo");
    201 
    202  for (let i = 0; i < 10; i++) {
    203    request = objectStore.add({});
    204    request.onerror = abortErrorHandler;
    205    request.onsuccess = function (event) {
    206      keys.push(event.target.result);
    207      if (keys.length == 5) {
    208        event.target.transaction.onabort = grabEventAndContinueHandler;
    209        event.target.transaction.abort();
    210      }
    211    };
    212  }
    213  event = yield undefined;
    214 
    215  is(event.type, "abort", "Got abort event");
    216  is(keys.length, 5, "Added 5 items in this transaction");
    217  is(abortEventCount, 5, "Got 5 abort error events");
    218 
    219  for (let i in keys) {
    220    request = db.transaction("foo").objectStore("foo").get(keys[i]);
    221    request.onerror = errorHandler;
    222    request.onsuccess = grabEventAndContinueHandler;
    223    event = yield undefined;
    224 
    225    is(event.target.result, undefined, "Object was removed by abort");
    226  }
    227 
    228  // Set up some predictible data
    229  transaction = db.transaction("foo", "readwrite");
    230  objectStore = transaction.objectStore("foo");
    231  objectStore.clear();
    232  objectStore.add({}, 1);
    233  objectStore.add({}, 2);
    234  request = objectStore.add({}, 1);
    235  request.onsuccess = function () {
    236    ok(false, "inserting duplicate key should fail");
    237  };
    238  request.onerror = function (event) {
    239    ok(true, "inserting duplicate key should fail");
    240    event.preventDefault();
    241  };
    242  transaction.oncomplete = grabEventAndContinueHandler;
    243  yield undefined;
    244 
    245  // Check when aborting is allowed
    246  abortEventCount = 0;
    247  let expectedAbortEventCount = 0;
    248 
    249  // During INITIAL
    250  transaction = db.transaction("foo");
    251  transaction.abort();
    252  try {
    253    transaction.abort();
    254    ok(false, "second abort should throw an error");
    255  } catch (ex) {
    256    ok(true, "second abort should throw an error");
    257  }
    258 
    259  // During LOADING
    260  transaction = db.transaction("foo");
    261  transaction.objectStore("foo").get(1).onerror = abortErrorHandler;
    262  expectedAbortEventCount++;
    263  transaction.abort();
    264  try {
    265    transaction.abort();
    266    ok(false, "second abort should throw an error");
    267  } catch (ex) {
    268    ok(true, "second abort should throw an error");
    269  }
    270 
    271  // During LOADING from callback
    272  transaction = db.transaction("foo");
    273  transaction.objectStore("foo").get(1).onsuccess = grabEventAndContinueHandler;
    274  event = yield undefined;
    275  transaction.objectStore("foo").get(1).onerror = abortErrorHandler;
    276  expectedAbortEventCount++;
    277  transaction.abort();
    278  try {
    279    transaction.abort();
    280    ok(false, "second abort should throw an error");
    281  } catch (ex) {
    282    ok(true, "second abort should throw an error");
    283  }
    284 
    285  // During LOADING from error callback
    286  transaction = db.transaction("foo", "readwrite");
    287  transaction.objectStore("foo").add({}, 1).onerror = function (event) {
    288    event.preventDefault();
    289 
    290    transaction.objectStore("foo").get(1).onerror = abortErrorHandler;
    291    expectedAbortEventCount++;
    292 
    293    transaction.abort();
    294    continueToNextStep();
    295  };
    296  yield undefined;
    297 
    298  // In between callbacks
    299  transaction = db.transaction("foo");
    300  function makeNewRequest() {
    301    let r = transaction.objectStore("foo").get(1);
    302    r.onsuccess = makeNewRequest;
    303    r.onerror = abortErrorHandler;
    304  }
    305  makeNewRequest();
    306  transaction.objectStore("foo").get(1).onsuccess = function () {
    307    executeSoon(function () {
    308      transaction.abort();
    309      expectedAbortEventCount++;
    310      continueToNextStep();
    311    });
    312  };
    313  yield undefined;
    314 
    315  // During COMMITTING
    316  transaction = db.transaction("foo", "readwrite");
    317  transaction.objectStore("foo").put({ hello: "world" }, 1).onsuccess =
    318    function () {
    319      continueToNextStep();
    320    };
    321  yield undefined;
    322  try {
    323    transaction.abort();
    324    ok(false, "second abort should throw an error");
    325  } catch (ex) {
    326    ok(true, "second abort should throw an error");
    327  }
    328  transaction.oncomplete = grabEventAndContinueHandler;
    329  event = yield undefined;
    330 
    331  // Since the previous transaction shouldn't have caused any error events,
    332  // we know that all events should have fired by now.
    333  is(abortEventCount, expectedAbortEventCount, "All abort errors fired");
    334 
    335  // Abort both failing and succeeding requests
    336  transaction = db.transaction("foo", "readwrite");
    337  transaction.onabort = transaction.oncomplete = grabEventAndContinueHandler;
    338  transaction.objectStore("foo").add({ indexKey: "key" }).onsuccess =
    339    function () {
    340      transaction.abort();
    341    };
    342  let request1 = transaction.objectStore("foo").add({ indexKey: "key" });
    343  request1.onsuccess = grabEventAndContinueHandler;
    344  request1.onerror = grabEventAndContinueHandler;
    345  let request2 = transaction.objectStore("foo").get(1);
    346  request2.onsuccess = grabEventAndContinueHandler;
    347  request2.onerror = grabEventAndContinueHandler;
    348 
    349  event = yield undefined;
    350  is(event.type, "error", "abort() should make all requests fail");
    351  is(event.target, request1, "abort() should make all requests fail");
    352  is(
    353    event.target.error.name,
    354    "AbortError",
    355    "abort() should make all requests fail"
    356  );
    357  event.preventDefault();
    358 
    359  event = yield undefined;
    360  is(event.type, "error", "abort() should make all requests fail");
    361  is(event.target, request2, "abort() should make all requests fail");
    362  is(
    363    event.target.error.name,
    364    "AbortError",
    365    "abort() should make all requests fail"
    366  );
    367  event.preventDefault();
    368 
    369  event = yield undefined;
    370  is(event.type, "abort", "transaction should fail");
    371  is(event.target, transaction, "transaction should fail");
    372 
    373  ok(abortFired, "Abort should have fired!");
    374 
    375  finishTest();
    376 }