 Chromium Code Reviews
 Chromium Code Reviews Issue 973513004:
  Allow data pipe producer/consumer handles to be re-sent.  (Closed) 
  Base URL: https://github.com/domokit/mojo.git@master
    
  
    Issue 973513004:
  Allow data pipe producer/consumer handles to be re-sent.  (Closed) 
  Base URL: https://github.com/domokit/mojo.git@master| Index: mojo/edk/system/data_pipe_impl_unittest.cc | 
| diff --git a/mojo/edk/system/data_pipe_impl_unittest.cc b/mojo/edk/system/data_pipe_impl_unittest.cc | 
| index 2c7e53f107309a9b67df58c30a97434d95f53cda..3c1faedecbf6d98a86fcab385e26165949d90616 100644 | 
| --- a/mojo/edk/system/data_pipe_impl_unittest.cc | 
| +++ b/mojo/edk/system/data_pipe_impl_unittest.cc | 
| @@ -164,10 +164,64 @@ class RemoteDataPipeImplTestHelper : public DataPipeImplTestHelper { | 
| } | 
| protected: | 
| + void SendDispatcher(size_t source_i, | 
| + scoped_refptr<Dispatcher> to_send, | 
| + scoped_refptr<Dispatcher>* to_receive) { | 
| + DCHECK(source_i == 0 || source_i == 1); | 
| + size_t dest_i = source_i ^ 1; | 
| + | 
| + // Write the dispatcher to MP |source_i| (port 0). Wait and receive on MP | 
| + // |dest_i| (port 0). (Add the waiter first, to avoid any handling the case | 
| + // where it's already readable.) | 
| + Waiter waiter; | 
| + waiter.Init(); | 
| + ASSERT_EQ(MOJO_RESULT_OK, | 
| + message_pipe(dest_i)->AddAwakable( | 
| + 0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 987, nullptr)); | 
| + { | 
| + DispatcherTransport transport( | 
| + test::DispatcherTryStartTransport(to_send.get())); | 
| + ASSERT_TRUE(transport.is_valid()); | 
| + | 
| + std::vector<DispatcherTransport> transports; | 
| + transports.push_back(transport); | 
| + ASSERT_EQ(MOJO_RESULT_OK, message_pipe(source_i)->WriteMessage( | 
| + 0, NullUserPointer(), 0, &transports, | 
| + MOJO_WRITE_MESSAGE_FLAG_NONE)); | 
| + transport.End(); | 
| + } | 
| + uint32_t context = 0; | 
| + ASSERT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); | 
| + EXPECT_EQ(987u, context); | 
| + HandleSignalsState hss = HandleSignalsState(); | 
| + message_pipe(dest_i)->RemoveAwakable(0, &waiter, &hss); | 
| + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, | 
| + hss.satisfied_signals); | 
| + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); | 
| + char read_buffer[100] = {}; | 
| + uint32_t read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); | 
| + DispatcherVector read_dispatchers; | 
| + uint32_t read_num_dispatchers = 10; // Maximum to get. | 
| + ASSERT_EQ(MOJO_RESULT_OK, | 
| + message_pipe(dest_i)->ReadMessage( | 
| + 0, UserPointer<void>(read_buffer), | 
| + MakeUserPointer(&read_buffer_size), &read_dispatchers, | 
| + &read_num_dispatchers, MOJO_READ_MESSAGE_FLAG_NONE)); | 
| + EXPECT_EQ(0u, static_cast<size_t>(read_buffer_size)); | 
| + ASSERT_EQ(1u, read_dispatchers.size()); | 
| + ASSERT_EQ(1u, read_num_dispatchers); | 
| + ASSERT_TRUE(read_dispatchers[0]); | 
| + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); | 
| + | 
| + *to_receive = read_dispatchers[0]; | 
| + } | 
| + | 
| scoped_refptr<MessagePipe> message_pipe(size_t i) { | 
| return message_pipes_[i]; | 
| } | 
| + scoped_refptr<DataPipe> dp() { return dp_; } | 
| + private: | 
| void EnsureMessagePipeClosed(size_t i) { | 
| if (!message_pipes_[i]) | 
| return; | 
| @@ -213,6 +267,9 @@ class RemoteDataPipeImplTestHelper : public DataPipeImplTestHelper { | 
| // RemoteProducerDataPipeImplTestHelper ---------------------------------------- | 
| +// Note about naming confusion: This class is named after the "local" class, | 
| +// i.e., |dp_| will have a |RemoteProducerDataPipeImpl|. The remote side, of | 
| +// course, will have a |RemoteConsumerDataPipeImpl|. | 
| class RemoteProducerDataPipeImplTestHelper | 
| : public RemoteDataPipeImplTestHelper { | 
| public: | 
| @@ -220,87 +277,49 @@ class RemoteProducerDataPipeImplTestHelper | 
| ~RemoteProducerDataPipeImplTestHelper() override {} | 
| void DoTransfer() override { | 
| - // Write the producer to MP 0 (port 0). Wait and receive on MP 1 (port 0). | 
| - // (Add the waiter first, to avoid any handling the case where it's already | 
| - // readable.) | 
| - Waiter waiter; | 
| - waiter.Init(); | 
| - ASSERT_EQ(MOJO_RESULT_OK, | 
| - message_pipe(1)->AddAwakable( | 
| - 0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 987, nullptr)); | 
| - { | 
| - // This is the producer dispatcher we'll send. | 
| - scoped_refptr<DataPipeProducerDispatcher> to_send = | 
| - new DataPipeProducerDispatcher(); | 
| - to_send->Init(dp_); | 
| - | 
| - DispatcherTransport transport( | 
| - test::DispatcherTryStartTransport(to_send.get())); | 
| - ASSERT_TRUE(transport.is_valid()); | 
| - | 
| - std::vector<DispatcherTransport> transports; | 
| - transports.push_back(transport); | 
| - ASSERT_EQ(MOJO_RESULT_OK, message_pipe(0)->WriteMessage( | 
| - 0, NullUserPointer(), 0, &transports, | 
| - MOJO_WRITE_MESSAGE_FLAG_NONE)); | 
| - transport.End(); | 
| - | 
| - // |to_send| should have been closed. This is |DCHECK()|ed when it is | 
| - // destroyed. | 
| - EXPECT_TRUE(to_send->HasOneRef()); | 
| - } | 
| - uint32_t context = 0; | 
| - ASSERT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); | 
| - EXPECT_EQ(987u, context); | 
| - HandleSignalsState hss = HandleSignalsState(); | 
| - message_pipe(1)->RemoveAwakable(0, &waiter, &hss); | 
| - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, | 
| - hss.satisfied_signals); | 
| - EXPECT_EQ(kAllSignals, hss.satisfiable_signals); | 
| - char read_buffer[100] = {}; | 
| - uint32_t read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); | 
| - DispatcherVector read_dispatchers; | 
| - uint32_t read_num_dispatchers = 10; // Maximum to get. | 
| - ASSERT_EQ(MOJO_RESULT_OK, | 
| - message_pipe(1)->ReadMessage( | 
| - 0, UserPointer<void>(read_buffer), | 
| - MakeUserPointer(&read_buffer_size), &read_dispatchers, | 
| - &read_num_dispatchers, MOJO_READ_MESSAGE_FLAG_NONE)); | 
| - EXPECT_EQ(0u, static_cast<size_t>(read_buffer_size)); | 
| - ASSERT_EQ(1u, read_dispatchers.size()); | 
| - ASSERT_EQ(1u, read_num_dispatchers); | 
| - ASSERT_TRUE(read_dispatchers[0]); | 
| - EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); | 
| - | 
| - ASSERT_EQ(Dispatcher::kTypeDataPipeProducer, | 
| - read_dispatchers[0]->GetType()); | 
| + // This is the producer dispatcher we'll send. | 
| + scoped_refptr<DataPipeProducerDispatcher> to_send = | 
| + new DataPipeProducerDispatcher(); | 
| + to_send->Init(dp()); | 
| + scoped_refptr<Dispatcher> to_receive; | 
| + SendDispatcher(0, to_send, &to_receive); | 
| + // |to_send| should have been closed. This is |DCHECK()|ed when it is | 
| + // destroyed. | 
| + EXPECT_TRUE(to_send->HasOneRef()); | 
| + to_send = nullptr; | 
| + | 
| + ASSERT_EQ(Dispatcher::kTypeDataPipeProducer, to_receive->GetType()); | 
| producer_dispatcher_ = | 
| - static_cast<DataPipeProducerDispatcher*>(read_dispatchers[0].get()); | 
| + static_cast<DataPipeProducerDispatcher*>(to_receive.get()); | 
| } | 
| DataPipe* dpp() override { | 
| if (producer_dispatcher_) | 
| return producer_dispatcher_->GetDataPipeForTest(); | 
| - return dp_.get(); | 
| + return dp().get(); | 
| } | 
| - DataPipe* dpc() override { return dp_.get(); } | 
| + DataPipe* dpc() override { return dp().get(); } | 
| void ProducerClose() override { | 
| if (producer_dispatcher_) | 
| ASSERT_EQ(MOJO_RESULT_OK, producer_dispatcher_->Close()); | 
| else | 
| - dp_->ProducerClose(); | 
| + dp()->ProducerClose(); | 
| } | 
| - void ConsumerClose() override { dp_->ConsumerClose(); } | 
| + void ConsumerClose() override { dp()->ConsumerClose(); } | 
| - private: | 
| + protected: | 
| scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher_; | 
| + private: | 
| DISALLOW_COPY_AND_ASSIGN(RemoteProducerDataPipeImplTestHelper); | 
| }; | 
| // RemoteConsumerDataPipeImplTestHelper ---------------------------------------- | 
| +// Note about naming confusion: This class is named after the "local" class, | 
| +// i.e., |dp_| will have a |RemoteConsumerDataPipeImpl|. The remote side, of | 
| +// course, will have a |RemoteProducerDataPipeImpl|. | 
| class RemoteConsumerDataPipeImplTestHelper | 
| : public RemoteDataPipeImplTestHelper { | 
| public: | 
| @@ -308,90 +327,125 @@ class RemoteConsumerDataPipeImplTestHelper | 
| ~RemoteConsumerDataPipeImplTestHelper() override {} | 
| void DoTransfer() override { | 
| - // Write the consumer to MP 0 (port 0). Wait and receive on MP 1 (port 0). | 
| - // (Add the waiter first, to avoid any handling the case where it's already | 
| - // readable.) | 
| - Waiter waiter; | 
| - waiter.Init(); | 
| - ASSERT_EQ(MOJO_RESULT_OK, | 
| - message_pipe(1)->AddAwakable( | 
| - 0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 987, nullptr)); | 
| - { | 
| - // This is the consumer dispatcher we'll send. | 
| - scoped_refptr<DataPipeConsumerDispatcher> to_send = | 
| - new DataPipeConsumerDispatcher(); | 
| - to_send->Init(dp_); | 
| - | 
| - DispatcherTransport transport( | 
| - test::DispatcherTryStartTransport(to_send.get())); | 
| - ASSERT_TRUE(transport.is_valid()); | 
| - | 
| - std::vector<DispatcherTransport> transports; | 
| - transports.push_back(transport); | 
| - ASSERT_EQ(MOJO_RESULT_OK, message_pipe(0)->WriteMessage( | 
| - 0, NullUserPointer(), 0, &transports, | 
| - MOJO_WRITE_MESSAGE_FLAG_NONE)); | 
| - transport.End(); | 
| - | 
| - // |to_send| should have been closed. This is |DCHECK()|ed when it is | 
| - // destroyed. | 
| - EXPECT_TRUE(to_send->HasOneRef()); | 
| - } | 
| - uint32_t context = 0; | 
| - ASSERT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); | 
| - EXPECT_EQ(987u, context); | 
| - HandleSignalsState hss = HandleSignalsState(); | 
| - message_pipe(1)->RemoveAwakable(0, &waiter, &hss); | 
| - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, | 
| - hss.satisfied_signals); | 
| - EXPECT_EQ(kAllSignals, hss.satisfiable_signals); | 
| - char read_buffer[100] = {}; | 
| - uint32_t read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); | 
| - DispatcherVector read_dispatchers; | 
| - uint32_t read_num_dispatchers = 10; // Maximum to get. | 
| - ASSERT_EQ(MOJO_RESULT_OK, | 
| - message_pipe(1)->ReadMessage( | 
| - 0, UserPointer<void>(read_buffer), | 
| - MakeUserPointer(&read_buffer_size), &read_dispatchers, | 
| - &read_num_dispatchers, MOJO_READ_MESSAGE_FLAG_NONE)); | 
| - EXPECT_EQ(0u, static_cast<size_t>(read_buffer_size)); | 
| - ASSERT_EQ(1u, read_dispatchers.size()); | 
| - ASSERT_EQ(1u, read_num_dispatchers); | 
| - ASSERT_TRUE(read_dispatchers[0]); | 
| - EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); | 
| - | 
| - ASSERT_EQ(Dispatcher::kTypeDataPipeConsumer, | 
| - read_dispatchers[0]->GetType()); | 
| + // This is the consumer dispatcher we'll send. | 
| + scoped_refptr<DataPipeConsumerDispatcher> to_send = | 
| + new DataPipeConsumerDispatcher(); | 
| + to_send->Init(dp()); | 
| + scoped_refptr<Dispatcher> to_receive; | 
| + SendDispatcher(0, to_send, &to_receive); | 
| + // |to_send| should have been closed. This is |DCHECK()|ed when it is | 
| + // destroyed. | 
| + EXPECT_TRUE(to_send->HasOneRef()); | 
| + to_send = nullptr; | 
| + | 
| + ASSERT_EQ(Dispatcher::kTypeDataPipeConsumer, to_receive->GetType()); | 
| consumer_dispatcher_ = | 
| - static_cast<DataPipeConsumerDispatcher*>(read_dispatchers[0].get()); | 
| + static_cast<DataPipeConsumerDispatcher*>(to_receive.get()); | 
| } | 
| - DataPipe* dpp() override { return dp_.get(); } | 
| + DataPipe* dpp() override { return dp().get(); } | 
| DataPipe* dpc() override { | 
| if (consumer_dispatcher_) | 
| return consumer_dispatcher_->GetDataPipeForTest(); | 
| - return dp_.get(); | 
| + return dp().get(); | 
| } | 
| - void ProducerClose() override { dp_->ProducerClose(); } | 
| + void ProducerClose() override { dp()->ProducerClose(); } | 
| void ConsumerClose() override { | 
| if (consumer_dispatcher_) | 
| ASSERT_EQ(MOJO_RESULT_OK, consumer_dispatcher_->Close()); | 
| else | 
| - dp_->ConsumerClose(); | 
| + dp()->ConsumerClose(); | 
| } | 
| - private: | 
| + protected: | 
| scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher_; | 
| + private: | 
| DISALLOW_COPY_AND_ASSIGN(RemoteConsumerDataPipeImplTestHelper); | 
| }; | 
| +// RemoteProducerDataPipeImplTestHelper2 --------------------------------------- | 
| + | 
| +// This is like |RemoteProducerDataPipeImplTestHelper|, but |DoTransfer()| does | 
| +// a second transfer. This thus tests passing a producer handle twice, and in | 
| +// particular tests (some of) |RemoteConsumerDataPipeImpl|'s | 
| +// |ProducerEndSerialize()| (instead of |LocalDataPipeImpl|'s). | 
| +// | 
| +// Note about naming confusion: This class is named after the "local" class, | 
| +// i.e., |dp_| will have a |RemoteProducerDataPipeImpl|. The remote side, of | 
| +// course, will have a |RemoteConsumerDataPipeImpl|. | 
| +class RemoteProducerDataPipeImplTestHelper2 | 
| + : public RemoteProducerDataPipeImplTestHelper { | 
| + public: | 
| + RemoteProducerDataPipeImplTestHelper2() {} | 
| + ~RemoteProducerDataPipeImplTestHelper2() override {} | 
| + | 
| + void DoTransfer() override { | 
| + // Do the first transfer. | 
| + RemoteProducerDataPipeImplTestHelper::DoTransfer(); | 
| 
Hajime Morrita
2015/03/03 03:00:38
It might be clearer just to call SendDispatcher()
 
viettrungluu
2015/03/03 05:17:45
Yeah, I went back and forth on that (since the sup
 | 
| + | 
| + // Now send it back the other way. | 
| + scoped_refptr<Dispatcher> to_receive; | 
| + SendDispatcher(1, producer_dispatcher_, &to_receive); | 
| + // |producer_dispatcher_| should have been closed. This is |DCHECK()|ed when | 
| + // it is destroyed. | 
| + EXPECT_TRUE(producer_dispatcher_->HasOneRef()); | 
| + producer_dispatcher_ = nullptr; | 
| + | 
| + ASSERT_EQ(Dispatcher::kTypeDataPipeProducer, to_receive->GetType()); | 
| + producer_dispatcher_ = | 
| + static_cast<DataPipeProducerDispatcher*>(to_receive.get()); | 
| + } | 
| + | 
| + private: | 
| + DISALLOW_COPY_AND_ASSIGN(RemoteProducerDataPipeImplTestHelper2); | 
| +}; | 
| + | 
| +// RemoteConsumerDataPipeImplTestHelper2 --------------------------------------- | 
| + | 
| +// This is like |RemoteConsumerDataPipeImplTestHelper|, but |DoTransfer()| does | 
| +// a second transfer. This thus tests passing a consumer handle twice, and in | 
| +// particular tests (some of) |RemoteProducerDataPipeImpl|'s | 
| +// |ConsumerEndSerialize()| (instead of |LocalDataPipeImpl|'s). | 
| +// | 
| +// Note about naming confusion: This class is named after the "local" class, | 
| +// i.e., |dp_| will have a |RemoteConsumerDataPipeImpl|. The remote side, of | 
| +// course, will have a |RemoteProducerDataPipeImpl|. | 
| +class RemoteConsumerDataPipeImplTestHelper2 | 
| + : public RemoteConsumerDataPipeImplTestHelper { | 
| + public: | 
| + RemoteConsumerDataPipeImplTestHelper2() {} | 
| + ~RemoteConsumerDataPipeImplTestHelper2() override {} | 
| + | 
| + void DoTransfer() override { | 
| + // Do the first transfer. | 
| + RemoteConsumerDataPipeImplTestHelper::DoTransfer(); | 
| 
Hajime Morrita
2015/03/03 03:00:38
Ditto.
 
viettrungluu
2015/03/03 05:17:45
Done.
 | 
| + | 
| + // Now send it back the other way. | 
| + scoped_refptr<Dispatcher> to_receive; | 
| + SendDispatcher(1, consumer_dispatcher_, &to_receive); | 
| + // |consumer_dispatcher_| should have been closed. This is |DCHECK()|ed when | 
| + // it is destroyed. | 
| + EXPECT_TRUE(consumer_dispatcher_->HasOneRef()); | 
| + consumer_dispatcher_ = nullptr; | 
| + | 
| + ASSERT_EQ(Dispatcher::kTypeDataPipeConsumer, to_receive->GetType()); | 
| + consumer_dispatcher_ = | 
| + static_cast<DataPipeConsumerDispatcher*>(to_receive.get()); | 
| + } | 
| + | 
| + private: | 
| + DISALLOW_COPY_AND_ASSIGN(RemoteConsumerDataPipeImplTestHelper2); | 
| +}; | 
| + | 
| // Test case instantiation ----------------------------------------------------- | 
| typedef testing::Types<LocalDataPipeImplTestHelper, | 
| RemoteProducerDataPipeImplTestHelper, | 
| - RemoteConsumerDataPipeImplTestHelper> HelperTypes; | 
| + RemoteConsumerDataPipeImplTestHelper, | 
| + RemoteProducerDataPipeImplTestHelper2, | 
| + RemoteConsumerDataPipeImplTestHelper2> HelperTypes; | 
| TYPED_TEST_CASE(DataPipeImplTest, HelperTypes); |