tor-browser

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

test_async_callbacks_with_spun_event_loops.cpp (4138B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 #include "storage_test_harness.h"
      5 #include "prthread.h"
      6 #include "nsIInterfaceRequestorUtils.h"
      7 
      8 #include "sqlite3.h"
      9 
     10 ////////////////////////////////////////////////////////////////////////////////
     11 //// Async Helpers
     12 
     13 /**
     14 * Spins the events loop for current thread until aCondition is true.
     15 */
     16 void spin_events_loop_until_true(const bool* const aCondition) {
     17  nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
     18  nsresult rv = NS_OK;
     19  bool processed = true;
     20  while (!(*aCondition) && NS_SUCCEEDED(rv)) {
     21    rv = thread->ProcessNextEvent(true, &processed);
     22  }
     23 }
     24 
     25 ////////////////////////////////////////////////////////////////////////////////
     26 //// mozIStorageStatementCallback implementation
     27 
     28 class UnownedCallback final : public mozIStorageStatementCallback {
     29 public:
     30  NS_DECL_ISUPPORTS
     31 
     32  // Whether the object has been destroyed.
     33  static bool sAlive;
     34  // Whether the first result was received.
     35  static bool sResult;
     36  // Whether an error was received.
     37  static bool sError;
     38 
     39  explicit UnownedCallback(mozIStorageConnection* aDBConn)
     40      : mDBConn(aDBConn), mCompleted(false) {
     41    sAlive = true;
     42    sResult = false;
     43    sError = false;
     44  }
     45 
     46 private:
     47  ~UnownedCallback() {
     48    sAlive = false;
     49    blocking_async_close(mDBConn);
     50  }
     51 
     52 public:
     53  NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet) override {
     54    sResult = true;
     55    spin_events_loop_until_true(&mCompleted);
     56    if (!sAlive) {
     57      MOZ_CRASH("The statement callback was destroyed prematurely.");
     58    }
     59    return NS_OK;
     60  }
     61 
     62  NS_IMETHOD HandleError(mozIStorageError* aError) override {
     63    sError = true;
     64    spin_events_loop_until_true(&mCompleted);
     65    if (!sAlive) {
     66      MOZ_CRASH("The statement callback was destroyed prematurely.");
     67    }
     68    return NS_OK;
     69  }
     70 
     71  NS_IMETHOD HandleCompletion(uint16_t aReason) override {
     72    mCompleted = true;
     73    return NS_OK;
     74  }
     75 
     76 protected:
     77  nsCOMPtr<mozIStorageConnection> mDBConn;
     78  bool mCompleted;
     79 };
     80 
     81 NS_IMPL_ISUPPORTS(UnownedCallback, mozIStorageStatementCallback)
     82 
     83 bool UnownedCallback::sAlive = false;
     84 bool UnownedCallback::sResult = false;
     85 bool UnownedCallback::sError = false;
     86 
     87 ////////////////////////////////////////////////////////////////////////////////
     88 //// Tests
     89 
     90 TEST(storage_async_callbacks_with_spun_event_loops,
     91     SpinEventsLoopInHandleResult)
     92 {
     93  nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
     94 
     95  // Create a test table and populate it.
     96  nsCOMPtr<mozIStorageStatement> stmt;
     97  db->CreateStatement("CREATE TABLE test (id INTEGER PRIMARY KEY)"_ns,
     98                      getter_AddRefs(stmt));
     99  stmt->Execute();
    100  stmt->Finalize();
    101 
    102  db->CreateStatement("INSERT INTO test (id) VALUES (?)"_ns,
    103                      getter_AddRefs(stmt));
    104  for (int32_t i = 0; i < 30; ++i) {
    105    stmt->BindInt32ByIndex(0, i);
    106    stmt->Execute();
    107    stmt->Reset();
    108  }
    109  stmt->Finalize();
    110 
    111  db->CreateStatement("SELECT * FROM test"_ns, getter_AddRefs(stmt));
    112  nsCOMPtr<mozIStoragePendingStatement> ps;
    113  do_check_success(
    114      stmt->ExecuteAsync(new UnownedCallback(db), getter_AddRefs(ps)));
    115  stmt->Finalize();
    116 
    117  spin_events_loop_until_true(&UnownedCallback::sResult);
    118 }
    119 
    120 TEST(storage_async_callbacks_with_spun_event_loops, SpinEventsLoopInHandleError)
    121 {
    122  nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
    123 
    124  // Create a test table and populate it.
    125  nsCOMPtr<mozIStorageStatement> stmt;
    126  db->CreateStatement("CREATE TABLE test (id INTEGER PRIMARY KEY)"_ns,
    127                      getter_AddRefs(stmt));
    128  stmt->Execute();
    129  stmt->Finalize();
    130 
    131  db->CreateStatement("INSERT INTO test (id) VALUES (1)"_ns,
    132                      getter_AddRefs(stmt));
    133  stmt->Execute();
    134  stmt->Finalize();
    135 
    136  // This will cause a constraint error.
    137  db->CreateStatement("INSERT INTO test (id) VALUES (1)"_ns,
    138                      getter_AddRefs(stmt));
    139  nsCOMPtr<mozIStoragePendingStatement> ps;
    140  do_check_success(
    141      stmt->ExecuteAsync(new UnownedCallback(db), getter_AddRefs(ps)));
    142  stmt->Finalize();
    143 
    144  spin_events_loop_until_true(&UnownedCallback::sError);
    145 }