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