• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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