post_task_and_reply_impl_unittest.cc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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. #include "base/threading/post_task_and_reply_impl.h"
  5. #include <utility>
  6. #include "base/auto_reset.h"
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/memory/ref_counted.h"
  11. #include "base/test/test_mock_time_task_runner.h"
  12. #include "base/threading/sequenced_task_runner_handle.h"
  13. #include "testing/gmock/include/gmock/gmock.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. using ::testing::_;
  16. namespace base {
  17. namespace internal {
  18. namespace {
  19. class PostTaskAndReplyTaskRunner : public internal::PostTaskAndReplyImpl {
  20. public:
  21. explicit PostTaskAndReplyTaskRunner(TaskRunner* destination)
  22. : destination_(destination) {}
  23. private:
  24. bool PostTask(const Location& from_here, OnceClosure task) override {
  25. return destination_->PostTask(from_here, std::move(task));
  26. }
  27. // Non-owning.
  28. const raw_ptr<TaskRunner> destination_;
  29. };
  30. class ObjectToDelete : public RefCounted<ObjectToDelete> {
  31. public:
  32. // |delete_flag| is set to true when this object is deleted
  33. ObjectToDelete(bool* delete_flag) : delete_flag_(delete_flag) {
  34. EXPECT_FALSE(*delete_flag_);
  35. }
  36. ObjectToDelete(const ObjectToDelete&) = delete;
  37. ObjectToDelete& operator=(const ObjectToDelete&) = delete;
  38. private:
  39. friend class RefCounted<ObjectToDelete>;
  40. ~ObjectToDelete() { *delete_flag_ = true; }
  41. const raw_ptr<bool> delete_flag_;
  42. };
  43. class MockObject {
  44. public:
  45. MockObject() = default;
  46. MockObject(const MockObject&) = delete;
  47. MockObject& operator=(const MockObject&) = delete;
  48. MOCK_METHOD1(Task, void(scoped_refptr<ObjectToDelete>));
  49. MOCK_METHOD1(Reply, void(scoped_refptr<ObjectToDelete>));
  50. };
  51. class MockRunsTasksInCurrentSequenceTaskRunner : public TestMockTimeTaskRunner {
  52. public:
  53. MockRunsTasksInCurrentSequenceTaskRunner(
  54. TestMockTimeTaskRunner::Type type =
  55. TestMockTimeTaskRunner::Type::kStandalone)
  56. : TestMockTimeTaskRunner(type) {}
  57. MockRunsTasksInCurrentSequenceTaskRunner(
  58. const MockRunsTasksInCurrentSequenceTaskRunner&) = delete;
  59. MockRunsTasksInCurrentSequenceTaskRunner& operator=(
  60. const MockRunsTasksInCurrentSequenceTaskRunner&) = delete;
  61. void StopAcceptingTasks() { accepts_tasks_ = false; }
  62. void RunUntilIdleWithRunsTasksInCurrentSequence() {
  63. AutoReset<bool> reset(&runs_tasks_in_current_sequence_, true);
  64. RunUntilIdle();
  65. }
  66. void ClearPendingTasksWithRunsTasksInCurrentSequence() {
  67. AutoReset<bool> reset(&runs_tasks_in_current_sequence_, true);
  68. ClearPendingTasks();
  69. }
  70. // TestMockTimeTaskRunner:
  71. bool RunsTasksInCurrentSequence() const override {
  72. return runs_tasks_in_current_sequence_;
  73. }
  74. bool PostDelayedTask(const Location& from_here,
  75. OnceClosure task,
  76. TimeDelta delay) override {
  77. if (!accepts_tasks_)
  78. return false;
  79. return TestMockTimeTaskRunner::PostDelayedTask(from_here, std::move(task),
  80. delay);
  81. }
  82. private:
  83. ~MockRunsTasksInCurrentSequenceTaskRunner() override = default;
  84. bool accepts_tasks_ = true;
  85. bool runs_tasks_in_current_sequence_ = false;
  86. };
  87. class PostTaskAndReplyImplTest : public testing::Test {
  88. public:
  89. PostTaskAndReplyImplTest(const PostTaskAndReplyImplTest&) = delete;
  90. PostTaskAndReplyImplTest& operator=(const PostTaskAndReplyImplTest&) = delete;
  91. protected:
  92. PostTaskAndReplyImplTest() = default;
  93. bool PostTaskAndReplyToMockObject() {
  94. return PostTaskAndReplyTaskRunner(post_runner_.get())
  95. .PostTaskAndReply(
  96. FROM_HERE,
  97. BindOnce(&MockObject::Task, Unretained(&mock_object_),
  98. MakeRefCounted<ObjectToDelete>(&delete_task_flag_)),
  99. BindOnce(&MockObject::Reply, Unretained(&mock_object_),
  100. MakeRefCounted<ObjectToDelete>(&delete_reply_flag_)));
  101. }
  102. void ExpectPostTaskAndReplyToMockObjectSucceeds() {
  103. // Expect the post to succeed.
  104. EXPECT_TRUE(PostTaskAndReplyToMockObject());
  105. // Expect the first task to be posted to |post_runner_|.
  106. EXPECT_TRUE(post_runner_->HasPendingTask());
  107. EXPECT_FALSE(reply_runner_->HasPendingTask());
  108. EXPECT_FALSE(delete_task_flag_);
  109. EXPECT_FALSE(delete_reply_flag_);
  110. }
  111. scoped_refptr<MockRunsTasksInCurrentSequenceTaskRunner> post_runner_ =
  112. MakeRefCounted<MockRunsTasksInCurrentSequenceTaskRunner>();
  113. scoped_refptr<MockRunsTasksInCurrentSequenceTaskRunner> reply_runner_ =
  114. MakeRefCounted<MockRunsTasksInCurrentSequenceTaskRunner>(
  115. TestMockTimeTaskRunner::Type::kBoundToThread);
  116. testing::StrictMock<MockObject> mock_object_;
  117. bool delete_task_flag_ = false;
  118. bool delete_reply_flag_ = false;
  119. };
  120. } // namespace
  121. TEST_F(PostTaskAndReplyImplTest, PostTaskAndReply) {
  122. ExpectPostTaskAndReplyToMockObjectSucceeds();
  123. EXPECT_CALL(mock_object_, Task(_));
  124. post_runner_->RunUntilIdleWithRunsTasksInCurrentSequence();
  125. testing::Mock::VerifyAndClear(&mock_object_);
  126. // The task should have been deleted right after being run.
  127. EXPECT_TRUE(delete_task_flag_);
  128. EXPECT_FALSE(delete_reply_flag_);
  129. // Expect the reply to be posted to |reply_runner_|.
  130. EXPECT_FALSE(post_runner_->HasPendingTask());
  131. EXPECT_TRUE(reply_runner_->HasPendingTask());
  132. EXPECT_CALL(mock_object_, Reply(_));
  133. reply_runner_->RunUntilIdleWithRunsTasksInCurrentSequence();
  134. testing::Mock::VerifyAndClear(&mock_object_);
  135. EXPECT_TRUE(delete_task_flag_);
  136. // The reply should have been deleted right after being run.
  137. EXPECT_TRUE(delete_reply_flag_);
  138. // Expect no pending task in |post_runner_| and |reply_runner_|.
  139. EXPECT_FALSE(post_runner_->HasPendingTask());
  140. EXPECT_FALSE(reply_runner_->HasPendingTask());
  141. }
  142. TEST_F(PostTaskAndReplyImplTest, TaskDoesNotRun) {
  143. ExpectPostTaskAndReplyToMockObjectSucceeds();
  144. // Clear the |post_runner_|. Both callbacks should be scheduled for deletion
  145. // on the |reply_runner_|.
  146. post_runner_->ClearPendingTasksWithRunsTasksInCurrentSequence();
  147. EXPECT_FALSE(post_runner_->HasPendingTask());
  148. EXPECT_TRUE(reply_runner_->HasPendingTask());
  149. EXPECT_FALSE(delete_task_flag_);
  150. EXPECT_FALSE(delete_reply_flag_);
  151. // Run the |reply_runner_|. Both callbacks should be deleted.
  152. reply_runner_->RunUntilIdleWithRunsTasksInCurrentSequence();
  153. EXPECT_TRUE(delete_task_flag_);
  154. EXPECT_TRUE(delete_reply_flag_);
  155. }
  156. TEST_F(PostTaskAndReplyImplTest, ReplyDoesNotRun) {
  157. ExpectPostTaskAndReplyToMockObjectSucceeds();
  158. EXPECT_CALL(mock_object_, Task(_));
  159. post_runner_->RunUntilIdleWithRunsTasksInCurrentSequence();
  160. testing::Mock::VerifyAndClear(&mock_object_);
  161. // The task should have been deleted right after being run.
  162. EXPECT_TRUE(delete_task_flag_);
  163. EXPECT_FALSE(delete_reply_flag_);
  164. // Expect the reply to be posted to |reply_runner_|.
  165. EXPECT_FALSE(post_runner_->HasPendingTask());
  166. EXPECT_TRUE(reply_runner_->HasPendingTask());
  167. // Clear the |reply_runner_| queue without running tasks. The reply callback
  168. // should be deleted.
  169. reply_runner_->ClearPendingTasksWithRunsTasksInCurrentSequence();
  170. EXPECT_TRUE(delete_task_flag_);
  171. EXPECT_TRUE(delete_reply_flag_);
  172. }
  173. // This is a regression test for crbug.com/922938.
  174. TEST_F(PostTaskAndReplyImplTest,
  175. PostTaskToStoppedTaskRunnerWithoutSequencedContext) {
  176. reply_runner_.reset();
  177. EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet());
  178. post_runner_->StopAcceptingTasks();
  179. // Expect the post to return false, but not to crash.
  180. EXPECT_FALSE(PostTaskAndReplyToMockObject());
  181. // Expect all tasks to be deleted.
  182. EXPECT_TRUE(delete_task_flag_);
  183. EXPECT_TRUE(delete_reply_flag_);
  184. }
  185. } // namespace internal
  186. } // namespace base