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());