/* -*- 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 mConnection; nsCOMPtr 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 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()); }