• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 <stdint.h>
6 #include <utility>
7 
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "mojo/public/cpp/bindings/binding.h"
11 #include "mojo/public/cpp/bindings/strong_binding.h"
12 #include "mojo/public/cpp/test_support/test_utils.h"
13 #include "mojo/public/interfaces/bindings/tests/sample_factory.mojom.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace mojo {
17 namespace test {
18 namespace {
19 
20 const char kText1[] = "hello";
21 const char kText2[] = "world";
22 
RecordString(std::string * storage,const base::Closure & closure,const std::string & str)23 void RecordString(std::string* storage,
24                   const base::Closure& closure,
25                   const std::string& str) {
26   *storage = str;
27   closure.Run();
28 }
29 
MakeStringRecorder(std::string * storage,const base::Closure & closure)30 base::Callback<void(const std::string&)> MakeStringRecorder(
31     std::string* storage,
32     const base::Closure& closure) {
33   return base::Bind(&RecordString, storage, closure);
34 }
35 
36 class ImportedInterfaceImpl : public imported::ImportedInterface {
37  public:
ImportedInterfaceImpl(InterfaceRequest<imported::ImportedInterface> request,const base::Closure & closure)38   ImportedInterfaceImpl(
39       InterfaceRequest<imported::ImportedInterface> request,
40       const base::Closure& closure)
41       : binding_(this, std::move(request)), closure_(closure) {}
42 
DoSomething()43   void DoSomething() override {
44     do_something_count_++;
45     closure_.Run();
46   }
47 
do_something_count()48   static int do_something_count() { return do_something_count_; }
49 
50  private:
51   static int do_something_count_;
52   Binding<ImportedInterface> binding_;
53   base::Closure closure_;
54 };
55 int ImportedInterfaceImpl::do_something_count_ = 0;
56 
57 class SampleNamedObjectImpl : public sample::NamedObject {
58  public:
SampleNamedObjectImpl(InterfaceRequest<sample::NamedObject> request)59   explicit SampleNamedObjectImpl(InterfaceRequest<sample::NamedObject> request)
60       : binding_(this, std::move(request)) {}
SetName(const std::string & name)61   void SetName(const std::string& name) override { name_ = name; }
62 
GetName(const GetNameCallback & callback)63   void GetName(const GetNameCallback& callback) override {
64     callback.Run(name_);
65   }
66 
67  private:
68   std::string name_;
69   StrongBinding<sample::NamedObject> binding_;
70 };
71 
72 class SampleFactoryImpl : public sample::Factory {
73  public:
SampleFactoryImpl(InterfaceRequest<sample::Factory> request)74   explicit SampleFactoryImpl(InterfaceRequest<sample::Factory> request)
75       : binding_(this, std::move(request)) {}
76 
DoStuff(sample::RequestPtr request,ScopedMessagePipeHandle pipe,const DoStuffCallback & callback)77   void DoStuff(sample::RequestPtr request,
78                ScopedMessagePipeHandle pipe,
79                const DoStuffCallback& callback) override {
80     std::string text1;
81     if (pipe.is_valid())
82       EXPECT_TRUE(ReadTextMessage(pipe.get(), &text1));
83 
84     std::string text2;
85     if (request->pipe.is_valid()) {
86       EXPECT_TRUE(ReadTextMessage(request->pipe.get(), &text2));
87 
88       // Ensure that simply accessing request->pipe does not close it.
89       EXPECT_TRUE(request->pipe.is_valid());
90     }
91 
92     ScopedMessagePipeHandle pipe0;
93     if (!text2.empty()) {
94       CreateMessagePipe(nullptr, &pipe0, &pipe1_);
95       EXPECT_TRUE(WriteTextMessage(pipe1_.get(), text2));
96     }
97 
98     sample::ResponsePtr response(sample::Response::New());
99     response->x = 2;
100     response->pipe = std::move(pipe0);
101     callback.Run(std::move(response), text1);
102 
103     if (request->obj)
104       request->obj->DoSomething();
105   }
106 
DoStuff2(ScopedDataPipeConsumerHandle pipe,const DoStuff2Callback & callback)107   void DoStuff2(ScopedDataPipeConsumerHandle pipe,
108                 const DoStuff2Callback& callback) override {
109     // Read the data from the pipe, writing the response (as a string) to
110     // DidStuff2().
111     ASSERT_TRUE(pipe.is_valid());
112     uint32_t data_size = 0;
113 
114     MojoHandleSignalsState state;
115     ASSERT_EQ(MOJO_RESULT_OK,
116               MojoWait(pipe.get().value(), MOJO_HANDLE_SIGNAL_READABLE,
117                        MOJO_DEADLINE_INDEFINITE, &state));
118     ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, state.satisfied_signals);
119     ASSERT_EQ(MOJO_RESULT_OK,
120               ReadDataRaw(
121                   pipe.get(), nullptr, &data_size, MOJO_READ_DATA_FLAG_QUERY));
122     ASSERT_NE(0, static_cast<int>(data_size));
123     char data[64];
124     ASSERT_LT(static_cast<int>(data_size), 64);
125     ASSERT_EQ(
126         MOJO_RESULT_OK,
127         ReadDataRaw(
128             pipe.get(), data, &data_size, MOJO_READ_DATA_FLAG_ALL_OR_NONE));
129 
130     callback.Run(data);
131   }
132 
CreateNamedObject(InterfaceRequest<sample::NamedObject> object_request)133   void CreateNamedObject(
134       InterfaceRequest<sample::NamedObject> object_request) override {
135     EXPECT_TRUE(object_request.is_pending());
136     new SampleNamedObjectImpl(std::move(object_request));
137   }
138 
139   // These aren't called or implemented, but exist here to test that the
140   // methods are generated with the correct argument types for imported
141   // interfaces.
RequestImportedInterface(InterfaceRequest<imported::ImportedInterface> imported,const RequestImportedInterfaceCallback & callback)142   void RequestImportedInterface(
143       InterfaceRequest<imported::ImportedInterface> imported,
144       const RequestImportedInterfaceCallback& callback) override {}
TakeImportedInterface(imported::ImportedInterfacePtr imported,const TakeImportedInterfaceCallback & callback)145   void TakeImportedInterface(
146       imported::ImportedInterfacePtr imported,
147       const TakeImportedInterfaceCallback& callback) override {}
148 
149  private:
150   ScopedMessagePipeHandle pipe1_;
151   Binding<sample::Factory> binding_;
152 };
153 
154 class HandlePassingTest : public testing::Test {
155  public:
HandlePassingTest()156   HandlePassingTest() {}
157 
TearDown()158   void TearDown() override { PumpMessages(); }
159 
PumpMessages()160   void PumpMessages() { base::RunLoop().RunUntilIdle(); }
161 
162  private:
163   base::MessageLoop loop_;
164 };
165 
DoStuff(bool * got_response,std::string * got_text_reply,const base::Closure & closure,sample::ResponsePtr response,const std::string & text_reply)166 void DoStuff(bool* got_response,
167              std::string* got_text_reply,
168              const base::Closure& closure,
169              sample::ResponsePtr response,
170              const std::string& text_reply) {
171   *got_text_reply = text_reply;
172 
173   if (response->pipe.is_valid()) {
174     std::string text2;
175     EXPECT_TRUE(ReadTextMessage(response->pipe.get(), &text2));
176 
177     // Ensure that simply accessing response.pipe does not close it.
178     EXPECT_TRUE(response->pipe.is_valid());
179 
180     EXPECT_EQ(std::string(kText2), text2);
181 
182     // Do some more tests of handle passing:
183     ScopedMessagePipeHandle p = std::move(response->pipe);
184     EXPECT_TRUE(p.is_valid());
185     EXPECT_FALSE(response->pipe.is_valid());
186   }
187 
188   *got_response = true;
189   closure.Run();
190 }
191 
DoStuff2(bool * got_response,std::string * got_text_reply,const base::Closure & closure,const std::string & text_reply)192 void DoStuff2(bool* got_response,
193               std::string* got_text_reply,
194               const base::Closure& closure,
195               const std::string& text_reply) {
196   *got_response = true;
197   *got_text_reply = text_reply;
198   closure.Run();
199 }
200 
TEST_F(HandlePassingTest,Basic)201 TEST_F(HandlePassingTest, Basic) {
202   sample::FactoryPtr factory;
203   SampleFactoryImpl factory_impl(GetProxy(&factory));
204 
205   MessagePipe pipe0;
206   EXPECT_TRUE(WriteTextMessage(pipe0.handle1.get(), kText1));
207 
208   MessagePipe pipe1;
209   EXPECT_TRUE(WriteTextMessage(pipe1.handle1.get(), kText2));
210 
211   imported::ImportedInterfacePtr imported;
212   base::RunLoop run_loop;
213   ImportedInterfaceImpl imported_impl(GetProxy(&imported),
214                                       run_loop.QuitClosure());
215 
216   sample::RequestPtr request(sample::Request::New());
217   request->x = 1;
218   request->pipe = std::move(pipe1.handle0);
219   request->obj = std::move(imported);
220   bool got_response = false;
221   std::string got_text_reply;
222   base::RunLoop run_loop2;
223   factory->DoStuff(std::move(request), std::move(pipe0.handle0),
224                    base::Bind(&DoStuff, &got_response, &got_text_reply,
225                               run_loop2.QuitClosure()));
226 
227   EXPECT_FALSE(got_response);
228   int count_before = ImportedInterfaceImpl::do_something_count();
229 
230   run_loop.Run();
231   run_loop2.Run();
232 
233   EXPECT_TRUE(got_response);
234   EXPECT_EQ(kText1, got_text_reply);
235   EXPECT_EQ(1, ImportedInterfaceImpl::do_something_count() - count_before);
236 }
237 
TEST_F(HandlePassingTest,PassInvalid)238 TEST_F(HandlePassingTest, PassInvalid) {
239   sample::FactoryPtr factory;
240   SampleFactoryImpl factory_impl(GetProxy(&factory));
241 
242   sample::RequestPtr request(sample::Request::New());
243   request->x = 1;
244   bool got_response = false;
245   std::string got_text_reply;
246   base::RunLoop run_loop;
247   factory->DoStuff(std::move(request), ScopedMessagePipeHandle(),
248                    base::Bind(&DoStuff, &got_response, &got_text_reply,
249                               run_loop.QuitClosure()));
250 
251   EXPECT_FALSE(got_response);
252 
253   run_loop.Run();
254 
255   EXPECT_TRUE(got_response);
256 }
257 
258 // Verifies DataPipeConsumer can be passed and read from.
TEST_F(HandlePassingTest,DataPipe)259 TEST_F(HandlePassingTest, DataPipe) {
260   sample::FactoryPtr factory;
261   SampleFactoryImpl factory_impl(GetProxy(&factory));
262 
263   // Writes a string to a data pipe and passes the data pipe (consumer) to the
264   // factory.
265   ScopedDataPipeProducerHandle producer_handle;
266   ScopedDataPipeConsumerHandle consumer_handle;
267   MojoCreateDataPipeOptions options = {sizeof(MojoCreateDataPipeOptions),
268                                        MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
269                                        1,
270                                        1024};
271   ASSERT_EQ(MOJO_RESULT_OK,
272             CreateDataPipe(&options, &producer_handle, &consumer_handle));
273   std::string expected_text_reply = "got it";
274   // +1 for \0.
275   uint32_t data_size = static_cast<uint32_t>(expected_text_reply.size() + 1);
276   ASSERT_EQ(MOJO_RESULT_OK,
277             WriteDataRaw(producer_handle.get(),
278                          expected_text_reply.c_str(),
279                          &data_size,
280                          MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
281 
282   bool got_response = false;
283   std::string got_text_reply;
284   base::RunLoop run_loop;
285   factory->DoStuff2(std::move(consumer_handle),
286                     base::Bind(&DoStuff2, &got_response, &got_text_reply,
287                                run_loop.QuitClosure()));
288 
289   EXPECT_FALSE(got_response);
290 
291   run_loop.Run();
292 
293   EXPECT_TRUE(got_response);
294   EXPECT_EQ(expected_text_reply, got_text_reply);
295 }
296 
TEST_F(HandlePassingTest,PipesAreClosed)297 TEST_F(HandlePassingTest, PipesAreClosed) {
298   sample::FactoryPtr factory;
299   SampleFactoryImpl factory_impl(GetProxy(&factory));
300 
301   MessagePipe extra_pipe;
302 
303   MojoHandle handle0_value = extra_pipe.handle0.get().value();
304   MojoHandle handle1_value = extra_pipe.handle1.get().value();
305 
306   {
307     std::vector<ScopedMessagePipeHandle> pipes(2);
308     pipes[0] = std::move(extra_pipe.handle0);
309     pipes[1] = std::move(extra_pipe.handle1);
310 
311     sample::RequestPtr request(sample::Request::New());
312     request->more_pipes = std::move(pipes);
313 
314     factory->DoStuff(std::move(request), ScopedMessagePipeHandle(),
315                      sample::Factory::DoStuffCallback());
316   }
317 
318   // We expect the pipes to have been closed.
319   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(handle0_value));
320   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(handle1_value));
321 }
322 
TEST_F(HandlePassingTest,CreateNamedObject)323 TEST_F(HandlePassingTest, CreateNamedObject) {
324   sample::FactoryPtr factory;
325   SampleFactoryImpl factory_impl(GetProxy(&factory));
326 
327   sample::NamedObjectPtr object1;
328   EXPECT_FALSE(object1);
329 
330   InterfaceRequest<sample::NamedObject> object1_request = GetProxy(&object1);
331   EXPECT_TRUE(object1_request.is_pending());
332   factory->CreateNamedObject(std::move(object1_request));
333   EXPECT_FALSE(object1_request.is_pending());  // We've passed the request.
334 
335   ASSERT_TRUE(object1);
336   object1->SetName("object1");
337 
338   sample::NamedObjectPtr object2;
339   factory->CreateNamedObject(GetProxy(&object2));
340   object2->SetName("object2");
341 
342   base::RunLoop run_loop, run_loop2;
343   std::string name1;
344   object1->GetName(MakeStringRecorder(&name1, run_loop.QuitClosure()));
345 
346   std::string name2;
347   object2->GetName(MakeStringRecorder(&name2, run_loop2.QuitClosure()));
348 
349   run_loop.Run();
350   run_loop2.Run();
351 
352   EXPECT_EQ(std::string("object1"), name1);
353   EXPECT_EQ(std::string("object2"), name2);
354 }
355 
356 }  // namespace
357 }  // namespace test
358 }  // namespace mojo
359