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 <utility>
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/containers/queue.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/synchronization/lock.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/platform_thread.h"
15 #include "mojo/public/cpp/bindings/associated_binding.h"
16 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
17 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
18 #include "mojo/public/cpp/bindings/associated_interface_request.h"
19 #include "mojo/public/cpp/bindings/binding.h"
20 #include "mojo/public/interfaces/bindings/tests/test_associated_interfaces.mojom.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace mojo {
24 namespace test {
25 namespace {
26
27 class TestTaskRunner : public base::SingleThreadTaskRunner {
28 public:
TestTaskRunner()29 TestTaskRunner()
30 : thread_id_(base::PlatformThread::CurrentRef()),
31 quit_called_(false),
32 task_ready_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
33 base::WaitableEvent::InitialState::NOT_SIGNALED) {}
34
PostNonNestableDelayedTask(const base::Location & from_here,base::OnceClosure task,base::TimeDelta delay)35 bool PostNonNestableDelayedTask(const base::Location& from_here,
36 base::OnceClosure task,
37 base::TimeDelta delay) override {
38 NOTREACHED();
39 return false;
40 }
41
PostDelayedTask(const base::Location & from_here,base::OnceClosure task,base::TimeDelta delay)42 bool PostDelayedTask(const base::Location& from_here,
43 base::OnceClosure task,
44 base::TimeDelta delay) override {
45 {
46 base::AutoLock locker(lock_);
47 tasks_.push(std::move(task));
48 }
49 task_ready_.Signal();
50 return true;
51 }
RunsTasksInCurrentSequence() const52 bool RunsTasksInCurrentSequence() const override {
53 return base::PlatformThread::CurrentRef() == thread_id_;
54 }
55
56 // Only quits when Quit() is called.
Run()57 void Run() {
58 DCHECK(RunsTasksInCurrentSequence());
59 quit_called_ = false;
60
61 while (true) {
62 {
63 base::AutoLock locker(lock_);
64 while (!tasks_.empty()) {
65 auto task = std::move(tasks_.front());
66 tasks_.pop();
67
68 {
69 base::AutoUnlock unlocker(lock_);
70 std::move(task).Run();
71 if (quit_called_)
72 return;
73 }
74 }
75 }
76 task_ready_.Wait();
77 }
78 }
79
Quit()80 void Quit() {
81 DCHECK(RunsTasksInCurrentSequence());
82 quit_called_ = true;
83 }
84
85 // Waits until one task is ready and runs it.
RunOneTask()86 void RunOneTask() {
87 DCHECK(RunsTasksInCurrentSequence());
88
89 while (true) {
90 {
91 base::AutoLock locker(lock_);
92 if (!tasks_.empty()) {
93 auto task = std::move(tasks_.front());
94 tasks_.pop();
95
96 {
97 base::AutoUnlock unlocker(lock_);
98 std::move(task).Run();
99 return;
100 }
101 }
102 }
103 task_ready_.Wait();
104 }
105 }
106
107 private:
~TestTaskRunner()108 ~TestTaskRunner() override {}
109
110 const base::PlatformThreadRef thread_id_;
111 bool quit_called_;
112 base::WaitableEvent task_ready_;
113
114 // Protect |tasks_|.
115 base::Lock lock_;
116 base::queue<base::OnceClosure> tasks_;
117
118 DISALLOW_COPY_AND_ASSIGN(TestTaskRunner);
119 };
120
121 template <typename BindingType, typename RequestType>
122 class IntegerSenderImpl : public IntegerSender {
123 public:
IntegerSenderImpl(RequestType request,scoped_refptr<base::SingleThreadTaskRunner> runner)124 IntegerSenderImpl(RequestType request,
125 scoped_refptr<base::SingleThreadTaskRunner> runner)
126 : binding_(this, std::move(request), std::move(runner)) {}
127
~IntegerSenderImpl()128 ~IntegerSenderImpl() override {}
129
130 using EchoHandler = base::Callback<void(int32_t, const EchoCallback&)>;
131
set_echo_handler(const EchoHandler & handler)132 void set_echo_handler(const EchoHandler& handler) { echo_handler_ = handler; }
133
Echo(int32_t value,const EchoCallback & callback)134 void Echo(int32_t value, const EchoCallback& callback) override {
135 if (echo_handler_.is_null())
136 callback.Run(value);
137 else
138 echo_handler_.Run(value, callback);
139 }
Send(int32_t value)140 void Send(int32_t value) override { NOTREACHED(); }
141
binding()142 BindingType* binding() { return &binding_; }
143
144 private:
145 BindingType binding_;
146 EchoHandler echo_handler_;
147 };
148
149 class IntegerSenderConnectionImpl : public IntegerSenderConnection {
150 public:
151 using SenderType = IntegerSenderImpl<AssociatedBinding<IntegerSender>,
152 IntegerSenderAssociatedRequest>;
153
IntegerSenderConnectionImpl(IntegerSenderConnectionRequest request,scoped_refptr<base::SingleThreadTaskRunner> runner,scoped_refptr<base::SingleThreadTaskRunner> sender_runner)154 explicit IntegerSenderConnectionImpl(
155 IntegerSenderConnectionRequest request,
156 scoped_refptr<base::SingleThreadTaskRunner> runner,
157 scoped_refptr<base::SingleThreadTaskRunner> sender_runner)
158 : binding_(this, std::move(request), std::move(runner)),
159 sender_runner_(std::move(sender_runner)) {}
160
~IntegerSenderConnectionImpl()161 ~IntegerSenderConnectionImpl() override {}
162
set_get_sender_notification(const base::Closure & notification)163 void set_get_sender_notification(const base::Closure& notification) {
164 get_sender_notification_ = notification;
165 }
GetSender(IntegerSenderAssociatedRequest sender)166 void GetSender(IntegerSenderAssociatedRequest sender) override {
167 sender_impl_.reset(new SenderType(std::move(sender), sender_runner_));
168 get_sender_notification_.Run();
169 }
170
AsyncGetSender(const AsyncGetSenderCallback & callback)171 void AsyncGetSender(const AsyncGetSenderCallback& callback) override {
172 NOTREACHED();
173 }
174
binding()175 Binding<IntegerSenderConnection>* binding() { return &binding_; }
176
sender_impl()177 SenderType* sender_impl() { return sender_impl_.get(); }
178
179 private:
180 Binding<IntegerSenderConnection> binding_;
181 std::unique_ptr<SenderType> sender_impl_;
182 scoped_refptr<base::SingleThreadTaskRunner> sender_runner_;
183 base::Closure get_sender_notification_;
184 };
185
186 class BindTaskRunnerTest : public testing::Test {
187 protected:
SetUp()188 void SetUp() override {
189 binding_task_runner_ = scoped_refptr<TestTaskRunner>(new TestTaskRunner);
190 ptr_task_runner_ = scoped_refptr<TestTaskRunner>(new TestTaskRunner);
191
192 auto request = MakeRequest(&ptr_, ptr_task_runner_);
193 impl_.reset(new ImplType(std::move(request), binding_task_runner_));
194 }
195
196 base::MessageLoop loop_;
197 scoped_refptr<TestTaskRunner> binding_task_runner_;
198 scoped_refptr<TestTaskRunner> ptr_task_runner_;
199
200 IntegerSenderPtr ptr_;
201 using ImplType =
202 IntegerSenderImpl<Binding<IntegerSender>, IntegerSenderRequest>;
203 std::unique_ptr<ImplType> impl_;
204 };
205
206 class AssociatedBindTaskRunnerTest : public testing::Test {
207 protected:
SetUp()208 void SetUp() override {
209 connection_binding_task_runner_ =
210 scoped_refptr<TestTaskRunner>(new TestTaskRunner);
211 connection_ptr_task_runner_ =
212 scoped_refptr<TestTaskRunner>(new TestTaskRunner);
213 sender_binding_task_runner_ =
214 scoped_refptr<TestTaskRunner>(new TestTaskRunner);
215 sender_ptr_task_runner_ = scoped_refptr<TestTaskRunner>(new TestTaskRunner);
216
217 auto connection_request =
218 MakeRequest(&connection_ptr_, connection_ptr_task_runner_);
219 connection_impl_.reset(new IntegerSenderConnectionImpl(
220 std::move(connection_request), connection_binding_task_runner_,
221 sender_binding_task_runner_));
222
223 connection_impl_->set_get_sender_notification(
224 base::Bind(&AssociatedBindTaskRunnerTest::QuitTaskRunner,
225 base::Unretained(this)));
226
227 connection_ptr_->GetSender(
228 MakeRequest(&sender_ptr_, sender_ptr_task_runner_));
229 connection_binding_task_runner_->Run();
230 }
231
QuitTaskRunner()232 void QuitTaskRunner() {
233 connection_binding_task_runner_->Quit();
234 }
235
236 base::MessageLoop loop_;
237 scoped_refptr<TestTaskRunner> connection_binding_task_runner_;
238 scoped_refptr<TestTaskRunner> connection_ptr_task_runner_;
239 scoped_refptr<TestTaskRunner> sender_binding_task_runner_;
240 scoped_refptr<TestTaskRunner> sender_ptr_task_runner_;
241
242 IntegerSenderConnectionPtr connection_ptr_;
243 std::unique_ptr<IntegerSenderConnectionImpl> connection_impl_;
244 IntegerSenderAssociatedPtr sender_ptr_;
245 };
246
DoSetFlagAndQuitTaskRunner(bool * flag,scoped_refptr<TestTaskRunner> task_runner)247 void DoSetFlagAndQuitTaskRunner(bool* flag,
248 scoped_refptr<TestTaskRunner> task_runner) {
249 *flag = true;
250 if (task_runner)
251 task_runner->Quit();
252 }
253
DoExpectValueSetFlagAndQuitTaskRunner(int32_t expected_value,bool * flag,scoped_refptr<TestTaskRunner> task_runner,int32_t value)254 void DoExpectValueSetFlagAndQuitTaskRunner(
255 int32_t expected_value,
256 bool* flag,
257 scoped_refptr<TestTaskRunner> task_runner,
258 int32_t value) {
259 EXPECT_EQ(expected_value, value);
260 DoSetFlagAndQuitTaskRunner(flag, task_runner);
261 }
262
DoExpectValueSetFlagForwardValueAndQuitTaskRunner(int32_t expected_value,bool * flag,scoped_refptr<TestTaskRunner> task_runner,int32_t value,const IntegerSender::EchoCallback & callback)263 void DoExpectValueSetFlagForwardValueAndQuitTaskRunner(
264 int32_t expected_value,
265 bool* flag,
266 scoped_refptr<TestTaskRunner> task_runner,
267 int32_t value,
268 const IntegerSender::EchoCallback& callback) {
269 EXPECT_EQ(expected_value, value);
270 *flag = true;
271 callback.Run(value);
272 task_runner->Quit();
273 }
274
SetFlagAndQuitTaskRunner(bool * flag,scoped_refptr<TestTaskRunner> task_runner)275 base::Closure SetFlagAndQuitTaskRunner(
276 bool* flag,
277 scoped_refptr<TestTaskRunner> task_runner) {
278 return base::Bind(&DoSetFlagAndQuitTaskRunner, flag, task_runner);
279 }
280
ExpectValueSetFlagAndQuitTaskRunner(int32_t expected_value,bool * flag,scoped_refptr<TestTaskRunner> task_runner)281 base::Callback<void(int32_t)> ExpectValueSetFlagAndQuitTaskRunner(
282 int32_t expected_value,
283 bool* flag,
284 scoped_refptr<TestTaskRunner> task_runner) {
285 return base::Bind(&DoExpectValueSetFlagAndQuitTaskRunner, expected_value,
286 flag, task_runner);
287 }
288
TEST_F(BindTaskRunnerTest,MethodCall)289 TEST_F(BindTaskRunnerTest, MethodCall) {
290 bool echo_called = false;
291 impl_->set_echo_handler(
292 base::Bind(&DoExpectValueSetFlagForwardValueAndQuitTaskRunner,
293 1024, &echo_called, binding_task_runner_));
294 bool echo_replied = false;
295 ptr_->Echo(1024, ExpectValueSetFlagAndQuitTaskRunner(1024, &echo_replied,
296 ptr_task_runner_));
297 binding_task_runner_->Run();
298 EXPECT_TRUE(echo_called);
299 ptr_task_runner_->Run();
300 EXPECT_TRUE(echo_replied);
301 }
302
TEST_F(BindTaskRunnerTest,BindingConnectionError)303 TEST_F(BindTaskRunnerTest, BindingConnectionError) {
304 bool connection_error_called = false;
305 impl_->binding()->set_connection_error_handler(
306 SetFlagAndQuitTaskRunner(&connection_error_called, binding_task_runner_));
307 ptr_.reset();
308 binding_task_runner_->Run();
309 EXPECT_TRUE(connection_error_called);
310 }
311
TEST_F(BindTaskRunnerTest,PtrConnectionError)312 TEST_F(BindTaskRunnerTest, PtrConnectionError) {
313 bool connection_error_called = false;
314 ptr_.set_connection_error_handler(
315 SetFlagAndQuitTaskRunner(&connection_error_called, ptr_task_runner_));
316 impl_->binding()->Close();
317 ptr_task_runner_->Run();
318 EXPECT_TRUE(connection_error_called);
319 }
320
ExpectValueSetFlagAndForward(int32_t expected_value,bool * flag,int32_t value,const IntegerSender::EchoCallback & callback)321 void ExpectValueSetFlagAndForward(int32_t expected_value,
322 bool* flag,
323 int32_t value,
324 const IntegerSender::EchoCallback& callback) {
325 EXPECT_EQ(expected_value, value);
326 *flag = true;
327 callback.Run(value);
328 }
329
TEST_F(AssociatedBindTaskRunnerTest,MethodCall)330 TEST_F(AssociatedBindTaskRunnerTest, MethodCall) {
331 bool echo_called = false;
332 connection_impl_->sender_impl()->set_echo_handler(
333 base::Bind(&ExpectValueSetFlagAndForward, 1024, &echo_called));
334
335 bool echo_replied = false;
336 sender_ptr_->Echo(
337 1024, ExpectValueSetFlagAndQuitTaskRunner(1024, &echo_replied, nullptr));
338
339 // The Echo request first arrives at the master endpoint's task runner, and
340 // then is forwarded to the associated endpoint's task runner.
341 connection_binding_task_runner_->RunOneTask();
342 sender_binding_task_runner_->RunOneTask();
343 EXPECT_TRUE(echo_called);
344
345 // Similarly, the Echo response arrives at the master endpoint's task runner
346 // and then is forwarded to the associated endpoint's task runner.
347 connection_ptr_task_runner_->RunOneTask();
348 sender_ptr_task_runner_->RunOneTask();
349 EXPECT_TRUE(echo_replied);
350 }
351
TEST_F(AssociatedBindTaskRunnerTest,BindingConnectionError)352 TEST_F(AssociatedBindTaskRunnerTest, BindingConnectionError) {
353 bool sender_impl_error = false;
354 connection_impl_->sender_impl()->binding()->set_connection_error_handler(
355 SetFlagAndQuitTaskRunner(&sender_impl_error,
356 sender_binding_task_runner_));
357 bool connection_impl_error = false;
358 connection_impl_->binding()->set_connection_error_handler(
359 SetFlagAndQuitTaskRunner(&connection_impl_error,
360 connection_binding_task_runner_));
361 bool sender_ptr_error = false;
362 sender_ptr_.set_connection_error_handler(
363 SetFlagAndQuitTaskRunner(&sender_ptr_error, sender_ptr_task_runner_));
364 connection_ptr_.reset();
365 sender_ptr_task_runner_->Run();
366 EXPECT_TRUE(sender_ptr_error);
367 connection_binding_task_runner_->Run();
368 EXPECT_TRUE(connection_impl_error);
369 sender_binding_task_runner_->Run();
370 EXPECT_TRUE(sender_impl_error);
371 }
372
TEST_F(AssociatedBindTaskRunnerTest,PtrConnectionError)373 TEST_F(AssociatedBindTaskRunnerTest, PtrConnectionError) {
374 bool sender_impl_error = false;
375 connection_impl_->sender_impl()->binding()->set_connection_error_handler(
376 SetFlagAndQuitTaskRunner(&sender_impl_error,
377 sender_binding_task_runner_));
378 bool connection_ptr_error = false;
379 connection_ptr_.set_connection_error_handler(
380 SetFlagAndQuitTaskRunner(&connection_ptr_error,
381 connection_ptr_task_runner_));
382 bool sender_ptr_error = false;
383 sender_ptr_.set_connection_error_handler(
384 SetFlagAndQuitTaskRunner(&sender_ptr_error, sender_ptr_task_runner_));
385 connection_impl_->binding()->Close();
386 sender_binding_task_runner_->Run();
387 EXPECT_TRUE(sender_impl_error);
388 connection_ptr_task_runner_->Run();
389 EXPECT_TRUE(connection_ptr_error);
390 sender_ptr_task_runner_->Run();
391 EXPECT_TRUE(sender_ptr_error);
392 }
393
394 } // namespace
395 } // namespace test
396 } // namespace mojo
397