Bug 1315138 - gtestify storage/test/*.cpp. r=mak,erahm.
authorNicholas Nethercote <nnethercote@mozilla.com>
Fri, 11 Nov 2016 09:59:23 +1100
changeset 323878 7f2bbd06a80c43cc1a569e916b4cc9c575eb3448
parent 323877 a494dd0ae2b0278403a36b38c64c0d48074b88bc
child 323879 189500d81aade9cb74be70de648c47faf1c0c3a3
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersmak, erahm
bugs1315138, 1318282
milestone53.0a1
Bug 1315138 - gtestify storage/test/*.cpp. r=mak,erahm. This change is mostly straightforward, except for the following. - It removes all the printing from the do_check_* macros because gtest macros do appropriate printing. - test_StatementCache.cpp needs some special gtest magic for the type parameterization. - It merges the four tests in test_unlock_notify.cpp because they rely on being executed in order, and so aren't independent. - storage_test_harness_tail.h is no longer necessary because gtest provides the test looping functionality. - It uses #include and the preprocessor to remove the duplication between test_deadlock_detector.cpp and xpcom/tests/DeadlockDetector.cpp. - It makes the test in test_service_init_background_thread.cpp a death test to force it to be the first storage gtest, because it fails otherwise. - It adds code to undo the SQLite mutex hooking as necessary, so that tests don't interfere with each other. - It de-virtualizes Spinner's destructor (as identified in bug 1318282).
python/mozbuild/mozbuild/frontend/emitter.py
storage/test/gtest/moz.build
storage/test/gtest/storage_test_harness.h
storage/test/gtest/test_AsXXX_helpers.cpp
storage/test/gtest/test_StatementCache.cpp
storage/test/gtest/test_asyncStatementExecution_transaction.cpp
storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp
storage/test/gtest/test_binding_params.cpp
storage/test/gtest/test_deadlock_detector.cpp
storage/test/gtest/test_file_perms.cpp
storage/test/gtest/test_mutex.cpp
storage/test/gtest/test_service_init_background_thread.cpp
storage/test/gtest/test_statement_scoper.cpp
storage/test/gtest/test_transaction_helper.cpp
storage/test/gtest/test_true_async.cpp
storage/test/gtest/test_unlock_notify.cpp
storage/test/moz.build
storage/test/storage_test_harness.h
storage/test/storage_test_harness_tail.h
storage/test/test_AsXXX_helpers.cpp
storage/test/test_StatementCache.cpp
storage/test/test_asyncStatementExecution_transaction.cpp
storage/test/test_async_callbacks_with_spun_event_loops.cpp
storage/test/test_binding_params.cpp
storage/test/test_deadlock_detector.cpp
storage/test/test_file_perms.cpp
storage/test/test_mutex.cpp
storage/test/test_service_init_background_thread.cpp
storage/test/test_statement_scoper.cpp
storage/test/test_transaction_helper.cpp
storage/test/test_true_async.cpp
storage/test/test_unlock_notify.cpp
testing/cppunittest.ini
toolkit/components/places/tests/gtest/places_test_harness.h
toolkit/components/places/tests/gtest/test_IHistory.cpp
xpcom/tests/gtest/TestDeadlockDetector.cpp
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -115,29 +115,16 @@ ALLOWED_XPCOM_GLUE = {
     ('TestStreamLoader', 'netwerk/test'),
     ('TestUpload', 'netwerk/test'),
     ('TestURLParser', 'netwerk/test'),
     ('urltest', 'netwerk/test'),
     ('TestBind', 'netwerk/test'),
     ('TestCookie', 'netwerk/test'),
     ('TestUDPSocket', 'netwerk/test'),
     ('xpcshell', 'js/xpconnect/shell'),
-    ('test_AsXXX_helpers', 'storage/test'),
-    ('test_async_callbacks_with_spun_event_loops', 'storage/test'),
-    ('test_asyncStatementExecution_transaction', 'storage/test'),
-    ('test_binding_params', 'storage/test'),
-    ('test_deadlock_detector', 'storage/test'),
-    ('test_file_perms', 'storage/test'),
-    ('test_mutex', 'storage/test'),
-    ('test_service_init_background_thread', 'storage/test'),
-    ('test_statement_scoper', 'storage/test'),
-    ('test_StatementCache', 'storage/test'),
-    ('test_transaction_helper', 'storage/test'),
-    ('test_true_async', 'storage/test'),
-    ('test_unlock_notify', 'storage/test'),
     ('testcrasher', 'toolkit/crashreporter/test'),
     ('mediaconduit_unittests', 'media/webrtc/signaling/test'),
     ('mediapipeline_unittest', 'media/webrtc/signaling/test'),
     ('sdp_file_parser', 'media/webrtc/signaling/fuzztest'),
     ('signaling_unittests', 'media/webrtc/signaling/test'),
     ('TestMailCookie', 'mailnews/base/test'),
     ('calbasecomps', 'calendar/base/backend/libical/build'),
     ('purplexpcom', 'extensions/purple/purplexpcom/src'),
new file mode 100644
--- /dev/null
+++ b/storage/test/gtest/moz.build
@@ -0,0 +1,33 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+    'test_AsXXX_helpers.cpp',
+    'test_async_callbacks_with_spun_event_loops.cpp',
+    'test_asyncStatementExecution_transaction.cpp',
+    'test_binding_params.cpp',
+    'test_file_perms.cpp',
+    'test_mutex.cpp',
+    'test_service_init_background_thread.cpp',
+    'test_statement_scoper.cpp',
+    'test_StatementCache.cpp',
+    'test_transaction_helper.cpp',
+    'test_true_async.cpp',
+    'test_unlock_notify.cpp',
+]
+
+if CONFIG['MOZ_DEBUG'] and CONFIG['OS_ARCH'] not in ('WINNT') and CONFIG['OS_TARGET'] != 'Android':
+    # FIXME bug 523392: test_deadlock_detector doesn't like Windows
+    # Bug 1054249: Doesn't work on Android
+    UNIFIED_SOURCES += [
+        'test_deadlock_detector.cpp',
+    ]
+
+LOCAL_INCLUDES += [
+    '../..',
+]
+
+FINAL_LIBRARY = 'xul-gtest'
rename from storage/test/storage_test_harness.h
rename to storage/test/gtest/storage_test_harness.h
--- a/storage/test/storage_test_harness.h
+++ b/storage/test/gtest/storage_test_harness.h
@@ -1,20 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "TestHarness.h"
+#ifndef storage_test_harness_h__
+#define storage_test_harness_h__
+
+#include "gtest/gtest.h"
 
+#include "prthread.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsDirectoryServiceUtils.h"
 #include "nsMemory.h"
-#include "prthread.h"
+#include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
-#include "nsDirectoryServiceDefs.h"
 #include "mozilla/ReentrantMonitor.h"
 
 #include "mozIStorageService.h"
 #include "mozIStorageConnection.h"
 #include "mozIStorageStatementCallback.h"
 #include "mozIStorageCompletionCallback.h"
 #include "mozIStorageBindingParamsArray.h"
 #include "mozIStorageBindingParams.h"
@@ -22,75 +28,36 @@
 #include "mozIStorageStatement.h"
 #include "mozIStoragePendingStatement.h"
 #include "mozIStorageError.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIEventTarget.h"
 
 #include "sqlite3.h"
 
-static int gTotalTests = 0;
-static int gPassedTests = 0;
-
 #define do_check_true(aCondition) \
-  PR_BEGIN_MACRO \
-    gTotalTests++; \
-    if (aCondition) { \
-      gPassedTests++; \
-    } else { \
-      fail("%s | Expected true, got false at line %d", __FILE__, __LINE__); \
-    } \
-  PR_END_MACRO
+  EXPECT_TRUE(aCondition)
 
 #define do_check_false(aCondition) \
-  PR_BEGIN_MACRO \
-    gTotalTests++; \
-    if (!aCondition) { \
-      gPassedTests++; \
-    } else { \
-      fail("%s | Expected false, got true at line %d", __FILE__, __LINE__); \
-    } \
-  PR_END_MACRO
+  EXPECT_FALSE(aCondition)
 
 #define do_check_success(aResult) \
   do_check_true(NS_SUCCEEDED(aResult))
 
-#ifdef LINUX
-// XXX Linux opt builds on tinderbox are orange due to linking with stdlib.
-// This is sad and annoying, but it's a workaround that works.
 #define do_check_eq(aExpected, aActual) \
   do_check_true(aExpected == aActual)
-#else
-#include <sstream>
-// Print nsresult as uint32_t
-std::ostream& operator<<(std::ostream& aStream, const nsresult aInput)
-{
-  return aStream << static_cast<uint32_t>(aInput);
-}
-#define do_check_eq(aExpected, aActual) \
-  PR_BEGIN_MACRO \
-    gTotalTests++; \
-    if (aExpected == aActual) { \
-      gPassedTests++; \
-    } else { \
-      std::ostringstream temp; \
-      temp << __FILE__ << " | Expected '" << aExpected << "', got '"; \
-      temp << aActual <<"' at line " << __LINE__; \
-      fail(temp.str().c_str()); \
-    } \
-  PR_END_MACRO
-#endif
 
-#define do_check_ok(aInvoc) do_check_true((aInvoc) == SQLITE_OK)
+#define do_check_ok(aInvoc) \
+  do_check_true((aInvoc) == SQLITE_OK)
 
 already_AddRefed<mozIStorageService>
 getService()
 {
   nsCOMPtr<mozIStorageService> ss =
-    do_GetService("@mozilla.org/storage/service;1");
+    do_CreateInstance("@mozilla.org/storage/service;1");
   do_check_true(ss);
   return ss.forget();
 }
 
 already_AddRefed<mozIStorageConnection>
 getMemoryDatabase()
 {
   nsCOMPtr<mozIStorageService> ss = getService();
@@ -276,28 +243,39 @@ extern "C" void wrapped_MutexEnter(sqlit
 
 extern "C" int wrapped_MutexTry(sqlite3_mutex *mutex)
 {
   if (::PR_GetCurrentThread() == watched_thread)
     mutex_used_on_watched_thread = true;
   return orig_mutex_methods.xMutexTry(mutex);
 }
 
-void hook_sqlite_mutex()
+class HookSqliteMutex
 {
-  // We need to initialize and teardown SQLite to get it to set up the
-  // default mutex handlers for us so we can steal them and wrap them.
-  do_check_ok(sqlite3_initialize());
-  do_check_ok(sqlite3_shutdown());
-  do_check_ok(::sqlite3_config(SQLITE_CONFIG_GETMUTEX, &orig_mutex_methods));
-  do_check_ok(::sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped_mutex_methods));
-  wrapped_mutex_methods.xMutexEnter = wrapped_MutexEnter;
-  wrapped_mutex_methods.xMutexTry = wrapped_MutexTry;
-  do_check_ok(::sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped_mutex_methods));
-}
+public:
+  HookSqliteMutex()
+  {
+    // We need to initialize and teardown SQLite to get it to set up the
+    // default mutex handlers for us so we can steal them and wrap them.
+    do_check_ok(sqlite3_initialize());
+    do_check_ok(sqlite3_shutdown());
+    do_check_ok(::sqlite3_config(SQLITE_CONFIG_GETMUTEX, &orig_mutex_methods));
+    do_check_ok(::sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped_mutex_methods));
+    wrapped_mutex_methods.xMutexEnter = wrapped_MutexEnter;
+    wrapped_mutex_methods.xMutexTry = wrapped_MutexTry;
+    do_check_ok(::sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped_mutex_methods));
+  }
+
+  ~HookSqliteMutex()
+  {
+    do_check_ok(sqlite3_shutdown());
+    do_check_ok(::sqlite3_config(SQLITE_CONFIG_MUTEX, &orig_mutex_methods));
+    do_check_ok(sqlite3_initialize());
+  }
+};
 
 /**
  * Call to clear the watch state and to set the watching against this thread.
  *
  * Check |mutex_used_on_watched_thread| to see if the mutex has fired since
  * this method was last called.  Since we're talking about the current thread,
  * there are no race issues to be concerned about
  */
