1 // Copyright 2016 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 "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
6
7 #include "base/memory/weak_ptr.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h"
10 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
11 #include "third_party/blink/renderer/platform/wtf/functional.h"
12
13 namespace blink {
14 namespace {
15
Increment(int * x)16 void Increment(int* x) {
17 ++*x;
18 }
19
GetIsActive(bool * is_active,TaskHandle * handle)20 void GetIsActive(bool* is_active, TaskHandle* handle) {
21 *is_active = handle->IsActive();
22 }
23
24 class CancellationTestHelper {
25 DISALLOW_NEW();
26
27 public:
CancellationTestHelper()28 CancellationTestHelper() {}
29
GetWeakPtr()30 base::WeakPtr<CancellationTestHelper> GetWeakPtr() {
31 return weak_ptr_factory_.GetWeakPtr();
32 }
33
RevokeWeakPtrs()34 void RevokeWeakPtrs() { weak_ptr_factory_.InvalidateWeakPtrs(); }
IncrementCounter()35 void IncrementCounter() { ++counter_; }
Counter() const36 int Counter() const { return counter_; }
37
38 private:
39 int counter_ = 0;
40 base::WeakPtrFactory<CancellationTestHelper> weak_ptr_factory_{this};
41 };
42
43 } // namespace
44
TEST(WebTaskRunnerTest,PostCancellableTaskTest)45 TEST(WebTaskRunnerTest, PostCancellableTaskTest) {
46 scoped_refptr<scheduler::FakeTaskRunner> task_runner =
47 base::MakeRefCounted<scheduler::FakeTaskRunner>();
48
49 // Run without cancellation.
50 int count = 0;
51 TaskHandle handle = PostCancellableTask(
52 *task_runner, FROM_HERE, WTF::Bind(&Increment, WTF::Unretained(&count)));
53 EXPECT_EQ(0, count);
54 EXPECT_TRUE(handle.IsActive());
55 task_runner->RunUntilIdle();
56 EXPECT_EQ(1, count);
57 EXPECT_FALSE(handle.IsActive());
58
59 count = 0;
60 handle = PostDelayedCancellableTask(
61 *task_runner, FROM_HERE, WTF::Bind(&Increment, WTF::Unretained(&count)),
62 base::TimeDelta::FromMilliseconds(1));
63 EXPECT_EQ(0, count);
64 EXPECT_TRUE(handle.IsActive());
65 task_runner->RunUntilIdle();
66 EXPECT_EQ(1, count);
67 EXPECT_FALSE(handle.IsActive());
68
69 count = 0;
70 handle = PostNonNestableCancellableTask(
71 *task_runner, FROM_HERE, WTF::Bind(&Increment, WTF::Unretained(&count)));
72 EXPECT_EQ(0, count);
73 EXPECT_TRUE(handle.IsActive());
74 task_runner->RunUntilIdle();
75 EXPECT_EQ(1, count);
76 EXPECT_FALSE(handle.IsActive());
77
78 count = 0;
79 handle = PostNonNestableDelayedCancellableTask(
80 *task_runner, FROM_HERE, WTF::Bind(&Increment, WTF::Unretained(&count)),
81 base::TimeDelta::FromMilliseconds(1));
82 EXPECT_EQ(0, count);
83 EXPECT_TRUE(handle.IsActive());
84 task_runner->RunUntilIdle();
85 EXPECT_EQ(1, count);
86 EXPECT_FALSE(handle.IsActive());
87
88 // Cancel a task.
89 count = 0;
90 handle = PostCancellableTask(*task_runner, FROM_HERE,
91 WTF::Bind(&Increment, WTF::Unretained(&count)));
92 handle.Cancel();
93 EXPECT_EQ(0, count);
94 EXPECT_FALSE(handle.IsActive());
95 task_runner->RunUntilIdle();
96 EXPECT_EQ(0, count);
97
98 count = 0;
99 handle = PostDelayedCancellableTask(
100 *task_runner, FROM_HERE, WTF::Bind(&Increment, WTF::Unretained(&count)),
101 base::TimeDelta::FromMilliseconds(1));
102 handle.Cancel();
103 EXPECT_EQ(0, count);
104 EXPECT_FALSE(handle.IsActive());
105 task_runner->RunUntilIdle();
106 EXPECT_EQ(0, count);
107
108 count = 0;
109 handle = PostNonNestableCancellableTask(
110 *task_runner, FROM_HERE, WTF::Bind(&Increment, WTF::Unretained(&count)));
111 handle.Cancel();
112 EXPECT_EQ(0, count);
113 EXPECT_FALSE(handle.IsActive());
114 task_runner->RunUntilIdle();
115 EXPECT_EQ(0, count);
116
117 count = 0;
118 handle = PostNonNestableDelayedCancellableTask(
119 *task_runner, FROM_HERE, WTF::Bind(&Increment, WTF::Unretained(&count)),
120 base::TimeDelta::FromMilliseconds(1));
121 handle.Cancel();
122 EXPECT_EQ(0, count);
123 EXPECT_FALSE(handle.IsActive());
124 task_runner->RunUntilIdle();
125 EXPECT_EQ(0, count);
126
127 // The task should be cancelled when the handle is dropped.
128 {
129 count = 0;
130 TaskHandle handle2 =
131 PostCancellableTask(*task_runner, FROM_HERE,
132 WTF::Bind(&Increment, WTF::Unretained(&count)));
133 EXPECT_TRUE(handle2.IsActive());
134 }
135 EXPECT_EQ(0, count);
136 task_runner->RunUntilIdle();
137 EXPECT_EQ(0, count);
138
139 // The task should be cancelled when another TaskHandle is assigned on it.
140 count = 0;
141 handle = PostCancellableTask(*task_runner, FROM_HERE,
142 WTF::Bind(&Increment, WTF::Unretained(&count)));
143 handle = PostCancellableTask(*task_runner, FROM_HERE, WTF::Bind([] {}));
144 EXPECT_EQ(0, count);
145 task_runner->RunUntilIdle();
146 EXPECT_EQ(0, count);
147
148 // Self assign should be nop.
149 count = 0;
150 handle = PostCancellableTask(*task_runner, FROM_HERE,
151 WTF::Bind(&Increment, WTF::Unretained(&count)));
152 #if defined(__clang__)
153 #pragma GCC diagnostic push
154 #pragma GCC diagnostic ignored "-Wself-move"
155 handle = std::move(handle);
156 #pragma GCC diagnostic pop
157 #else
158 handle = std::move(handle);
159 #endif // defined(__clang__)
160 EXPECT_EQ(0, count);
161 task_runner->RunUntilIdle();
162 EXPECT_EQ(1, count);
163
164 // handle->isActive() should switch to false before the task starts running.
165 bool is_active = false;
166 handle =
167 PostCancellableTask(*task_runner, FROM_HERE,
168 WTF::Bind(&GetIsActive, WTF::Unretained(&is_active),
169 WTF::Unretained(&handle)));
170 EXPECT_TRUE(handle.IsActive());
171 task_runner->RunUntilIdle();
172 EXPECT_FALSE(is_active);
173 EXPECT_FALSE(handle.IsActive());
174 }
175
TEST(WebTaskRunnerTest,CancellationCheckerTest)176 TEST(WebTaskRunnerTest, CancellationCheckerTest) {
177 scoped_refptr<scheduler::FakeTaskRunner> task_runner =
178 base::MakeRefCounted<scheduler::FakeTaskRunner>();
179
180 int count = 0;
181 TaskHandle handle = PostCancellableTask(
182 *task_runner, FROM_HERE, WTF::Bind(&Increment, WTF::Unretained(&count)));
183 EXPECT_EQ(0, count);
184
185 // TaskHandle::isActive should detect the deletion of posted task.
186 auto queue = task_runner->TakePendingTasksForTesting();
187 ASSERT_EQ(1u, queue.size());
188 EXPECT_FALSE(queue[0].first.IsCancelled());
189 EXPECT_TRUE(handle.IsActive());
190 queue.clear();
191 EXPECT_FALSE(handle.IsActive());
192 EXPECT_EQ(0, count);
193
194 count = 0;
195 CancellationTestHelper helper;
196 handle =
197 PostCancellableTask(*task_runner, FROM_HERE,
198 WTF::Bind(&CancellationTestHelper::IncrementCounter,
199 helper.GetWeakPtr()));
200 EXPECT_EQ(0, helper.Counter());
201
202 // The cancellation of the posted task should be propagated to TaskHandle.
203 queue = task_runner->TakePendingTasksForTesting();
204 ASSERT_EQ(1u, queue.size());
205 EXPECT_FALSE(queue[0].first.IsCancelled());
206 EXPECT_TRUE(handle.IsActive());
207 helper.RevokeWeakPtrs();
208 EXPECT_TRUE(queue[0].first.IsCancelled());
209 EXPECT_FALSE(handle.IsActive());
210 }
211
212 } // namespace blink
213