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 }