@@ -382,8 +360,11 @@ get_conn_async_thread(mozIStorageConnect
   // same one as the one we report from getInterface.
   nsCOMPtr<nsIEventTarget> target = do_GetInterface(db);
   nsCOMPtr<nsIThread> allegedAsyncThread = do_QueryInterface(target);
   PRThread *allegedPRThread;
   (void)allegedAsyncThread->GetPRThread(&allegedPRThread);
   do_check_eq(allegedPRThread, last_non_watched_thread);
   return asyncThread.forget();
 }
+
+#endif // storage_test_harness_h__
+
rename from storage/test/test_AsXXX_helpers.cpp
rename to storage/test/gtest/test_AsXXX_helpers.cpp
--- a/storage/test/test_AsXXX_helpers.cpp
+++ b/storage/test/gtest/test_AsXXX_helpers.cpp
@@ -16,17 +16,17 @@
 
 class Spinner : public AsyncStatementSpinner
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_ASYNCSTATEMENTSPINNER
   Spinner() {}
 protected:
-  virtual ~Spinner() {}
+  ~Spinner() {}
 };
 
 NS_IMPL_ISUPPORTS_INHERITED0(Spinner,
                              AsyncStatementSpinner)
 
 NS_IMETHODIMP
 Spinner::HandleResult(mozIStorageResultSet *aResultSet)
 {
@@ -46,18 +46,17 @@ Spinner::HandleResult(mozIStorageResultS
   len = 100;
   do_check_eq(row->AsSharedBlob(0, &len), (const uint8_t*)nullptr);
   do_check_eq(len, 0);
 
   do_check_eq(row->IsNull(0), true);
   return NS_OK;
 }
 
-void
-test_NULLFallback()
+TEST(storage_AsXXX_helpers, NULLFallback)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   nsCOMPtr<mozIStorageStatement> stmt;
   (void)db->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT NULL"
   ), getter_AddRefs(stmt));
 
@@ -91,37 +90,26 @@ test_NULLFallback()
   do_check_eq(valueArray->AsSharedWString(0, &len), (const char16_t*)nullptr);
   do_check_eq(len, 0);
   len = 100;
   do_check_eq(valueArray->AsSharedBlob(0, &len), (const uint8_t*)nullptr);
   do_check_eq(len, 0);
   do_check_eq(valueArray->IsNull(0), true);
 }
 
-void
-test_asyncNULLFallback()
+TEST(storage_AsXXX_helpers, asyncNULLFallback)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   (void)db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "SELECT NULL"
   ), getter_AddRefs(stmt));
 
   nsCOMPtr<mozIStoragePendingStatement> pendingStmt;
   do_check_true(NS_SUCCEEDED(stmt->ExecuteAsync(nullptr, getter_AddRefs(pendingStmt))));
   do_check_true(pendingStmt);
   stmt->Finalize();
   RefPtr<Spinner> asyncSpin(new Spinner());
   db->AsyncClose(asyncSpin);
   asyncSpin->SpinUntilCompleted();
-
 }
 
-void (*gTests[])(void) = {
-  test_NULLFallback
-, test_asyncNULLFallback
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "AsXXX helpers"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_StatementCache.cpp
rename to storage/test/gtest/test_StatementCache.cpp
--- a/storage/test/test_StatementCache.cpp
+++ b/storage/test/gtest/test_StatementCache.cpp
@@ -46,118 +46,102 @@ public:
   {
     this->Assign(aOther);
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Functions
 
-template<typename StringType>
-void
-test_GetCachedStatement()
+// This is some gtest magic that allows us to parameterize tests by |const
+// char[]| and |StringWrapper|.
+template <typename T>
+class storage_StatementCache : public ::testing::Test {};
+typedef ::testing::Types<const char[], StringWrapper> TwoStringTypes;
+
+TYPED_TEST_CASE(storage_StatementCache, TwoStringTypes);
+TYPED_TEST(storage_StatementCache, GetCachedStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
   SyncCache cache(db);
 
-  StringType sql = "SELECT * FROM sqlite_master";
+  TypeParam sql = "SELECT * FROM sqlite_master";
 
   // Make sure we get a statement back with the right state.
   nsCOMPtr<mozIStorageStatement> stmt = cache.GetCachedStatement(sql);
   do_check_true(stmt);
   int32_t state;
   do_check_success(stmt->GetState(&state));
   do_check_eq(mozIStorageBaseStatement::MOZ_STORAGE_STATEMENT_READY, state);
 
   // Check to make sure we get the same copy the second time we ask.
   nsCOMPtr<mozIStorageStatement> stmt2 = cache.GetCachedStatement(sql);
   do_check_true(stmt2);
   do_check_eq(stmt.get(), stmt2.get());
 }
 
-template <typename StringType>
-void
-test_FinalizeStatements()
+TYPED_TEST_CASE(storage_StatementCache, TwoStringTypes);
+TYPED_TEST(storage_StatementCache, FinalizeStatements)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
   SyncCache cache(db);
 
-  StringType sql = "SELECT * FROM sqlite_master";
+  TypeParam sql = "SELECT * FROM sqlite_master";
 
   // Get a statement, and then tell the cache to finalize.
   nsCOMPtr<mozIStorageStatement> stmt = cache.GetCachedStatement(sql);
   do_check_true(stmt);
 
   cache.FinalizeStatements();
 
   // We should be in an invalid state at this point.
   int32_t state;
   do_check_success(stmt->GetState(&state));
   do_check_eq(mozIStorageBaseStatement::MOZ_STORAGE_STATEMENT_INVALID, state);
 
   // Should be able to close the database now too.
   do_check_success(db->Close());
 }
 
-template<typename StringType>
-void
-test_GetCachedAsyncStatement()
+TYPED_TEST_CASE(storage_StatementCache, TwoStringTypes);
+TYPED_TEST(storage_StatementCache, GetCachedAsyncStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
   AsyncCache cache(db);
 
-  StringType sql = "SELECT * FROM sqlite_master";
+  TypeParam sql = "SELECT * FROM sqlite_master";
 
   // Make sure we get a statement back with the right state.
   nsCOMPtr<mozIStorageAsyncStatement> stmt = cache.GetCachedStatement(sql);
   do_check_true(stmt);
   int32_t state;
   do_check_success(stmt->GetState(&state));
   do_check_eq(mozIStorageBaseStatement::MOZ_STORAGE_STATEMENT_READY, state);
 
   // Check to make sure we get the same copy the second time we ask.
   nsCOMPtr<mozIStorageAsyncStatement> stmt2 = cache.GetCachedStatement(sql);
   do_check_true(stmt2);
   do_check_eq(stmt.get(), stmt2.get());
 }
 
-template <typename StringType>
-void
-test_FinalizeAsyncStatements()
+TYPED_TEST_CASE(storage_StatementCache, TwoStringTypes);
+TYPED_TEST(storage_StatementCache, FinalizeAsyncStatements)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
   AsyncCache cache(db);
 
-  StringType sql = "SELECT * FROM sqlite_master";
+  TypeParam sql = "SELECT * FROM sqlite_master";
 
   // Get a statement, and then tell the cache to finalize.
   nsCOMPtr<mozIStorageAsyncStatement> stmt = cache.GetCachedStatement(sql);
   do_check_true(stmt);
 
   cache.FinalizeStatements();
 
   // We should be in an invalid state at this point.
   int32_t state;
   do_check_success(stmt->GetState(&state));
   do_check_eq(mozIStorageBaseStatement::MOZ_STORAGE_STATEMENT_INVALID, state);
 
   // Should be able to close the database now too.
   do_check_success(db->AsyncClose(nullptr));
 }
 
-////////////////////////////////////////////////////////////////////////////////
-//// Test Harness Stuff
-
-void (*gTests[])(void) = {
-  test_GetCachedStatement<const char []>,
-  test_GetCachedStatement<StringWrapper>,
-  test_FinalizeStatements<const char []>,
-  test_FinalizeStatements<StringWrapper>,
-  test_GetCachedAsyncStatement<const char []>,
-  test_GetCachedAsyncStatement<StringWrapper>,
-  test_FinalizeAsyncStatements<const char []>,
-  test_FinalizeAsyncStatements<StringWrapper>,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "StatementCache"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_asyncStatementExecution_transaction.cpp
rename to storage/test/gtest/test_asyncStatementExecution_transaction.cpp
--- a/storage/test/test_asyncStatementExecution_transaction.cpp
+++ b/storage/test/gtest/test_asyncStatementExecution_transaction.cpp
@@ -79,18 +79,17 @@ check_transaction(mozIStorageConnection 
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
 /**
  * Test that executing multiple readonly AsyncStatements doesn't create a
  * transaction.
  */
-void
-test_MultipleAsyncReadStatements()
+TEST(storage_asyncStatementExecution_transaction, MultipleAsyncReadStatements)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageAsyncStatement> stmt1;
   db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "SELECT * FROM sqlite_master"
   ), getter_AddRefs(stmt1));
@@ -107,18 +106,17 @@ test_MultipleAsyncReadStatements()
 
   check_transaction(db, stmts, ArrayLength(stmts), false);
 }
 
 /**
  * Test that executing multiple readonly Statements doesn't create a
  * transaction.
  */
