Bug 1315138 - gtestify storage/test/*.cpp. r=mak,erahm.
authorNicholas Nethercote <nnethercote@mozilla.com>
Fri, 11 Nov 2016 09:59:23 +1100
changeset 323812 7f2bbd06a80c43cc1a569e916b4cc9c575eb3448
parent 323811 a494dd0ae2b0278403a36b38c64c0d48074b88bc
child 323813 189500d81aade9cb74be70de648c47faf1c0c3a3
push id84242
push usernnethercote@mozilla.com
push dateTue, 22 Nov 2016 22:07:28 +0000
treeherdermozilla-inbound@7f2bbd06a80c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak, erahm
bugs1315138, 1318282
milestone53.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 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);
 }