Bug 638123 - Test for bug 637957.
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 28 Apr 2011 19:55:09 +0200
changeset 69004 18d8734519e7eba62e8a86bca9535e0ac578bce3
parent 69003 cbf8fa67dd5bcc43871f26c4c09f6a0c73565178
child 69005 ad9ca556b46c11ea024add21ae678bd7b39eb1ea
push id76
push userbzbarsky@mozilla.com
push dateTue, 05 Jul 2011 17:00:57 +0000
treeherdermozilla-beta@d3a2732c35f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs638123, 637957
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 638123 - Test for bug 637957. r=sdwilsh
storage/test/Makefile.in
storage/test/test_async_callbacks_with_spun_event_loops.cpp
--- a/storage/test/Makefile.in
+++ b/storage/test/Makefile.in
@@ -54,16 +54,17 @@ CPP_UNIT_TESTS = \
   test_statement_scoper.cpp \
   test_mutex.cpp \
   test_binding_params.cpp \
   test_true_async.cpp \
   test_unlock_notify.cpp \
   test_service_init_background_thread.cpp \
   test_AsXXX_helpers.cpp \
   test_StatementCache.cpp \
+  test_async_callbacks_with_spun_event_loops.cpp \
   $(NULL)
 
 ifdef MOZ_DEBUG
 # FIXME bug 523392: test_deadlock_detector doesn't like Windows
 # FIXME bug 523378: also fails on OS X
 ifneq (,$(filter-out WINNT WINCE Darwin,$(OS_ARCH)))
 CPP_UNIT_TESTS += \
   test_deadlock_detector.cpp \
new file mode 100644
--- /dev/null
+++ b/storage/test/test_async_callbacks_with_spun_event_loops.cpp
@@ -0,0 +1,184 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+#include "storage_test_harness.h"
+#include "prthread.h"
+#include "nsIEventTarget.h"
+#include "nsIInterfaceRequestorUtils.h"
+
+#include "sqlite3.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//// Async Helpers
+
+/**
+ * Invoke AsyncClose on the given connection, blocking the main thread until we
+ * get the completion notification.
+ */
+void
+blocking_async_close(mozIStorageConnection *db)
+{
+  nsRefPtr<AsyncStatementSpinner> spinner(new AsyncStatementSpinner());
+
+  db->AsyncClose(spinner);
+  spinner->SpinUntilCompleted();
+}
+
+/**
+ * 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;
+  PRBool processed = PR_TRUE;
+  while (!(*aCondition) && NS_SUCCEEDED(rv)) {
+    rv = thread->ProcessNextEvent(true, &processed);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//// mozIStorageStatementCallback implementation
+
+class UnownedCallback : 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;
+
+  UnownedCallback(mozIStorageConnection* aDBConn)
+  : mDBConn(aDBConn)
+  , mCompleted(false)
+  {
+    sAlive = true;
+    sResult = false;
+    sError = false;
+  }
+
+  ~UnownedCallback()
+  {
+    sAlive = false;
+    blocking_async_close(mDBConn);
+  }
+
+  NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet)
+  {
+    sResult = true;
+    spin_events_loop_until_true(&mCompleted);
+    if (!sAlive) {
+      NS_RUNTIMEABORT("The statement callback was destroyed prematurely.");
+    }
+    return NS_OK;
+  }
+
+  NS_IMETHOD HandleError(mozIStorageError* aError)
+  {
+    sError = true;
+    spin_events_loop_until_true(&mCompleted);
+    if (!sAlive) {
+      NS_RUNTIMEABORT("The statement callback was destroyed prematurely.");
+    }
+    return NS_OK;
+  }
+
+  NS_IMETHOD HandleCompletion(PRUint16 aReason)
+  {
+    mCompleted = true;
+    return NS_OK;
+  }
+
+protected:
+  nsCOMPtr<mozIStorageConnection> mDBConn;
+  bool mCompleted;
+};
+
+NS_IMPL_ISUPPORTS1(UnownedCallback, mozIStorageStatementCallback);
+
+bool UnownedCallback::sAlive = false;
+bool UnownedCallback::sResult = false;
+bool UnownedCallback::sError = false;
+
+////////////////////////////////////////////////////////////////////////////////
+//// Tests
+
+void
+test_SpinEventsLoopInHandleResult()
+{
+  nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
+
+  // Create a test table and populate it.
+  nsCOMPtr<mozIStorageStatement> stmt;
+  db->CreateStatement(NS_LITERAL_CSTRING(
+    "CREATE TABLE test (id INTEGER PRIMARY KEY)"
+  ), getter_AddRefs(stmt));
+  stmt->Execute();
+  stmt->Finalize();
+
+  db->CreateStatement(NS_LITERAL_CSTRING(
+    "INSERT INTO test (id) VALUES (?)"
+  ), getter_AddRefs(stmt));
+  for (PRInt32 i = 0; i < 30; ++i) {
+    stmt->BindInt32ByIndex(0, i);
+    stmt->Execute();
+    stmt->Reset();
+  }
+  stmt->Finalize();
+
+  db->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT * FROM test"
+  ), 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);
+}
+
+void
+test_SpinEventsLoopInHandleError()
+{
+  nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
+
+  // Create a test table and populate it.
+  nsCOMPtr<mozIStorageStatement> stmt;
+  db->CreateStatement(NS_LITERAL_CSTRING(
+    "CREATE TABLE test (id INTEGER PRIMARY KEY)"
+  ), getter_AddRefs(stmt));
+  stmt->Execute();
+  stmt->Finalize();
+
+  db->CreateStatement(NS_LITERAL_CSTRING(
+    "INSERT INTO test (id) VALUES (1)"
+  ), getter_AddRefs(stmt));
+  stmt->Execute();
+  stmt->Finalize();
+
+  // This will cause a constraint error.
+  db->CreateStatement(NS_LITERAL_CSTRING(
+    "INSERT INTO test (id) VALUES (1)"
+  ), 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);
+}
+
+void (*gTests[])(void) = {
+  test_SpinEventsLoopInHandleResult,
+  test_SpinEventsLoopInHandleError,
+};
+
+const char *file = __FILE__;
+#define TEST_NAME "test async callbacks with spun event loops"
+#define TEST_FILE file
+#include "storage_test_harness_tail.h"