cancelable_task_tracker_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // Copyright 2014 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. #include "base/task/cancelable_task_tracker.h"
  5. #include <cstddef>
  6. #include <tuple>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/check_op.h"
  10. #include "base/location.h"
  11. #include "base/memory/ref_counted.h"
  12. #include "base/memory/weak_ptr.h"
  13. #include "base/run_loop.h"
  14. #include "base/task/single_thread_task_runner.h"
  15. #include "base/test/bind.h"
  16. #include "base/test/gtest_util.h"
  17. #include "base/test/task_environment.h"
  18. #include "base/test/test_simple_task_runner.h"
  19. #include "base/threading/thread.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. namespace base {
  22. namespace {
  23. class CancelableTaskTrackerTest : public testing::Test {
  24. protected:
  25. ~CancelableTaskTrackerTest() override { RunLoop().RunUntilIdle(); }
  26. CancelableTaskTracker task_tracker_;
  27. private:
  28. // Needed by CancelableTaskTracker methods.
  29. test::TaskEnvironment task_environment_;
  30. };
  31. } // namespace
  32. // With the task tracker, post a task, a task with a reply, and get a
  33. // new task id without canceling any of them. The tasks and the reply
  34. // should run and the "is canceled" callback should return false.
  35. TEST_F(CancelableTaskTrackerTest, NoCancel) {
  36. Thread worker_thread("worker thread");
  37. ASSERT_TRUE(worker_thread.Start());
  38. std::ignore =
  39. task_tracker_.PostTask(worker_thread.task_runner().get(), FROM_HERE,
  40. MakeExpectedRunClosure(FROM_HERE));
  41. std::ignore = task_tracker_.PostTaskAndReply(
  42. worker_thread.task_runner().get(), FROM_HERE,
  43. MakeExpectedRunClosure(FROM_HERE), MakeExpectedRunClosure(FROM_HERE));
  44. CancelableTaskTracker::IsCanceledCallback is_canceled;
  45. std::ignore = task_tracker_.NewTrackedTaskId(&is_canceled);
  46. worker_thread.Stop();
  47. RunLoop().RunUntilIdle();
  48. EXPECT_FALSE(is_canceled.Run());
  49. }
  50. // Post a task with the task tracker but cancel it before running the
  51. // task runner. The task should not run.
  52. TEST_F(CancelableTaskTrackerTest, CancelPostedTask) {
  53. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  54. new TestSimpleTaskRunner());
  55. CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask(
  56. test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE));
  57. EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
  58. EXPECT_EQ(1U, test_task_runner->NumPendingTasks());
  59. task_tracker_.TryCancel(task_id);
  60. test_task_runner->RunUntilIdle();
  61. }
  62. // Post a task with reply with the task tracker and cancel it before
  63. // running the task runner. Neither the task nor the reply should
  64. // run.
  65. TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) {
  66. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  67. new TestSimpleTaskRunner());
  68. CancelableTaskTracker::TaskId task_id =
  69. task_tracker_.PostTaskAndReply(test_task_runner.get(),
  70. FROM_HERE,
  71. MakeExpectedNotRunClosure(FROM_HERE),
  72. MakeExpectedNotRunClosure(FROM_HERE));
  73. EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
  74. task_tracker_.TryCancel(task_id);
  75. test_task_runner->RunUntilIdle();
  76. }
  77. // Post a task with reply with the task tracker and cancel it after
  78. // running the task runner but before running the current message
  79. // loop. The task should run but the reply should not.
  80. TEST_F(CancelableTaskTrackerTest, CancelReply) {
  81. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  82. new TestSimpleTaskRunner());
  83. CancelableTaskTracker::TaskId task_id =
  84. task_tracker_.PostTaskAndReply(test_task_runner.get(),
  85. FROM_HERE,
  86. MakeExpectedRunClosure(FROM_HERE),
  87. MakeExpectedNotRunClosure(FROM_HERE));
  88. EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
  89. test_task_runner->RunUntilIdle();
  90. task_tracker_.TryCancel(task_id);
  91. }
  92. // Post a task with reply with the task tracker on a worker thread and
  93. // cancel it before running the current message loop. The task should
  94. // run but the reply should not.
  95. TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
  96. Thread worker_thread("worker thread");
  97. ASSERT_TRUE(worker_thread.Start());
  98. CancelableTaskTracker::TaskId task_id = task_tracker_.PostTaskAndReply(
  99. worker_thread.task_runner().get(), FROM_HERE, DoNothing(),
  100. MakeExpectedNotRunClosure(FROM_HERE));
  101. EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
  102. task_tracker_.TryCancel(task_id);
  103. worker_thread.Stop();
  104. }
  105. void ExpectIsCanceled(
  106. const CancelableTaskTracker::IsCanceledCallback& is_canceled,
  107. bool expected_is_canceled) {
  108. EXPECT_EQ(expected_is_canceled, is_canceled.Run());
  109. }
  110. // Create a new task ID and check its status on a separate thread
  111. // before and after canceling. The is-canceled callback should be
  112. // thread-safe (i.e., nothing should blow up).
  113. TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
  114. CancelableTaskTracker::IsCanceledCallback is_canceled;
  115. CancelableTaskTracker::TaskId task_id =
  116. task_tracker_.NewTrackedTaskId(&is_canceled);
  117. EXPECT_FALSE(is_canceled.Run());
  118. Thread other_thread("other thread");
  119. ASSERT_TRUE(other_thread.Start());
  120. other_thread.task_runner()->PostTask(
  121. FROM_HERE, BindOnce(&ExpectIsCanceled, is_canceled, false));
  122. other_thread.Stop();
  123. task_tracker_.TryCancel(task_id);
  124. ASSERT_TRUE(other_thread.Start());
  125. other_thread.task_runner()->PostTask(
  126. FROM_HERE, BindOnce(&ExpectIsCanceled, is_canceled, true));
  127. other_thread.Stop();
  128. }
  129. // With the task tracker, post a task, a task with a reply, get a new
  130. // task id, and then cancel all of them. None of the tasks nor the
  131. // reply should run and the "is canceled" callback should return
  132. // true.
  133. TEST_F(CancelableTaskTrackerTest, CancelAll) {
  134. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  135. new TestSimpleTaskRunner());
  136. std::ignore = task_tracker_.PostTask(test_task_runner.get(), FROM_HERE,
  137. MakeExpectedNotRunClosure(FROM_HERE));
  138. std::ignore = task_tracker_.PostTaskAndReply(
  139. test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE),
  140. MakeExpectedNotRunClosure(FROM_HERE));
  141. CancelableTaskTracker::IsCanceledCallback is_canceled;
  142. std::ignore = task_tracker_.NewTrackedTaskId(&is_canceled);
  143. task_tracker_.TryCancelAll();
  144. test_task_runner->RunUntilIdle();
  145. RunLoop().RunUntilIdle();
  146. EXPECT_TRUE(is_canceled.Run());
  147. }
  148. // With the task tracker, post a task, a task with a reply, get a new
  149. // task id, and then cancel all of them. None of the tasks nor the
  150. // reply should run and the "is canceled" callback should return
  151. // true.
  152. TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) {
  153. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  154. new TestSimpleTaskRunner());
  155. CancelableTaskTracker::IsCanceledCallback is_canceled;
  156. {
  157. // Create another task tracker with a smaller scope.
  158. CancelableTaskTracker task_tracker;
  159. std::ignore = task_tracker.PostTask(test_task_runner.get(), FROM_HERE,
  160. MakeExpectedNotRunClosure(FROM_HERE));
  161. std::ignore = task_tracker.PostTaskAndReply(
  162. test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE),
  163. MakeExpectedNotRunClosure(FROM_HERE));
  164. std::ignore = task_tracker_.NewTrackedTaskId(&is_canceled);
  165. }
  166. test_task_runner->RunUntilIdle();
  167. RunLoop().RunUntilIdle();
  168. EXPECT_FALSE(is_canceled.Run());
  169. }
  170. // Post a task and cancel it. HasTrackedTasks() should return false as soon as
  171. // TryCancel() returns, otherwise we may have leaked per-task state.
  172. TEST_F(CancelableTaskTrackerTest, HasTrackedTasksCancelById) {
  173. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  174. new TestSimpleTaskRunner());
  175. EXPECT_FALSE(task_tracker_.HasTrackedTasks());
  176. CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask(
  177. test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE));
  178. EXPECT_TRUE(task_tracker_.HasTrackedTasks());
  179. task_tracker_.TryCancel(task_id);
  180. EXPECT_FALSE(task_tracker_.HasTrackedTasks());
  181. test_task_runner->RunUntilIdle();
  182. RunLoop().RunUntilIdle();
  183. }
  184. // Post a task and then cancel all tasks. HasTrackedTasks() should return false
  185. // as soon as TryCancelAll() is called.
  186. TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPostCancelAll) {
  187. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  188. new TestSimpleTaskRunner());
  189. EXPECT_FALSE(task_tracker_.HasTrackedTasks());
  190. std::ignore = task_tracker_.PostTask(test_task_runner.get(), FROM_HERE,
  191. MakeExpectedNotRunClosure(FROM_HERE));
  192. task_tracker_.TryCancelAll();
  193. EXPECT_FALSE(task_tracker_.HasTrackedTasks());
  194. test_task_runner->RunUntilIdle();
  195. RunLoop().RunUntilIdle();
  196. }
  197. // Post a task with a reply and cancel it. HasTrackedTasks() should return false
  198. // as soon as TryCancelAll() is called.
  199. TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPostWithReplyCancelAll) {
  200. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  201. new TestSimpleTaskRunner());
  202. EXPECT_FALSE(task_tracker_.HasTrackedTasks());
  203. std::ignore = task_tracker_.PostTaskAndReply(
  204. test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE),
  205. MakeExpectedNotRunClosure(FROM_HERE));
  206. task_tracker_.TryCancelAll();
  207. EXPECT_FALSE(task_tracker_.HasTrackedTasks());
  208. test_task_runner->RunUntilIdle();
  209. RunLoop().RunUntilIdle();
  210. }
  211. // Create a new tracked task ID. HasTrackedTasks() should return false as soon
  212. // as TryCancelAll() is called.
  213. TEST_F(CancelableTaskTrackerTest, HasTrackedTasksIsCancelledCancelAll) {
  214. EXPECT_FALSE(task_tracker_.HasTrackedTasks());
  215. CancelableTaskTracker::IsCanceledCallback is_canceled;
  216. std::ignore = task_tracker_.NewTrackedTaskId(&is_canceled);
  217. task_tracker_.TryCancelAll();
  218. EXPECT_FALSE(task_tracker_.HasTrackedTasks());
  219. }
  220. // The death tests below make sure that calling task tracker member
  221. // functions from a thread different from its owner thread DCHECKs in
  222. // debug mode.
  223. class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
  224. protected:
  225. CancelableTaskTrackerDeathTest() {
  226. // The default style "fast" does not support multi-threaded tests.
  227. ::testing::FLAGS_gtest_death_test_style = "threadsafe";
  228. }
  229. };
  230. // Runs |fn| with |task_tracker|, expecting it to crash in debug mode.
  231. void MaybeRunDeadlyTaskTrackerMemberFunction(
  232. CancelableTaskTracker* task_tracker,
  233. OnceCallback<void(CancelableTaskTracker*)> fn) {
  234. EXPECT_DCHECK_DEATH(std::move(fn).Run(task_tracker));
  235. }
  236. void PostDoNothingTask(CancelableTaskTracker* task_tracker) {
  237. std::ignore = task_tracker->PostTask(
  238. scoped_refptr<TestSimpleTaskRunner>(new TestSimpleTaskRunner()).get(),
  239. FROM_HERE, DoNothing());
  240. }
  241. TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
  242. Thread bad_thread("bad thread");
  243. ASSERT_TRUE(bad_thread.Start());
  244. bad_thread.task_runner()->PostTask(
  245. FROM_HERE,
  246. BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction,
  247. Unretained(&task_tracker_), BindOnce(&PostDoNothingTask)));
  248. }
  249. void TryCancel(CancelableTaskTracker::TaskId task_id,
  250. CancelableTaskTracker* task_tracker) {
  251. task_tracker->TryCancel(task_id);
  252. }
  253. TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
  254. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  255. new TestSimpleTaskRunner());
  256. Thread bad_thread("bad thread");
  257. ASSERT_TRUE(bad_thread.Start());
  258. CancelableTaskTracker::TaskId task_id =
  259. task_tracker_.PostTask(test_task_runner.get(), FROM_HERE, DoNothing());
  260. EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
  261. bad_thread.task_runner()->PostTask(
  262. FROM_HERE,
  263. BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction,
  264. Unretained(&task_tracker_), BindOnce(&TryCancel, task_id)));
  265. test_task_runner->RunUntilIdle();
  266. }
  267. TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
  268. scoped_refptr<TestSimpleTaskRunner> test_task_runner(
  269. new TestSimpleTaskRunner());
  270. Thread bad_thread("bad thread");
  271. ASSERT_TRUE(bad_thread.Start());
  272. CancelableTaskTracker::TaskId task_id =
  273. task_tracker_.PostTask(test_task_runner.get(), FROM_HERE, DoNothing());
  274. EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
  275. bad_thread.task_runner()->PostTask(
  276. FROM_HERE, BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction,
  277. Unretained(&task_tracker_),
  278. BindOnce(&CancelableTaskTracker::TryCancelAll)));
  279. test_task_runner->RunUntilIdle();
  280. }
  281. } // namespace base