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.
8 #include "mojo/public/bindings/lib/connector.h"
9 #include "mojo/public/bindings/lib/message_queue.h"
10 #include "mojo/public/environment/environment.h"
11 #include "mojo/public/system/macros.h"
12 #include "mojo/public/utility/run_loop.h"
13 #include "testing/gtest/include/gtest/gtest.h"
18 class MessageAccumulator : public MessageReceiver {
20 MessageAccumulator() {
23 virtual bool Accept(Message* message) MOJO_OVERRIDE {
28 bool IsEmpty() const {
29 return queue_.IsEmpty();
32 void Pop(Message* message) {
37 internal::MessageQueue queue_;
40 class ConnectorTest : public testing::Test {
45 virtual void SetUp() MOJO_OVERRIDE {
46 CreateMessagePipe(&handle0_, &handle1_);
49 virtual void TearDown() MOJO_OVERRIDE {
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);
66 ScopedMessagePipeHandle handle0_;
67 ScopedMessagePipeHandle handle1_;
74 TEST_F(ConnectorTest, Basic) {
75 internal::Connector connector0(handle0_.Pass());
76 internal::Connector connector1(handle1_.Pass());
78 const char kText[] = "hello world";
81 AllocMessage(kText, &message);
83 connector0.Accept(&message);
85 MessageAccumulator accumulator;
86 connector1.set_incoming_receiver(&accumulator);
90 ASSERT_FALSE(accumulator.IsEmpty());
92 Message message_received;
93 accumulator.Pop(&message_received);
95 EXPECT_EQ(std::string(kText),
97 reinterpret_cast<char*>(message_received.data->payload)));
100 TEST_F(ConnectorTest, Basic_EarlyIncomingReceiver) {
101 internal::Connector connector0(handle0_.Pass());
102 internal::Connector connector1(handle1_.Pass());
104 MessageAccumulator accumulator;
105 connector1.set_incoming_receiver(&accumulator);
107 const char kText[] = "hello world";
110 AllocMessage(kText, &message);
112 connector0.Accept(&message);
116 ASSERT_FALSE(accumulator.IsEmpty());
118 Message message_received;
119 accumulator.Pop(&message_received);
121 EXPECT_EQ(std::string(kText),
123 reinterpret_cast<char*>(message_received.data->payload)));
126 TEST_F(ConnectorTest, Basic_TwoMessages) {
127 internal::Connector connector0(handle0_.Pass());
128 internal::Connector connector1(handle1_.Pass());
130 const char* kText[] = { "hello", "world" };
132 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
134 AllocMessage(kText[i], &message);
136 connector0.Accept(&message);
139 MessageAccumulator accumulator;
140 connector1.set_incoming_receiver(&accumulator);
144 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
145 ASSERT_FALSE(accumulator.IsEmpty());
147 Message message_received;
148 accumulator.Pop(&message_received);
150 EXPECT_EQ(std::string(kText[i]),
152 reinterpret_cast<char*>(message_received.data->payload)));
156 TEST_F(ConnectorTest, WriteToClosedPipe) {
157 internal::Connector connector0(handle0_.Pass());
159 const char kText[] = "hello world";
162 AllocMessage(kText, &message);
164 // Close the other end of the pipe.
167 // Not observed yet because we haven't spun the RunLoop yet.
168 EXPECT_FALSE(connector0.encountered_error());
170 // Write failures are not reported.
171 bool ok = connector0.Accept(&message);
174 // Still not observed.
175 EXPECT_FALSE(connector0.encountered_error());
177 // Spin the RunLoop, and then we should start observing the closed pipe.
180 EXPECT_TRUE(connector0.encountered_error());
183 // Enable this test once MojoWriteMessage supports passing handles.
184 TEST_F(ConnectorTest, MessageWithHandles) {
185 internal::Connector connector0(handle0_.Pass());
186 internal::Connector connector1(handle1_.Pass());
188 const char kText[] = "hello world";
191 AllocMessage(kText, &message);
193 ScopedMessagePipeHandle handles[2];
194 CreateMessagePipe(&handles[0], &handles[1]);
195 message.handles.push_back(handles[0].release());
197 connector0.Accept(&message);
199 // The message should have been transferred, releasing the handles.
200 EXPECT_TRUE(message.handles.empty());
202 MessageAccumulator accumulator;
203 connector1.set_incoming_receiver(&accumulator);
207 ASSERT_FALSE(accumulator.IsEmpty());
209 Message message_received;
210 accumulator.Pop(&message_received);
212 EXPECT_EQ(std::string(kText),
214 reinterpret_cast<char*>(message_received.data->payload)));
215 ASSERT_EQ(1U, message_received.handles.size());
217 // Now send a message to the transferred handle and confirm it's sent through
218 // to the orginal pipe.
219 // TODO(vtl): Do we need a better way of "downcasting" the handle types?
220 ScopedMessagePipeHandle smph;
221 smph.reset(MessagePipeHandle(message_received.handles[0].value()));
222 message_received.handles[0] = Handle(); // |smph| now owns this handle.
224 internal::Connector connector_received(smph.Pass());
225 internal::Connector connector_original(handles[1].Pass());
227 AllocMessage(kText, &message);
229 connector_received.Accept(&message);
230 connector_original.set_incoming_receiver(&accumulator);
233 ASSERT_FALSE(accumulator.IsEmpty());
235 accumulator.Pop(&message_received);
237 EXPECT_EQ(std::string(kText),
239 reinterpret_cast<char*>(message_received.data->payload)));