tor-browser

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

test_connection_asyncClose.js (5311B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /*
      6 * Thorough branch coverage for asyncClose.
      7 *
      8 * Coverage of asyncClose by connection state at time of AsyncClose invocation:
      9 * - (asyncThread && mDBConn) => AsyncCloseConnection used, actually closes
     10 *   - test_asyncClose_does_not_complete_before_statements
     11 *   - test_double_asyncClose_throws
     12 *   - test_asyncClose_does_not_throw_without_callback
     13 * - (asyncThread && !mDBConn) => AsyncCloseConnection used, although no close
     14 *   is required.  Note that this is only possible in the event that
     15 *   openAsyncDatabase was used and we failed to open the database.
     16 *   Additionally, the async connection will never be exposed to the caller and
     17 *   AsyncInitDatabase will be the one to (automatically) call AsyncClose.
     18 *   - test_asyncClose_failed_open
     19 * - (!asyncThread && mDBConn) => Close() invoked, actually closes
     20 *   - test_asyncClose_on_sync_db
     21 * - (!asyncThread && !mDBConn) => Close() invoked, no close needed, errors.
     22 *   This happens if the database has already been closed.
     23 *   - test_double_asyncClose_throws
     24 */
     25 
     26 /**
     27 * Sanity check that our close indeed happens after asynchronously executed
     28 * statements scheduled during the same turn of the event loop.  Note that we
     29 * just care that the statement says it completed without error, we're not
     30 * worried that the close will happen and then the statement will magically
     31 * complete.
     32 */
     33 add_task(async function test_asyncClose_does_not_complete_before_statements() {
     34  let db = Services.storage.openDatabase(getTestDB());
     35  let stmt = db.createStatement("SELECT * FROM sqlite_master");
     36  // Issue the executeAsync but don't yield for it...
     37  let asyncStatementPromise = executeAsync(stmt);
     38  stmt.finalize();
     39 
     40  // Issue the close.  (And now the order of yielding doesn't matter.)
     41  // Branch coverage: (asyncThread && mDBConn)
     42  await asyncClose(db);
     43  equal(
     44    await asyncStatementPromise,
     45    Ci.mozIStorageStatementCallback.REASON_FINISHED
     46  );
     47 });
     48 
     49 /**
     50 * Open an async database (ensures the async thread is created) and then invoke
     51 * AsyncClose() twice without yielding control flow.  The first will initiate
     52 * the actual async close after calling setClosedState which synchronously
     53 * impacts what the second call will observe.  The second call will then see the
     54 * async thread is not available and fall back to invoking Close() which will
     55 * notice the mDBConn is already gone.
     56 */
     57 if (!AppConstants.DEBUG) {
     58  add_task(async function test_double_asyncClose_throws() {
     59    let db = await openAsyncDatabase(getTestDB());
     60 
     61    // (Don't yield control flow yet, save the promise for after we make the
     62    // second call.)
     63    // Branch coverage: (asyncThread && mDBConn)
     64    let realClosePromise = await asyncClose(db);
     65    try {
     66      // Branch coverage: (!asyncThread && !mDBConn)
     67      db.asyncClose();
     68      ok(false, "should have thrown");
     69    } catch (e) {
     70      equal(e.result, Cr.NS_ERROR_NOT_INITIALIZED);
     71    }
     72 
     73    await realClosePromise;
     74  });
     75 }
     76 
     77 /**
     78 * Create a sync db connection and never take it asynchronous and then call
     79 * asyncClose on it.  This will bring the async thread to life to perform the
     80 * shutdown to avoid blocking the main thread, although we won't be able to
     81 * tell the difference between this happening and the method secretly shunting
     82 * to close().
     83 */
     84 add_task(async function test_asyncClose_on_sync_db() {
     85  let db = Services.storage.openDatabase(getTestDB());
     86 
     87  // Branch coverage: (!asyncThread && mDBConn)
     88  await asyncClose(db);
     89  ok(true, "closed sync connection asynchronously");
     90 });
     91 
     92 /**
     93 * Fail to asynchronously open a DB in order to get an async thread existing
     94 * without having an open database and asyncClose invoked.  As per the file
     95 * doc-block, note that asyncClose will automatically be invoked by the
     96 * AsyncInitDatabase when it fails to open the database.  We will never be
     97 * provided with a reference to the connection and so cannot call AsyncClose on
     98 * it ourselves.
     99 */
    100 add_task(async function test_asyncClose_failed_open() {
    101  // This will fail and the promise will be rejected.
    102  let openPromise = openAsyncDatabase(getFakeDB());
    103  await openPromise.then(
    104    () => {
    105      ok(false, "we should have failed to open the db; this test is broken!");
    106    },
    107    () => {
    108      ok(true, "correctly failed to open db; bg asyncClose should happen");
    109    }
    110  );
    111  // (NB: we are unable to observe the thread shutdown, but since we never open
    112  // a database, this test is not going to interfere with other tests so much.)
    113 });
    114 
    115 // THE TEST BELOW WANTS TO BE THE LAST TEST WE RUN.  DO NOT MAKE IT SAD.
    116 /**
    117 * Verify that asyncClose without a callback does not explode.  Without a
    118 * callback the shutdown is not actually observable, so we run this test last
    119 * in order to avoid weird overlaps.
    120 */
    121 add_task(async function test_asyncClose_does_not_throw_without_callback() {
    122  let db = await openAsyncDatabase(getTestDB());
    123  // Branch coverage: (asyncThread && mDBConn)
    124  db.asyncClose();
    125  ok(true, "if we shutdown cleanly and do not crash, then we succeeded");
    126 });
    127 // OBEY SHOUTING UPPER-CASE COMMENTS.
    128 // ADD TESTS ABOVE THE FORMER TEST, NOT BELOW IT.