-void
-test_MultipleReadStatements()
+TEST(storage_asyncStatementExecution_transaction, MultipleReadStatements)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageStatement> stmt1;
   db->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT * FROM sqlite_master"
   ), getter_AddRefs(stmt1));
@@ -135,18 +133,17 @@ test_MultipleReadStatements()
 
   check_transaction(db, stmts, ArrayLength(stmts), false);
 }
 
 /**
  * Test that executing multiple AsyncStatements causing writes creates a
  * transaction.
  */
-void
-test_MultipleAsyncReadWriteStatements()
+TEST(storage_asyncStatementExecution_transaction, MultipleAsyncReadWriteStatements)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageAsyncStatement> stmt1;
   db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "SELECT * FROM sqlite_master"
   ), getter_AddRefs(stmt1));
@@ -162,18 +159,17 @@ test_MultipleAsyncReadWriteStatements()
   };
 
   check_transaction(db, stmts, ArrayLength(stmts), true);
 }
 
 /**
  * Test that executing multiple Statements causing writes creates a transaction.
  */
-void
-test_MultipleReadWriteStatements()
+TEST(storage_asyncStatementExecution_transaction, MultipleReadWriteStatements)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageStatement> stmt1;
   db->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT * FROM sqlite_master"
   ), getter_AddRefs(stmt1));
@@ -190,18 +186,17 @@ test_MultipleReadWriteStatements()
 
   check_transaction(db, stmts, ArrayLength(stmts), true);
 }
 
 /**
  * Test that executing multiple AsyncStatements causing writes creates a
  * single transaction.
  */
-void
-test_MultipleAsyncWriteStatements()
+TEST(storage_asyncStatementExecution_transaction, MultipleAsyncWriteStatements)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageAsyncStatement> stmt1;
   db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "CREATE TABLE test1 (id INTEGER PRIMARY KEY)"
   ), getter_AddRefs(stmt1));
@@ -218,18 +213,17 @@ test_MultipleAsyncWriteStatements()
 
   check_transaction(db, stmts, ArrayLength(stmts), true);
 }
 
 /**
  * Test that executing multiple Statements causing writes creates a
  * single transaction.
  */
-void
-test_MultipleWriteStatements()
+TEST(storage_asyncStatementExecution_transaction, MultipleWriteStatements)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageStatement> stmt1;
   db->CreateStatement(NS_LITERAL_CSTRING(
     "CREATE TABLE test1 (id INTEGER PRIMARY KEY)"
   ), getter_AddRefs(stmt1));
@@ -246,18 +240,17 @@ test_MultipleWriteStatements()
 
   check_transaction(db, stmts, ArrayLength(stmts), true);
 }
 
 /**
  * Test that executing a single read-only AsyncStatement doesn't create a
  * transaction.
  */
-void
-test_SingleAsyncReadStatement()
+TEST(storage_asyncStatementExecution_transaction, SingleAsyncReadStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "SELECT * FROM sqlite_master"
   ), getter_AddRefs(stmt));
@@ -268,18 +261,17 @@ test_SingleAsyncReadStatement()
 
   check_transaction(db, stmts, ArrayLength(stmts), false);
 }
 
 /**
  * Test that executing a single read-only Statement doesn't create a
  * transaction.
  */
-void
-test_SingleReadStatement()
+TEST(storage_asyncStatementExecution_transaction, SingleReadStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageStatement> stmt;
   db->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT * FROM sqlite_master"
   ), getter_AddRefs(stmt));
@@ -290,18 +282,17 @@ test_SingleReadStatement()
 
   check_transaction(db, stmts, ArrayLength(stmts), false);
 }
 
 /**
  * Test that executing a single AsyncStatement causing writes creates a
  * transaction.
  */
-void
-test_SingleAsyncWriteStatement()
+TEST(storage_asyncStatementExecution_transaction, SingleAsyncWriteStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "CREATE TABLE test (id INTEGER PRIMARY KEY)"
   ), getter_AddRefs(stmt));
@@ -311,18 +302,17 @@ test_SingleAsyncWriteStatement()
   };
 
   check_transaction(db, stmts, ArrayLength(stmts), true);
 }
 
 /**
  * Test that executing a single Statement causing writes creates a transaction.
  */
-void
-test_SingleWriteStatement()
+TEST(storage_asyncStatementExecution_transaction, SingleWriteStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageStatement> stmt;
   db->CreateStatement(NS_LITERAL_CSTRING(
     "CREATE TABLE test (id INTEGER PRIMARY KEY)"
   ), getter_AddRefs(stmt));
@@ -333,18 +323,17 @@ test_SingleWriteStatement()
 
   check_transaction(db, stmts, ArrayLength(stmts), true);
 }
 
 /**
  * Test that executing a single read-only AsyncStatement with multiple params
  * doesn't create a transaction.
  */
-void
-test_MultipleParamsAsyncReadStatement()
+TEST(storage_asyncStatementExecution_transaction, MultipleParamsAsyncReadStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   db->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "SELECT :param FROM sqlite_master"
   ), getter_AddRefs(stmt));
@@ -367,18 +356,17 @@ test_MultipleParamsAsyncReadStatement()
 
   check_transaction(db, stmts, ArrayLength(stmts), false);
 }
 
 /**
  * Test that executing a single read-only Statement with multiple params
  * doesn't create a transaction.
  */
-void
-test_MultipleParamsReadStatement()
+TEST(storage_asyncStatementExecution_transaction, MultipleParamsReadStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create statements and execute them
   nsCOMPtr<mozIStorageStatement> stmt;
   db->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT :param FROM sqlite_master"
   ), getter_AddRefs(stmt));
@@ -401,18 +389,17 @@ test_MultipleParamsReadStatement()
 
   check_transaction(db, stmts, ArrayLength(stmts), false);
 }
 
 /**
  * Test that executing a single write AsyncStatement with multiple params
  * creates a transaction.
  */
-void
-test_MultipleParamsAsyncWriteStatement()
+TEST(storage_asyncStatementExecution_transaction, MultipleParamsAsyncWriteStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create a table for writes
   nsCOMPtr<mozIStorageStatement> tableStmt;
   db->CreateStatement(NS_LITERAL_CSTRING(
     "CREATE TABLE test (id INTEGER PRIMARY KEY)"
   ), getter_AddRefs(tableStmt));
@@ -443,18 +430,17 @@ test_MultipleParamsAsyncWriteStatement()
 
   check_transaction(db, stmts, ArrayLength(stmts), true);
 }
 
 /**
  * Test that executing a single write Statement with multiple params
  * creates a transaction.
  */
-void
-test_MultipleParamsWriteStatement()
+TEST(storage_asyncStatementExecution_transaction, MultipleParamsWriteStatement)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- create a table for writes
   nsCOMPtr<mozIStorageStatement> tableStmt;
   db->CreateStatement(NS_LITERAL_CSTRING(
     "CREATE TABLE test (id INTEGER PRIMARY KEY)"
   ), getter_AddRefs(tableStmt));
@@ -480,30 +466,8 @@ test_MultipleParamsWriteStatement()
   paramsArray = nullptr;
 
   mozIStorageBaseStatement *stmts[] = {
     stmt,
   };
 
   check_transaction(db, stmts, ArrayLength(stmts), true);
 }
-
-void (*gTests[])(void) = {
-  test_MultipleAsyncReadStatements,
-  test_MultipleReadStatements,
-  test_MultipleAsyncReadWriteStatements,
-  test_MultipleReadWriteStatements,
-  test_MultipleAsyncWriteStatements,
-  test_MultipleWriteStatements,
-  test_SingleAsyncReadStatement,
-  test_SingleReadStatement,
-  test_SingleAsyncWriteStatement,
-  test_SingleWriteStatement,
-  test_MultipleParamsAsyncReadStatement,
-  test_MultipleParamsReadStatement,
-  test_MultipleParamsAsyncWriteStatement,
-  test_MultipleParamsWriteStatement,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "async statement execution transaction"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_async_callbacks_with_spun_event_loops.cpp
rename to storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp
--- a/storage/test/test_async_callbacks_with_spun_event_loops.cpp
+++ b/storage/test/gtest/test_async_callbacks_with_spun_event_loops.cpp
@@ -93,18 +93,17 @@ NS_IMPL_ISUPPORTS(UnownedCallback, mozIS
 
 bool UnownedCallback::sAlive = false;
 bool UnownedCallback::sResult = false;
 bool UnownedCallback::sError = false;
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
-void
-test_SpinEventsLoopInHandleResult()
+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(NS_LITERAL_CSTRING(
     "CREATE TABLE test (id INTEGER PRIMARY KEY)"
   ), getter_AddRefs(stmt));
@@ -127,18 +126,17 @@ test_SpinEventsLoopInHandleResult()
   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()
+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(NS_LITERAL_CSTRING(
     "CREATE TABLE test (id INTEGER PRIMARY KEY)"
   ), getter_AddRefs(stmt));
@@ -157,18 +155,8 @@ test_SpinEventsLoopInHandleError()
   ), 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"
rename from storage/test/test_binding_params.cpp
rename to storage/test/gtest/test_binding_params.cpp
--- a/storage/test/test_binding_params.cpp
+++ b/storage/test/gtest/test_binding_params.cpp
@@ -10,18 +10,17 @@
 
 using namespace mozilla;
 
 /**
  * This file tests binding and reading out string parameters through the
  * mozIStorageStatement API.
  */
 
-void
-test_ASCIIString()
+TEST(storage_binding_params, ASCIIString)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Create table with a single string column.
   (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE test (str STRING)"
   ));
 
@@ -53,18 +52,17 @@ test_ASCIIString()
     do_check_true(NS_SUCCEEDED(select->GetUTF8String(0, result)));
   }
 
   do_check_true(result == inserted);
 
   (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM test"));
 }
 
-void
-test_CString()
+TEST(storage_binding_params, CString)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Create table with a single string column.
   (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE test (str STRING)"
   ));
 
@@ -100,18 +98,17 @@ test_CString()
     do_check_true(NS_SUCCEEDED(select->GetUTF8String(0, result)));
 
     do_check_true(result == inserted);
   }
 
   (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM test"));
 }
 
-void
-test_UTFStrings()
+TEST(storage_binding_params, UTFStrings)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Create table with a single string column.
   (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE test (str STRING)"
   ));
 
@@ -198,18 +195,8 @@ test_UTFStrings()
     do_check_true(NS_SUCCEEDED(select->GetString(0, result)));
 
     do_check_true(result == insertedUTF16);
   }
 
   (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM test"));
 }
 
