summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'libappfuse/tests/FuseAppLoopTest.cc')
-rw-r--r--libappfuse/tests/FuseAppLoopTest.cc307
1 files changed, 307 insertions, 0 deletions
diff --git a/libappfuse/tests/FuseAppLoopTest.cc b/libappfuse/tests/FuseAppLoopTest.cc
new file mode 100644
index 000000000..25906cf1c
--- /dev/null
+++ b/libappfuse/tests/FuseAppLoopTest.cc
@@ -0,0 +1,307 @@
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specic language governing permissions and
14 * limitations under the License.
15 */
16
17#include "libappfuse/FuseAppLoop.h"
18
19#include <sys/socket.h>
20
21#include <android-base/logging.h>
22#include <android-base/unique_fd.h>
23#include <gtest/gtest.h>
24#include <thread>
25
26namespace android {
27namespace fuse {
28namespace {
29
30constexpr unsigned int kTestFileSize = 1024;
31
32struct CallbackRequest {
33 uint32_t code;
34 uint64_t inode;
35};
36
37class Callback : public FuseAppLoopCallback {
38 public:
39 std::vector<CallbackRequest> requests;
40
41 bool IsActive() override {
42 return true;
43 }
44
45 int64_t OnGetSize(uint64_t inode) override {
46 if (inode == FUSE_ROOT_ID) {
47 return 0;
48 } else {
49 return kTestFileSize;
50 }
51 }
52
53 int32_t OnFsync(uint64_t inode) override {
54 requests.push_back({
55 .code = FUSE_FSYNC,
56 .inode = inode
57 });
58 return 0;
59 }
60
61 int32_t OnWrite(uint64_t inode,
62 uint64_t offset ATTRIBUTE_UNUSED,
63 uint32_t size ATTRIBUTE_UNUSED,
64 const void* data ATTRIBUTE_UNUSED) override {
65 requests.push_back({
66 .code = FUSE_WRITE,
67 .inode = inode
68 });
69 return 0;
70 }
71
72 int32_t OnRead(uint64_t inode,
73 uint64_t offset ATTRIBUTE_UNUSED,
74 uint32_t size ATTRIBUTE_UNUSED,
75 void* data ATTRIBUTE_UNUSED) override {
76 requests.push_back({
77 .code = FUSE_READ,
78 .inode = inode
79 });
80 return 0;
81 }
82
83 int32_t OnOpen(uint64_t inode) override {
84 requests.push_back({
85 .code = FUSE_OPEN,
86 .inode = inode
87 });
88 return 0;
89 }
90
91 int32_t OnRelease(uint64_t inode) override {
92 requests.push_back({
93 .code = FUSE_RELEASE,
94 .inode = inode
95 });
96 return 0;
97 }
98};
99
100class FuseAppLoopTest : public ::testing::Test {
101 private:
102 std::thread thread_;
103
104 protected:
105 base::unique_fd sockets_[2];
106 Callback callback_;
107 FuseRequest request_;
108 FuseResponse response_;
109
110 void SetUp() override {
111 base::SetMinimumLogSeverity(base::VERBOSE);
112 int sockets[2];
113 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets));
114 sockets_[0].reset(sockets[0]);
115 sockets_[1].reset(sockets[1]);
116 thread_ = std::thread([this] {
117 StartFuseAppLoop(sockets_[1].release(), &callback_);
118 });
119 }
120
121 void CheckCallback(
122 size_t data_size, uint32_t code, size_t expected_out_size) {
123 request_.Reset(data_size, code, 1);
124 request_.header.nodeid = 10;
125
126 ASSERT_TRUE(request_.Write(sockets_[0]));
127 ASSERT_TRUE(response_.Read(sockets_[0]));
128
129 Close();
130
131 EXPECT_EQ(kFuseSuccess, response_.header.error);
132 EXPECT_EQ(sizeof(fuse_out_header) + expected_out_size,
133 response_.header.len);
134 EXPECT_EQ(1u, response_.header.unique);
135
136 ASSERT_EQ(1u, callback_.requests.size());
137 EXPECT_EQ(code, callback_.requests[0].code);
138 EXPECT_EQ(10u, callback_.requests[0].inode);
139 }
140
141 void Close() {
142 sockets_[0].reset();
143 sockets_[1].reset();
144 if (thread_.joinable()) {
145 thread_.join();
146 }
147 }
148
149 void TearDown() override {
150 Close();
151 }
152};
153
154} // namespace
155
156TEST_F(FuseAppLoopTest, LookUp) {
157 request_.Reset(3u, FUSE_LOOKUP, 1);
158 request_.header.nodeid = FUSE_ROOT_ID;
159 strcpy(request_.lookup_name, "10");
160
161 ASSERT_TRUE(request_.Write(sockets_[0].get()));
162 ASSERT_TRUE(response_.Read(sockets_[0].get()));
163
164 EXPECT_EQ(kFuseSuccess, response_.header.error);
165 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_entry_out),
166 response_.header.len);
167 EXPECT_EQ(1u, response_.header.unique);
168
169 EXPECT_EQ(10u, response_.entry_out.nodeid);
170 EXPECT_EQ(0u, response_.entry_out.generation);
171 EXPECT_EQ(10u, response_.entry_out.entry_valid);
172 EXPECT_EQ(10u, response_.entry_out.attr_valid);
173 EXPECT_EQ(0u, response_.entry_out.entry_valid_nsec);
174 EXPECT_EQ(0u, response_.entry_out.attr_valid_nsec);
175
176 EXPECT_EQ(10u, response_.entry_out.attr.ino);
177 EXPECT_EQ(kTestFileSize, response_.entry_out.attr.size);
178 EXPECT_EQ(0u, response_.entry_out.attr.blocks);
179 EXPECT_EQ(0u, response_.entry_out.attr.atime);
180 EXPECT_EQ(0u, response_.entry_out.attr.mtime);
181 EXPECT_EQ(0u, response_.entry_out.attr.ctime);
182 EXPECT_EQ(0u, response_.entry_out.attr.atimensec);
183 EXPECT_EQ(0u, response_.entry_out.attr.mtimensec);
184 EXPECT_EQ(0u, response_.entry_out.attr.ctimensec);
185 EXPECT_EQ(S_IFREG | 0777u, response_.entry_out.attr.mode);
186 EXPECT_EQ(0u, response_.entry_out.attr.nlink);
187 EXPECT_EQ(0u, response_.entry_out.attr.uid);
188 EXPECT_EQ(0u, response_.entry_out.attr.gid);
189 EXPECT_EQ(0u, response_.entry_out.attr.rdev);
190 EXPECT_EQ(0u, response_.entry_out.attr.blksize);
191 EXPECT_EQ(0u, response_.entry_out.attr.padding);
192}
193
194TEST_F(FuseAppLoopTest, LookUp_InvalidName) {
195 request_.Reset(3u, FUSE_LOOKUP, 1);
196 request_.header.nodeid = FUSE_ROOT_ID;
197 strcpy(request_.lookup_name, "aa");
198
199 ASSERT_TRUE(request_.Write(sockets_[0].get()));
200 ASSERT_TRUE(response_.Read(sockets_[0].get()));
201
202 EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
203 EXPECT_EQ(-ENOENT, response_.header.error);
204 EXPECT_EQ(1u, response_.header.unique);
205}
206
207TEST_F(FuseAppLoopTest, LookUp_TooLargeName) {
208 request_.Reset(21u, FUSE_LOOKUP, 1);
209 request_.header.nodeid = FUSE_ROOT_ID;
210 strcpy(request_.lookup_name, "18446744073709551616");
211
212 ASSERT_TRUE(request_.Write(sockets_[0].get()));
213 ASSERT_TRUE(response_.Read(sockets_[0].get()));
214
215 EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
216 EXPECT_EQ(-ENOENT, response_.header.error);
217 EXPECT_EQ(1u, response_.header.unique);
218}
219
220TEST_F(FuseAppLoopTest, GetAttr) {
221 request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
222 request_.header.nodeid = 10;
223
224 ASSERT_TRUE(request_.Write(sockets_[0].get()));
225 ASSERT_TRUE(response_.Read(sockets_[0].get()));
226
227 EXPECT_EQ(kFuseSuccess, response_.header.error);
228 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
229 response_.header.len);
230 EXPECT_EQ(1u, response_.header.unique);
231
232 EXPECT_EQ(10u, response_.attr_out.attr_valid);
233 EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
234
235 EXPECT_EQ(10u, response_.attr_out.attr.ino);
236 EXPECT_EQ(kTestFileSize, response_.attr_out.attr.size);
237 EXPECT_EQ(0u, response_.attr_out.attr.blocks);
238 EXPECT_EQ(0u, response_.attr_out.attr.atime);
239 EXPECT_EQ(0u, response_.attr_out.attr.mtime);
240 EXPECT_EQ(0u, response_.attr_out.attr.ctime);
241 EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
242 EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
243 EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
244 EXPECT_EQ(S_IFREG | 0777u, response_.attr_out.attr.mode);
245 EXPECT_EQ(0u, response_.attr_out.attr.nlink);
246 EXPECT_EQ(0u, response_.attr_out.attr.uid);
247 EXPECT_EQ(0u, response_.attr_out.attr.gid);
248 EXPECT_EQ(0u, response_.attr_out.attr.rdev);
249 EXPECT_EQ(0u, response_.attr_out.attr.blksize);
250 EXPECT_EQ(0u, response_.attr_out.attr.padding);
251}
252
253TEST_F(FuseAppLoopTest, GetAttr_Root) {
254 request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
255 request_.header.nodeid = FUSE_ROOT_ID;
256
257 ASSERT_TRUE(request_.Write(sockets_[0].get()));
258 ASSERT_TRUE(response_.Read(sockets_[0].get()));
259
260 EXPECT_EQ(kFuseSuccess, response_.header.error);
261 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
262 response_.header.len);
263 EXPECT_EQ(1u, response_.header.unique);
264
265 EXPECT_EQ(10u, response_.attr_out.attr_valid);
266 EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
267
268 EXPECT_EQ(static_cast<unsigned>(FUSE_ROOT_ID), response_.attr_out.attr.ino);
269 EXPECT_EQ(0u, response_.attr_out.attr.size);
270 EXPECT_EQ(0u, response_.attr_out.attr.blocks);
271 EXPECT_EQ(0u, response_.attr_out.attr.atime);
272 EXPECT_EQ(0u, response_.attr_out.attr.mtime);
273 EXPECT_EQ(0u, response_.attr_out.attr.ctime);
274 EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
275 EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
276 EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
277 EXPECT_EQ(S_IFDIR | 0777u, response_.attr_out.attr.mode);
278 EXPECT_EQ(0u, response_.attr_out.attr.nlink);
279 EXPECT_EQ(0u, response_.attr_out.attr.uid);
280 EXPECT_EQ(0u, response_.attr_out.attr.gid);
281 EXPECT_EQ(0u, response_.attr_out.attr.rdev);
282 EXPECT_EQ(0u, response_.attr_out.attr.blksize);
283 EXPECT_EQ(0u, response_.attr_out.attr.padding);
284}
285
286TEST_F(FuseAppLoopTest, Open) {
287 CheckCallback(sizeof(fuse_open_in), FUSE_OPEN, sizeof(fuse_open_out));
288}
289
290TEST_F(FuseAppLoopTest, Fsync) {
291 CheckCallback(0u, FUSE_FSYNC, 0u);
292}
293
294TEST_F(FuseAppLoopTest, Release) {
295 CheckCallback(0u, FUSE_RELEASE, 0u);
296}
297
298TEST_F(FuseAppLoopTest, Read) {
299 CheckCallback(sizeof(fuse_read_in), FUSE_READ, 0u);
300}
301
302TEST_F(FuseAppLoopTest, Write) {
303 CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
304}
305
306} // namespace fuse
307} // namespace android