diff options
Diffstat (limited to 'storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp')
-rw-r--r-- | storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp b/storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp new file mode 100644 index 0000000000..bd437b61ec --- /dev/null +++ b/storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp @@ -0,0 +1,146 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +#include "storage_test_harness.h" +#include "prthread.h" +#include "nsIInterfaceRequestorUtils.h" +#include "mozilla/Attributes.h" + +#include "sqlite3.h" + +//////////////////////////////////////////////////////////////////////////////// +//// Async Helpers + +/** + * Spins the events loop for current thread until aCondition is true. + */ +void spin_events_loop_until_true(const bool* const aCondition) { + nsCOMPtr<nsIThread> thread(::do_GetCurrentThread()); + nsresult rv = NS_OK; + bool processed = true; + while (!(*aCondition) && NS_SUCCEEDED(rv)) { + rv = thread->ProcessNextEvent(true, &processed); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//// mozIStorageStatementCallback implementation + +class UnownedCallback final : public mozIStorageStatementCallback { + public: + NS_DECL_ISUPPORTS + + // Whether the object has been destroyed. + static bool sAlive; + // Whether the first result was received. + static bool sResult; + // Whether an error was received. + static bool sError; + + explicit UnownedCallback(mozIStorageConnection* aDBConn) + : mDBConn(aDBConn), mCompleted(false) { + sAlive = true; + sResult = false; + sError = false; + } + + private: + ~UnownedCallback() { + sAlive = false; + blocking_async_close(mDBConn); + } + + public: + NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet) override { + sResult = true; + spin_events_loop_until_true(&mCompleted); + if (!sAlive) { + MOZ_CRASH("The statement callback was destroyed prematurely."); + } + return NS_OK; + } + + NS_IMETHOD HandleError(mozIStorageError* aError) override { + sError = true; + spin_events_loop_until_true(&mCompleted); + if (!sAlive) { + MOZ_CRASH("The statement callback was destroyed prematurely."); + } + return NS_OK; + } + + NS_IMETHOD HandleCompletion(uint16_t aReason) override { + mCompleted = true; + return NS_OK; + } + + protected: + nsCOMPtr<mozIStorageConnection> mDBConn; + bool mCompleted; +}; + +NS_IMPL_ISUPPORTS(UnownedCallback, mozIStorageStatementCallback) + +bool UnownedCallback::sAlive = false; +bool UnownedCallback::sResult = false; +bool UnownedCallback::sError = false; + +//////////////////////////////////////////////////////////////////////////////// +//// Tests + +TEST(storage_async_callbacks_with_spun_event_loops, + SpinEventsLoopInHandleResult) +{ + nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); + + // Create a test table and populate it. + nsCOMPtr<mozIStorageStatement> stmt; + db->CreateStatement("CREATE TABLE test (id INTEGER PRIMARY KEY)"_ns, + getter_AddRefs(stmt)); + stmt->Execute(); + stmt->Finalize(); + + db->CreateStatement("INSERT INTO test (id) VALUES (?)"_ns, + getter_AddRefs(stmt)); + for (int32_t i = 0; i < 30; ++i) { + stmt->BindInt32ByIndex(0, i); + stmt->Execute(); + stmt->Reset(); + } + stmt->Finalize(); + + db->CreateStatement("SELECT * FROM test"_ns, getter_AddRefs(stmt)); + nsCOMPtr<mozIStoragePendingStatement> ps; + do_check_success( + stmt->ExecuteAsync(new UnownedCallback(db), getter_AddRefs(ps))); + stmt->Finalize(); + + spin_events_loop_until_true(&UnownedCallback::sResult); +} + +TEST(storage_async_callbacks_with_spun_event_loops, SpinEventsLoopInHandleError) +{ + nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); + + // Create a test table and populate it. + nsCOMPtr<mozIStorageStatement> stmt; + db->CreateStatement("CREATE TABLE test (id INTEGER PRIMARY KEY)"_ns, + getter_AddRefs(stmt)); + stmt->Execute(); + stmt->Finalize(); + + db->CreateStatement("INSERT INTO test (id) VALUES (1)"_ns, + getter_AddRefs(stmt)); + stmt->Execute(); + stmt->Finalize(); + + // This will cause a constraint error. + db->CreateStatement("INSERT INTO test (id) VALUES (1)"_ns, + getter_AddRefs(stmt)); + nsCOMPtr<mozIStoragePendingStatement> ps; + do_check_success( + stmt->ExecuteAsync(new UnownedCallback(db), getter_AddRefs(ps))); + stmt->Finalize(); + + spin_events_loop_until_true(&UnownedCallback::sError); +} |