• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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