• 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/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