-void (*gTests[])(void) = {
-  test_ASCIIString,
-  test_CString,
-  test_UTFStrings,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "binding string params"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_deadlock_detector.cpp
rename to storage/test/gtest/test_deadlock_detector.cpp
--- a/storage/test/test_deadlock_detector.cpp
+++ b/storage/test/gtest/test_deadlock_detector.cpp
@@ -1,37 +1,29 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: sw=4 ts=4 et :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/**
- * Note: This file is a copy of xpcom/tests/TestDeadlockDetector.cpp, but all
- *       mutexes were turned into SQLiteMutexes.
- */
-
-#include "prenv.h"
-#include "prerror.h"
-#include "prio.h"
-#include "prproces.h"
-
-#include "nsMemory.h"
+// Note: This file is essentially a copy of
+// xpcom/tests/gtest/TestDeadlockDetector.cpp, but all mutexes were turned into
+// SQLiteMutexes. We use #include and some macros to avoid actual source code
+// duplication.
 
 #include "mozilla/CondVar.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "SQLiteMutex.h"
 
-#include "TestHarness.h"
+#include "gtest/gtest.h"
 
 using namespace mozilla;
 
 /**
- * Helper class to allocate a sqlite3_mutex for our SQLiteMutex.  Also makes
- * keeping the test files in sync easier.
+ * Helper class to allocate a sqlite3_mutex for our SQLiteMutex.
  */
 class TestMutex : public mozilla::storage::SQLiteMutex
 {
 public:
     explicit TestMutex(const char* aName)
     : mozilla::storage::SQLiteMutex(aName)
     , mInner(sqlite3_mutex_alloc(SQLITE_MUTEX_FAST))
     {
@@ -52,551 +44,23 @@ public:
     void Unlock()
     {
         unlock();
     }
 private:
   sqlite3_mutex *mInner;
 };
 
-static PRThread*
-spawn(void (*run)(void*), void* arg)
-{
-    return PR_CreateThread(PR_SYSTEM_THREAD,
-                           run,
-                           arg,
-                           PR_PRIORITY_NORMAL,
-                           PR_GLOBAL_THREAD,
-                           PR_JOINABLE_THREAD,
-                           0);
-}
-
-#define PASS()                                  \
-    do {                                        \
-        passed(__FUNCTION__);                   \
-        return NS_OK;                           \
-    } while (0)
-
-#define FAIL(why)                               \
-    do {                                        \
-        fail("%s | %s - %s", __FILE__, __FUNCTION__, why); \
-        return NS_ERROR_FAILURE;                \
-    } while (0)
-
-//-----------------------------------------------------------------------------
-
-static const char* sPathToThisBinary;
-static const char* sAssertBehaviorEnv = "XPCOM_DEBUG_BREAK=abort";
-
-class Subprocess
-{
-public:
-    // not available until process finishes
-    int32_t mExitCode;
-    nsCString mStdout;
-    nsCString mStderr;
-
-    explicit Subprocess(const char* aTestName) {
-        // set up stdio redirection
-        PRFileDesc* readStdin;  PRFileDesc* writeStdin;
-        PRFileDesc* readStdout; PRFileDesc* writeStdout;
-        PRFileDesc* readStderr; PRFileDesc* writeStderr;
-        PRProcessAttr* pattr = PR_NewProcessAttr();
-
-        NS_ASSERTION(pattr, "couldn't allocate process attrs");
-
-        NS_ASSERTION(PR_SUCCESS == PR_CreatePipe(&readStdin, &writeStdin),
-                     "couldn't create child stdin pipe");
-        NS_ASSERTION(PR_SUCCESS == PR_SetFDInheritable(readStdin, true),
-                     "couldn't set child stdin inheritable");
-        PR_ProcessAttrSetStdioRedirect(pattr, PR_StandardInput, readStdin);
-
-        NS_ASSERTION(PR_SUCCESS == PR_CreatePipe(&readStdout, &writeStdout),
-                     "couldn't create child stdout pipe");
-        NS_ASSERTION(PR_SUCCESS == PR_SetFDInheritable(writeStdout, true),
-                     "couldn't set child stdout inheritable");
-        PR_ProcessAttrSetStdioRedirect(pattr, PR_StandardOutput, writeStdout);
-
-        NS_ASSERTION(PR_SUCCESS == PR_CreatePipe(&readStderr, &writeStderr),
-                     "couldn't create child stderr pipe");
-        NS_ASSERTION(PR_SUCCESS == PR_SetFDInheritable(writeStderr, true),
-                     "couldn't set child stderr inheritable");
-        PR_ProcessAttrSetStdioRedirect(pattr, PR_StandardError, writeStderr);
-
-        // set up argv with test name to run
-        char* const newArgv[3] = {
-            strdup(sPathToThisBinary),
-            strdup(aTestName),
-            0
-        };
-
-        // make sure the child will abort if an assertion fails
-        NS_ASSERTION(PR_SUCCESS == PR_SetEnv(sAssertBehaviorEnv),
-                     "couldn't set XPCOM_DEBUG_BREAK env var");
-
-        PRProcess* proc;
-        NS_ASSERTION(proc = PR_CreateProcess(sPathToThisBinary,
-                                             newArgv,
-                                             0, // inherit environment
-                                             pattr),
-                     "couldn't create process");
-        PR_Close(readStdin);
-        PR_Close(writeStdout);
-        PR_Close(writeStderr);
-
-        mProc = proc;
-        mStdinfd = writeStdin;
-        mStdoutfd = readStdout;
-        mStderrfd = readStderr;
-
-        free(newArgv[0]);
-        free(newArgv[1]);
-        PR_DestroyProcessAttr(pattr);
-    }
-
-    void RunToCompletion(uint32_t aWaitMs)
-    {
-        PR_Close(mStdinfd);
-
-        PRPollDesc pollfds[2];
-        int32_t nfds;
-        bool stdoutOpen = true, stderrOpen = true;
-        char buf[4096];
-
-        PRIntervalTime now = PR_IntervalNow();
-        PRIntervalTime deadline = now + PR_MillisecondsToInterval(aWaitMs);
-
-        while ((stdoutOpen || stderrOpen) && now < deadline) {
-            nfds = 0;
-            if (stdoutOpen) {
-                pollfds[nfds].fd = mStdoutfd;
-                pollfds[nfds].in_flags = PR_POLL_READ;
-                pollfds[nfds].out_flags = 0;
-                ++nfds;
-            }
-            if (stderrOpen) {
-                pollfds[nfds].fd = mStderrfd;
-                pollfds[nfds].in_flags = PR_POLL_READ;
-                pollfds[nfds].out_flags = 0;
-                ++nfds;
-            }
-
-            int32_t rv = PR_Poll(pollfds, nfds, deadline - now);
-            NS_ASSERTION(0 <= rv, PR_ErrorToName(PR_GetError()));
-
-            if (0 == rv) {      // timeout
-                fputs("(timed out!)\n", stderr);
-                Finish(false); // abnormal
-                return;
-            }
-
-            for (int32_t i = 0; i < nfds; ++i) {
-                if (!pollfds[i].out_flags)
-                    continue;
+// This global variable is defined in toolkit/xre/nsSigHandlers.cpp.
+// It's declared in xpcom/tests/gtest/TestDeadlockDetector.cpp, but we #include
+// that within the |storage| namespace, so we need to declare it again here.
+extern unsigned int _gdb_sleep_duration;
 
-                bool isStdout = mStdoutfd == pollfds[i].fd;
-                int32_t len = 0;
-
-                if (PR_POLL_READ & pollfds[i].out_flags) {
-                    len = PR_Read(pollfds[i].fd, buf, sizeof(buf) - 1);
-                    NS_ASSERTION(0 <= len, PR_ErrorToName(PR_GetError()));
-                }
-                else if (!(PR_POLL_HUP & pollfds[i].out_flags)) {
-                    NS_ERROR(PR_ErrorToName(PR_GetError()));
-                }
-
-                if (0 < len) {
-                    buf[len] = '\0';
-                    if (isStdout)
-                        mStdout += buf;
-                    else
-                        mStderr += buf;
-                }
-                else if (isStdout) {
-                    stdoutOpen = false;
-                }
-                else {
-                    stderrOpen = false;
-                }
-            }
-
-            now = PR_IntervalNow();
-        }
-
-        if (stdoutOpen)
-            fputs("(stdout still open!)\n", stderr);
-        if (stderrOpen)
-            fputs("(stderr still open!)\n", stderr);
-        if (now > deadline)
-            fputs("(timed out!)\n", stderr);
-
-        Finish(!stdoutOpen && !stderrOpen && now <= deadline);
-    }
-
-private:
-    void Finish(bool normalExit) {
-        if (!normalExit) {
-            PR_KillProcess(mProc);
-            mExitCode = -1;
-            int32_t dummy;
-            PR_WaitProcess(mProc, &dummy);
-        }
-        else {
-            PR_WaitProcess(mProc, &mExitCode); // this had better not block ...
-        }
-
-        PR_Close(mStdoutfd);
-        PR_Close(mStderrfd);
-    }
-
-    PRProcess* mProc;
-    PRFileDesc* mStdinfd;         // writeable
-    PRFileDesc* mStdoutfd;        // readable
-    PRFileDesc* mStderrfd;        // readable
-};
+// These are the two macros that differentiate this file from the XPCOM one.
+#define MUTEX TestMutex
+#define TESTNAME(name) storage_##name
 
-//-----------------------------------------------------------------------------
-// Harness for checking detector errors
-bool
-CheckForDeadlock(const char* test, const char* const* findTokens)
-{
-    Subprocess proc(test);
-    proc.RunToCompletion(5000);
-
-    if (0 == proc.mExitCode)
-        return false;
-
-    int32_t idx = 0;
-    for (const char* const* tp = findTokens; *tp; ++tp) {
-        const char* const token = *tp;
-#ifdef MOZILLA_INTERNAL_API
-        idx = proc.mStderr.Find(token, false, idx);
-#else
-        nsCString tokenCString(token);
-        idx = proc.mStderr.Find(tokenCString, idx);
-#endif
-        if (-1 == idx) {
-            printf("(missed token '%s' in output)\n", token);
-            puts("----------------------------------\n");
-            puts(proc.mStderr.get());
-            puts("----------------------------------\n");
-            return false;
-        }
-        idx += strlen(token);
-    }
-
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-// Single-threaded sanity tests
-
-// Stupidest possible deadlock.
-int
-Sanity_Child()
-{
-    TestMutex m1("dd.sanity.m1");
-    m1.Lock();
-    m1.Lock();
-    return 0;                  // not reached
-}
-
-nsresult
-Sanity()
-{
-    const char* const tokens[] = {
-        "###!!! ERROR: Potential deadlock detected",
-        "=== Cyclical dependency starts at\n--- Mutex : dd.sanity.m1",
-        "=== Cycle completed at\n--- Mutex : dd.sanity.m1",
-        "###!!! Deadlock may happen NOW!", // better catch these easy cases...
-        "###!!! ASSERTION: Potential deadlock detected",
-        0
-    };
-    if (CheckForDeadlock("Sanity", tokens)) {
-        PASS();
-    } else {
-        FAIL("deadlock not detected");
-    }
-}
-
-// Slightly less stupid deadlock.
-int
-Sanity2_Child()
-{
-    TestMutex m1("dd.sanity2.m1");
-    TestMutex m2("dd.sanity2.m2");
-    m1.Lock();
-    m2.Lock();
-    m1.Lock();
-    return 0;                  // not reached
+// We need to use a namespace to avoid duplicate definitions of some functions
+// within TestDeadlockDetector.cpp.
+namespace storage {
+#include "../../../xpcom/tests/gtest/TestDeadlockDetector.cpp"
 }
 
-nsresult
-Sanity2()
-{
-    const char* const tokens[] = {
-        "###!!! ERROR: Potential deadlock detected",
-        "=== Cyclical dependency starts at\n--- Mutex : dd.sanity2.m1",
-        "--- Next dependency:\n--- Mutex : dd.sanity2.m2",
-        "=== Cycle completed at\n--- Mutex : dd.sanity2.m1",
-        "###!!! Deadlock may happen NOW!", // better catch these easy cases...
-        "###!!! ASSERTION: Potential deadlock detected",
-        0
-    };
-    if (CheckForDeadlock("Sanity2", tokens)) {
-        PASS();
-    } else {
-        FAIL("deadlock not detected");
-    }
-}
-
-
-int
-Sanity3_Child()
-{
-    TestMutex m1("dd.sanity3.m1");
-    TestMutex m2("dd.sanity3.m2");
-    TestMutex m3("dd.sanity3.m3");
-    TestMutex m4("dd.sanity3.m4");
-
-    m1.Lock();
-    m2.Lock();
-    m3.Lock();
-    m4.Lock();
-    m4.Unlock();
-    m3.Unlock();
-    m2.Unlock();
-    m1.Unlock();
-
-    m4.Lock();
-    m1.Lock();
-    return 0;
-}
-
-nsresult
-Sanity3()
-{
-    const char* const tokens[] = {
-        "###!!! ERROR: Potential deadlock detected",
-        "=== Cyclical dependency starts at\n--- Mutex : dd.sanity3.m1",
-        "--- Next dependency:\n--- Mutex : dd.sanity3.m2",
-        "--- Next dependency:\n--- Mutex : dd.sanity3.m3",
-        "--- Next dependency:\n--- Mutex : dd.sanity3.m4",
-        "=== Cycle completed at\n--- Mutex : dd.sanity3.m1",
-        "###!!! ASSERTION: Potential deadlock detected",
-        0
-    };
-    if (CheckForDeadlock("Sanity3", tokens)) {
-        PASS();
-    } else {
-        FAIL("deadlock not detected");
-    }
-}
-
-
-int
-Sanity4_Child()
-{
-    mozilla::ReentrantMonitor m1("dd.sanity4.m1");
-    TestMutex m2("dd.sanity4.m2");
-    m1.Enter();
-    m2.Lock();
-    m1.Enter();
-    return 0;
-}
-
-nsresult
-Sanity4()
-{
-    const char* const tokens[] = {
-        "Re-entering ReentrantMonitor after acquiring other resources",
-        "###!!! ERROR: Potential deadlock detected",
-        "=== Cyclical dependency starts at\n--- ReentrantMonitor : dd.sanity4.m1",
-        "--- Next dependency:\n--- Mutex : dd.sanity4.m2",
-        "=== Cycle completed at\n--- ReentrantMonitor : dd.sanity4.m1",
-        "###!!! ASSERTION: Potential deadlock detected",
-        0
-    };
-    if (CheckForDeadlock("Sanity4", tokens)) {
-        PASS();
-    } else {
-        FAIL("deadlock not detected");
-    }
-}
-
-//-----------------------------------------------------------------------------
-// Multithreaded tests
-
-TestMutex* ttM1;
-TestMutex* ttM2;
-
-static void
-TwoThreads_thread(void* arg)
-{
-    int32_t m1First = NS_PTR_TO_INT32(arg);
-    if (m1First) {
-        ttM1->Lock();
-        ttM2->Lock();
-        ttM2->Unlock();
-        ttM1->Unlock();
-    }
-    else {
-        ttM2->Lock();
-        ttM1->Lock();
-        ttM1->Unlock();
-        ttM2->Unlock();
-    }
-}
-
-int
-TwoThreads_Child()
-{
-    ttM1 = new TestMutex("dd.twothreads.m1");
-    ttM2 = new TestMutex("dd.twothreads.m2");
-    if (!ttM1 || !ttM2)
-        NS_RUNTIMEABORT("couldn't allocate mutexes");
-
-    PRThread* t1 = spawn(TwoThreads_thread, (void*) 0);
-    PR_JoinThread(t1);
-
-    PRThread* t2 = spawn(TwoThreads_thread, (void*) 1);
-    PR_JoinThread(t2);
-
-    return 0;
-}
-
-nsresult
-TwoThreads()
-{
-    const char* const tokens[] = {
-        "###!!! ERROR: Potential deadlock detected",
-        "=== Cyclical dependency starts at\n--- Mutex : dd.twothreads.m2",
-        "--- Next dependency:\n--- Mutex : dd.twothreads.m1",
-        "=== Cycle completed at\n--- Mutex : dd.twothreads.m2",
-        "###!!! ASSERTION: Potential deadlock detected",
-        0
-    };
-
-    if (CheckForDeadlock("TwoThreads", tokens)) {
-        PASS();
-    } else {
-        FAIL("deadlock not detected");
-    }
-}
-
-
-TestMutex* cndMs[4];
-const uint32_t K = 100000;
-
-static void
-ContentionNoDeadlock_thread(void* arg)
-{
-    int32_t starti = NS_PTR_TO_INT32(arg);
-
-    for (uint32_t k = 0; k < K; ++k) {
-        for (int32_t i = starti; i < (int32_t) ArrayLength(cndMs); ++i)
-            cndMs[i]->Lock();
-        // comment out the next two lines for deadlocking fun!
-        for (int32_t i = ArrayLength(cndMs) - 1; i >= starti; --i)
-            cndMs[i]->Unlock();
-
-        starti = (starti + 1) % 3;
-    }
-}
-
-int
-ContentionNoDeadlock_Child()
-{
-    PRThread* threads[3];
-
-    for (uint32_t i = 0; i < ArrayLength(cndMs); ++i)
-        cndMs[i] = new TestMutex("dd.cnd.ms");
-
-    for (int32_t i = 0; i < (int32_t) ArrayLength(threads); ++i)
-        threads[i] = spawn(ContentionNoDeadlock_thread, NS_INT32_TO_PTR(i));
-
-    for (uint32_t i = 0; i < ArrayLength(threads); ++i)
-        PR_JoinThread(threads[i]);
-
-    for (uint32_t i = 0; i < ArrayLength(cndMs); ++i)
-        delete cndMs[i];
-
-    return 0;
-}
-
-nsresult
-ContentionNoDeadlock()
-{
-    const char * func = __func__;
-    Subprocess proc(func);
-    proc.RunToCompletion(60000);
-    if (0 != proc.mExitCode) {
-        printf("(expected 0 == return code, got %d)\n", proc.mExitCode);
-        puts("(output)\n----------------------------------\n");
-        puts(proc.mStdout.get());
-        puts("----------------------------------\n");
-        puts("(error output)\n----------------------------------\n");
-        puts(proc.mStderr.get());
-        puts("----------------------------------\n");
-
-        FAIL("deadlock");
-    }
-    PASS();
-}
-
-
-
-//-----------------------------------------------------------------------------
-
-int
-main(int argc, char** argv)
-{
-    if (1 < argc) {
-        // XXX can we run w/o scoped XPCOM?
-        const char* test = argv[1];
-        ScopedXPCOM xpcom(test);
-        if (xpcom.failed())
-            return 1;
-
-        // running in a spawned process.  call the specificed child function.
-        if (!strcmp("Sanity", test))
-            return Sanity_Child();
-        if (!strcmp("Sanity2", test))
-            return Sanity2_Child();
-        if (!strcmp("Sanity3", test))
-            return Sanity3_Child();
-        if (!strcmp("Sanity4", test))
-            return Sanity4_Child();
-
-        if (!strcmp("TwoThreads", test))
-            return TwoThreads_Child();
-        if (!strcmp("ContentionNoDeadlock", test))
-            return ContentionNoDeadlock_Child();
-
-        fail("%s | %s - unknown child test", __FILE__, __FUNCTION__);
-        return 1;
-    }
-
-    ScopedXPCOM xpcom("Storage deadlock detector correctness (" __FILE__ ")");
-    if (xpcom.failed())
-        return 1;
-
-    // in the first invocation of this process.  we will be the "driver".
-    int rv = 0;
-
-    sPathToThisBinary = argv[0];
-
-    if (NS_FAILED(Sanity()))
-        rv = 1;
-    if (NS_FAILED(Sanity2()))
-        rv = 1;
-    if (NS_FAILED(Sanity3()))
-        rv = 1;
-    if (NS_FAILED(Sanity4()))
-        rv = 1;
-
-    if (NS_FAILED(TwoThreads()))
-        rv = 1;
-    if (NS_FAILED(ContentionNoDeadlock()))
-        rv = 1;
-
-    return rv;
-}
rename from storage/test/test_file_perms.cpp
rename to storage/test/gtest/test_file_perms.cpp
--- a/storage/test/test_file_perms.cpp
+++ b/storage/test/gtest/test_file_perms.cpp
@@ -8,18 +8,17 @@
 #include "nsIFile.h"
 #include "prio.h"
 
 /**
  * This file tests that the file permissions of the sqlite files match what
  * we request they be
  */
 
-void
-test_file_perms()
+TEST(storage_file_perms, Test)
 {
   nsCOMPtr<mozIStorageConnection> db(getDatabase());
   nsCOMPtr<nsIFile> dbFile;
   do_check_success(db->GetDatabaseFile(getter_AddRefs(dbFile)));
 
   uint32_t perms = 0;
   do_check_success(dbFile->GetPermissions(&perms));
 
@@ -29,16 +28,8 @@ test_file_perms()
   do_check_true(perms == (PR_IRUSR | PR_IWUSR));
 #elif defined(XP_WIN)
   do_check_true(perms == (PR_IRUSR | PR_IWUSR | PR_IRGRP | PR_IWGRP | PR_IROTH | PR_IWOTH));
 #else
   do_check_true(perms == (PR_IRUSR | PR_IWUSR | PR_IRGRP | PR_IROTH));
 #endif
 }
 
-void (*gTests[])(void) = {
-  test_file_perms,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "file perms"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_mutex.cpp
rename to storage/test/gtest/test_mutex.cpp
--- a/storage/test/test_mutex.cpp
+++ b/storage/test/gtest/test_mutex.cpp
@@ -10,18 +10,17 @@
 
 using namespace mozilla;
 using namespace mozilla::storage;
 
 /**
  * This file test our sqlite3_mutex wrapper in SQLiteMutex.h.
  */
 
-void
-test_AutoLock()
+TEST(storage_mutex, AutoLock)
 {
   int lockTypes[] = {
     SQLITE_MUTEX_FAST,
     SQLITE_MUTEX_RECURSIVE,
   };
   for (size_t i = 0; i < ArrayLength(lockTypes); i++) {
     // Get our test mutex (we have to allocate a SQLite mutex of the right type
     // too!).
@@ -38,18 +37,17 @@ test_AutoLock()
     }
     mutex.assertNotCurrentThreadOwns();
 
     // Free the wrapped mutex - we don't need it anymore.
     sqlite3_mutex_free(inner);
   }
 }
 
-void
-test_AutoUnlock()
+TEST(storage_mutex, AutoUnlock)
 {
   int lockTypes[] = {
     SQLITE_MUTEX_FAST,
     SQLITE_MUTEX_RECURSIVE,
   };
   for (size_t i = 0; i < ArrayLength(lockTypes); i++) {
     // Get our test mutex (we have to allocate a SQLite mutex of the right type
     // too!).
@@ -69,17 +67,8 @@ test_AutoUnlock()
       mutex.assertCurrentThreadOwns();
     }
 
     // Free the wrapped mutex - we don't need it anymore.
     sqlite3_mutex_free(inner);
   }
 }
 
-void (*gTests[])(void) = {
-  test_AutoLock,
-  test_AutoUnlock,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "SQLiteMutex"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_service_init_background_thread.cpp
rename to storage/test/gtest/test_service_init_background_thread.cpp
--- a/storage/test/test_service_init_background_thread.cpp
+++ b/storage/test/gtest/test_service_init_background_thread.cpp
@@ -4,18 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "storage_test_harness.h"
 
 #include "nsThreadUtils.h"
 
 /**
- * This file tests that the storage service can be initialized off of the main
- * thread without issue.
+ * This file tests that the storage service cannot be initialized off the main
+ * thread.
  */
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Helpers
 
 class ServiceInitializer : public mozilla::Runnable
 {
 public:
@@ -27,32 +27,30 @@ public:
     do_check_false(service);
     return NS_OK;
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Functions
 
-void
-test_service_initialization_on_background_thread()
+// HACK ALERT: this test fails if it runs after any of the other storage tests
+// because the storage service will have been initialized and the
+// do_GetService() call in ServiceInitializer::Run will succeed. So we need a
+// way to force it to run before all the other storage gtests. As it happens,
+// gtest has a concept of "death tests" that, among other things, run before
+// all non-death tests. By merely using a "DeathTest" suffix here this becomes
+// a death test -- even though it doesn't use any of the normal death test
+// features -- which ensures this is the first storage test to run.
+TEST(storage_service_init_background_thread_DeathTest, Test)
 {
   nsCOMPtr<nsIRunnable> event = new ServiceInitializer();
   do_check_true(event);
 
   nsCOMPtr<nsIThread> thread;
   do_check_success(NS_NewThread(getter_AddRefs(thread)));
 
   do_check_success(thread->Dispatch(event, NS_DISPATCH_NORMAL));
 
   // Shutting down the thread will spin the event loop until all work in its
   // event queue is completed.  This will act as our thread synchronization.
   do_check_success(thread->Shutdown());
 }
-
-void (*gTests[])(void) = {
-  test_service_initialization_on_background_thread,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "Background Thread Initialization"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_statement_scoper.cpp
rename to storage/test/gtest/test_statement_scoper.cpp
--- a/storage/test/test_statement_scoper.cpp
+++ b/storage/test/gtest/test_statement_scoper.cpp
@@ -7,18 +7,17 @@
 #include "storage_test_harness.h"
 
 #include "mozStorageHelper.h"
 
 /**
  * This file test our statement scoper in mozStorageHelper.h.
  */
 
-void
-test_automatic_reset()
+TEST(storage_statement_scoper, automatic_reset)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Need to create a table to populate sqlite_master with an entry.
   (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE test (id INTEGER PRIMARY KEY)"
   ));
 
@@ -46,18 +45,17 @@ test_automatic_reset()
   }
 
   // And we should be ready again.
   state = -1;
   (void)stmt->GetState(&state);
   do_check_true(state == mozIStorageStatement::MOZ_STORAGE_STATEMENT_READY);
 }
 
-void
-test_Abandon()
+TEST(storage_statement_scoper, Abandon)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Need to create a table to populate sqlite_master with an entry.
   (void)db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE test (id INTEGER PRIMARY KEY)"
   ));
 
@@ -87,18 +85,8 @@ test_Abandon()
     scoper.Abandon();
   }
 
   // And we should still be executing.
   state = -1;
   (void)stmt->GetState(&state);
   do_check_true(state == mozIStorageStatement::MOZ_STORAGE_STATEMENT_EXECUTING);
 }
