1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdlib.h>
#include <string.h>
#include "mojo/public/bindings/lib/message_builder.h"
#include "mojo/public/bindings/lib/message_queue.h"
#include "mojo/public/bindings/lib/router.h"
#include "mojo/public/cpp/environment/environment.h"
#include "mojo/public/cpp/system/macros.h"
#include "mojo/public/cpp/utility/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace test {
namespace {
void AllocRequestMessage(uint32_t name, const char* text, Message* message) {
size_t payload_size = strlen(text) + 1; // Plus null terminator.
internal::RequestMessageBuilder builder(name, payload_size);
memcpy(builder.buffer()->Allocate(payload_size), text, payload_size);
builder.Finish(message);
}
void AllocResponseMessage(uint32_t name, const char* text,
uint64_t request_id, Message* message) {
size_t payload_size = strlen(text) + 1; // Plus null terminator.
internal::ResponseMessageBuilder builder(name, payload_size, request_id);
memcpy(builder.buffer()->Allocate(payload_size), text, payload_size);
builder.Finish(message);
}
class MessageAccumulator : public MessageReceiver {
public:
explicit MessageAccumulator(internal::MessageQueue* queue) : queue_(queue) {
}
virtual bool Accept(Message* message) MOJO_OVERRIDE {
queue_->Push(message);
return true;
}
virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder)
MOJO_OVERRIDE {
return false;
}
private:
internal::MessageQueue* queue_;
};
class ResponseGenerator : public MessageReceiver {
public:
ResponseGenerator() {
}
virtual bool Accept(Message* message) MOJO_OVERRIDE {
return false;
}
virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder)
MOJO_OVERRIDE {
EXPECT_TRUE(message->has_flag(internal::kMessageExpectsResponse));
return SendResponse(message->name(), message->request_id(), responder);
}
bool SendResponse(uint32_t name, uint64_t request_id,
MessageReceiver* responder) {
Message response;
AllocResponseMessage(name, "world", request_id, &response);
bool result = responder->Accept(&response);
delete responder;
return result;
}
};
class LazyResponseGenerator : public ResponseGenerator {
public:
LazyResponseGenerator() : responder_(NULL), name_(0), request_id_(0) {
}
virtual ~LazyResponseGenerator() {
delete responder_;
}
virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder)
MOJO_OVERRIDE {
name_ = message->name();
request_id_ = message->request_id();
responder_ = responder;
return true;
}
bool has_responder() const { return !!responder_; }
void Complete() {
SendResponse(name_, request_id_, responder_);
responder_ = NULL;
}
private:
MessageReceiver* responder_;
uint32_t name_;
uint32_t request_id_;
};
class RouterTest : public testing::Test {
public:
RouterTest() {
}
virtual void SetUp() MOJO_OVERRIDE {
CreateMessagePipe(&handle0_, &handle1_);
}
virtual void TearDown() MOJO_OVERRIDE {
}
void PumpMessages() {
loop_.RunUntilIdle();
}
protected:
ScopedMessagePipeHandle handle0_;
ScopedMessagePipeHandle handle1_;
private:
Environment env_;
RunLoop loop_;
};
TEST_F(RouterTest, BasicRequestResponse) {
internal::Router router0(handle0_.Pass());
internal::Router router1(handle1_.Pass());
ResponseGenerator generator;
router1.set_incoming_receiver(&generator);
Message request;
AllocRequestMessage(1, "hello", &request);
internal::MessageQueue message_queue;
router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
PumpMessages();
EXPECT_FALSE(message_queue.IsEmpty());
Message response;
message_queue.Pop(&response);
EXPECT_EQ(std::string("world"),
std::string(reinterpret_cast<const char*>(response.payload())));
}
TEST_F(RouterTest, RequestWithNoReceiver) {
internal::Router router0(handle0_.Pass());
internal::Router router1(handle1_.Pass());
// Without an incoming receiver set on router1, we expect router0 to observe
// an error as a result of sending a message.
Message request;
AllocRequestMessage(1, "hello", &request);
internal::MessageQueue message_queue;
router0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
PumpMessages();
EXPECT_TRUE(router0.encountered_error());
EXPECT_TRUE(router1.encountered_error());
EXPECT_TRUE(message_queue.IsEmpty());
}
TEST_F(RouterTest, LateResponse) {
// Test that things won't blow up if we try to send a message to a
// MessageReceiver, which was given to us via AcceptWithResponder,
// after the router has gone away.
LazyResponseGenerator generator;
{
internal::Router router0(handle0_.Pass());
internal::Router router1(handle1_.Pass());
router1.set_incoming_receiver(&generator);
Message request;
AllocRequestMessage(1, "hello", &request);
internal::MessageQueue message_queue;
router0.AcceptWithResponder(&request,
new MessageAccumulator(&message_queue));
PumpMessages();
EXPECT_TRUE(generator.has_responder());
}
generator.Complete(); // This should end up doing nothing.
}
} // namespace
} // namespace test
} // namespace mojo
|