Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: chrome/nacl/nacl_ipc_adapter_unittest.cc

Issue 9863005: Initial implementation of an IPC adapter to expose Chrome IPC to Native Client. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/nacl/nacl_ipc_adapter.h"
6
7 #include <string.h>
8
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop.h"
11 #include "base/message_loop_proxy.h"
12 #include "base/threading/platform_thread.h"
13 #include "base/threading/simple_thread.h"
14 #include "ipc/ipc_test_sink.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace {
18
19 class NaClIPCAdapterTest : public testing::Test {
20 public:
21 NaClIPCAdapterTest() {}
22
23 // testing::Test implementation.
24 virtual void SetUp() OVERRIDE {
25 sink_ = new IPC::TestSink;
26
27 // Takes ownership of the sink_ pointer.
28 adapter_ = new NaClIPCAdapter(scoped_ptr<IPC::Channel>(sink_),
29 base::MessageLoopProxy::current());
30 }
31 virtual void TearDown() OVERRIDE {
32 sink_ = NULL; // This pointer is actually owned by the IPCAdapter.
33 adapter_ = NULL;
34 }
35
36 protected:
37 MessageLoop message_loop_;
38
39 scoped_refptr<NaClIPCAdapter> adapter_;
40
41 // Messages sent from nacl to the adapter end up here. Note that we create
42 // this pointer and pass ownership of it to the IPC adapter, who will keep
43 // it alive as long as the adapter is alive. This means that when the
44 // adapter goes away, this pointer will become invalid.
45 //
46 // In real life the adapter needs to take ownership so the channel can be
47 // destroyed on the right thread.
48 IPC::TestSink* sink_;
49 };
50
51 } // namespace
52
53 // Tests a simple message getting rewritten sent from native code to NaCl.
54 TEST_F(NaClIPCAdapterTest, SimpleReceiveRewriting) {
55 int routing_id = 0x89898989;
56 int type = 0x55555555;
57 IPC::Message input(routing_id, type, IPC::Message::PRIORITY_NORMAL);
58
59 int value = 0x12345678;
60 input.WriteInt(value);
61 adapter_->OnMessageReceived(input);
62
63 // Buffer just need to be big enough for our message with one int.
64 const int kBufSize = 64;
65 char buf[kBufSize];
66
67 int bytes_read = adapter_->BlockingReceive(buf, kBufSize);
68 EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int),
69 bytes_read);
70
71 const NaClIPCAdapter::NaClMessageHeader* output_header =
72 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf);
73 EXPECT_EQ(sizeof(int), output_header->payload_size);
74 EXPECT_EQ(routing_id, output_header->routing);
75 EXPECT_EQ(type, output_header->type);
76 EXPECT_EQ(IPC::Message::PRIORITY_NORMAL, output_header->flags);
77 EXPECT_EQ(0, output_header->num_fds);
78 EXPECT_EQ(0, output_header->pad);
79
80 // Validate the payload.
81 EXPECT_EQ(value,
82 *reinterpret_cast<const int*>(&buf[
83 sizeof(NaClIPCAdapter::NaClMessageHeader)]));
84 }
85
86 // Tests a simple message getting rewritten sent from NaCl to native code.
87 TEST_F(NaClIPCAdapterTest, SendRewriting) {
88 int routing_id = 0x89898989;
89 int type = 0x55555555;
90 int value = 0x12345678;
91
92 // Send a message with one int inside it.
93 const int buf_size = sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int);
94 char buf[buf_size] = {0};
95
96 NaClIPCAdapter::NaClMessageHeader* header =
97 reinterpret_cast<NaClIPCAdapter::NaClMessageHeader*>(buf);
98 header->payload_size = sizeof(int);
99 header->routing = routing_id;
100 header->type = type;
101 header->flags = 0;
102 header->num_fds = 0;
103 *reinterpret_cast<int*>(
104 &buf[sizeof(NaClIPCAdapter::NaClMessageHeader)]) = value;
105
106 int result = adapter_->Send(buf, buf_size);
107 EXPECT_EQ(buf_size, result);
108
109 // Check that the message came out the other end in the test sink
110 // (messages are posted to we have to pump).
111 message_loop_.RunAllPending();
112 ASSERT_EQ(1, sink_->message_count());
113 const IPC::Message* msg = sink_->GetMessageAt(0);
114
115 EXPECT_EQ(sizeof(int), msg->payload_size());
116 EXPECT_EQ(header->routing, msg->routing_id());
117 EXPECT_EQ(header->type, msg->type());
118
119 // Now test the partial send case. We should be able to break the message
120 // into two parts and it should still work.
121 sink_->ClearMessages();
122 int first_chunk_size = 7;
123 result = adapter_->Send(buf, first_chunk_size);
124 EXPECT_EQ(first_chunk_size, result);
125
126 // First partial send should not have made any messages.
127 message_loop_.RunAllPending();
128 ASSERT_EQ(0, sink_->message_count());
129
130 // Second partial send should do the same.
131 int second_chunk_size = 2;
132 result = adapter_->Send(&buf[first_chunk_size], second_chunk_size);
133 EXPECT_EQ(second_chunk_size, result);
134 message_loop_.RunAllPending();
135 ASSERT_EQ(0, sink_->message_count());
136
137 // Send the rest of the message in a third chunk.
138 int third_chunk_size = buf_size - first_chunk_size - second_chunk_size;
139 result = adapter_->Send(&buf[first_chunk_size + second_chunk_size],
140 third_chunk_size);
141 EXPECT_EQ(third_chunk_size, result);
142
143 // Last send should have generated one message.
144 message_loop_.RunAllPending();
145 ASSERT_EQ(1, sink_->message_count());
146 msg = sink_->GetMessageAt(0);
147 EXPECT_EQ(sizeof(int), msg->payload_size());
148 EXPECT_EQ(header->routing, msg->routing_id());
149 EXPECT_EQ(header->type, msg->type());
150 }
151
152 // Tests when a buffer is too small to receive the entire message.
153 TEST_F(NaClIPCAdapterTest, PartialReceive) {
154 int routing_id_1 = 0x89898989;
155 int type_1 = 0x55555555;
156 IPC::Message input_1(routing_id_1, type_1, IPC::Message::PRIORITY_NORMAL);
157 int value_1 = 0x12121212;
158 input_1.WriteInt(value_1);
159 adapter_->OnMessageReceived(input_1);
160
161 int routing_id_2 = 0x90909090;
162 int type_2 = 0x66666666;
163 IPC::Message input_2(routing_id_2, type_2, IPC::Message::PRIORITY_NORMAL);
164 int value_2 = 0x23232323;
165 input_2.WriteInt(value_2);
166 adapter_->OnMessageReceived(input_2);
167
168 const int kBufSize = 64;
169 char buf[kBufSize];
170
171 // Read part of the first message.
172 int bytes_requested = 7;
173 int bytes_read = adapter_->BlockingReceive(buf, bytes_requested);
174 ASSERT_EQ(bytes_requested, bytes_read);
175
176 // Read the rest, this should give us the rest of the first message only.
177 bytes_read += adapter_->BlockingReceive(&buf[bytes_requested],
178 kBufSize - bytes_requested);
179 EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int),
180 bytes_read);
181
182 // Make sure we got the right message.
183 const NaClIPCAdapter::NaClMessageHeader* output_header =
184 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf);
185 EXPECT_EQ(sizeof(int), output_header->payload_size);
186 EXPECT_EQ(routing_id_1, output_header->routing);
187 EXPECT_EQ(type_1, output_header->type);
188
189 // Read the second message to make sure we went on to it.
190 bytes_read = adapter_->BlockingReceive(buf, kBufSize);
191 EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int),
192 bytes_read);
193 output_header =
194 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf);
195 EXPECT_EQ(sizeof(int), output_header->payload_size);
196 EXPECT_EQ(routing_id_2, output_header->routing);
197 EXPECT_EQ(type_2, output_header->type);
198 }
199
200 // Tests sending messages that are too large. We test sends that are too
201 // small implicitly here and in the success case because in that case it
202 // succeeds and buffers the data.
203 TEST_F(NaClIPCAdapterTest, SendOverflow) {
204 int routing_id = 0x89898989;
205 int type = 0x55555555;
206 int value = 0x12345678;
207
208 // Make a message with one int inside it. Reserve some extra space so
209 // we can test what happens when we send too much data.
210 const int buf_size = sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int);
211 const int big_buf_size = buf_size + 4;
212 char buf[big_buf_size] = {0};
213
214 NaClIPCAdapter::NaClMessageHeader* header =
215 reinterpret_cast<NaClIPCAdapter::NaClMessageHeader*>(buf);
216 header->payload_size = sizeof(int);
217 header->routing = routing_id;
218 header->type = type;
219 header->flags = 0;
220 header->num_fds = 0;
221 *reinterpret_cast<int*>(
222 &buf[sizeof(NaClIPCAdapter::NaClMessageHeader)]) = value;
223
224 // Send too much data and make sure that the send fails.
225 int result = adapter_->Send(buf, big_buf_size);
226 EXPECT_EQ(-1, result);
227 message_loop_.RunAllPending();
228 ASSERT_EQ(0, sink_->message_count());
229
230 // Send too much data in two chunks and make sure that the send fails.
231 int first_chunk_size = 7;
232 result = adapter_->Send(buf, first_chunk_size);
233 EXPECT_EQ(first_chunk_size, result);
234
235 // First partial send should not have made any messages.
236 message_loop_.RunAllPending();
237 ASSERT_EQ(0, sink_->message_count());
238
239 int second_chunk_size = big_buf_size - first_chunk_size;
240 result = adapter_->Send(&buf[first_chunk_size], second_chunk_size);
241 EXPECT_EQ(-1, result);
242 message_loop_.RunAllPending();
243 ASSERT_EQ(0, sink_->message_count());
244 }
245
246 // Tests that when the IPC channel reports an error, that waiting reads are
247 // unblocked and return a -1 error code.
248 TEST_F(NaClIPCAdapterTest, ReadWithChannelError) {
249 // Have a background thread that waits a bit and calls the channel error
250 // handler. This should wake up any waiting threads and immediately return
251 // -1. There is an inherent race condition in that we can't be sure if the
252 // other thread is actually waiting when this happens. This is OK, since the
253 // behavior (which we also explicitly test later) is to return -1 if the
254 // channel has already had an error when you start waiting.
255 class MyThread : public base::SimpleThread {
256 public:
257 explicit MyThread(NaClIPCAdapter* adapter)
258 : SimpleThread("NaClIPCAdapterThread"),
259 adapter_(adapter) {}
260 virtual void Run() {
261 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
262 adapter_->OnChannelError();
263 }
264 private:
265 scoped_refptr<NaClIPCAdapter> adapter_;
266 };
267 MyThread thread(adapter_);
268
269 // IMPORTANT: do not return early from here down (including ASSERT_*) because
270 // the thread needs to joined or it will assert.
271 thread.Start();
272
273 // Request data. This will normally (modulo races) block until data is
274 // received or there is an error, and the thread above will wake us up
275 // after 1s.
276 const int kBufSize = 64;
277 char buf[kBufSize];
278 int result = adapter_->BlockingReceive(buf, kBufSize);
279 EXPECT_EQ(-1, result);
280
281 // Test the "previously had an error" case. BlockingReceive should return
282 // immediately if there was an error.
283 result = adapter_->BlockingReceive(buf, kBufSize);
284 EXPECT_EQ(-1, result);
285
286 thread.Join();
287 }
288
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698