-
-void (*gTests[])(void) = {
-  test_automatic_reset,
-  test_Abandon,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "statement scoper"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_transaction_helper.cpp
rename to storage/test/gtest/test_transaction_helper.cpp
--- a/storage/test/test_transaction_helper.cpp
+++ b/storage/test/gtest/test_transaction_helper.cpp
@@ -12,21 +12,20 @@
 using namespace mozilla;
 using namespace mozilla::storage;
 
 bool has_transaction(mozIStorageConnection* aDB) {
   return !(static_cast<Connection *>(aDB)->getAutocommit());
 }
 
 /**
- * This file test our Transaction helper in mozStorageHelper.h.
+ * This file tests our Transaction helper in mozStorageHelper.h.
  */
 
-void
-test_Commit()
+TEST(storage_transaction_helper, Commit)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Create a table in a transaction, call Commit, and make sure that it does
   // exists after the transaction falls out of scope.
   {
     mozStorageTransaction transaction(db, false);
     do_check_true(has_transaction(db));
@@ -37,18 +36,17 @@ test_Commit()
   }
   do_check_false(has_transaction(db));
 
   bool exists = false;
   (void)db->TableExists(NS_LITERAL_CSTRING("test"), &exists);
   do_check_true(exists);
 }
 
-void
-test_Rollback()
+TEST(storage_transaction_helper, Rollback)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Create a table in a transaction, call Rollback, and make sure that it does
   // not exists after the transaction falls out of scope.
   {
     mozStorageTransaction transaction(db, true);
     do_check_true(has_transaction(db));
@@ -59,18 +57,17 @@ test_Rollback()
   }
   do_check_false(has_transaction(db));
 
   bool exists = true;
   (void)db->TableExists(NS_LITERAL_CSTRING("test"), &exists);
   do_check_false(exists);
 }
 
