OLD | NEW |
| (Empty) |
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 | |
6 #include <errno.h> | |
7 #include <fcntl.h> | |
8 #include <pthread.h> | |
9 #include <sys/stat.h> | |
10 | |
11 #include <map> | |
12 #include <string> | |
13 | |
14 #include "nacl_mounts/kernel_handle.h" | |
15 #include "nacl_mounts/kernel_object.h" | |
16 #include "nacl_mounts/mount.h" | |
17 #include "nacl_mounts/path.h" | |
18 | |
19 #include "gtest/gtest.h" | |
20 | |
21 namespace { | |
22 | |
23 class MountRefMock : public Mount { | |
24 public: | |
25 MountRefMock(int* mount_count, int* handle_count) | |
26 : mount_count(mount_count), | |
27 handle_count(handle_count) { | |
28 (*mount_count)++; | |
29 } | |
30 | |
31 ~MountRefMock() { | |
32 (*mount_count)--; | |
33 } | |
34 | |
35 public: | |
36 MountNode* Open(const Path& path, int mode) { return NULL; } | |
37 int Close(MountNode* node) { return 0; } | |
38 int Unlink(const Path& path) { return 0; } | |
39 int Mkdir(const Path& path, int permissions) { return 0; } | |
40 int Rmdir(const Path& path) { return 0; } | |
41 int Remove(const Path& path) { return 0; } | |
42 | |
43 public: | |
44 int* mount_count; | |
45 int* handle_count; | |
46 }; | |
47 | |
48 class KernelHandleRefMock : public KernelHandle { | |
49 public: | |
50 KernelHandleRefMock(Mount* mnt, MountNode* node, int flags) | |
51 : KernelHandle(mnt, node, flags) { | |
52 MountRefMock* mock_mount = static_cast<MountRefMock*>(mnt); | |
53 (*mock_mount->handle_count)++; | |
54 } | |
55 | |
56 ~KernelHandleRefMock() { | |
57 MountRefMock* mock_mount = static_cast<MountRefMock*>(mount_); | |
58 (*mock_mount->handle_count)--; | |
59 } | |
60 }; | |
61 | |
62 class KernelObjectTest : public ::testing::Test { | |
63 public: | |
64 KernelObjectTest() | |
65 : mount_count(0), | |
66 handle_count(0) { | |
67 proxy = new KernelObject; | |
68 mnt = new MountRefMock(&mount_count, &handle_count); | |
69 } | |
70 | |
71 ~KernelObjectTest() { | |
72 // mnt is ref-counted, it doesn't need to be explicitly deleted. | |
73 delete proxy; | |
74 } | |
75 | |
76 KernelObject* proxy; | |
77 MountRefMock* mnt; | |
78 int mount_count; | |
79 int handle_count; | |
80 }; | |
81 | |
82 } // namespace | |
83 | |
84 | |
85 TEST_F(KernelObjectTest, Referencing) { | |
86 KernelHandle* handle = new KernelHandleRefMock(mnt, NULL, 0); | |
87 KernelHandle* handle2 = new KernelHandleRefMock(mnt, NULL, 0); | |
88 | |
89 // Objects should have one ref when we start | |
90 EXPECT_EQ(1, mnt->RefCount()); | |
91 EXPECT_EQ(1, handle->RefCount()); | |
92 | |
93 // Objects should have two refs when we get here | |
94 int fd1 = proxy->AllocateFD(handle); | |
95 EXPECT_EQ(2, mnt->RefCount()); | |
96 EXPECT_EQ(2, handle->RefCount()); | |
97 | |
98 // If we "dup" the handle, we should bump the refs | |
99 int fd2 = proxy->AllocateFD(handle); | |
100 EXPECT_EQ(3, mnt->RefCount()); | |
101 EXPECT_EQ(3, handle->RefCount()); | |
102 | |
103 // If use a new handle with the same values... bump the refs | |
104 int fd3 = proxy->AllocateFD(handle2); | |
105 EXPECT_EQ(4, mnt->RefCount()); | |
106 EXPECT_EQ(2, handle2->RefCount()); | |
107 | |
108 // Handles are expectd to come out in order | |
109 EXPECT_EQ(0, fd1); | |
110 EXPECT_EQ(1, fd2); | |
111 EXPECT_EQ(2, fd3); | |
112 | |
113 // We should find the handle by either fd | |
114 EXPECT_EQ(handle, proxy->AcquireHandle(fd1)); | |
115 EXPECT_EQ(handle, proxy->AcquireHandle(fd2)); | |
116 | |
117 // A non existant fd should fail | |
118 EXPECT_EQ(NULL, proxy->AcquireHandle(-1)); | |
119 EXPECT_EQ(EBADF, errno); | |
120 EXPECT_EQ(NULL, proxy->AcquireHandle(100)); | |
121 EXPECT_EQ(EBADF, errno); | |
122 | |
123 // Acquiring the handle, should have ref'd it | |
124 EXPECT_EQ(4, mnt->RefCount()); | |
125 EXPECT_EQ(5, handle->RefCount()); | |
126 | |
127 // Release the handle for each call to acquire | |
128 proxy->ReleaseHandle(handle); | |
129 proxy->ReleaseHandle(handle); | |
130 | |
131 // Release the handle for each time we constructed something | |
132 proxy->ReleaseHandle(handle); | |
133 proxy->ReleaseHandle(handle2); | |
134 proxy->ReleaseMount(mnt); | |
135 | |
136 // We should now only have references used by the KernelProxy | |
137 EXPECT_EQ(2, handle->RefCount()); | |
138 EXPECT_EQ(1, handle2->RefCount()); | |
139 EXPECT_EQ(3, mnt->RefCount()); | |
140 | |
141 EXPECT_EQ(2, handle_count); | |
142 EXPECT_EQ(1, mount_count); | |
143 | |
144 proxy->FreeFD(fd1); | |
145 EXPECT_EQ(2, handle_count); | |
146 EXPECT_EQ(1, mount_count); | |
147 | |
148 proxy->FreeFD(fd3); | |
149 EXPECT_EQ(1, handle_count); | |
150 EXPECT_EQ(1, mount_count); | |
151 | |
152 proxy->FreeFD(fd2); | |
153 EXPECT_EQ(0, handle_count); | |
154 EXPECT_EQ(0, mount_count); | |
155 } | |
156 | |
157 TEST_F(KernelObjectTest, AssignFD) { | |
158 EXPECT_EQ(0, handle_count); | |
159 | |
160 KernelHandle* handle = new KernelHandleRefMock(mnt, NULL, 0); | |
161 | |
162 EXPECT_EQ(1, handle_count); | |
163 EXPECT_EQ(1, handle->RefCount()); | |
164 | |
165 proxy->AssignFD(2, handle); | |
166 EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(0)); | |
167 EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(1)); | |
168 EXPECT_EQ(handle, proxy->AcquireHandle(2)); | |
169 proxy->ReleaseHandle(handle); | |
170 | |
171 EXPECT_EQ(1, handle_count); | |
172 EXPECT_EQ(2, handle->RefCount()); | |
173 | |
174 proxy->AssignFD(0, handle); | |
175 EXPECT_EQ(handle, proxy->AcquireHandle(0)); | |
176 EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(1)); | |
177 EXPECT_EQ(handle, proxy->AcquireHandle(2)); | |
178 proxy->ReleaseHandle(handle); | |
179 proxy->ReleaseHandle(handle); | |
180 | |
181 EXPECT_EQ(1, handle_count); | |
182 EXPECT_EQ(3, handle->RefCount()); | |
183 | |
184 proxy->FreeFD(0); | |
185 proxy->FreeFD(2); | |
186 proxy->ReleaseHandle(handle); // handle is constructed with a refcount of 1. | |
187 | |
188 EXPECT_EQ(0, handle_count); | |
189 } | |
OLD | NEW |