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