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