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