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