-void
-test_AutoCommit()
+TEST(storage_transaction_helper, AutoCommit)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Create a table in a transaction, and make sure that it exists after the
   // transaction falls out of scope.  This means the Commit was successful.
   {
     mozStorageTransaction transaction(db, true);
     do_check_true(has_transaction(db));
@@ -80,18 +77,17 @@ test_AutoCommit()
   }
   do_check_false(has_transaction(db));
 
   bool exists = false;
   (void)db->TableExists(NS_LITERAL_CSTRING("test"), &exists);
   do_check_true(exists);
 }
 
-void
-test_AutoRollback()
+TEST(storage_transaction_helper, AutoRollback)
 {
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Create a table in a transaction, and make sure that it does not exists
   // after the transaction falls out of scope.  This means the Rollback was
   // successful.
   {
     mozStorageTransaction transaction(db, false);
@@ -102,31 +98,28 @@ test_AutoRollback()
   }
   do_check_false(has_transaction(db));
 
   bool exists = true;
   (void)db->TableExists(NS_LITERAL_CSTRING("test"), &exists);
   do_check_false(exists);
 }
 
-void
-test_null_database_connection()
+TEST(storage_transaction_helper, null_database_connection)
 {
   // We permit the use of the Transaction helper when passing a null database
   // in, so we need to make sure this still works without crashing.
   mozStorageTransaction transaction(nullptr, false);
   do_check_true(NS_SUCCEEDED(transaction.Commit()));
   do_check_true(NS_SUCCEEDED(transaction.Rollback()));
 }
 
-void
-test_async_Commit()
+TEST(storage_transaction_helper, async_Commit)
 {
-  // note this will be active for any following test.
-  hook_sqlite_mutex();
+  HookSqliteMutex hook;
 
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- wedge the thread
   nsCOMPtr<nsIThread> target(get_conn_async_thread(db));
   do_check_true(target);
   RefPtr<ThreadWedger> wedger (new ThreadWedger(target));
 
@@ -154,22 +147,8 @@ test_async_Commit()
   stmt->Finalize();
   do_check_false(has_transaction(db));
   bool exists = false;
   (void)db->TableExists(NS_LITERAL_CSTRING("test"), &exists);
   do_check_true(exists);
 
   blocking_async_close(db);
 }
