1 // Copyright 2014 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.
9 #include <sys/select.h>
14 #include "dev_fs_for_testing.h"
15 #include "fake_ppapi/fake_messaging_interface.h"
16 #include "gtest/gtest.h"
17 #include "nacl_io/devfs/dev_fs.h"
18 #include "nacl_io/filesystem.h"
19 #include "nacl_io/ioctl.h"
20 #include "nacl_io/kernel_intercept.h"
21 #include "nacl_io/kernel_proxy.h"
22 #include "nacl_io/osdirent.h"
24 using namespace nacl_io;
28 class JSPipeTest : public ::testing::Test {
32 ASSERT_EQ(0, fs_.Access(Path("/jspipe1"), R_OK | W_OK));
33 ASSERT_EQ(EACCES, fs_.Access(Path("/jspipe1"), X_OK));
34 ASSERT_EQ(0, fs_.Open(Path("/jspipe1"), O_RDWR, &pipe_dev_));
35 ASSERT_NE(NULL_NODE, pipe_dev_.get());
38 void TearDown() { ki_uninit(); }
46 TEST_F(JSPipeTest, InvalidIoctl) {
47 // 123 is not a valid ioctl request.
48 EXPECT_EQ(EINVAL, pipe_dev_->Ioctl(123));
51 TEST_F(JSPipeTest, JSPipeInput) {
52 // First we send some data into the pipe. This is how messages
53 // from javascript are injected into the pipe nodes.
54 std::string message("hello, how are you?\n");
55 struct tioc_nacl_input_string packaged_message;
56 packaged_message.length = message.size();
57 packaged_message.buffer = message.data();
58 ASSERT_EQ(0, pipe_dev_->Ioctl(TIOCNACLINPUT, &packaged_message));
60 // Now we make buffer we'll read into.
61 // We fill the buffer and a backup buffer with arbitrary data
62 // and compare them after reading to make sure read doesn't
63 // clobber parts of the buffer it shouldn't.
66 char backup_buffer[100];
67 memset(buffer, 'a', sizeof(buffer));
68 memset(backup_buffer, 'a', sizeof(backup_buffer));
70 // We read a small chunk first to ensure it doesn't give us
71 // more than we ask for.
73 ASSERT_EQ(0, pipe_dev_->Read(attrs, buffer, 5, &bytes_read));
74 EXPECT_EQ(5, bytes_read);
75 EXPECT_EQ(0, memcmp(message.data(), buffer, 5));
76 EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, sizeof(buffer)-5));
78 // Now we ask for more data than is left in the pipe, to ensure
79 // it doesn't give us more than there is.
80 ASSERT_EQ(0, pipe_dev_->Read(attrs, buffer + 5, sizeof(buffer)-5,
82 EXPECT_EQ(bytes_read, message.size() - 5);
83 EXPECT_EQ(0, memcmp(message.data(), buffer, message.size()));
84 EXPECT_EQ(0, memcmp(buffer + message.size(),
85 backup_buffer + message.size(),
86 100 - message.size()));
89 TEST_F(JSPipeTest, JSPipeOutput) {
90 const char* message = "hello";
91 const int message_len = strlen(message);
93 int bytes_written = 999;
95 ASSERT_EQ(0, pipe_dev_->Write(attrs, message, message_len, &bytes_written));
96 ASSERT_EQ(message_len, bytes_written);
98 // Verify that the correct messages was sent via PostMessage.
99 FakeMessagingInterface* iface =
100 (FakeMessagingInterface*)fs_.ppapi()->GetMessagingInterface();
101 VarArrayInterface* array_iface = fs_.ppapi()->GetVarArrayInterface();
102 VarInterface* var_iface = fs_.ppapi()->GetVarInterface();
103 VarArrayBufferInterface* buffer_iface =
104 fs_.ppapi()->GetVarArrayBufferInterface();
106 // Verify that exaclty one message was sent of type PP_VARTYPE_ARRAY
107 ASSERT_EQ(1, iface->messages.size());
108 PP_Var array = iface->messages[0];
109 ASSERT_EQ(PP_VARTYPE_ARRAY, array.type);
111 // Verify that the array contains two element, the prefix,
112 // and an ArrayBuffer containing the message.
113 ASSERT_EQ(2, array_iface->GetLength(array));
114 PP_Var item0 = array_iface->Get(array, 0);
115 PP_Var item1 = array_iface->Get(array, 1);
116 ASSERT_EQ(PP_VARTYPE_STRING, item0.type);
117 ASSERT_EQ(PP_VARTYPE_ARRAY_BUFFER, item1.type);
119 const char* item0_string = var_iface->VarToUtf8(item0, &len);
120 ASSERT_STREQ("jspipe1", std::string(item0_string, len).c_str());
121 ASSERT_EQ(0, memcmp(message, buffer_iface->Map(item1), strlen(message)));
122 var_iface->Release(item0);
123 var_iface->Release(item1);
126 TEST_F(JSPipeTest, JSPipeOutputWithNulls) {
128 int message_len = sizeof(message);
130 // Construct a 20-byte message containing the string 'hello' but with
131 // null chars on either end.
132 memset(message, 0 , message_len);
133 memcpy(message+10, "hello", 5);
135 int bytes_written = 999;
137 EXPECT_EQ(0, pipe_dev_->Write(attrs, message, message_len, &bytes_written));
138 EXPECT_EQ(message_len, bytes_written);
140 // Verify that the correct messages was sent via PostMessage.
141 FakeMessagingInterface* iface =
142 (FakeMessagingInterface*)fs_.ppapi()->GetMessagingInterface();
143 VarArrayInterface* array_iface = fs_.ppapi()->GetVarArrayInterface();
144 VarInterface* var_iface = fs_.ppapi()->GetVarInterface();
145 VarArrayBufferInterface* buffer_iface =
146 fs_.ppapi()->GetVarArrayBufferInterface();
148 // Verify that exactly one message was sent of type PP_VARTYPE_ARRAY
149 EXPECT_EQ(1, iface->messages.size());
150 PP_Var array = iface->messages[0];
151 ASSERT_EQ(PP_VARTYPE_ARRAY, array.type);
153 // Verify that the array contains two element, the prefix,
154 // and an ArrayBuffer containing the message.
155 ASSERT_EQ(2, array_iface->GetLength(array));
156 PP_Var item0 = array_iface->Get(array, 0);
157 PP_Var item1 = array_iface->Get(array, 1);
158 ASSERT_EQ(PP_VARTYPE_STRING, item0.type);
159 ASSERT_EQ(PP_VARTYPE_ARRAY_BUFFER, item1.type);
161 ASSERT_STREQ("jspipe1", var_iface->VarToUtf8(item0, &len));
162 ASSERT_EQ(0, memcmp(message, buffer_iface->Map(item1), strlen(message)));
163 var_iface->Release(item0);
164 var_iface->Release(item1);
167 static int ki_ioctl_wrapper(int fd, int request, ...) {
169 va_start(ap, request);
170 int rtn = ki_ioctl(fd, request, ap);
175 static int JSPipeWrite(int fd, const char* string) {
176 struct tioc_nacl_input_string input;
177 input.buffer = string;
178 input.length = strlen(input.buffer);
179 return ki_ioctl_wrapper(fd, TIOCNACLINPUT, &input);
185 // -1 -> Error occured
186 static int IsReadable(int fd) {
187 struct timeval timeout = {0, 0};
192 FD_SET(fd, &readfds);
193 FD_SET(fd, &errorfds);
194 int rtn = ki_select(fd + 1, &readfds, NULL, &errorfds, &timeout);
196 return 0; // not readable
199 if (FD_ISSET(fd, &errorfds))
201 if (!FD_ISSET(fd, &readfds))
203 return 1; // readable
206 TEST_F(JSPipeTest, JSPipeSelect) {
207 struct timeval timeout;
212 int pipe_fd = ki_open("/dev/jspipe1", O_RDONLY);
213 ASSERT_GT(pipe_fd, 0) << "jspipe1 open failed: " << errno;
217 FD_SET(pipe_fd, &readfds);
218 FD_SET(pipe_fd, &errorfds);
219 // 10 millisecond timeout
221 timeout.tv_usec = 10 * 1000;
222 // Should timeout when no input is available.
223 int rtn = ki_select(pipe_fd + 1, &readfds, NULL, &errorfds, &timeout);
224 ASSERT_EQ(0, rtn) << "select failed: " << rtn << " err=" << strerror(errno);
225 ASSERT_FALSE(FD_ISSET(pipe_fd, &readfds));
226 ASSERT_FALSE(FD_ISSET(pipe_fd, &errorfds));
231 FD_SET(pipe_fd, &readfds);
232 FD_SET(pipe_fd, &writefds);
233 FD_SET(pipe_fd, &errorfds);
234 // Pipe should be writable on startup.
235 rtn = ki_select(pipe_fd + 1, &readfds, &writefds, &errorfds, NULL);
237 ASSERT_TRUE(FD_ISSET(pipe_fd, &writefds));
238 ASSERT_FALSE(FD_ISSET(pipe_fd, &readfds));
239 ASSERT_FALSE(FD_ISSET(pipe_fd, &errorfds));
241 // Send 4 bytes to the pipe
242 ASSERT_EQ(0, JSPipeWrite(pipe_fd, "test"));
244 // Pipe should now be readable
245 ASSERT_EQ(1, IsReadable(pipe_fd));