summaryrefslogtreecommitdiffstats
path: root/storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp
diff options
context:
space:
mode:
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.cpp146
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);
+}