-
-void (*gTests[])(void) = {
-  test_Commit,
-  test_Rollback,
-  test_AutoCommit,
-  test_AutoRollback,
-  test_null_database_connection,
-  test_async_Commit,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "transaction helper"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_true_async.cpp
rename to storage/test/gtest/test_true_async.cpp
--- a/storage/test/test_true_async.cpp
+++ b/storage/test/gtest/test_true_async.cpp
@@ -4,21 +4,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "storage_test_harness.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
-void
-test_TrueAsyncStatement()
+TEST(storage_true_async, TrueAsyncStatement)
 {
-  // (only the first test needs to call this)
-  hook_sqlite_mutex();
+  HookSqliteMutex hook;
 
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // Start watching for forbidden mutex usage.
   watch_for_mutex_use_on_this_thread();
 
   // - statement with nothing to bind
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
@@ -68,19 +66,20 @@ test_TrueAsyncStatement()
 
   blocking_async_close(db);
 }
 
 /**
  * Test that cancellation before a statement is run successfully stops the
  * statement from executing.
  */
-void
-test_AsyncCancellation()
+TEST(storage_true_async, AsyncCancellation)
 {
+  HookSqliteMutex hook;
+
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
 
   // -- wedge the thread
   nsCOMPtr<nsIThread> target(get_conn_async_thread(db));
   do_check_true(target);
   RefPtr<ThreadWedger> wedger (new ThreadWedger(target));
 
   // -- create statements and cancel them
@@ -139,19 +138,19 @@ test_AsyncCancellation()
 }
 
 /**
  * Test that the destructor for an asynchronous statement which has a
  *  sqlite3_stmt will dispatch that statement to the async thread for
  *  finalization rather than trying to finalize it on the main thread
  *  (and thereby running afoul of our mutex use detector).
  */
-void test_AsyncDestructorFinalizesOnAsyncThread()
+TEST(storage_true_async, AsyncDestructorFinalizesOnAsyncThread)
 {
-  // test_TrueAsyncStatement called hook_sqlite_mutex() for us
+  HookSqliteMutex hook;
 
   nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
   watch_for_mutex_use_on_this_thread();
 
   // -- create an async statement
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   db->CreateAsyncStatement(
     NS_LITERAL_CSTRING("CREATE TABLE test (id INTEGER PRIMARY KEY)"),
@@ -168,19 +167,8 @@ void test_AsyncDestructorFinalizesOnAsyn
   // -- verify the mutex was not touched
   do_check_false(mutex_used_on_watched_thread);
 
   // -- make sure the statement actually gets finalized / cleanup
   // the close will assert if we failed to finalize!
   blocking_async_close(db);
 }
 
-void (*gTests[])(void) = {
-  // this test must be first because it hooks the mutex mechanics
-  test_TrueAsyncStatement,
-  test_AsyncCancellation,
-  test_AsyncDestructorFinalizesOnAsyncThread
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "true async statement"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
rename from storage/test/test_unlock_notify.cpp
rename to storage/test/gtest/test_unlock_notify.cpp
--- a/storage/test/test_unlock_notify.cpp
+++ b/storage/test/gtest/test_unlock_notify.cpp
@@ -248,19 +248,16 @@ test_drop_table_does_not_loop()
     tester->Notify(READ_LOCK);
 
     // Make sure the tester finishes its test before we move on.
     tester->WaitFor(TEST_DONE);
   }
   tester->Shutdown();
 }
 
-void (*gTests[])(void) = {
-  setup,
-  test_step_locked_does_not_block_main_thread,
-  test_drop_index_does_not_loop,
-  test_drop_table_does_not_loop,
-};
-
-const char *file = __FILE__;
-#define TEST_NAME "sqlite3_unlock_notify"
-#define TEST_FILE file
-#include "storage_test_harness_tail.h"
+TEST(storage_unlock_notify, Test)
+{
+  // These must execute in order.
+  setup();
+  test_step_locked_does_not_block_main_thread();
+  test_drop_index_does_not_loop();
+  test_drop_table_does_not_loop();
+}
--- a/storage/test/moz.build
+++ b/storage/test/moz.build
@@ -1,37 +1,10 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 
-GeckoCppUnitTests([
-    'test_AsXXX_helpers',
-    'test_async_callbacks_with_spun_event_loops',
-    'test_asyncStatementExecution_transaction',
-    'test_binding_params',
-    'test_file_perms',
-    'test_mutex',
-    'test_service_init_background_thread',
-    'test_statement_scoper',
-    'test_StatementCache',
-    'test_transaction_helper',
-    'test_true_async',
-    'test_unlock_notify',
-])
+TEST_DIRS += ['gtest']
 
-if CONFIG['MOZ_DEBUG'] and CONFIG['OS_ARCH'] not in ('WINNT', 'Darwin'):
-    # FIXME bug 523392: test_deadlock_detector doesn't like Windows
-    # FIXME bug 523378: also fails on OS X
-    GeckoCppUnitTests([
-        'test_deadlock_detector',
-    ])
-
-LOCAL_INCLUDES += [
-    '..',
-]
-
-USE_LIBS += [
-    'sqlite',
-]
deleted file mode 100644
--- a/storage/test/storage_test_harness_tail.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef TEST_NAME
-#error "Must #define TEST_NAME before including storage_test_harness_tail.h"
-#endif
-
-#ifndef TEST_FILE
-#error "Must #define TEST_FILE before include storage_test_harness_tail.h"
-#endif
-
-int
-main(int aArgc,
-     char **aArgv)
-{
-  ScopedXPCOM xpcom(TEST_NAME);
-
-  for (size_t i = 0; i < mozilla::ArrayLength(gTests); i++)
-    gTests[i]();
-
-  if (gPassedTests == gTotalTests)
-    passed(TEST_FILE);
-
-  (void)printf("%i of %i tests passed\n", gPassedTests, gTotalTests);
-}
--- a/testing/cppunittest.ini
+++ b/testing/cppunittest.ini
@@ -67,24 +67,10 @@ skip-if = os == 'b2g' || os == 'android'
 [nrappkit_unittest]
 [rlogringbuffer_unittest]
 [runnable_utils_unittest]
 [sctp_unittest]
 [signaling_unittests]
 [signaling_unittests_standalone]
 [simpletokenbucket_unittest]
 [sockettransportservice_unittest]
-[test_AsXXX_helpers]
-[test_StatementCache]
-[test_asyncStatementExecution_transaction]
-[test_async_callbacks_with_spun_event_loops]
-[test_binding_params]
-[test_deadlock_detector]
-skip-if = os == 'b2g' || (os == 'android' && debug) # Bug 1054249
-[test_file_perms]
-[test_mutex]
-[test_service_init_background_thread]
-[test_statement_scoper]
-[test_transaction_helper]
-[test_true_async]
-[test_unlock_notify]
 [transport_unittests]
 [turn_unittest]
--- a/toolkit/components/places/tests/gtest/places_test_harness.h
+++ b/toolkit/components/places/tests/gtest/places_test_harness.h
@@ -110,62 +110,62 @@ private:
 NS_IMPL_ISUPPORTS(
   WaitForTopicSpinner,
   nsIObserver
 )
 
 /**
  * Spins current thread until an async statement is executed.
  */
-class AsyncStatementSpinner final : public mozIStorageStatementCallback
+class PlacesAsyncStatementSpinner final : public mozIStorageStatementCallback
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGESTATEMENTCALLBACK
 
-  AsyncStatementSpinner();
+  PlacesAsyncStatementSpinner();
   void SpinUntilCompleted();
   uint16_t completionReason;
 
 protected:
-  ~AsyncStatementSpinner() {}
+  ~PlacesAsyncStatementSpinner() {}
 
   volatile bool mCompleted;
 };
 
