Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / tests / nacl_io_test / kernel_object_test.cc
blobe168d790d92e28bfad08318e80bc6cf65ccc1ba5
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 <sys/stat.h>
10 #include <map>
11 #include <string>
13 #include "gtest/gtest.h"
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"
20 using namespace nacl_io;
22 namespace {
24 class NodeForTesting : public Node {
25 public:
26 explicit NodeForTesting(Filesystem* fs) : Node(fs) {}
29 class FilesystemForTesting : public Filesystem {
30 public:
31 FilesystemForTesting() {}
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;
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; }
47 class KernelHandleForTesting : public KernelHandle {
48 public:
49 KernelHandleForTesting(const ScopedFilesystem& fs, const ScopedNode& node)
50 : KernelHandle(fs, node) {}
53 class KernelObjectTest : public ::testing::Test {
54 public:
55 void SetUp() {
56 fs.reset(new FilesystemForTesting());
57 node.reset(new NodeForTesting(fs.get()));
60 void TearDown() {
61 // fs is ref-counted, it doesn't need to be explicitly deleted.
62 node.reset(NULL);
63 fs.reset(NULL);
66 KernelObject proxy;
67 ScopedFilesystem fs;
68 ScopedNode node;
71 } // namespace
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());
78 // Pass the filesystem and node into a KernelHandle
79 KernelHandle* raw_handle = new KernelHandleForTesting(fs, node);
80 ScopedKernelHandle handle_a(raw_handle);
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());
87 ScopedKernelHandle handle_b = handle_a;
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());
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());
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());
110 // Handles are expected to come out in order
111 EXPECT_EQ(0, fd1);
112 EXPECT_EQ(1, fd2);
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());
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());
126 EXPECT_EQ(4, handle_a->RefCount());
127 EXPECT_EQ(2, fs->RefCount());
128 EXPECT_EQ(2, node->RefCount());
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());
136 EXPECT_EQ(EBADF, proxy.AcquireHandle(100, &handle_b));
137 EXPECT_EQ(NULL, handle_b.get());
139 // Now only the KernelProxy should reference the KernelHandle in the
140 // FD to KernelHandle Map.
141 handle_a.reset();
142 handle_b.reset();
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());
152 proxy.FreeFD(fd1);
153 EXPECT_EQ(1, fs->RefCount());
154 EXPECT_EQ(1, node->RefCount());
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());
162 KernelHandle* raw_handle = new KernelHandleForTesting(fs, node);
163 ScopedKernelHandle handle(raw_handle);
165 EXPECT_EQ(2, fs->RefCount());
166 EXPECT_EQ(2, node->RefCount());
167 EXPECT_EQ(1, raw_handle->RefCount());
169 proxy.AllocateFD(handle, "/example");
170 EXPECT_EQ(2, fs->RefCount());
171 EXPECT_EQ(2, node->RefCount());
172 EXPECT_EQ(2, raw_handle->RefCount());
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());
180 handle.reset();
181 EXPECT_EQ(2, raw_handle->RefCount());
183 proxy.AcquireHandle(5, &handle);
184 EXPECT_EQ(3, raw_handle->RefCount());
185 EXPECT_EQ(raw_handle, handle.get());