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 235