-NS_IMPL_ISUPPORTS(AsyncStatementSpinner,
+NS_IMPL_ISUPPORTS(PlacesAsyncStatementSpinner,
                   mozIStorageStatementCallback)
 
-AsyncStatementSpinner::AsyncStatementSpinner()
+PlacesAsyncStatementSpinner::PlacesAsyncStatementSpinner()
 : completionReason(0)
 , mCompleted(false)
 {
 }
 
 NS_IMETHODIMP
-AsyncStatementSpinner::HandleResult(mozIStorageResultSet *aResultSet)
+PlacesAsyncStatementSpinner::HandleResult(mozIStorageResultSet *aResultSet)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-AsyncStatementSpinner::HandleError(mozIStorageError *aError)
+PlacesAsyncStatementSpinner::HandleError(mozIStorageError *aError)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-AsyncStatementSpinner::HandleCompletion(uint16_t aReason)
+PlacesAsyncStatementSpinner::HandleCompletion(uint16_t aReason)
 {
   completionReason = aReason;
   mCompleted = true;
   return NS_OK;
 }
 
-void AsyncStatementSpinner::SpinUntilCompleted()
+void PlacesAsyncStatementSpinner::SpinUntilCompleted()
 {
   nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
   nsresult rv = NS_OK;
   bool processed = true;
   while (!mCompleted && NS_SUCCEEDED(rv)) {
     rv = thread->ProcessNextEvent(true, &processed);
   }
 }
@@ -307,17 +307,18 @@ do_wait_async_updates() {
 
   db->CreateAsyncStatement(NS_LITERAL_CSTRING("BEGIN EXCLUSIVE"),
                            getter_AddRefs(stmt));
   nsCOMPtr<mozIStoragePendingStatement> pending;
   (void)stmt->ExecuteAsync(nullptr, getter_AddRefs(pending));
 
   db->CreateAsyncStatement(NS_LITERAL_CSTRING("COMMIT"),
                            getter_AddRefs(stmt));
-  RefPtr<AsyncStatementSpinner> spinner = new AsyncStatementSpinner();
+  RefPtr<PlacesAsyncStatementSpinner> spinner =
+    new PlacesAsyncStatementSpinner();
   (void)stmt->ExecuteAsync(spinner, getter_AddRefs(pending));
 
   spinner->SpinUntilCompleted();
 }
 
 /**
  * Adds a URI to the database.
  *
--- a/toolkit/components/places/tests/gtest/test_IHistory.cpp
+++ b/toolkit/components/places/tests/gtest/test_IHistory.cpp
@@ -123,17 +123,18 @@ test_wait_checkpoint()
 {
   // This "fake" test is here to wait for the initial WAL checkpoint we force
   // after creating the database schema, since that may happen at any time,
   // and cause concurrent readers to access an older checkpoint.
   nsCOMPtr<mozIStorageConnection> db = do_get_db();
   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   db->CreateAsyncStatement(NS_LITERAL_CSTRING("SELECT 1"),
                            getter_AddRefs(stmt));
-  RefPtr<AsyncStatementSpinner> spinner = new AsyncStatementSpinner();
+  RefPtr<PlacesAsyncStatementSpinner> spinner =
+    new PlacesAsyncStatementSpinner();
   nsCOMPtr<mozIStoragePendingStatement> pending;
   (void)stmt->ExecuteAsync(spinner, getter_AddRefs(pending));
   spinner->SpinUntilCompleted();
 
   // Run the next test.
   run_next_test();
 }
 
--- a/xpcom/tests/gtest/TestDeadlockDetector.cpp
+++ b/xpcom/tests/gtest/TestDeadlockDetector.cpp
@@ -20,16 +20,27 @@
 #include "nsICrashReporter.h"
 #include "nsServiceManagerUtils.h"
 #endif
 
 #include "gtest/gtest.h"
 
 using namespace mozilla;
 
+// The code in this file is also used by
+// storage/test/gtest/test_deadlock_detector.cpp. The following two macros are
+// used to provide the necessary differentiation between this file and that
+// file.
+#ifndef MUTEX
+#define MUTEX mozilla::Mutex
+#endif
+#ifndef TESTNAME
+#define TESTNAME(name) XPCOM##name
+#endif
+
 static PRThread*
 spawn(void (*run)(void*), void* arg)
 {
     return PR_CreateThread(PR_SYSTEM_THREAD,
                            run,
                            arg,
                            PR_PRIORITY_NORMAL,
                            PR_GLOBAL_THREAD,
@@ -39,26 +50,26 @@ spawn(void (*run)(void*), void* arg)
 
 // This global variable is defined in toolkit/xre/nsSigHandlers.cpp.
 extern unsigned int _gdb_sleep_duration;
 
 /**
  * Simple test fixture that makes sure the gdb sleep setup in the
  * ah crap handler is bypassed during the death tests.
  */
-class DeadlockDetectorTest : public ::testing::Test
+class TESTNAME(DeadlockDetectorTest) : public ::testing::Test
 {
 protected:
   void SetUp() final {
-    mOldSleepDuration = _gdb_sleep_duration;
-    _gdb_sleep_duration = 0;
+    mOldSleepDuration = ::_gdb_sleep_duration;
+    ::_gdb_sleep_duration = 0;
   }
 
   void TearDown() final {
-    _gdb_sleep_duration = mOldSleepDuration;
+    ::_gdb_sleep_duration = mOldSleepDuration;
   }
 
 private:
   unsigned int mOldSleepDuration;
 };
 
 void DisableCrashReporter()
 {
@@ -75,23 +86,23 @@ void DisableCrashReporter()
 // Single-threaded sanity tests
 
 // Stupidest possible deadlock.
 int
 Sanity_Child()
 {
     DisableCrashReporter();
 
-    mozilla::Mutex m1("dd.sanity.m1");
+    MUTEX m1("dd.sanity.m1");
     m1.Lock();
     m1.Lock();
     return 0;                  // not reached
 }
 
-TEST_F(DeadlockDetectorTest, SanityDeathTest)
+TEST_F(TESTNAME(DeadlockDetectorTest), TESTNAME(SanityDeathTest))
 {
     const char* const regex =
         "###!!! ERROR: Potential deadlock detected.*"
         "=== Cyclical dependency starts at.*--- Mutex : dd.sanity.m1.*"
         "=== Cycle completed at.*--- Mutex : dd.sanity.m1.*"
         "###!!! Deadlock may happen NOW!.*" // better catch these easy cases...
         "###!!! ASSERTION: Potential deadlock detected.*";
 
@@ -99,25 +110,25 @@ TEST_F(DeadlockDetectorTest, SanityDeath
 }
 
 // Slightly less stupid deadlock.
 int
 Sanity2_Child()
 {
     DisableCrashReporter();
 
-    mozilla::Mutex m1("dd.sanity2.m1");
-    mozilla::Mutex m2("dd.sanity2.m2");
+    MUTEX m1("dd.sanity2.m1");
+    MUTEX m2("dd.sanity2.m2");
     m1.Lock();
     m2.Lock();
     m1.Lock();
     return 0;                  // not reached
 }
 
-TEST_F(DeadlockDetectorTest, Sanity2DeathTest)
+TEST_F(TESTNAME(DeadlockDetectorTest), TESTNAME(Sanity2DeathTest))
 {
     const char* const regex =
         "###!!! ERROR: Potential deadlock detected.*"
         "=== Cyclical dependency starts at.*--- Mutex : dd.sanity2.m1.*"
         "--- Next dependency:.*--- Mutex : dd.sanity2.m2.*"
         "=== Cycle completed at.*--- Mutex : dd.sanity2.m1.*"
         "###!!! Deadlock may happen NOW!.*" // better catch these easy cases...
         "###!!! ASSERTION: Potential deadlock detected.*";
@@ -125,36 +136,36 @@ TEST_F(DeadlockDetectorTest, Sanity2Deat
     ASSERT_DEATH_IF_SUPPORTED(Sanity2_Child(), regex);
 }
 
 int
 Sanity3_Child()
 {
     DisableCrashReporter();
 
-    mozilla::Mutex m1("dd.sanity3.m1");
-    mozilla::Mutex m2("dd.sanity3.m2");
-    mozilla::Mutex m3("dd.sanity3.m3");
-    mozilla::Mutex m4("dd.sanity3.m4");
+    MUTEX m1("dd.sanity3.m1");
+    MUTEX m2("dd.sanity3.m2");
+    MUTEX m3("dd.sanity3.m3");
+    MUTEX m4("dd.sanity3.m4");
 
     m1.Lock();
     m2.Lock();
     m3.Lock();
     m4.Lock();
     m4.Unlock();
     m3.Unlock();
     m2.Unlock();
     m1.Unlock();
 
     m4.Lock();
     m1.Lock();
     return 0;
 }
 
-TEST_F(DeadlockDetectorTest, Sanity3DeathTest)
+TEST_F(TESTNAME(DeadlockDetectorTest), TESTNAME(Sanity3DeathTest))
 {
     const char* const regex =
         "###!!! ERROR: Potential deadlock detected.*"
         "=== Cyclical dependency starts at.*--- Mutex : dd.sanity3.m1.*"
         "--- Next dependency:.*--- Mutex : dd.sanity3.m2.*"
         "--- Next dependency:.*--- Mutex : dd.sanity3.m3.*"
         "--- Next dependency:.*--- Mutex : dd.sanity3.m4.*"
         "=== Cycle completed at.*--- Mutex : dd.sanity3.m1.*"
@@ -164,24 +175,24 @@ TEST_F(DeadlockDetectorTest, Sanity3Deat
 }
 
 int
 Sanity4_Child()
 {
     DisableCrashReporter();
 
     mozilla::ReentrantMonitor m1("dd.sanity4.m1");
-    mozilla::Mutex m2("dd.sanity4.m2");
+    MUTEX m2("dd.sanity4.m2");
     m1.Enter();
     m2.Lock();
     m1.Enter();
     return 0;
 }
 
-TEST_F(DeadlockDetectorTest, Sanity4DeathTest)
+TEST_F(TESTNAME(DeadlockDetectorTest), TESTNAME(Sanity4DeathTest))
 {
     const char* const regex =
         "Re-entering ReentrantMonitor after acquiring other resources.*"
         "###!!! ERROR: Potential deadlock detected.*"
         "=== Cyclical dependency starts at.*--- ReentrantMonitor : dd.sanity4.m1.*"
         "--- Next dependency:.*--- Mutex : dd.sanity4.m2.*"
         "=== Cycle completed at.*--- ReentrantMonitor : dd.sanity4.m1.*"
         "###!!! ASSERTION: Potential deadlock detected.*";
@@ -195,31 +206,31 @@ TEST_F(DeadlockDetectorTest, Sanity4Deat
  * Helper for passing state to threads in the multithread tests.
  */
 struct ThreadState
 {
   /**
    * Locks to use during the test. This is just a reference and is owned by
    * the main test thread.
    */
-  const nsTArray<mozilla::Mutex*>& locks;
+  const nsTArray<MUTEX*>& locks;
 
   /**
    * Integer argument used to identify each thread.
    */
   int id;
 };
 
 static void
 TwoThreads_thread(void* arg)
 {
     ThreadState* state = static_cast<ThreadState*>(arg);
 
-    mozilla::Mutex* ttM1 = state->locks[0];
-    mozilla::Mutex* ttM2 = state->locks[1];
+    MUTEX* ttM1 = state->locks[0];
+    MUTEX* ttM2 = state->locks[1];
 
     if (state->id) {
         ttM1->Lock();
         ttM2->Lock();
         ttM2->Unlock();
         ttM1->Unlock();
     }
     else {
@@ -230,19 +241,19 @@ TwoThreads_thread(void* arg)
     }
 }
 
 int
 TwoThreads_Child()
 {
     DisableCrashReporter();
 
-    nsTArray<mozilla::Mutex*> locks = {
-      new mozilla::Mutex("dd.twothreads.m1"),
-      new mozilla::Mutex("dd.twothreads.m2")
+    nsTArray<MUTEX*> locks = {
+      new MUTEX("dd.twothreads.m1"),
+      new MUTEX("dd.twothreads.m2")
     };
 
     ThreadState state_1 {locks, 0};
     PRThread* t1 = spawn(TwoThreads_thread, &state_1);
     PR_JoinThread(t1);
 
     ThreadState state_2 {locks, 1};
     PRThread* t2 = spawn(TwoThreads_thread, &state_2);
@@ -250,17 +261,17 @@ TwoThreads_Child()
 
     for (auto& lock : locks) {
       delete lock;
     }
 
     return 0;
 }
 
-TEST_F(DeadlockDetectorTest, TwoThreadsDeathTest)
+TEST_F(TESTNAME(DeadlockDetectorTest), TESTNAME(TwoThreadsDeathTest))
 {
     const char* const regex =
         "###!!! ERROR: Potential deadlock detected.*"
         "=== Cyclical dependency starts at.*--- Mutex : dd.twothreads.m2.*"
         "--- Next dependency:.*--- Mutex : dd.twothreads.m1.*"
         "=== Cycle completed at.*--- Mutex : dd.twothreads.m2.*"
         "###!!! ASSERTION: Potential deadlock detected.*";
 
@@ -288,35 +299,35 @@ ContentionNoDeadlock_thread(void* arg)
 }
 
 int
 ContentionNoDeadlock_Child()
 {
     const size_t kMutexCount = 4;
 
     PRThread* threads[3];
-    nsTArray<mozilla::Mutex*> locks;
+    nsTArray<MUTEX*> locks;
     ThreadState states[] = {
       { locks, 0 },
       { locks, 1 },
       { locks, 2 }
     };
 
     for (uint32_t i = 0; i < kMutexCount; ++i)
-        locks.AppendElement(new mozilla::Mutex("dd.cnd.ms"));
+        locks.AppendElement(new MUTEX("dd.cnd.ms"));
 
     for (int32_t i = 0; i < (int32_t) ArrayLength(threads); ++i)
         threads[i] = spawn(ContentionNoDeadlock_thread, states + i);
 
     for (uint32_t i = 0; i < ArrayLength(threads); ++i)
         PR_JoinThread(threads[i]);
 
     for (uint32_t i = 0; i < locks.Length(); ++i)
         delete locks[i];
 
     return 0;
 }
 
-TEST_F(DeadlockDetectorTest, ContentionNoDeadlock)
+TEST_F(TESTNAME(DeadlockDetectorTest), TESTNAME(ContentionNoDeadlock))
 {
   // Just check that this test runs to completion.
   ASSERT_EQ(ContentionNoDeadlock_Child(), 0);
 }