1 // Copyright 2019 The Chromium Authors
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/sequence_manager/task_queue.h"
6
7 #include "base/message_loop/message_pump.h"
8 #include "base/message_loop/message_pump_type.h"
9 #include "base/task/sequence_manager/sequence_manager.h"
10 #include "base/task/sequence_manager/test/sequence_manager_for_test.h"
11 #include "base/task/single_thread_task_runner.h"
12 #include "base/task/task_features.h"
13 #include "base/test/bind.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace base {
18 namespace sequence_manager {
19 namespace internal {
20 // To avoid symbol collisions in jumbo builds.
21 namespace task_queue_unittest {
22 namespace {
23
TEST(TaskQueueTest,TaskQueueVoters)24 TEST(TaskQueueTest, TaskQueueVoters) {
25 auto sequence_manager = CreateSequenceManagerOnCurrentThreadWithPump(
26 MessagePump::Create(MessagePumpType::DEFAULT));
27
28 auto queue =
29 sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ));
30
31 // The task queue should be initially enabled.
32 EXPECT_TRUE(queue->IsQueueEnabled());
33
34 std::unique_ptr<TaskQueue::QueueEnabledVoter> voter1 =
35 queue->CreateQueueEnabledVoter();
36 std::unique_ptr<TaskQueue::QueueEnabledVoter> voter2 =
37 queue->CreateQueueEnabledVoter();
38 std::unique_ptr<TaskQueue::QueueEnabledVoter> voter3 =
39 queue->CreateQueueEnabledVoter();
40 std::unique_ptr<TaskQueue::QueueEnabledVoter> voter4 =
41 queue->CreateQueueEnabledVoter();
42
43 // Voters should initially vote for the queue to be enabled.
44 EXPECT_TRUE(queue->IsQueueEnabled());
45
46 // If any voter wants to disable, the queue is disabled.
47 voter1->SetVoteToEnable(false);
48 EXPECT_FALSE(queue->IsQueueEnabled());
49
50 // If the voter is deleted then the queue should be re-enabled.
51 voter1.reset();
52 EXPECT_TRUE(queue->IsQueueEnabled());
53
54 // If any of the remaining voters wants to disable, the queue should be
55 // disabled.
56 voter2->SetVoteToEnable(false);
57 EXPECT_FALSE(queue->IsQueueEnabled());
58
59 // If another queue votes to disable, nothing happens because it's already
60 // disabled.
61 voter3->SetVoteToEnable(false);
62 EXPECT_FALSE(queue->IsQueueEnabled());
63
64 // There are two votes to disable, so one of them voting to enable does
65 // nothing.
66 voter2->SetVoteToEnable(true);
67 EXPECT_FALSE(queue->IsQueueEnabled());
68
69 // IF all queues vote to enable then the queue is enabled.
70 voter3->SetVoteToEnable(true);
71 EXPECT_TRUE(queue->IsQueueEnabled());
72 }
73
TEST(TaskQueueTest,ShutdownQueueBeforeEnabledVoterDeleted)74 TEST(TaskQueueTest, ShutdownQueueBeforeEnabledVoterDeleted) {
75 auto sequence_manager = CreateSequenceManagerOnCurrentThreadWithPump(
76 MessagePump::Create(MessagePumpType::DEFAULT));
77 auto queue =
78 sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ));
79
80 std::unique_ptr<TaskQueue::QueueEnabledVoter> voter =
81 queue->CreateQueueEnabledVoter();
82
83 voter->SetVoteToEnable(true); // NOP
84 queue.reset();
85
86 // This should complete without DCHECKing.
87 voter.reset();
88 }
89
TEST(TaskQueueTest,ShutdownQueueBeforeDisabledVoterDeleted)90 TEST(TaskQueueTest, ShutdownQueueBeforeDisabledVoterDeleted) {
91 auto sequence_manager = CreateSequenceManagerOnCurrentThreadWithPump(
92 MessagePump::Create(MessagePumpType::DEFAULT));
93 auto queue =
94 sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ));
95
96 std::unique_ptr<TaskQueue::QueueEnabledVoter> voter =
97 queue->CreateQueueEnabledVoter();
98
99 voter->SetVoteToEnable(false);
100 queue.reset();
101
102 // This should complete without DCHECKing.
103 voter.reset();
104 }
105
TEST(TaskQueueTest,CanceledTaskRemoved)106 TEST(TaskQueueTest, CanceledTaskRemoved) {
107 auto sequence_manager = CreateSequenceManagerOnCurrentThreadWithPump(
108 MessagePump::Create(MessagePumpType::DEFAULT));
109 auto queue =
110 sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ));
111
112 // Get the default task runner.
113 auto task_runner = queue->task_runner();
114 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 0u);
115
116 bool task_ran = false;
117 DelayedTaskHandle delayed_task_handle =
118 task_runner->PostCancelableDelayedTask(
119 subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE,
120 BindLambdaForTesting([&task_ran] { task_ran = true; }), Seconds(20));
121 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 1u);
122
123 // The task is only removed from the queue if the feature is enabled.
124 delayed_task_handle.CancelTask();
125 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 0u);
126
127 // In any case, the task never actually ran.
128 EXPECT_FALSE(task_ran);
129 }
130
131 // Tests that a task posted through `PostCancelableDelayedTask()` is not
132 // considered canceled once it has reached the |delayed_work_queue| and is
133 // therefore not removed.
134 //
135 // This is a regression test for a bug in `Task::IsCanceled()` (see
136 // https://crbug.com/1288882). Note that this function is only called on tasks
137 // inside the |delayed_work_queue|, and not for tasks in the
138 // |delayed_incoming_queue|. This is because a task posted through
139 // `PostCancelableDelayedTask()` is always valid while it is in the
140 // |delayed_incoming_queue|, since canceling it would remove it from the queue.
TEST(TaskQueueTest,ValidCancelableTaskIsNotCanceled)141 TEST(TaskQueueTest, ValidCancelableTaskIsNotCanceled) {
142 auto sequence_manager = CreateSequenceManagerOnCurrentThreadWithPump(
143 MessagePump::Create(MessagePumpType::DEFAULT));
144 auto queue =
145 sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ));
146
147 // Get the default task runner.
148 auto task_runner = queue->task_runner();
149 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 0u);
150
151 // RunLoop requires the SingleThreadTaskRunner::CurrentDefaultHandle to be
152 // set.
153 SingleThreadTaskRunner::CurrentDefaultHandle
154 single_thread_task_runner_current_default_handle(task_runner);
155 RunLoop run_loop;
156
157 // To reach the |delayed_work_queue|, the task must be posted with a non-
158 // zero delay, which is then moved to the |delayed_work_queue| when it is
159 // ripe. To achieve this, run the RunLoop for exactly the same delay of the
160 // cancelable task. Since real time waiting happens, chose a very small delay.
161 constexpr TimeDelta kTestDelay = Microseconds(1);
162 task_runner->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), kTestDelay);
163
164 DelayedTaskHandle delayed_task_handle =
165 task_runner->PostCancelableDelayedTask(
166 subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE, DoNothing(),
167 kTestDelay);
168 run_loop.Run();
169
170 // Now only the cancelable delayed task remains and it is ripe.
171 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 1u);
172
173 // ReclaimMemory doesn't remove the task because it is valid (not canceled).
174 sequence_manager->ReclaimMemory();
175 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 1u);
176
177 // Clean-up.
178 delayed_task_handle.CancelTask();
179 }
180
181 } // namespace
182 } // namespace task_queue_unittest
183 } // namespace internal
184 } // namespace sequence_manager
185 } // namespace base
186