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