summaryrefslogtreecommitdiffstats
path: root/storage/test/gtest/test_interruptSynchronousConnection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/test/gtest/test_interruptSynchronousConnection.cpp')
-rw-r--r--storage/test/gtest/test_interruptSynchronousConnection.cpp81
1 files changed, 81 insertions, 0 deletions
diff --git a/storage/test/gtest/test_interruptSynchronousConnection.cpp b/storage/test/gtest/test_interruptSynchronousConnection.cpp
new file mode 100644
index 0000000000..dfa19bc86e
--- /dev/null
+++ b/storage/test/gtest/test_interruptSynchronousConnection.cpp
@@ -0,0 +1,81 @@
+/* -*- 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 "gtest/gtest.h"
+
+#include "storage_test_harness.h"
+
+#include "mozilla/SpinEventLoopUntil.h"
+
+class SynchronousConnectionInterruptionTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ mConnection =
+ getDatabase(nullptr, mozIStorageService::CONNECTION_INTERRUPTIBLE);
+ ASSERT_TRUE(mConnection);
+
+ ASSERT_EQ(NS_OK, NS_NewNamedThread("Test Thread", getter_AddRefs(mThread)));
+ }
+
+ void TearDown() override {
+ // We might close the database connection early in test cases.
+ mozilla::Unused << mConnection->Close();
+
+ ASSERT_EQ(NS_OK, mThread->Shutdown());
+ }
+
+ nsCOMPtr<mozIStorageConnection> mConnection;
+
+ nsCOMPtr<nsIThread> mThread;
+
+ bool mDone = false;
+};
+
+TEST_F(SynchronousConnectionInterruptionTest,
+ shouldBeAbleToInterruptInfiniteOperation) {
+ // Delay is modest because we don't want to get interrupted by
+ // some unrelated hang or memory guard
+ const uint32_t delayMs = 500;
+
+ ASSERT_EQ(NS_OK, mThread->DelayedDispatch(
+ NS_NewRunnableFunction(
+ "InterruptRunnable",
+ [this]() {
+ ASSERT_EQ(NS_OK, mConnection->Interrupt());
+ mDone = true;
+ }),
+ delayMs));
+
+ const nsCString infiniteQuery =
+ "WITH RECURSIVE test(n) "
+ "AS (VALUES(1) UNION ALL SELECT n + 1 FROM test) "
+ "SELECT t.n FROM test, test AS t;"_ns;
+ nsCOMPtr<mozIStorageStatement> stmt;
+ ASSERT_EQ(NS_OK,
+ mConnection->CreateStatement(infiniteQuery, getter_AddRefs(stmt)));
+ ASSERT_EQ(NS_ERROR_ABORT, stmt->Execute());
+ ASSERT_EQ(NS_OK, stmt->Finalize());
+
+ ASSERT_TRUE(mDone);
+
+ ASSERT_EQ(NS_OK, mConnection->Close());
+}
+
+TEST_F(SynchronousConnectionInterruptionTest, interruptAfterCloseWillFail) {
+ ASSERT_EQ(NS_OK, mConnection->Close());
+
+ ASSERT_EQ(
+ NS_OK,
+ mThread->Dispatch(NS_NewRunnableFunction("InterruptRunnable", [this]() {
+ ASSERT_EQ(NS_ERROR_NOT_INITIALIZED, mConnection->Interrupt());
+ mDone = true;
+ })));
+
+ ASSERT_TRUE(mozilla::SpinEventLoopUntil("interruptAfterCloseWillFail"_ns,
+ [this]() { return mDone; }));
+
+ ASSERT_EQ(NS_ERROR_NOT_INITIALIZED, mConnection->Close());
+}