1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/task_scheduler/lazy_task_runner.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/sequence_checker_impl.h"
10 #include "base/task_scheduler/scoped_set_task_priority_for_current_thread.h"
11 #include "base/test/scoped_task_environment.h"
12 #include "base/threading/thread_checker_impl.h"
13 #include "build/build_config.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 #if defined(OS_WIN)
17 #include "base/win/com_init_util.h"
18 #endif
19
20 namespace base {
21
22 namespace {
23
24 LazySequencedTaskRunner g_sequenced_task_runner_user_visible =
25 LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_VISIBLE});
26 LazySequencedTaskRunner g_sequenced_task_runner_user_blocking =
27 LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_BLOCKING});
28
29 LazySingleThreadTaskRunner g_single_thread_task_runner_user_visible =
30 LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
31 {TaskPriority::USER_VISIBLE},
32 SingleThreadTaskRunnerThreadMode::SHARED);
33 LazySingleThreadTaskRunner g_single_thread_task_runner_user_blocking =
34 LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
35 {TaskPriority::USER_BLOCKING},
36 SingleThreadTaskRunnerThreadMode::SHARED);
37
38 #if defined(OS_WIN)
39 LazyCOMSTATaskRunner g_com_sta_task_runner_user_visible =
40 LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
41 {TaskPriority::USER_VISIBLE},
42 SingleThreadTaskRunnerThreadMode::SHARED);
43 LazyCOMSTATaskRunner g_com_sta_task_runner_user_blocking =
44 LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
45 {TaskPriority::USER_BLOCKING},
46 SingleThreadTaskRunnerThreadMode::SHARED);
47 #endif // defined(OS_WIN)
48
InitCheckers(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker)49 void InitCheckers(SequenceCheckerImpl* sequence_checker,
50 ThreadCheckerImpl* thread_checker) {
51 sequence_checker->DetachFromSequence();
52 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
53 thread_checker->DetachFromThread();
54 EXPECT_TRUE(thread_checker->CalledOnValidThread());
55 }
56
ExpectSequencedEnvironment(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker,TaskPriority expected_priority)57 void ExpectSequencedEnvironment(SequenceCheckerImpl* sequence_checker,
58 ThreadCheckerImpl* thread_checker,
59 TaskPriority expected_priority) {
60 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
61 EXPECT_FALSE(thread_checker->CalledOnValidThread());
62 EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread());
63 }
64
ExpectSingleThreadEnvironment(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker,TaskPriority expected_priority,bool expect_com_sta=false)65 void ExpectSingleThreadEnvironment(SequenceCheckerImpl* sequence_checker,
66 ThreadCheckerImpl* thread_checker,
67 TaskPriority expected_priority
68 #if defined(OS_WIN)
69 ,
70 bool expect_com_sta = false
71 #endif
72 ) {
73 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
74 EXPECT_TRUE(thread_checker->CalledOnValidThread());
75 EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread());
76
77 #if defined(OS_WIN)
78 if (expect_com_sta)
79 win::AssertComApartmentType(win::ComApartmentType::STA);
80 #endif
81 }
82
83 class TaskSchedulerLazyTaskRunnerEnvironmentTest : public testing::Test {
84 protected:
85 TaskSchedulerLazyTaskRunnerEnvironmentTest() = default;
86
TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner,bool expect_single_thread,TaskPriority expected_priority,bool expect_com_sta=false)87 void TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner,
88 bool expect_single_thread,
89 TaskPriority expected_priority
90 #if defined(OS_WIN)
91 ,
92 bool expect_com_sta = false
93 #endif
94 ) {
95 SequenceCheckerImpl sequence_checker;
96 ThreadCheckerImpl thread_checker;
97 task_runner->PostTask(FROM_HERE,
98 BindOnce(&InitCheckers, Unretained(&sequence_checker),
99 Unretained(&thread_checker)));
100 scoped_task_environment_.RunUntilIdle();
101
102 OnceClosure task =
103 expect_single_thread
104 ? BindOnce(&ExpectSingleThreadEnvironment,
105 Unretained(&sequence_checker),
106 Unretained(&thread_checker), expected_priority
107 #if defined(OS_WIN)
108 ,
109 expect_com_sta
110 #endif
111 )
112 : BindOnce(&ExpectSequencedEnvironment,
113 Unretained(&sequence_checker),
114 Unretained(&thread_checker), expected_priority);
115 task_runner->PostTask(FROM_HERE, std::move(task));
116 scoped_task_environment_.RunUntilIdle();
117 }
118
119 test::ScopedTaskEnvironment scoped_task_environment_;
120
121 private:
122 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerLazyTaskRunnerEnvironmentTest);
123 };
124
125 } // namespace
126
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazySequencedTaskRunnerUserVisible)127 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
128 LazySequencedTaskRunnerUserVisible) {
129 TestTaskRunnerEnvironment(g_sequenced_task_runner_user_visible.Get(), false,
130 TaskPriority::USER_VISIBLE);
131 }
132
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazySequencedTaskRunnerUserBlocking)133 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
134 LazySequencedTaskRunnerUserBlocking) {
135 TestTaskRunnerEnvironment(g_sequenced_task_runner_user_blocking.Get(), false,
136 TaskPriority::USER_BLOCKING);
137 }
138
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazySingleThreadTaskRunnerUserVisible)139 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
140 LazySingleThreadTaskRunnerUserVisible) {
141 TestTaskRunnerEnvironment(g_single_thread_task_runner_user_visible.Get(),
142 true, TaskPriority::USER_VISIBLE);
143 }
144
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazySingleThreadTaskRunnerUserBlocking)145 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
146 LazySingleThreadTaskRunnerUserBlocking) {
147 TestTaskRunnerEnvironment(g_single_thread_task_runner_user_blocking.Get(),
148 true, TaskPriority::USER_BLOCKING);
149 }
150
151 #if defined(OS_WIN)
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazyCOMSTATaskRunnerUserVisible)152 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
153 LazyCOMSTATaskRunnerUserVisible) {
154 TestTaskRunnerEnvironment(g_com_sta_task_runner_user_visible.Get(), true,
155 TaskPriority::USER_VISIBLE, true);
156 }
157
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazyCOMSTATaskRunnerUserBlocking)158 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
159 LazyCOMSTATaskRunnerUserBlocking) {
160 TestTaskRunnerEnvironment(g_com_sta_task_runner_user_blocking.Get(), true,
161 TaskPriority::USER_BLOCKING, true);
162 }
163 #endif // defined(OS_WIN)
164
TEST(TaskSchdulerLazyTaskRunnerTest,LazySequencedTaskRunnerReset)165 TEST(TaskSchdulerLazyTaskRunnerTest, LazySequencedTaskRunnerReset) {
166 for (int i = 0; i < 2; ++i) {
167 test::ScopedTaskEnvironment scoped_task_environment;
168 // If the TaskRunner isn't released when the test::ScopedTaskEnvironment
169 // goes out of scope, the second invocation of the line below will access a
170 // deleted TaskScheduler and crash.
171 g_sequenced_task_runner_user_visible.Get()->PostTask(FROM_HERE,
172 DoNothing());
173 }
174 }
175
TEST(TaskSchdulerLazyTaskRunnerTest,LazySingleThreadTaskRunnerReset)176 TEST(TaskSchdulerLazyTaskRunnerTest, LazySingleThreadTaskRunnerReset) {
177 for (int i = 0; i < 2; ++i) {
178 test::ScopedTaskEnvironment scoped_task_environment;
179 // If the TaskRunner isn't released when the test::ScopedTaskEnvironment
180 // goes out of scope, the second invocation of the line below will access a
181 // deleted TaskScheduler and crash.
182 g_single_thread_task_runner_user_visible.Get()->PostTask(FROM_HERE,
183 DoNothing());
184 }
185 }
186
187 #if defined(OS_WIN)
TEST(TaskSchdulerLazyTaskRunnerTest,LazyCOMSTATaskRunnerReset)188 TEST(TaskSchdulerLazyTaskRunnerTest, LazyCOMSTATaskRunnerReset) {
189 for (int i = 0; i < 2; ++i) {
190 test::ScopedTaskEnvironment scoped_task_environment;
191 // If the TaskRunner isn't released when the test::ScopedTaskEnvironment
192 // goes out of scope, the second invocation of the line below will access a
193 // deleted TaskScheduler and crash.
194 g_com_sta_task_runner_user_visible.Get()->PostTask(FROM_HERE, DoNothing());
195 }
196 }
197 #endif // defined(OS_WIN)
198
199 } // namespace base
200