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 <stdlib.h> 6 #include <string.h> 7 8 #include "mojo/public/cpp/bindings/lib/connector.h" 9 #include "mojo/public/cpp/bindings/lib/message_builder.h" 10 #include "mojo/public/cpp/bindings/lib/message_queue.h" 11 #include "mojo/public/cpp/environment/environment.h" 12 #include "mojo/public/cpp/system/macros.h" 13 #include "mojo/public/cpp/utility/run_loop.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace mojo { 17 namespace test { 18 namespace { 19 20 class MessageAccumulator : public MessageReceiver { 21 public: 22 MessageAccumulator() { 23 } 24 25 virtual bool Accept(Message* message) MOJO_OVERRIDE { 26 queue_.Push(message); 27 return true; 28 } 29 30 bool IsEmpty() const { 31 return queue_.IsEmpty(); 32 } 33 34 void Pop(Message* message) { 35 queue_.Pop(message); 36 } 37 38 private: 39 internal::MessageQueue queue_; 40 }; 41 42 class ConnectorTest : public testing::Test { 43 public: 44 ConnectorTest() { 45 } 46 47 virtual void SetUp() MOJO_OVERRIDE { 48 CreateMessagePipe(NULL, &handle0_, &handle1_); 49 } 50 51 virtual void TearDown() MOJO_OVERRIDE { 52 } 53 54 void AllocMessage(const char* text, Message* message) { 55 size_t payload_size = strlen(text) + 1; // Plus null terminator. 56 internal::MessageBuilder builder(1, payload_size); 57 memcpy(builder.buffer()->Allocate(payload_size), text, payload_size); 58 builder.Finish(message); 59 } 60 61 void PumpMessages() { 62 loop_.RunUntilIdle(); 63 } 64 65 protected: 66 ScopedMessagePipeHandle handle0_; 67 ScopedMessagePipeHandle handle1_; 68 69 private: 70 Environment env_; 71 RunLoop loop_; 72 }; 73 74 TEST_F(ConnectorTest, Basic) { 75 internal::Connector connector0(handle0_.Pass()); 76 internal::Connector connector1(handle1_.Pass()); 77 78 const char kText[] = "hello world"; 79 80 Message message; 81 AllocMessage(kText, &message); 82 83 connector0.Accept(&message); 84 85 MessageAccumulator accumulator; 86 connector1.set_incoming_receiver(&accumulator); 87 88 PumpMessages(); 89 90 ASSERT_FALSE(accumulator.IsEmpty()); 91 92 Message message_received; 93 accumulator.Pop(&message_received); 94 95 EXPECT_EQ( 96 std::string(kText), 97 std::string(reinterpret_cast<const char*>(message_received.payload()))); 98 } 99 100 TEST_F(ConnectorTest, Basic_EarlyIncomingReceiver) { 101 internal::Connector connector0(handle0_.Pass()); 102 internal::Connector connector1(handle1_.Pass()); 103 104 MessageAccumulator accumulator; 105 connector1.set_incoming_receiver(&accumulator); 106 107 const char kText[] = "hello world"; 108 109 Message message; 110 AllocMessage(kText, &message); 111 112 connector0.Accept(&message); 113 114 PumpMessages(); 115 116 ASSERT_FALSE(accumulator.IsEmpty()); 117 118 Message message_received; 119 accumulator.Pop(&message_received); 120 121 EXPECT_EQ( 122 std::string(kText), 123 std::string(reinterpret_cast<const char*>(message_received.payload()))); 124 } 125 126 TEST_F(ConnectorTest, Basic_TwoMessages) { 127 internal::Connector connector0(handle0_.Pass()); 128 internal::Connector connector1(handle1_.Pass()); 129 130 const char* kText[] = { "hello", "world" }; 131 132 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) { 133 Message message; 134 AllocMessage(kText[i], &message); 135 136 connector0.Accept(&message); 137 } 138 139 MessageAccumulator accumulator; 140 connector1.set_incoming_receiver(&accumulator); 141 142 PumpMessages(); 143 144 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) { 145 ASSERT_FALSE(accumulator.IsEmpty()); 146 147 Message message_received; 148 accumulator.Pop(&message_received); 149 150 EXPECT_EQ( 151 std::string(kText[i]), 152 std::string(reinterpret_cast<const char*>(message_received.payload()))); 153 } 154 } 155 156 TEST_F(ConnectorTest, WriteToClosedPipe) { 157 internal::Connector connector0(handle0_.Pass()); 158 159 const char kText[] = "hello world"; 160 161 Message message; 162 AllocMessage(kText, &message); 163 164 // Close the other end of the pipe. 165 handle1_.reset(); 166 167 // Not observed yet because we haven't spun the RunLoop yet. 168 EXPECT_FALSE(connector0.encountered_error()); 169 170 // Write failures are not reported. 171 bool ok = connector0.Accept(&message); 172 EXPECT_TRUE(ok); 173 174 // Still not observed. 175 EXPECT_FALSE(connector0.encountered_error()); 176 177 // Spin the RunLoop, and then we should start observing the closed pipe. 178 PumpMessages(); 179 180 EXPECT_TRUE(connector0.encountered_error()); 181 } 182 183 TEST_F(ConnectorTest, MessageWithHandles) { 184 internal::Connector connector0(handle0_.Pass()); 185 internal::Connector connector1(handle1_.Pass()); 186 187 const char kText[] = "hello world"; 188 189 Message message1; 190 AllocMessage(kText, &message1); 191 192 MessagePipe pipe; 193 message1.mutable_handles()->push_back(pipe.handle0.release()); 194 195 connector0.Accept(&message1); 196 197 // The message should have been transferred, releasing the handles. 198 EXPECT_TRUE(message1.handles()->empty()); 199 200 MessageAccumulator accumulator; 201 connector1.set_incoming_receiver(&accumulator); 202 203 PumpMessages(); 204 205 ASSERT_FALSE(accumulator.IsEmpty()); 206 207 Message message_received; 208 accumulator.Pop(&message_received); 209 210 EXPECT_EQ( 211 std::string(kText), 212 std::string(reinterpret_cast<const char*>(message_received.payload()))); 213 ASSERT_EQ(1U, message_received.handles()->size()); 214 215 // Now send a message to the transferred handle and confirm it's sent through 216 // to the orginal pipe. 217 // TODO(vtl): Do we need a better way of "downcasting" the handle types? 218 ScopedMessagePipeHandle smph; 219 smph.reset(MessagePipeHandle(message_received.handles()->front().value())); 220 message_received.mutable_handles()->front() = Handle(); 221 // |smph| now owns this handle. 222 223 internal::Connector connector_received(smph.Pass()); 224 internal::Connector connector_original(pipe.handle1.Pass()); 225 226 Message message2; 227 AllocMessage(kText, &message2); 228 229 connector_received.Accept(&message2); 230 connector_original.set_incoming_receiver(&accumulator); 231 PumpMessages(); 232 233 ASSERT_FALSE(accumulator.IsEmpty()); 234 235 accumulator.Pop(&message_received); 236 237 EXPECT_EQ( 238 std::string(kText), 239 std::string(reinterpret_cast<const char*>(message_received.payload()))); 240 } 241 242 } // namespace 243 } // namespace test 244 } // namespace mojo 245