- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / tests / nacl_io_test / kernel_proxy_test.cc
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 <errno.h>
6 #include <fcntl.h>
7 #include <pthread.h>
8 #include <stdio.h>
9 #include <sys/stat.h>
10
11 #include <map>
12 #include <string>
13
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16
17 #include "mount_mock.h"
18 #include "mount_node_mock.h"
19
20 #include "nacl_io/kernel_intercept.h"
21 #include "nacl_io/kernel_proxy.h"
22 #include "nacl_io/mount.h"
23 #include "nacl_io/mount_mem.h"
24 #include "nacl_io/osmman.h"
25 #include "nacl_io/path.h"
26 #include "nacl_io/typed_mount_factory.h"
27
28 using namespace nacl_io;
29 using namespace sdk_util;
30
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;
39
40 namespace {
41
42 class KernelProxyFriend : public KernelProxy {
43  public:
44   Mount* RootMount() {
45     ScopedMount mnt;
46     Path path;
47
48     AcquireMountAndRelPath("/", &mnt, &path);
49     return mnt.get();
50   }
51 };
52
53 class KernelProxyTest : public ::testing::Test {
54  public:
55   KernelProxyTest() {}
56
57   void SetUp() {
58     ki_init(&kp_);
59     // Unmount the passthrough FS and mount a memfs.
60     EXPECT_EQ(0, kp_.umount("/"));
61     EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL));
62   }
63
64   void TearDown() {
65     ki_uninit();
66   }
67
68  protected:
69   KernelProxyFriend kp_;
70 };
71
72 }  // namespace
73
74 static int ki_fcntl_wrapper(int fd, int request, ...) {
75   va_list ap;
76   va_start(ap, request);
77   int rtn = ki_fcntl(fd, request, ap);
78   va_end(ap);
79   return rtn;
80 }
81
82 /**
83  * Test for fcntl commands F_SETFD and F_GETFD.  This
84  * is tested here rather than in the mount_node tests
85  * since the fd flags are not stored in the kernel_handle
86  * or the mount node but directly in the FD mapping.
87  */
88 TEST_F(KernelProxyTest, Fcntl_GETFD) {
89   int fd = ki_open("/test", O_RDWR | O_CREAT);
90   ASSERT_NE(-1, fd);
91
92   // FD flags should start as zero.
93   ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_GETFD));
94
95   // Check that setting FD_CLOEXEC works
96   int flags = FD_CLOEXEC;
97   ASSERT_EQ(0, ki_fcntl_wrapper(fd, F_SETFD, flags))
98     << "fcntl failed with: " << strerror(errno);
99   ASSERT_EQ(FD_CLOEXEC, ki_fcntl_wrapper(fd, F_GETFD));
100
101   // Check that setting invalid flag causes EINVAL
102   flags = FD_CLOEXEC + 1;
103   ASSERT_EQ(-1, ki_fcntl_wrapper(fd, F_SETFD, flags));
104   ASSERT_EQ(EINVAL, errno);
105 }
106
107 TEST_F(KernelProxyTest, FileLeak) {
108   const size_t buffer_size = 1024;
109   char filename[128];
110   int garbage[buffer_size];
111
112   MountMem* mount = (MountMem*)kp_.RootMount();
113   ScopedMountNode root;
114
115   ASSERT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
116   ASSERT_EQ(0, root->ChildCount());
117
118   for (int file_num = 0; file_num < 4096; file_num++) {
119     sprintf(filename, "/foo%i.tmp", file_num++);
120     FILE* f = fopen(filename, "w");
121     ASSERT_NE((FILE*)NULL, f);
122     ASSERT_EQ(1, root->ChildCount());
123     ASSERT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f));
124     fclose(f);
125     ASSERT_EQ(0, remove(filename));
126   }
127   ASSERT_EQ(0, root->ChildCount());
128 }
129
130 TEST_F(KernelProxyTest, WorkingDirectory) {
131   char text[1024];
132
133   text[0] = 0;
134   ki_getcwd(text, sizeof(text));
135   EXPECT_STREQ("/", text);
136
137   char* alloc = ki_getwd(NULL);
138   EXPECT_EQ((char*)NULL, alloc);
139   EXPECT_EQ(EFAULT, errno);
140
141   text[0] = 0;
142   alloc = ki_getwd(text);
143   EXPECT_STREQ("/", alloc);
144
145   EXPECT_EQ(-1, ki_chdir("/foo"));
146   EXPECT_EQ(ENOENT, errno);
147
148   EXPECT_EQ(0, ki_chdir("/"));
149
150   EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
151   EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
152   EXPECT_EQ(EEXIST, errno);
153
154   memset(text, 0, sizeof(text));
155   EXPECT_EQ(0, ki_chdir("foo"));
156   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
157   EXPECT_STREQ("/foo", text);
158
159   memset(text, 0, sizeof(text));
160   EXPECT_EQ(-1, ki_chdir("foo"));
161   EXPECT_EQ(ENOENT, errno);
162   EXPECT_EQ(0, ki_chdir(".."));
163   EXPECT_EQ(0, ki_chdir("/foo"));
164   EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
165   EXPECT_STREQ("/foo", text);
166 }
167
168 TEST_F(KernelProxyTest, MemMountIO) {
169   char text[1024];
170   int fd1, fd2, fd3;
171   int len;
172
173   // Fail to delete non existant "/foo"
174   EXPECT_EQ(-1, ki_rmdir("/foo"));
175   EXPECT_EQ(ENOENT, errno);
176
177   // Create "/foo"
178   EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
179   EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
180   EXPECT_EQ(EEXIST, errno);
181
182   // Delete "/foo"
183   EXPECT_EQ(0, ki_rmdir("/foo"));
184
185   // Recreate "/foo"
186   EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
187
188   // Fail to open "/foo/bar"
189   EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY));
190   EXPECT_EQ(ENOENT, errno);
191
192   // Create bar "/foo/bar"
193   fd1 = ki_open("/foo/bar", O_RDWR | O_CREAT);
194   ASSERT_NE(-1, fd1);
195
196   // Open (optionally create) bar "/foo/bar"
197   fd2 = ki_open("/foo/bar", O_RDWR | O_CREAT);
198   ASSERT_NE(-1, fd2);
199
200   // Fail to exclusively create bar "/foo/bar"
201   EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL));
202   EXPECT_EQ(EEXIST, errno);
203
204   // Write hello and world to same node with different descriptors
205   // so that we overwrite each other
206   EXPECT_EQ(5, ki_write(fd2, "WORLD", 5));
207   EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
208
209   fd3 = ki_open("/foo/bar", O_RDONLY);
210   ASSERT_NE(-1, fd3);
211
212   len = ki_read(fd3, text, sizeof(text));
213   ASSERT_EQ(5, len);
214   text[len] = 0;
215   EXPECT_STREQ("HELLO", text);
216   EXPECT_EQ(0, ki_close(fd1));
217   EXPECT_EQ(0, ki_close(fd2));
218
219   fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND);
220   ASSERT_NE(-1, fd1);
221   EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
222
223   len = ki_read(fd3, text, sizeof(text));
224   ASSERT_EQ(5, len);
225   text[len] = 0;
226   EXPECT_STREQ("WORLD", text);
227
228   fd2 = ki_open("/foo/bar", O_RDONLY);
229   ASSERT_NE(-1, fd2);
230   len = ki_read(fd2, text, sizeof(text));
231   if (len > 0)
232     text[len] = 0;
233   EXPECT_EQ(10, len);
234   EXPECT_STREQ("HELLOWORLD", text);
235 }
236
237 TEST_F(KernelProxyTest, MemMountLseek) {
238   int fd = ki_open("/foo", O_CREAT | O_RDWR);
239   ASSERT_GT(fd, -1);
240   EXPECT_EQ(9, ki_write(fd, "Some text", 9));
241
242   EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
243   EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END));
244   EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
245   EXPECT_EQ(EINVAL, errno);
246
247   // Seek past end of file.
248   EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
249   char buffer[4];
250   memset(&buffer[0], 0xfe, 4);
251   EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END));
252   EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
253   EXPECT_EQ(4, ki_read(fd, &buffer[0], 4));
254   EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
255 }
256
257 TEST_F(KernelProxyTest, CloseTwice) {
258   int fd = ki_open("/foo", O_CREAT | O_RDWR);
259   ASSERT_GT(fd, -1);
260
261   EXPECT_EQ(9, ki_write(fd, "Some text", 9));
262
263   int fd2 = ki_dup(fd);
264   ASSERT_GT(fd2, -1);
265
266   EXPECT_EQ(0, ki_close(fd));
267   EXPECT_EQ(0, ki_close(fd2));
268 }
269
270 TEST_F(KernelProxyTest, MemMountDup) {
271   int fd = ki_open("/foo", O_CREAT | O_RDWR);
272   ASSERT_GT(fd, -1);
273
274   int dup_fd = ki_dup(fd);
275   ASSERT_NE(-1, dup_fd);
276
277   ASSERT_EQ(9, ki_write(fd, "Some text", 9));
278   ASSERT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
279   ASSERT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
280
281   int dup2_fd = 123;
282   ASSERT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
283   ASSERT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
284
285   int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
286
287   ASSERT_EQ(fd, ki_dup2(new_fd, fd));
288   // fd, new_fd -> "/bar"
289   // dup_fd, dup2_fd -> "/foo"
290
291   // We should still be able to write to dup_fd (i.e. it should not be closed).
292   ASSERT_EQ(4, ki_write(dup_fd, "more", 4));
293
294   ASSERT_EQ(0, ki_close(dup2_fd));
295   // fd, new_fd -> "/bar"
296   // dup_fd -> "/foo"
297
298   ASSERT_EQ(dup_fd, ki_dup2(fd, dup_fd));
299   // fd, new_fd, dup_fd -> "/bar"
300 }
301
302 namespace {
303
304 StringMap_t g_StringMap;
305
306 class MountMockInit : public MountMem {
307  public:
308   virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
309     g_StringMap = args;
310     if (args.find("false") != args.end())
311       return EINVAL;
312     return 0;
313   }
314
315   friend class TypedMountFactory<MountMockInit>;
316 };
317
318 class KernelProxyMountMock : public KernelProxy {
319   virtual Error Init(PepperInterface* ppapi) {
320     KernelProxy::Init(NULL);
321     factories_["initfs"] = new TypedMountFactory<MountMockInit>;
322     return 0;
323   }
324 };
325
326 class KernelProxyMountTest : public ::testing::Test {
327  public:
328   KernelProxyMountTest() {}
329
330   void SetUp() {
331     ki_init(&kp_);
332   }
333
334   void TearDown() {
335     ki_uninit();
336   }
337
338  private:
339   KernelProxyMountMock kp_;
340 };
341
342 }  // namespace
343
344 TEST_F(KernelProxyMountTest, MountInit) {
345   int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
346
347   EXPECT_EQ("bar", g_StringMap["foo"]);
348   EXPECT_EQ(-1, res1);
349   EXPECT_EQ(EINVAL, errno);
350
351   int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
352   EXPECT_NE(-1, res2);
353   EXPECT_EQ("y", g_StringMap["x"]);
354 }
355
356 namespace {
357
358 int g_MMapCount = 0;
359
360 class MountNodeMockMMap : public MountNode {
361  public:
362   MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
363     EXPECT_EQ(0, Init(0));
364   }
365
366   virtual Error MMap(void* addr,
367                      size_t length,
368                      int prot,
369                      int flags,
370                      size_t offset,
371                      void** out_addr) {
372     node_mmap_count_++;
373     switch (g_MMapCount++) {
374       case 0:
375         *out_addr = reinterpret_cast<void*>(0x1000);
376         break;
377       case 1:
378         *out_addr = reinterpret_cast<void*>(0x2000);
379         break;
380       case 2:
381         *out_addr = reinterpret_cast<void*>(0x3000);
382         break;
383       default:
384         return EPERM;
385     }
386
387     return 0;
388   }
389
390  private:
391   int node_mmap_count_;
392 };
393
394 class MountMockMMap : public Mount {
395  public:
396   virtual Error Access(const Path& path, int a_mode) { return 0; }
397   virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
398     out_node->reset(new MountNodeMockMMap(this));
399     return 0;
400   }
401
402   virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) {
403     out_node->reset(NULL);
404     return ENOSYS;
405   }
406   virtual Error Unlink(const Path& path) { return ENOSYS; }
407   virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
408   virtual Error Rmdir(const Path& path) { return ENOSYS; }
409   virtual Error Remove(const Path& path) { return ENOSYS; }
410
411   friend class TypedMountFactory<MountMockMMap>;
412 };
413
414 class KernelProxyMockMMap : public KernelProxy {
415   virtual Error Init(PepperInterface* ppapi) {
416     KernelProxy::Init(NULL);
417     factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>;
418     return 0;
419   }
420 };
421
422 class KernelProxyMMapTest : public ::testing::Test {
423  public:
424   KernelProxyMMapTest() {}
425
426   void SetUp() {
427     ki_init(&kp_);
428   }
429
430   void TearDown() {
431     ki_uninit();
432   }
433
434  private:
435   KernelProxyMockMMap kp_;
436 };
437
438 }  // namespace
439
440 TEST_F(KernelProxyMMapTest, MMap) {
441   ASSERT_EQ(0, ki_umount("/"));
442   ASSERT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
443   int fd = ki_open("/file", O_RDWR | O_CREAT);
444   ASSERT_NE(-1, fd);
445
446   void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
447   ASSERT_EQ(reinterpret_cast<void*>(0x1000), addr1);
448   ASSERT_EQ(1, g_MMapCount);
449
450   void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
451   ASSERT_EQ(reinterpret_cast<void*>(0x2000), addr2);
452   ASSERT_EQ(2, g_MMapCount);
453
454   void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
455   ASSERT_EQ(reinterpret_cast<void*>(0x3000), addr3);
456   ASSERT_EQ(3, g_MMapCount);
457
458   ki_close(fd);
459
460   // We no longer track mmap'd regions, so munmap is a no-op.
461   ASSERT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
462   // We don't track regions, so the mmap count hasn't changed.
463   ASSERT_EQ(3, g_MMapCount);
464 }
465
466 namespace {
467
468 class SingletonMountFactory : public MountFactory {
469  public:
470   SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {}
471
472   virtual Error CreateMount(int dev,
473                             StringMap_t& args,
474                             PepperInterface* ppapi,
475                             ScopedMount* out_mount) {
476     *out_mount = mount_;
477     return 0;
478   }
479
480  private:
481   ScopedMount mount_;
482 };
483
484 class KernelProxyError : public KernelProxy {
485  public:
486   KernelProxyError() : mnt_(new MountMock) {}
487
488   virtual Error Init(PepperInterface* ppapi) {
489     KernelProxy::Init(ppapi);
490     factories_["testfs"] = new SingletonMountFactory(mnt_);
491
492     EXPECT_CALL(*mnt_, Destroy()).Times(1);
493     return 0;
494   }
495
496   ScopedRef<MountMock> mnt() { return mnt_; }
497
498  private:
499   ScopedRef<MountMock> mnt_;
500 };
501
502 class KernelProxyErrorTest : public ::testing::Test {
503  public:
504   KernelProxyErrorTest() {}
505
506   void SetUp() {
507     ki_init(&kp_);
508     // Unmount the passthrough FS and mount a testfs.
509     EXPECT_EQ(0, kp_.umount("/"));
510     EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
511   }
512
513   void TearDown() {
514     ki_uninit();
515   }
516
517   ScopedRef<MountMock> mnt() { return kp_.mnt(); }
518
519  private:
520   KernelProxyError kp_;
521 };
522
523 }  // namespace
524
525 TEST_F(KernelProxyErrorTest, WriteError) {
526   ScopedRef<MountMock> mock_mnt(mnt());
527   ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
528   EXPECT_CALL(*mock_mnt, Open(_, _, _))
529       .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
530
531   EXPECT_CALL(*mock_node, Write(_, _, _, _))
532       .WillOnce(DoAll(SetArgPointee<3>(0),  // Wrote 0 bytes.
533                       Return(1234)));       // Returned error 1234.
534
535   EXPECT_CALL(*mock_node, Destroy()).Times(1);
536
537   int fd = ki_open("/dummy", O_WRONLY);
538   EXPECT_NE(0, fd);
539
540   char buf[20];
541   EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
542   // The Mount should be able to return whatever error it wants and have it
543   // propagate through.
544   EXPECT_EQ(1234, errno);
545 }
546
547 TEST_F(KernelProxyErrorTest, ReadError) {
548   ScopedRef<MountMock> mock_mnt(mnt());
549   ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
550   EXPECT_CALL(*mock_mnt, Open(_, _, _))
551       .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
552
553   EXPECT_CALL(*mock_node, Read(_, _, _, _))
554       .WillOnce(DoAll(SetArgPointee<3>(0),  // Read 0 bytes.
555                       Return(1234)));       // Returned error 1234.
556
557   EXPECT_CALL(*mock_node, Destroy()).Times(1);
558
559   int fd = ki_open("/dummy", O_RDONLY);
560   EXPECT_NE(0, fd);
561
562   char buf[20];
563   EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
564   // The Mount should be able to return whatever error it wants and have it
565   // propagate through.
566   EXPECT_EQ(1234, errno);
567 }
568