255 lines
8.5 KiB
C++
255 lines
8.5 KiB
C++
// Copyright 2016 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/task/sequenced_task_runner.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "base/functional/bind.h"
|
|
#include "base/functional/callback.h"
|
|
#include "base/functional/callback_helpers.h"
|
|
#include "base/gtest_prod_util.h"
|
|
#include "base/location.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/memory/scoped_refptr.h"
|
|
#include "base/run_loop.h"
|
|
#include "base/sequence_checker_impl.h"
|
|
#include "base/task/sequenced_task_runner.h"
|
|
#include "base/task/thread_pool.h"
|
|
#include "base/test/bind.h"
|
|
#include "base/test/null_task_runner.h"
|
|
#include "base/test/task_environment.h"
|
|
#include "base/test/test_mock_time_task_runner.h"
|
|
#include "base/test/test_simple_task_runner.h"
|
|
#include "base/threading/thread.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace base {
|
|
namespace {
|
|
|
|
class FlagOnDelete {
|
|
public:
|
|
FlagOnDelete(bool* deleted,
|
|
scoped_refptr<SequencedTaskRunner> expected_deletion_sequence)
|
|
: deleted_(deleted),
|
|
expected_deletion_sequence_(std::move(expected_deletion_sequence)) {}
|
|
FlagOnDelete(const FlagOnDelete&) = delete;
|
|
FlagOnDelete& operator=(const FlagOnDelete&) = delete;
|
|
|
|
~FlagOnDelete() {
|
|
EXPECT_FALSE(*deleted_);
|
|
*deleted_ = true;
|
|
if (expected_deletion_sequence_)
|
|
EXPECT_TRUE(expected_deletion_sequence_->RunsTasksInCurrentSequence());
|
|
}
|
|
|
|
private:
|
|
raw_ptr<bool> deleted_;
|
|
const scoped_refptr<SequencedTaskRunner> expected_deletion_sequence_;
|
|
};
|
|
|
|
class SequencedTaskRunnerTest : public testing::Test {
|
|
public:
|
|
SequencedTaskRunnerTest(const SequencedTaskRunnerTest&) = delete;
|
|
SequencedTaskRunnerTest& operator=(const SequencedTaskRunnerTest&) = delete;
|
|
|
|
protected:
|
|
SequencedTaskRunnerTest() : foreign_thread_("foreign") {}
|
|
|
|
void SetUp() override {
|
|
foreign_thread_.Start();
|
|
foreign_runner_ = foreign_thread_.task_runner();
|
|
}
|
|
|
|
scoped_refptr<SequencedTaskRunner> foreign_runner_;
|
|
|
|
Thread foreign_thread_;
|
|
|
|
private:
|
|
test::TaskEnvironment task_environment_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
using SequenceBoundUniquePtr =
|
|
std::unique_ptr<FlagOnDelete, OnTaskRunnerDeleter>;
|
|
|
|
TEST_F(SequencedTaskRunnerTest, OnTaskRunnerDeleterOnMainThread) {
|
|
bool deleted_on_main_thread = false;
|
|
SequenceBoundUniquePtr ptr(
|
|
new FlagOnDelete(&deleted_on_main_thread,
|
|
SequencedTaskRunner::GetCurrentDefault()),
|
|
OnTaskRunnerDeleter(SequencedTaskRunner::GetCurrentDefault()));
|
|
EXPECT_FALSE(deleted_on_main_thread);
|
|
foreign_runner_->PostTask(FROM_HERE, DoNothingWithBoundArgs(std::move(ptr)));
|
|
|
|
{
|
|
RunLoop run_loop;
|
|
foreign_runner_->PostTaskAndReply(FROM_HERE, BindOnce([] {}),
|
|
run_loop.QuitClosure());
|
|
run_loop.Run();
|
|
}
|
|
EXPECT_TRUE(deleted_on_main_thread);
|
|
}
|
|
|
|
TEST_F(SequencedTaskRunnerTest, OnTaskRunnerDeleterTargetStoppedEarly) {
|
|
bool deleted_on_main_thread = false;
|
|
FlagOnDelete* raw = new FlagOnDelete(
|
|
&deleted_on_main_thread, SequencedTaskRunner::GetCurrentDefault());
|
|
SequenceBoundUniquePtr ptr(raw, OnTaskRunnerDeleter(foreign_runner_));
|
|
EXPECT_FALSE(deleted_on_main_thread);
|
|
|
|
// Stopping the target ahead of deleting |ptr| should make its
|
|
// OnTaskRunnerDeleter no-op.
|
|
foreign_thread_.Stop();
|
|
ptr = nullptr;
|
|
EXPECT_FALSE(deleted_on_main_thread);
|
|
|
|
delete raw;
|
|
EXPECT_TRUE(deleted_on_main_thread);
|
|
}
|
|
|
|
TEST_F(SequencedTaskRunnerTest, DelayedTaskHandle_RunTask) {
|
|
auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
|
|
|
|
bool task_ran = false;
|
|
DelayedTaskHandle delayed_task_handle =
|
|
task_runner->PostCancelableDelayedTask(
|
|
subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
|
|
BindLambdaForTesting([&task_ran]() { task_ran = true; }), Seconds(1));
|
|
EXPECT_TRUE(delayed_task_handle.IsValid());
|
|
EXPECT_TRUE(task_runner->HasPendingTask());
|
|
|
|
// Run the delayed task.
|
|
task_runner->FastForwardUntilNoTasksRemain();
|
|
|
|
EXPECT_FALSE(delayed_task_handle.IsValid());
|
|
EXPECT_FALSE(task_runner->HasPendingTask());
|
|
EXPECT_TRUE(task_ran);
|
|
}
|
|
|
|
TEST_F(SequencedTaskRunnerTest, DelayedTaskHandle_CancelTask) {
|
|
auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
|
|
|
|
bool task_ran = false;
|
|
DelayedTaskHandle delayed_task_handle =
|
|
task_runner->PostCancelableDelayedTask(
|
|
subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
|
|
BindLambdaForTesting([&task_ran]() { task_ran = true; }), Seconds(1));
|
|
EXPECT_TRUE(delayed_task_handle.IsValid());
|
|
EXPECT_TRUE(task_runner->HasPendingTask());
|
|
|
|
// Cancel the delayed task.
|
|
delayed_task_handle.CancelTask();
|
|
|
|
EXPECT_FALSE(delayed_task_handle.IsValid());
|
|
EXPECT_FALSE(task_runner->HasPendingTask());
|
|
EXPECT_FALSE(task_ran);
|
|
}
|
|
|
|
TEST_F(SequencedTaskRunnerTest, DelayedTaskHandle_DestroyTask) {
|
|
auto task_runner = MakeRefCounted<TestMockTimeTaskRunner>();
|
|
|
|
bool task_ran = false;
|
|
DelayedTaskHandle delayed_task_handle =
|
|
task_runner->PostCancelableDelayedTask(
|
|
subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
|
|
BindLambdaForTesting([&task_ran]() { task_ran = true; }), Seconds(1));
|
|
EXPECT_TRUE(delayed_task_handle.IsValid());
|
|
EXPECT_TRUE(task_runner->HasPendingTask());
|
|
|
|
// Destroy the pending task.
|
|
task_runner->ClearPendingTasks();
|
|
|
|
EXPECT_FALSE(delayed_task_handle.IsValid());
|
|
EXPECT_FALSE(task_runner->HasPendingTask());
|
|
EXPECT_FALSE(task_ran);
|
|
}
|
|
|
|
// Tests that if PostCancelableDelayedTask() fails, the returned handle will be
|
|
// invalid.
|
|
TEST_F(SequencedTaskRunnerTest, DelayedTaskHandle_PostTaskFailed) {
|
|
auto task_runner = MakeRefCounted<NullTaskRunner>();
|
|
|
|
bool task_ran = false;
|
|
DelayedTaskHandle delayed_task_handle =
|
|
task_runner->PostCancelableDelayedTask(
|
|
subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
|
|
BindLambdaForTesting([&task_ran]() { task_ran = true; }), Seconds(1));
|
|
EXPECT_FALSE(delayed_task_handle.IsValid());
|
|
EXPECT_FALSE(task_ran);
|
|
}
|
|
|
|
namespace {
|
|
|
|
// Tests for the SequencedTaskRunner::CurrentDefaultHandle machinery.
|
|
class SequencedTaskRunnerCurrentDefaultHandleTest : public ::testing::Test {
|
|
protected:
|
|
// Verifies that the context it runs on has a
|
|
// SequencedTaskRunner::CurrentDefaultHandle and that posting to it results in
|
|
// the posted task running in that same context (sequence).
|
|
static void VerifyCurrentSequencedTaskRunner() {
|
|
ASSERT_TRUE(SequencedTaskRunner::HasCurrentDefault());
|
|
scoped_refptr<SequencedTaskRunner> task_runner =
|
|
SequencedTaskRunner::GetCurrentDefault();
|
|
ASSERT_TRUE(task_runner);
|
|
|
|
// Use SequenceCheckerImpl to make sure it's not a no-op in Release builds.
|
|
std::unique_ptr<SequenceCheckerImpl> sequence_checker =
|
|
std::make_unique<SequenceCheckerImpl>();
|
|
task_runner->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(
|
|
&SequencedTaskRunnerCurrentDefaultHandleTest::CheckValidSequence,
|
|
std::move(sequence_checker)));
|
|
}
|
|
|
|
static void CheckValidSequence(
|
|
std::unique_ptr<SequenceCheckerImpl> sequence_checker) {
|
|
EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
|
|
}
|
|
|
|
test::TaskEnvironment task_environment_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest, FromTaskEnvironment) {
|
|
VerifyCurrentSequencedTaskRunner();
|
|
RunLoop().RunUntilIdle();
|
|
}
|
|
|
|
TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,
|
|
FromThreadPoolSequencedTask) {
|
|
base::ThreadPool::CreateSequencedTaskRunner({})->PostTask(
|
|
FROM_HERE, base::BindOnce(&SequencedTaskRunnerCurrentDefaultHandleTest::
|
|
VerifyCurrentSequencedTaskRunner));
|
|
task_environment_.RunUntilIdle();
|
|
}
|
|
|
|
TEST_F(SequencedTaskRunnerCurrentDefaultHandleTest,
|
|
NoHandleFromUnsequencedTask) {
|
|
base::ThreadPool::PostTask(base::BindOnce(
|
|
[]() { EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault()); }));
|
|
task_environment_.RunUntilIdle();
|
|
}
|
|
|
|
TEST(SequencedTaskRunnerCurrentDefaultHandleTestWithoutTaskEnvironment,
|
|
FromHandleInScope) {
|
|
scoped_refptr<SequencedTaskRunner> test_task_runner =
|
|
MakeRefCounted<TestSimpleTaskRunner>();
|
|
EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault());
|
|
EXPECT_FALSE(SingleThreadTaskRunner::HasCurrentDefault());
|
|
{
|
|
SequencedTaskRunner::CurrentDefaultHandle current_default(test_task_runner);
|
|
EXPECT_TRUE(SequencedTaskRunner::HasCurrentDefault());
|
|
EXPECT_FALSE(SingleThreadTaskRunner::HasCurrentDefault());
|
|
EXPECT_EQ(test_task_runner, SequencedTaskRunner::GetCurrentDefault());
|
|
}
|
|
EXPECT_FALSE(SequencedTaskRunner::HasCurrentDefault());
|
|
EXPECT_FALSE(SingleThreadTaskRunner::HasCurrentDefault());
|
|
}
|
|
|
|
} // namespace base
|