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