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.
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;
24 class NodeForTesting : public Node {
26 explicit NodeForTesting(Filesystem* fs) : Node(fs) {}
29 class FilesystemForTesting : public Filesystem {
31 FilesystemForTesting() {}
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);
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 {
49 KernelHandleForTesting(const ScopedFilesystem& fs, const ScopedNode& node)
50 : KernelHandle(fs, node) {}
53 class KernelObjectTest : public ::testing::Test {
56 fs.reset(new FilesystemForTesting());
57 node.reset(new NodeForTesting(fs.get()));
61 // fs is ref-counted, it doesn't need to be explicitly deleted.
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
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.
144 EXPECT_EQ(2, raw_handle->RefCount());
145 EXPECT_EQ(2, fs->RefCount());
146 EXPECT_EQ(2, node->RefCount());
148 EXPECT_EQ(1, raw_handle->RefCount());
149 EXPECT_EQ(2, fs->RefCount());
150 EXPECT_EQ(2, node->RefCount());
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());
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());