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