Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / native_client_sdk / src / tests / nacl_io_test / kernel_proxy_test.cc
bloba84442c73c64acfc6869e421e4cac853d2ae1b42
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.
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <pthread.h>
8 #include <stdio.h>
9 #include <sys/stat.h>
11 #include <map>
12 #include <string>
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
17 #include "mock_fs.h"
18 #include "mock_node.h"
20 #include "nacl_io/filesystem.h"
21 #include "nacl_io/kernel_intercept.h"
22 #include "nacl_io/kernel_proxy.h"
23 #include "nacl_io/memfs/mem_fs.h"
24 #include "nacl_io/osmman.h"
25 #include "nacl_io/path.h"
26 #include "nacl_io/typed_fs_factory.h"
28 using namespace nacl_io;
29 using namespace sdk_util;
31 using ::testing::_;
32 using ::testing::DoAll;
33 using ::testing::Invoke;
34 using ::testing::Return;
35 using ::testing::SaveArg;
36 using ::testing::SetArgPointee;
37 using ::testing::StrEq;
38 using ::testing::WithArgs;
40 namespace {
42 class KernelProxyTest_KernelProxy : public KernelProxy {
43 public:
44 Filesystem* RootFs() {
45 ScopedFilesystem fs;
46 Path path;
48 AcquireFsAndRelPath("/", &fs, &path);
49 return fs.get();
53 class KernelProxyTest : public ::testing::Test {
54 public:
55 KernelProxyTest() {}
57 void SetUp() {
58 ASSERT_EQ(0, ki_push_state_for_testing());
59 ASSERT_EQ(0, ki_init(&kp_));
60 // Unmount the passthrough FS and mount a memfs.
61 EXPECT_EQ(0, kp_.umount("/"));
62 EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL));
65 void TearDown() { ki_uninit(); }
67 protected:
68 KernelProxyTest_KernelProxy kp_;
71 } // namespace
73 static int ki_fcntl_wrapper(int fd, int request, ...) {
74 va_list ap;
75 va_start(ap, request);
76 int rtn = ki_fcntl(fd, request, ap);
77 va_end(ap);
78 return rtn;
81 /**
82 * Test for fcntl commands F_SETFD and F_GETFD. This
83 * is tested here rather than in the mount_node tests
84 * since the fd flags are not stored in the kernel_handle
85 * or the filesystem node but directly in the FD mapping.
87 TEST_F(KernelProxyTest, Fcntl_GETFD) {
88 int fd = ki_open("/test", O_RDWR | O_CREAT);
89 ASSERT_NE(-1, fd);
91 // FD flags should start as zero.
92 ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD));
94 // Check that setting FD_CLOEXEC works
95 int flags = FD_CLOEXEC;
96 ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags))
97 << "fcntl failed with: " << strerror(errno);
98 ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD));
100 // Check that setting invalid flag causes EINVAL
101 flags = FD_CLOEXEC + 1;
102 ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags));
103 ASSERT_EQ(EINVAL, errno);
106 TEST_F(KernelProxyTest, FileLeak) {
107 const size_t buffer_size = 1024;
108 char filename[128];
109 int garbage[buffer_size];
111 MemFs* filesystem = (MemFs*)kp_.RootFs();
112 ScopedNode root;
114 ASSERT_EQ(0, filesystem->Open(Path("/"), O_RDONLY, &root));
115 ASSERT_EQ(0, root->ChildCount());
117 for (int file_num = 0; file_num < 4096; file_num++) {
118 sprintf(filename, "/foo%i.tmp", file_num++);
119 int fd = ki_open(filename, O_WRONLY | O_CREAT);
120 ASSERT_GT(fd, -1);
121 ASSERT_EQ(1, root->ChildCount());
122 ASSERT_EQ(buffer_size, ki_write(fd, garbage, buffer_size));
123 ki_close(fd);
124 ASSERT_EQ(0, ki_remove(filename));
126 ASSERT_EQ(0, root->ChildCount());
129 static bool g_handler_called = false;
130 static void sighandler(int) { g_handler_called = true; }
132 TEST_F(KernelProxyTest, Sigaction) {
133 struct sigaction action;
134 struct sigaction oaction;
135 memset(&action, 0, sizeof(action));
137 // Invalid signum
138 ASSERT_EQ(-1, ki_sigaction(-1, NULL, &oaction));
139 ASSERT_EQ(-1, ki_sigaction(SIGSTOP, NULL, &oaction));
140 ASSERT_EQ(EINVAL, errno);
142 // Get existing handler
143 memset(&oaction, 0, sizeof(oaction));
144 ASSERT_EQ(0, ki_sigaction(SIGINT, NULL, &oaction));
145 ASSERT_EQ(SIG_DFL, oaction.sa_handler);
147 // Attempt to set handler for unsupported signum
148 action.sa_handler = sighandler;
149 ASSERT_EQ(-1, ki_sigaction(SIGINT, &action, NULL));
150 ASSERT_EQ(EINVAL, errno);
152 // Attempt to set handler for supported signum
153 action.sa_handler = sighandler;
154 ASSERT_EQ(0, ki_sigaction(SIGWINCH, &action, NULL));
156 memset(&oaction, 0, sizeof(oaction));
157 ASSERT_EQ(0, ki_sigaction(SIGWINCH, NULL, &oaction));
158 ASSERT_EQ((sighandler_t*)sighandler, (sighandler_t*)oaction.sa_handler);
161 TEST_F(KernelProxyTest, KillSignals) {
162 // SIGSEGV can't be sent via kill(2)
163 ASSERT_EQ(-1, ki_kill(0, SIGSEGV)) << "kill(SEGV) failed to return an error";
164 ASSERT_EQ(EINVAL, errno) << "kill(SEGV) failed to set errno to EINVAL";
166 // Our implemenation should understand SIGWINCH
167 ASSERT_EQ(0, ki_kill(0, SIGWINCH)) << "kill(SIGWINCH) failed: " << errno;
169 // And USR1/USR2
170 ASSERT_EQ(0, ki_kill(0, SIGUSR1)) << "kill(SIGUSR1) failed: " << errno;
171 ASSERT_EQ(0, ki_kill(0, SIGUSR2)) << "kill(SIGUSR2) failed: " << errno;
174 TEST_F(KernelProxyTest, KillPIDValues) {
175 // Any PID other than 0, -1 and getpid() should yield ESRCH
176 // since there is only one valid process under NaCl
177 int mypid = getpid();
178 ASSERT_EQ(0, ki_kill(0, SIGWINCH));
179 ASSERT_EQ(0, ki_kill(-1, SIGWINCH));
180 ASSERT_EQ(0, ki_kill(mypid, SIGWINCH));
182 // Don't use mypid + 1 since getpid() actually returns -1
183 // when the IRT interface is missing (e.g. within chrome),
184 // and 0 is always a valid PID when calling kill().
185 int invalid_pid = mypid + 10;
186 ASSERT_EQ(-1, ki_kill(invalid_pid, SIGWINCH));
187 ASSERT_EQ(ESRCH, errno);
190 TEST_F(KernelProxyTest, SignalValues) {
191 ASSERT_EQ(ki_signal(SIGSEGV, sighandler), SIG_ERR)
192 << "registering SEGV handler didn't fail";
193 ASSERT_EQ(errno, EINVAL) << "signal(SEGV) failed to set errno to EINVAL";
195 ASSERT_EQ(ki_signal(-1, sighandler), SIG_ERR)
196 << "registering handler for invalid signal didn't fail";
197 ASSERT_EQ(errno, EINVAL) << "signal(-1) failed to set errno to EINVAL";
200 TEST_F(KernelProxyTest, SignalHandlerValues) {
201 // Unsupported signal.
202 ASSERT_NE(SIG_ERR, ki_signal(SIGSEGV, SIG_DFL));
203 ASSERT_EQ(SIG_ERR, ki_signal(SIGSEGV, SIG_IGN));
204 ASSERT_EQ(SIG_ERR, ki_signal(SIGSEGV, sighandler));
206 // Supported signal.
207 ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, SIG_DFL));
208 ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, SIG_IGN));
209 ASSERT_NE(SIG_ERR, ki_signal(SIGWINCH, sighandler));
212 TEST_F(KernelProxyTest, SignalSigwinch) {
213 g_handler_called = false;
215 // Register WINCH handler
216 sighandler_t newsig = sighandler;
217 sighandler_t oldsig = ki_signal(SIGWINCH, newsig);
218 ASSERT_NE(oldsig, SIG_ERR);
220 // Send signal.
221 ki_kill(0, SIGWINCH);
223 // Verify that handler was called
224 EXPECT_TRUE(g_handler_called);
226 // Restore existing handler
227 oldsig = ki_signal(SIGWINCH, oldsig);
229 // Verify the our newsig was returned as previous handler
230 ASSERT_EQ(oldsig, newsig);
233 TEST_F(KernelProxyTest, Rename) {
234 // Create a dummy file
235 int file1 = ki_open("/test1.txt", O_RDWR | O_CREAT);
236 ASSERT_GT(file1, -1);
237 ASSERT_EQ(0, ki_close(file1));
239 // Test the renaming works
240 ASSERT_EQ(0, ki_rename("/test1.txt", "/test2.txt"));
242 // Test that renaming across mount points fails
243 ASSERT_EQ(0, ki_mount("", "/foo", "memfs", 0, ""));
244 ASSERT_EQ(-1, ki_rename("/test2.txt", "/foo/test2.txt"));
245 ASSERT_EQ(EXDEV, errno);
248 TEST_F(KernelProxyTest, WorkingDirectory) {
249 char text[1024];
251 text[0] = 0;
252 ki_getcwd(text, sizeof(text));
253 EXPECT_STREQ("/", text);
255 char* alloc = ki_getwd(NULL);
256 EXPECT_EQ((char*)NULL, alloc);
257 EXPECT_EQ(EFAULT, errno);
259 text[0] = 0;
260 alloc = ki_getwd(text);
261 EXPECT_STREQ("/", alloc);
263 EXPECT_EQ(-1, ki_chdir("/foo"));
264 EXPECT_EQ(ENOENT, errno);
266 EXPECT_EQ(0, ki_chdir("/"));
268 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
269 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
270 EXPECT_EQ(EEXIST, errno);
272 memset(text, 0, sizeof(text));
273 EXPECT_EQ(0, ki_chdir("foo"));
274 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
275 EXPECT_STREQ("/foo", text);
277 memset(text, 0, sizeof(text));
278 EXPECT_EQ(-1, ki_chdir("foo"));
279 EXPECT_EQ(ENOENT, errno);
280 EXPECT_EQ(0, ki_chdir(".."));
281 EXPECT_EQ(0, ki_chdir("/foo"));
282 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
283 EXPECT_STREQ("/foo", text);
286 TEST_F(KernelProxyTest, FDPathMapping) {
287 char text[1024];
289 int fd1, fd2, fd3, fd4, fd5;
291 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
292 EXPECT_EQ(0, ki_mkdir("/foo/bar", S_IREAD | S_IWRITE));
293 EXPECT_EQ(0, ki_mkdir("/example", S_IREAD | S_IWRITE));
294 ki_chdir("/foo");
296 fd1 = ki_open("/example", O_RDONLY);
297 EXPECT_NE(-1, fd1);
298 EXPECT_EQ(ki_fchdir(fd1), 0);
299 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
300 EXPECT_STREQ("/example", text);
302 EXPECT_EQ(0, ki_chdir("/foo"));
303 fd2 = ki_open("../example", O_RDONLY);
304 EXPECT_NE(-1, fd2);
305 EXPECT_EQ(0, ki_fchdir(fd2));
306 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
307 EXPECT_STREQ("/example", text);
309 EXPECT_EQ(0, ki_chdir("/foo"));
310 fd3 = ki_open("../test", O_CREAT | O_RDWR);
311 EXPECT_NE(-1, fd3);
312 EXPECT_EQ(-1, ki_fchdir(fd3));
313 EXPECT_EQ(ENOTDIR, errno);
315 EXPECT_EQ(0, ki_chdir("/foo"));
316 fd4 = ki_open("bar", O_RDONLY);
317 EXPECT_EQ(0, ki_fchdir(fd4));
318 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
319 EXPECT_STREQ("/foo/bar", text);
320 EXPECT_EQ(0, ki_chdir("/example"));
321 EXPECT_EQ(0, ki_fchdir(fd4));
322 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
323 EXPECT_STREQ("/foo/bar", text);
325 EXPECT_EQ(0, ki_chdir("/example"));
326 fd5 = ki_dup(fd4);
327 ASSERT_GT(fd5, -1);
328 ASSERT_NE(fd4, fd5);
329 EXPECT_EQ(0, ki_fchdir(fd5));
330 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
331 EXPECT_STREQ("/foo/bar", text);
333 fd5 = 123;
335 EXPECT_EQ(0, ki_chdir("/example"));
336 EXPECT_EQ(fd5, ki_dup2(fd4, fd5));
337 EXPECT_EQ(0, ki_fchdir(fd5));
338 EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
339 EXPECT_STREQ("/foo/bar", text);
342 TEST_F(KernelProxyTest, MemMountIO) {
343 char text[1024];
344 int fd1, fd2, fd3;
345 int len;
347 // Fail to delete non existant "/foo"
348 EXPECT_EQ(-1, ki_rmdir("/foo"));
349 EXPECT_EQ(ENOENT, errno);
351 // Create "/foo"
352 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
353 EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
354 EXPECT_EQ(EEXIST, errno);
356 // Delete "/foo"
357 EXPECT_EQ(0, ki_rmdir("/foo"));
359 // Recreate "/foo"
360 EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
362 // Fail to open "/foo/bar"
363 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY));
364 EXPECT_EQ(ENOENT, errno);
366 // Create bar "/foo/bar"
367 fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT);
368 ASSERT_NE(-1, fd1);
370 // Open (optionally create) bar "/foo/bar"
371 fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT);
372 ASSERT_NE(-1, fd2);
374 // Fail to exclusively create bar "/foo/bar"
375 EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL));
376 EXPECT_EQ(EEXIST, errno);
378 // Write hello and world to same node with different descriptors
379 // so that we overwrite each other
380 EXPECT_EQ(5, ki_write(fd2, "WORLD", 5));
381 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
383 fd3 = ki_open("/foo/bar", O_RDONLY);
384 ASSERT_NE(-1, fd3);
386 len = ki_read(fd3, text, sizeof(text));
387 ASSERT_EQ(5, len);
388 text[len] = 0;
389 EXPECT_STREQ("HELLO", text);
390 EXPECT_EQ(0, ki_close(fd1));
391 EXPECT_EQ(0, ki_close(fd2));
393 fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND);
394 ASSERT_NE(-1, fd1);
395 EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
397 len = ki_read(fd3, text, sizeof(text));
398 ASSERT_EQ(5, len);
399 text[len] = 0;
400 EXPECT_STREQ("WORLD", text);
402 fd2 = ki_open("/foo/bar", O_RDONLY);
403 ASSERT_NE(-1, fd2);
404 len = ki_read(fd2, text, sizeof(text));
405 if (len > 0)
406 text[len] = 0;
407 EXPECT_EQ(10, len);
408 EXPECT_STREQ("HELLOWORLD", text);
411 TEST_F(KernelProxyTest, MemMountFTruncate) {
412 char text[1024];
413 int fd1, fd2;
415 // Open a file write only, write some text, then test that using a
416 // separate file descriptor pointing to it that it is correctly
417 // truncated at a specified number of bytes (2).
418 fd1 = ki_open("/trunc", O_WRONLY | O_CREAT);
419 ASSERT_NE(-1, fd1);
420 fd2 = ki_open("/trunc", O_RDONLY);
421 ASSERT_NE(-1, fd2);
422 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
423 EXPECT_EQ(0, ki_ftruncate(fd1, 2));
424 // Verify the remaining file (using fd2, opened pre-truncation) is
425 // only 2 bytes in length.
426 EXPECT_EQ(2, ki_read(fd2, text, sizeof(text)));
427 EXPECT_EQ(0, ki_close(fd1));
428 EXPECT_EQ(0, ki_close(fd2));
431 TEST_F(KernelProxyTest, MemMountTruncate) {
432 char text[1024];
433 int fd1;
435 // Open a file write only, write some text, then test that by
436 // referring to it by its path and truncating it we correctly truncate
437 // it at a specified number of bytes (2).
438 fd1 = ki_open("/trunc", O_WRONLY | O_CREAT);
439 ASSERT_NE(-1, fd1);
440 EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
441 EXPECT_EQ(0, ki_close(fd1));
442 EXPECT_EQ(0, ki_truncate("/trunc", 2));
443 // Verify the text is only 2 bytes long with new file descriptor.
444 fd1 = ki_open("/trunc", O_RDONLY);
445 ASSERT_NE(-1, fd1);
446 EXPECT_EQ(2, ki_read(fd1, text, sizeof(text)));
447 EXPECT_EQ(0, ki_close(fd1));
450 TEST_F(KernelProxyTest, MemMountLseek) {
451 int fd = ki_open("/foo", O_CREAT | O_RDWR);
452 ASSERT_GT(fd, -1);
453 ASSERT_EQ(9, ki_write(fd, "Some text", 9));
455 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
456 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_END));
457 ASSERT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
458 ASSERT_EQ(EINVAL, errno);
460 // Seek past end of file.
461 ASSERT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
462 char buffer[4];
463 memset(&buffer[0], 0xfe, 4);
464 ASSERT_EQ(9, ki_lseek(fd, -4, SEEK_END));
465 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
466 ASSERT_EQ(4, ki_read(fd, &buffer[0], 4));
467 ASSERT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
470 TEST_F(KernelProxyTest, CloseTwice) {
471 int fd = ki_open("/foo", O_CREAT | O_RDWR);
472 ASSERT_GT(fd, -1);
474 EXPECT_EQ(9, ki_write(fd, "Some text", 9));
476 int fd2 = ki_dup(fd);
477 ASSERT_GT(fd2, -1);
479 EXPECT_EQ(0, ki_close(fd));
480 EXPECT_EQ(0, ki_close(fd2));
483 TEST_F(KernelProxyTest, MemMountDup) {
484 int fd = ki_open("/foo", O_CREAT | O_RDWR);
485 ASSERT_GT(fd, -1);
487 int dup_fd = ki_dup(fd);
488 ASSERT_NE(-1, dup_fd);
490 ASSERT_EQ(9, ki_write(fd, "Some text", 9));
491 ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
492 ASSERT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
494 int dup2_fd = 123;
495 ASSERT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
496 ASSERT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
498 int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
500 ASSERT_EQ(fd, ki_dup2(new_fd, fd));
501 // fd, new_fd -> "/bar"
502 // dup_fd, dup2_fd -> "/foo"
504 // We should still be able to write to dup_fd (i.e. it should not be closed).
505 ASSERT_EQ(4, ki_write(dup_fd, "more", 4));
507 ASSERT_EQ(0, ki_close(dup2_fd));
508 // fd, new_fd -> "/bar"
509 // dup_fd -> "/foo"
511 ASSERT_EQ(dup_fd, ki_dup2(fd, dup_fd));
512 // fd, new_fd, dup_fd -> "/bar"
515 TEST_F(KernelProxyTest, Lstat) {
516 int fd = ki_open("/foo", O_CREAT | O_RDWR);
517 ASSERT_GT(fd, -1);
518 ASSERT_EQ(0, ki_mkdir("/bar", S_IREAD | S_IWRITE));
520 struct stat buf;
521 EXPECT_EQ(0, ki_lstat("/foo", &buf));
522 EXPECT_EQ(0, buf.st_size);
523 EXPECT_TRUE(S_ISREG(buf.st_mode));
525 EXPECT_EQ(0, ki_lstat("/bar", &buf));
526 EXPECT_EQ(0, buf.st_size);
527 EXPECT_TRUE(S_ISDIR(buf.st_mode));
529 EXPECT_EQ(-1, ki_lstat("/no-such-file", &buf));
530 EXPECT_EQ(ENOENT, errno);
533 TEST_F(KernelProxyTest, UseAfterClose) {
534 int fd = ki_open("/dummy", O_CREAT | O_WRONLY);
535 ASSERT_GT(fd, -1);
536 EXPECT_EQ(5, ki_write(fd, "hello", 5));
537 EXPECT_EQ(0, ki_close(fd));
538 EXPECT_EQ(-1, ki_write(fd, "hello", 5));
539 EXPECT_EQ(EBADF, errno);
542 namespace {
544 StringMap_t g_string_map;
545 bool g_fs_ioctl_called;
546 int g_fs_dev;
548 class KernelProxyMountTest_Filesystem : public MemFs {
549 public:
550 virtual Error Init(const FsInitArgs& args) {
551 MemFs::Init(args);
553 g_string_map = args.string_map;
554 g_fs_dev = args.dev;
556 if (g_string_map.find("false") != g_string_map.end())
557 return EINVAL;
558 return 0;
561 virtual Error Filesystem_VIoctl(int request, va_list arglist) {
562 g_fs_ioctl_called = true;
563 return 0;
566 friend class TypedFsFactory<KernelProxyMountTest_Filesystem>;
569 class KernelProxyMountTest_KernelProxy : public KernelProxy {
570 virtual Error Init(PepperInterface* ppapi) {
571 KernelProxy::Init(NULL);
572 factories_["initfs"] = new TypedFsFactory<KernelProxyMountTest_Filesystem>;
573 return 0;
577 class KernelProxyMountTest : public ::testing::Test {
578 public:
579 KernelProxyMountTest() {}
581 void SetUp() {
582 g_string_map.clear();
583 g_fs_dev = -1;
584 g_fs_ioctl_called = false;
586 ASSERT_EQ(0, ki_push_state_for_testing());
587 ASSERT_EQ(0, ki_init(&kp_));
590 void TearDown() {
591 g_string_map.clear();
592 ki_uninit();
595 protected:
596 KernelProxyMountTest_KernelProxy kp_;
599 // Helper function for calling ki_ioctl without having
600 // to construct a va_list.
601 int ki_ioctl_wrapper(int fd, int request, ...) {
602 va_list ap;
603 va_start(ap, request);
604 int rtn = ki_ioctl(fd, request, ap);
605 va_end(ap);
606 return rtn;
609 } // namespace
611 TEST_F(KernelProxyMountTest, MountInit) {
612 int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
614 EXPECT_EQ("bar", g_string_map["foo"]);
615 EXPECT_EQ(-1, res1);
616 EXPECT_EQ(EINVAL, errno);
618 int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
619 EXPECT_NE(-1, res2);
620 EXPECT_EQ("y", g_string_map["x"]);
623 TEST_F(KernelProxyMountTest, MountAndIoctl) {
624 ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, ""));
625 ASSERT_NE(-1, g_fs_dev);
627 char path[100];
628 snprintf(path, 100, "dev/fs/%d", g_fs_dev);
630 int fd = ki_open(path, O_RDONLY);
631 ASSERT_GT(fd, -1);
633 EXPECT_EQ(0, ki_ioctl_wrapper(fd, 0xdeadbeef));
634 EXPECT_EQ(true, g_fs_ioctl_called);
637 static void mount_callback(const char* source,
638 const char* target,
639 const char* filesystemtype,
640 unsigned long mountflags,
641 const void* data,
642 dev_t dev,
643 void* user_data) {
644 EXPECT_STREQ("/", source);
645 EXPECT_STREQ("/mnt1", target);
646 EXPECT_STREQ("initfs", filesystemtype);
647 EXPECT_EQ(0, mountflags);
648 EXPECT_STREQ("", (const char*) data);
649 EXPECT_EQ(g_fs_dev, dev);
651 bool* callback_called = static_cast<bool*>(user_data);
652 *callback_called = true;
655 TEST_F(KernelProxyMountTest, MountCallback) {
656 bool callback_called = false;
657 kp_.SetMountCallback(&mount_callback, &callback_called);
658 ASSERT_EQ(0, ki_mount("/", "/mnt1", "initfs", 0, ""));
659 ASSERT_NE(-1, g_fs_dev);
660 EXPECT_EQ(true, callback_called);
663 namespace {
665 int g_MMapCount = 0;
667 class KernelProxyMMapTest_Node : public Node {
668 public:
669 KernelProxyMMapTest_Node(Filesystem* filesystem)
670 : Node(filesystem), node_mmap_count_(0) {
671 EXPECT_EQ(0, Init(0));
674 virtual Error MMap(void* addr,
675 size_t length,
676 int prot,
677 int flags,
678 size_t offset,
679 void** out_addr) {
680 node_mmap_count_++;
681 switch (g_MMapCount++) {
682 case 0:
683 *out_addr = reinterpret_cast<void*>(0x1000);
684 break;
685 case 1:
686 *out_addr = reinterpret_cast<void*>(0x2000);
687 break;
688 case 2:
689 *out_addr = reinterpret_cast<void*>(0x3000);
690 break;
691 default:
692 return EPERM;
695 return 0;
698 private:
699 int node_mmap_count_;
702 class KernelProxyMMapTest_Filesystem : public Filesystem {
703 public:
704 virtual Error Access(const Path& path, int a_mode) { return 0; }
705 virtual Error Open(const Path& path, int mode, ScopedNode* out_node) {
706 out_node->reset(new KernelProxyMMapTest_Node(this));
707 return 0;
710 virtual Error OpenResource(const Path& path, ScopedNode* out_node) {
711 out_node->reset(NULL);
712 return ENOSYS;
714 virtual Error Unlink(const Path& path) { return ENOSYS; }
715 virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
716 virtual Error Rmdir(const Path& path) { return ENOSYS; }
717 virtual Error Remove(const Path& path) { return ENOSYS; }
718 virtual Error Rename(const Path& path, const Path& newpath) { return ENOSYS; }
720 friend class TypedFsFactory<KernelProxyMMapTest_Filesystem>;
723 class KernelProxyMMapTest_KernelProxy : public KernelProxy {
724 virtual Error Init(PepperInterface* ppapi) {
725 KernelProxy::Init(NULL);
726 factories_["mmapfs"] = new TypedFsFactory<KernelProxyMMapTest_Filesystem>;
727 return 0;
731 class KernelProxyMMapTest : public ::testing::Test {
732 public:
733 KernelProxyMMapTest() {}
735 void SetUp() {
736 ASSERT_EQ(0, ki_push_state_for_testing());
737 ASSERT_EQ(0, ki_init(&kp_));
740 void TearDown() { ki_uninit(); }
742 private:
743 KernelProxyMMapTest_KernelProxy kp_;
746 } // namespace
748 TEST_F(KernelProxyMMapTest, MMap) {
749 ASSERT_EQ(0, ki_umount("/"));
750 ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
751 int fd = ki_open("/file", O_RDWR | O_CREAT);
752 ASSERT_NE(-1, fd);
754 void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
755 ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1);
756 ASSERT_EQ(1, g_MMapCount);
758 void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
759 ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2);
760 ASSERT_EQ(2, g_MMapCount);
762 void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
763 ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3);
764 ASSERT_EQ(3, g_MMapCount);
766 ki_close(fd);
768 // We no longer track mmap'd regions, so munmap is a no-op.
769 ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
770 // We don't track regions, so the mmap count hasn't changed.
771 ASSERT_EQ(3, g_MMapCount);
774 namespace {
776 class SingletonFsFactory : public FsFactory {
777 public:
778 SingletonFsFactory(const ScopedFilesystem& filesystem) : mount_(filesystem) {}
780 virtual Error CreateFilesystem(const FsInitArgs& args,
781 ScopedFilesystem* out_fs) {
782 *out_fs = mount_;
783 return 0;
786 private:
787 ScopedFilesystem mount_;
790 class KernelProxyErrorTest_KernelProxy : public KernelProxy {
791 public:
792 KernelProxyErrorTest_KernelProxy() : fs_(new MockFs) {}
794 virtual Error Init(PepperInterface* ppapi) {
795 KernelProxy::Init(ppapi);
796 factories_["testfs"] = new SingletonFsFactory(fs_);
798 EXPECT_CALL(*fs_, Destroy()).Times(1);
799 return 0;
802 ScopedRef<MockFs> fs() { return fs_; }
804 private:
805 ScopedRef<MockFs> fs_;
808 class KernelProxyErrorTest : public ::testing::Test {
809 public:
810 KernelProxyErrorTest() {}
812 void SetUp() {
813 ASSERT_EQ(0, ki_push_state_for_testing());
814 ASSERT_EQ(0, ki_init(&kp_));
815 // Unmount the passthrough FS and mount a testfs.
816 EXPECT_EQ(0, kp_.umount("/"));
817 EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
820 void TearDown() { ki_uninit(); }
822 ScopedRef<MockFs> fs() { return kp_.fs(); }
824 private:
825 KernelProxyErrorTest_KernelProxy kp_;
828 } // namespace
830 TEST_F(KernelProxyErrorTest, WriteError) {
831 ScopedRef<MockFs> mock_fs(fs());
832 ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs));
833 EXPECT_CALL(*mock_fs, Open(_, _, _))
834 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
836 EXPECT_CALL(*mock_node, Write(_, _, _, _))
837 .WillOnce(DoAll(SetArgPointee<3>(0), // Wrote 0 bytes.
838 Return(1234))); // Returned error 1234.
840 EXPECT_CALL(*mock_node, Destroy()).Times(1);
842 int fd = ki_open("/dummy", O_WRONLY);
843 EXPECT_NE(0, fd);
845 char buf[20];
846 EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
847 // The Filesystem should be able to return whatever error it wants and have it
848 // propagate through.
849 EXPECT_EQ(1234, errno);
852 TEST_F(KernelProxyErrorTest, ReadError) {
853 ScopedRef<MockFs> mock_fs(fs());
854 ScopedRef<MockNode> mock_node(new MockNode(&*mock_fs));
855 EXPECT_CALL(*mock_fs, Open(_, _, _))
856 .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
858 EXPECT_CALL(*mock_node, Read(_, _, _, _))
859 .WillOnce(DoAll(SetArgPointee<3>(0), // Read 0 bytes.
860 Return(1234))); // Returned error 1234.
862 EXPECT_CALL(*mock_node, Destroy()).Times(1);
864 int fd = ki_open("/dummy", O_RDONLY);
865 EXPECT_NE(0, fd);
867 char buf[20];
868 EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
869 // The Filesystem should be able to return whatever error it wants and have it
870 // propagate through.
871 EXPECT_EQ(1234, errno);