- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / tests / nacl_io_test / kernel_object_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 <sys/stat.h>
9
10 #include <map>
11 #include <string>
12
13 #include "gtest/gtest.h"
14
15 #include "nacl_io/kernel_handle.h"
16 #include "nacl_io/kernel_object.h"
17 #include "nacl_io/mount.h"
18 #include "nacl_io/path.h"
19
20 using namespace nacl_io;
21
22 namespace {
23
24 class MountNodeRefMock : public MountNode {
25  public:
26   MountNodeRefMock(Mount* mnt) : MountNode(mnt) {}
27 };
28
29 class MountRefMock : public Mount {
30  public:
31   MountRefMock() {}
32
33  public:
34   Error Access(const Path& path, int a_mode) { return ENOSYS; }
35   Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
36     out_node->reset(NULL);
37     return ENOSYS;
38   }
39   Error Unlink(const Path& path) { return 0; }
40   Error Mkdir(const Path& path, int permissions) { return 0; }
41   Error Rmdir(const Path& path) { return 0; }
42   Error Remove(const Path& path) { return 0; }
43 };
44
45 class KernelHandleRefMock : public KernelHandle {
46  public:
47   KernelHandleRefMock(const ScopedMount& mnt, const ScopedMountNode& node)
48       : KernelHandle(mnt, node) {}
49 };
50
51 class KernelObjectTest : public ::testing::Test {
52  public:
53   void SetUp() {
54     mnt.reset(new MountRefMock());
55     node.reset(new MountNodeRefMock(mnt.get()));
56   }
57
58   void TearDown() {
59     // mnt is ref-counted, it doesn't need to be explicitly deleted.
60     node.reset(NULL);
61     mnt.reset(NULL);
62   }
63
64   KernelObject proxy;
65   ScopedMount mnt;
66   ScopedMountNode node;
67 };
68
69 }  // namespace
70
71 #include <nacl_io/mount_mem.h>
72 #include <nacl_io/mount_http.h>
73
74 TEST_F(KernelObjectTest, Referencing) {
75   // The mount and node should have 1 ref count at this point
76   EXPECT_EQ(1, mnt->RefCount());
77   EXPECT_EQ(1, node->RefCount());
78
79   // Pass the mount and node into a KernelHandle
80   KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
81   ScopedKernelHandle handle_a(raw_handle);
82
83   // The mount and node should have 1 ref count at this point
84   EXPECT_EQ(1, handle_a->RefCount());
85   EXPECT_EQ(2, mnt->RefCount());
86   EXPECT_EQ(2, node->RefCount());
87
88   ScopedKernelHandle handle_b = handle_a;
89
90   // There should be two references to the KernelHandle, the mount and node
91   // should be unchanged.
92   EXPECT_EQ(2, handle_a->RefCount());
93   EXPECT_EQ(2, handle_b->RefCount());
94   EXPECT_EQ(handle_a.get(), handle_b.get());
95   EXPECT_EQ(2, mnt->RefCount());
96   EXPECT_EQ(2, node->RefCount());
97
98   // Allocating an FD should cause the KernelProxy to ref the handle and
99   // the node and mount should be unchanged.
100   int fd1 = proxy.AllocateFD(handle_a);
101   EXPECT_EQ(3, handle_a->RefCount());
102   EXPECT_EQ(2, mnt->RefCount());
103   EXPECT_EQ(2, node->RefCount());
104
105   // If we "dup" the handle, we should bump the ref count on the handle
106   int fd2 = proxy.AllocateFD(handle_b);
107   EXPECT_EQ(4, handle_a->RefCount());
108   EXPECT_EQ(2, mnt->RefCount());
109   EXPECT_EQ(2, node->RefCount());
110
111   // Handles are expected to come out in order
112   EXPECT_EQ(0, fd1);
113   EXPECT_EQ(1, fd2);
114
115   // Now we "free" the handles, since the proxy should hold them.
116   handle_a.reset(NULL);
117   handle_b.reset(NULL);
118   EXPECT_EQ(2, mnt->RefCount());
119   EXPECT_EQ(2, node->RefCount());
120
121   // We should find the handle by either fd
122   EXPECT_EQ(0, proxy.AcquireHandle(fd1, &handle_a));
123   EXPECT_EQ(0, proxy.AcquireHandle(fd2, &handle_b));
124   EXPECT_EQ(raw_handle, handle_a.get());
125   EXPECT_EQ(raw_handle, handle_b.get());
126
127   EXPECT_EQ(4, handle_a->RefCount());
128   EXPECT_EQ(2, mnt->RefCount());
129   EXPECT_EQ(2, node->RefCount());
130
131   // A non existent fd should fail, and handleA should decrement as handleB
132   // is released by the call.
133   EXPECT_EQ(EBADF, proxy.AcquireHandle(-1, &handle_b));
134   EXPECT_EQ(NULL, handle_b.get());
135   EXPECT_EQ(3, handle_a->RefCount());
136
137   EXPECT_EQ(EBADF, proxy.AcquireHandle(100, &handle_b));
138   EXPECT_EQ(NULL, handle_b.get());
139
140   // Now only the KernelProxy should reference the KernelHandle in the
141   // FD to KernelHandle Map.
142   handle_a.reset();
143   handle_b.reset();
144
145   EXPECT_EQ(2, raw_handle->RefCount());
146   EXPECT_EQ(2, mnt->RefCount());
147   EXPECT_EQ(2, node->RefCount());
148   proxy.FreeFD(fd2);
149   EXPECT_EQ(1, raw_handle->RefCount());
150   EXPECT_EQ(2, mnt->RefCount());
151   EXPECT_EQ(2, node->RefCount());
152
153   proxy.FreeFD(fd1);
154   EXPECT_EQ(1, mnt->RefCount());
155   EXPECT_EQ(1, node->RefCount());
156 }
157
158 TEST_F(KernelObjectTest, FreeAndReassignFD) {
159   // The mount and node should have 1 ref count at this point
160   EXPECT_EQ(1, mnt->RefCount());
161   EXPECT_EQ(1, node->RefCount());
162
163   KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
164   ScopedKernelHandle handle(raw_handle);
165
166   EXPECT_EQ(2, mnt->RefCount());
167   EXPECT_EQ(2, node->RefCount());
168   EXPECT_EQ(1, raw_handle->RefCount());
169
170   proxy.AllocateFD(handle);
171   EXPECT_EQ(2, mnt->RefCount());
172   EXPECT_EQ(2, node->RefCount());
173   EXPECT_EQ(2, raw_handle->RefCount());
174
175   proxy.FreeAndReassignFD(5, handle);
176   EXPECT_EQ(2, mnt->RefCount());
177   EXPECT_EQ(2, node->RefCount());
178   EXPECT_EQ(3, raw_handle->RefCount());
179
180   handle.reset();
181   EXPECT_EQ(2, raw_handle->RefCount());
182
183   proxy.AcquireHandle(5, &handle);
184   EXPECT_EQ(3, raw_handle->RefCount());
185   EXPECT_EQ(raw_handle, handle.get());
186 }