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; }),
121 Seconds(20));
122 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 1u);
123
124 // The task is only removed from the queue if the feature is enabled.
125 delayed_task_handle.CancelTask();
126 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 0u);
127
128 // In any case, the task never actually ran.
129 EXPECT_FALSE(task_ran);
130 }
131
132 // Tests that a task posted through `PostCancelableDelayedTask()` is not
133 // considered canceled once it has reached the |delayed_work_queue| and is
134 // therefore not removed.
135 //
136 // This is a regression test for a bug in `Task::IsCanceled()` (see
137 // https://crbug.com/1288882). Note that this function is only called on tasks
138 // inside the |delayed_work_queue|, and not for tasks in the
139 // |delayed_incoming_queue|. This is because a task posted through
140 // `PostCancelableDelayedTask()` is always valid while it is in the
141 // |delayed_incoming_queue|, since canceling it would remove it from the queue.
TEST(TaskQueueTest,ValidCancelableTaskIsNotCanceled)142 TEST(TaskQueueTest, ValidCancelableTaskIsNotCanceled) {
143 auto sequence_manager = CreateSequenceManagerOnCurrentThreadWithPump(
144 MessagePump::Create(MessagePumpType::DEFAULT));
145 auto queue =
146 sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ));
147
148 // Get the default task runner.
149 auto task_runner = queue->task_runner();
150 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 0u);
151
152 // RunLoop requires the SingleThreadTaskRunner::CurrentDefaultHandle to be
153 // set.
154 SingleThreadTaskRunner::CurrentDefaultHandle
155 single_thread_task_runner_current_default_handle(task_runner);
156 RunLoop run_loop;
157
158 // To reach the |delayed_work_queue|, the task must be posted with a non-
159 // zero delay, which is then moved to the |delayed_work_queue| when it is
160 // ripe. To achieve this, run the RunLoop for exactly the same delay of the
161 // cancelable task. Since real time waiting happens, chose a very small delay.
162 constexpr TimeDelta kTestDelay = Microseconds(1);
163 task_runner->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), kTestDelay);
164
165 DelayedTaskHandle delayed_task_handle =
166 task_runner->PostCancelableDelayedTask(
167 subtle::PostDelayedTaskPassKeyForTesting(), FROM_HERE, DoNothing(),
168 kTestDelay);
169 run_loop.Run();
170
171 // Now only the cancelable delayed task remains and it is ripe.
172 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 1u);
173
174 // ReclaimMemory doesn't remove the task because it is valid (not canceled).
175 sequence_manager->ReclaimMemory();
176 EXPECT_EQ(queue->GetNumberOfPendingTasks(), 1u);
177
178 // Clean-up.
179 delayed_task_handle.CancelTask();
180 }
181
182 } // namespace
183 } // namespace task_queue_unittest
184 } // namespace internal
185 } // namespace sequence_manager
186 } // namespace base
187