blob: 7f14b99e5971435c4dc90796a84a15fa5263cc2d [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/task/post_task.h"
#include "base/bind_helpers.h"
#include "base/metrics/statistics_recorder.h"
#include "base/task/task_executor.h"
#include "base/task/test_task_traits_extension.h"
#include "base/test/gtest_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
namespace base {
namespace {
class MockTaskExecutor : public TaskExecutor {
public:
MockTaskExecutor() {
ON_CALL(*this, PostDelayedTaskWithTraitsMock(_, _, _, _))
.WillByDefault(Invoke([this](const Location& from_here,
const TaskTraits& traits,
OnceClosure& task, TimeDelta delay) {
return runner_->PostDelayedTask(from_here, std::move(task), delay);
}));
ON_CALL(*this, CreateTaskRunnerWithTraits(_))
.WillByDefault(Return(runner_));
ON_CALL(*this, CreateSequencedTaskRunnerWithTraits(_))
.WillByDefault(Return(runner_));
ON_CALL(*this, CreateSingleThreadTaskRunnerWithTraits(_, _))
.WillByDefault(Return(runner_));
#if defined(OS_WIN)
ON_CALL(*this, CreateCOMSTATaskRunnerWithTraits(_, _))
.WillByDefault(Return(runner_));
#endif // defined(OS_WIN)
}
// TaskExecutor:
// Helper because gmock doesn't support move-only types.
bool PostDelayedTaskWithTraits(const Location& from_here,
const TaskTraits& traits,
OnceClosure task,
TimeDelta delay) override {
return PostDelayedTaskWithTraitsMock(from_here, traits, task, delay);
}
MOCK_METHOD4(PostDelayedTaskWithTraitsMock,
bool(const Location& from_here,
const TaskTraits& traits,
OnceClosure& task,
TimeDelta delay));
MOCK_METHOD1(CreateTaskRunnerWithTraits,
scoped_refptr<TaskRunner>(const TaskTraits& traits));
MOCK_METHOD1(CreateSequencedTaskRunnerWithTraits,
scoped_refptr<SequencedTaskRunner>(const TaskTraits& traits));
MOCK_METHOD2(CreateSingleThreadTaskRunnerWithTraits,
scoped_refptr<SingleThreadTaskRunner>(
const TaskTraits& traits,
SingleThreadTaskRunnerThreadMode thread_mode));
#if defined(OS_WIN)
MOCK_METHOD2(CreateCOMSTATaskRunnerWithTraits,
scoped_refptr<SingleThreadTaskRunner>(
const TaskTraits& traits,
SingleThreadTaskRunnerThreadMode thread_mode));
#endif // defined(OS_WIN)
TestSimpleTaskRunner* runner() const { return runner_.get(); }
private:
scoped_refptr<TestSimpleTaskRunner> runner_ =
MakeRefCounted<TestSimpleTaskRunner>();
DISALLOW_COPY_AND_ASSIGN(MockTaskExecutor);
};
} // namespace
class PostTaskTestWithExecutor : public ::testing::Test {
public:
PostTaskTestWithExecutor()
: recorder_for_testing_(StatisticsRecorder::CreateTemporaryForTesting()),
scoped_task_environment_() {}
void SetUp() override {
RegisterTaskExecutor(TestTaskTraitsExtension::kExtensionId, &executor_);
}
void TearDown() override {
UnregisterTaskExecutorForTesting(TestTaskTraitsExtension::kExtensionId);
}
protected:
testing::StrictMock<MockTaskExecutor> executor_;
std::unique_ptr<StatisticsRecorder> recorder_for_testing_;
test::ScopedTaskEnvironment scoped_task_environment_;
};
TEST_F(PostTaskTestWithExecutor, PostTaskToTaskScheduler) {
// Tasks without extension should not go to the TestTaskExecutor.
EXPECT_TRUE(PostTask(FROM_HERE, DoNothing()));
EXPECT_FALSE(executor_.runner()->HasPendingTask());
EXPECT_TRUE(PostTaskWithTraits(FROM_HERE, {MayBlock()}, DoNothing()));
EXPECT_FALSE(executor_.runner()->HasPendingTask());
// Task runners without extension should not be the executor's.
auto task_runner = CreateTaskRunnerWithTraits({});
EXPECT_NE(executor_.runner(), task_runner);
auto sequenced_task_runner = CreateSequencedTaskRunnerWithTraits({});
EXPECT_NE(executor_.runner(), sequenced_task_runner);
auto single_thread_task_runner = CreateSingleThreadTaskRunnerWithTraits({});
EXPECT_NE(executor_.runner(), single_thread_task_runner);
#if defined(OS_WIN)
auto comsta_task_runner = CreateCOMSTATaskRunnerWithTraits({});
EXPECT_NE(executor_.runner(), comsta_task_runner);
#endif // defined(OS_WIN)
}
#if !defined(STARBOARD)
// Cobalt does not support tasks with extension yet.
TEST_F(PostTaskTestWithExecutor, PostTaskToTaskExecutor) {
// Tasks with extension should go to the executor.
{
TaskTraits traits = {TestExtensionBoolTrait()};
TaskTraits traits_with_explicit_priority =
TaskTraits::Override(traits, {TaskPriority::USER_VISIBLE});
EXPECT_CALL(executor_, PostDelayedTaskWithTraitsMock(
_, traits_with_explicit_priority, _, _))
.Times(1);
EXPECT_TRUE(PostTaskWithTraits(FROM_HERE, traits, DoNothing()));
EXPECT_TRUE(executor_.runner()->HasPendingTask());
executor_.runner()->ClearPendingTasks();
}
{
TaskTraits traits = {MayBlock(), TestExtensionBoolTrait()};
TaskTraits traits_with_explicit_priority =
TaskTraits::Override(traits, {TaskPriority::USER_VISIBLE});
EXPECT_CALL(executor_, PostDelayedTaskWithTraitsMock(
_, traits_with_explicit_priority, _, _))
.Times(1);
EXPECT_TRUE(PostTaskWithTraits(FROM_HERE, traits, DoNothing()));
EXPECT_TRUE(executor_.runner()->HasPendingTask());
executor_.runner()->ClearPendingTasks();
}
{
TaskTraits traits = {TestExtensionEnumTrait::kB, TestExtensionBoolTrait()};
TaskTraits traits_with_explicit_priority =
TaskTraits::Override(traits, {TaskPriority::USER_VISIBLE});
EXPECT_CALL(executor_, PostDelayedTaskWithTraitsMock(
_, traits_with_explicit_priority, _, _))
.Times(1);
EXPECT_TRUE(PostTaskWithTraits(FROM_HERE, traits, DoNothing()));
EXPECT_TRUE(executor_.runner()->HasPendingTask());
executor_.runner()->ClearPendingTasks();
}
// Task runners with extension should be the executor's.
{
TaskTraits traits = {TestExtensionBoolTrait()};
TaskTraits traits_with_explicit_priority =
TaskTraits::Override(traits, {TaskPriority::USER_VISIBLE});
EXPECT_CALL(executor_,
CreateTaskRunnerWithTraits(traits_with_explicit_priority))
.Times(1);
auto task_runner = CreateTaskRunnerWithTraits(traits);
EXPECT_EQ(executor_.runner(), task_runner);
EXPECT_CALL(executor_, CreateSequencedTaskRunnerWithTraits(
traits_with_explicit_priority))
.Times(1);
auto sequenced_task_runner = CreateSequencedTaskRunnerWithTraits(traits);
EXPECT_EQ(executor_.runner(), sequenced_task_runner);
EXPECT_CALL(executor_, CreateSingleThreadTaskRunnerWithTraits(
traits_with_explicit_priority, _))
.Times(1);
auto single_thread_task_runner =
CreateSingleThreadTaskRunnerWithTraits(traits);
EXPECT_EQ(executor_.runner(), single_thread_task_runner);
#if defined(OS_WIN)
EXPECT_CALL(executor_, CreateCOMSTATaskRunnerWithTraits(
traits_with_explicit_priority, _))
.Times(1);
auto comsta_task_runner = CreateCOMSTATaskRunnerWithTraits(traits);
EXPECT_EQ(executor_.runner(), comsta_task_runner);
#endif // defined(OS_WIN)
}
}
#endif // !defined(STARBOARD)
TEST_F(PostTaskTestWithExecutor, RegisterExecutorTwice) {
testing::FLAGS_gtest_death_test_style = "threadsafe";
EXPECT_DCHECK_DEATH(
RegisterTaskExecutor(TestTaskTraitsExtension::kExtensionId, &executor_));
}
} // namespace base