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