blob: 3d7490abf585fb5c43cb722f4a365d2e0e82212a [file] [log] [blame]
// Copyright 2017 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/lazy_task_runner.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/statistics_recorder.h"
#include "base/sequence_checker_impl.h"
#include "base/task/scoped_set_task_priority_for_current_thread.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_checker_impl.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
#include "base/win/com_init_util.h"
#endif
namespace base {
namespace {
LazySequencedTaskRunner g_sequenced_task_runner_user_visible =
LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_VISIBLE});
LazySequencedTaskRunner g_sequenced_task_runner_user_blocking =
LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_BLOCKING});
LazySingleThreadTaskRunner g_single_thread_task_runner_user_visible =
LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
{TaskPriority::USER_VISIBLE},
SingleThreadTaskRunnerThreadMode::SHARED);
LazySingleThreadTaskRunner g_single_thread_task_runner_user_blocking =
LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
{TaskPriority::USER_BLOCKING},
SingleThreadTaskRunnerThreadMode::SHARED);
#if defined(OS_WIN)
LazyCOMSTATaskRunner g_com_sta_task_runner_user_visible =
LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
{TaskPriority::USER_VISIBLE},
SingleThreadTaskRunnerThreadMode::SHARED);
LazyCOMSTATaskRunner g_com_sta_task_runner_user_blocking =
LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
{TaskPriority::USER_BLOCKING},
SingleThreadTaskRunnerThreadMode::SHARED);
#endif // defined(OS_WIN)
void InitCheckers(SequenceCheckerImpl* sequence_checker,
ThreadCheckerImpl* thread_checker) {
sequence_checker->DetachFromSequence();
EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
thread_checker->DetachFromThread();
EXPECT_TRUE(thread_checker->CalledOnValidThread());
}
void ExpectSequencedEnvironment(SequenceCheckerImpl* sequence_checker,
ThreadCheckerImpl* thread_checker,
TaskPriority expected_priority) {
EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
EXPECT_FALSE(thread_checker->CalledOnValidThread());
EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread());
}
void ExpectSingleThreadEnvironment(SequenceCheckerImpl* sequence_checker,
ThreadCheckerImpl* thread_checker,
TaskPriority expected_priority
#if defined(OS_WIN)
,
bool expect_com_sta = false
#endif
) {
EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
EXPECT_TRUE(thread_checker->CalledOnValidThread());
EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread());
#if defined(OS_WIN)
if (expect_com_sta)
win::AssertComApartmentType(win::ComApartmentType::STA);
#endif
}
class TaskSchedulerLazyTaskRunnerEnvironmentTest : public testing::Test {
protected:
TaskSchedulerLazyTaskRunnerEnvironmentTest()
: recorder_for_testing_(StatisticsRecorder::CreateTemporaryForTesting()),
scoped_task_environment_() {
GlobalHistogramAllocator::ReleaseForTesting();
}
void TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner,
bool expect_single_thread,
TaskPriority expected_priority
#if defined(OS_WIN)
,
bool expect_com_sta = false
#endif
) {
SequenceCheckerImpl sequence_checker;
ThreadCheckerImpl thread_checker;
task_runner->PostTask(FROM_HERE,
BindOnce(&InitCheckers, Unretained(&sequence_checker),
Unretained(&thread_checker)));
scoped_task_environment_.RunUntilIdle();
OnceClosure task =
expect_single_thread
? BindOnce(&ExpectSingleThreadEnvironment,
Unretained(&sequence_checker),
Unretained(&thread_checker), expected_priority
#if defined(OS_WIN)
,
expect_com_sta
#endif
)
: BindOnce(&ExpectSequencedEnvironment,
Unretained(&sequence_checker),
Unretained(&thread_checker), expected_priority);
task_runner->PostTask(FROM_HERE, std::move(task));
scoped_task_environment_.RunUntilIdle();
}
std::unique_ptr<StatisticsRecorder> recorder_for_testing_;
test::ScopedTaskEnvironment scoped_task_environment_;
private:
DISALLOW_COPY_AND_ASSIGN(TaskSchedulerLazyTaskRunnerEnvironmentTest);
};
} // namespace
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
LazySequencedTaskRunnerUserVisible) {
TestTaskRunnerEnvironment(g_sequenced_task_runner_user_visible.Get(), false,
TaskPriority::USER_VISIBLE);
}
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
LazySequencedTaskRunnerUserBlocking) {
TestTaskRunnerEnvironment(g_sequenced_task_runner_user_blocking.Get(), false,
TaskPriority::USER_BLOCKING);
}
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
LazySingleThreadTaskRunnerUserVisible) {
TestTaskRunnerEnvironment(g_single_thread_task_runner_user_visible.Get(),
true, TaskPriority::USER_VISIBLE);
}
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
LazySingleThreadTaskRunnerUserBlocking) {
TestTaskRunnerEnvironment(g_single_thread_task_runner_user_blocking.Get(),
true, TaskPriority::USER_BLOCKING);
}
#if defined(OS_WIN)
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
LazyCOMSTATaskRunnerUserVisible) {
TestTaskRunnerEnvironment(g_com_sta_task_runner_user_visible.Get(), true,
TaskPriority::USER_VISIBLE, true);
}
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
LazyCOMSTATaskRunnerUserBlocking) {
TestTaskRunnerEnvironment(g_com_sta_task_runner_user_blocking.Get(), true,
TaskPriority::USER_BLOCKING, true);
}
#endif // defined(OS_WIN)
TEST(TaskSchdulerLazyTaskRunnerTest, LazySequencedTaskRunnerReset) {
std::unique_ptr<StatisticsRecorder> recorder_for_testing_ =
StatisticsRecorder::CreateTemporaryForTesting();
for (int i = 0; i < 2; ++i) {
test::ScopedTaskEnvironment scoped_task_environment;
// If the TaskRunner isn't released when the test::ScopedTaskEnvironment
// goes out of scope, the second invocation of the line below will access a
// deleted TaskScheduler and crash.
g_sequenced_task_runner_user_visible.Get()->PostTask(FROM_HERE,
DoNothing());
}
}
TEST(TaskSchdulerLazyTaskRunnerTest, LazySingleThreadTaskRunnerReset) {
std::unique_ptr<StatisticsRecorder> recorder_for_testing_ =
StatisticsRecorder::CreateTemporaryForTesting();
for (int i = 0; i < 2; ++i) {
test::ScopedTaskEnvironment scoped_task_environment;
// If the TaskRunner isn't released when the test::ScopedTaskEnvironment
// goes out of scope, the second invocation of the line below will access a
// deleted TaskScheduler and crash.
g_single_thread_task_runner_user_visible.Get()->PostTask(FROM_HERE,
DoNothing());
}
}
#if defined(OS_WIN)
TEST(TaskSchdulerLazyTaskRunnerTest, LazyCOMSTATaskRunnerReset) {
std::unique_ptr<StatisticsRecorder> recorder_for_testing_ =
StatisticsRecorder::CreateTemporaryForTesting();
for (int i = 0; i < 2; ++i) {
test::ScopedTaskEnvironment scoped_task_environment;
// If the TaskRunner isn't released when the test::ScopedTaskEnvironment
// goes out of scope, the second invocation of the line below will access a
// deleted TaskScheduler and crash.
g_com_sta_task_runner_user_visible.Get()->PostTask(FROM_HERE, DoNothing());
}
}
#endif // defined(OS_WIN)
} // namespace base