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
26 #include "libappfuse/EpollController.h"
27 #include "libappfuse/FuseBridgeLoop.h"
28
29 namespace android {
30 namespace fuse {
31 namespace {
32
33 constexpr unsigned int kTestFileSize = 1024;
34
35 struct CallbackRequest {
36 uint32_t code;
37 uint64_t inode;
38 };
39
40 class Callback : public FuseAppLoopCallback {
41 public:
42 std::vector<CallbackRequest> requests;
43 FuseAppLoop* loop;
44
OnGetAttr(uint64_t seq,uint64_t inode)45 void OnGetAttr(uint64_t seq, uint64_t inode) override {
46 EXPECT_NE(FUSE_ROOT_ID, static_cast<int>(inode));
47 EXPECT_TRUE(loop->ReplyGetAttr(seq, inode, kTestFileSize, S_IFREG | 0777));
48 }
49
OnLookup(uint64_t unique,uint64_t inode)50 void OnLookup(uint64_t unique, uint64_t inode) override {
51 EXPECT_NE(FUSE_ROOT_ID, static_cast<int>(inode));
52 EXPECT_TRUE(loop->ReplyLookup(unique, inode, kTestFileSize));
53 }
54
OnFsync(uint64_t seq,uint64_t inode)55 void OnFsync(uint64_t seq, uint64_t inode) override {
56 requests.push_back({.code = FUSE_FSYNC, .inode = inode});
57 loop->ReplySimple(seq, 0);
58 }
59
OnWrite(uint64_t seq,uint64_t inode,uint64_t offset ATTRIBUTE_UNUSED,uint32_t size ATTRIBUTE_UNUSED,const void * data ATTRIBUTE_UNUSED)60 void OnWrite(uint64_t seq, uint64_t inode, uint64_t offset ATTRIBUTE_UNUSED,
61 uint32_t size ATTRIBUTE_UNUSED, const void* data ATTRIBUTE_UNUSED) override {
62 requests.push_back({.code = FUSE_WRITE, .inode = inode});
63 loop->ReplyWrite(seq, 0);
64 }
65
OnRead(uint64_t seq,uint64_t inode,uint64_t offset ATTRIBUTE_UNUSED,uint32_t size ATTRIBUTE_UNUSED)66 void OnRead(uint64_t seq, uint64_t inode, uint64_t offset ATTRIBUTE_UNUSED,
67 uint32_t size ATTRIBUTE_UNUSED) override {
68 requests.push_back({.code = FUSE_READ, .inode = inode});
69 loop->ReplySimple(seq, 0);
70 }
71
OnOpen(uint64_t seq,uint64_t inode)72 void OnOpen(uint64_t seq, uint64_t inode) override {
73 requests.push_back({.code = FUSE_OPEN, .inode = inode});
74 loop->ReplyOpen(seq, inode);
75 }
76
OnRelease(uint64_t seq,uint64_t inode)77 void OnRelease(uint64_t seq, uint64_t inode) override {
78 requests.push_back({.code = FUSE_RELEASE, .inode = inode});
79 loop->ReplySimple(seq, 0);
80 }
81 };
82
83 class FuseAppLoopTest : public ::testing::Test {
84 protected:
85 std::thread thread_;
86 base::unique_fd sockets_[2];
87 Callback callback_;
88 FuseRequest request_;
89 FuseResponse response_;
90 std::unique_ptr<FuseAppLoop> loop_;
91
SetUp()92 void SetUp() override {
93 base::SetMinimumLogSeverity(base::VERBOSE);
94 ASSERT_TRUE(SetupMessageSockets(&sockets_));
95 loop_.reset(new FuseAppLoop(std::move(sockets_[1])));
96 callback_.loop = loop_.get();
97 thread_ = std::thread([this] { loop_->Start(&callback_); });
98 }
99
CheckCallback(size_t data_size,uint32_t code,size_t expected_out_size)100 void CheckCallback(
101 size_t data_size, uint32_t code, size_t expected_out_size) {
102 request_.Reset(data_size, code, 1);
103 request_.header.nodeid = 10;
104
105 ASSERT_TRUE(request_.Write(sockets_[0]));
106 ASSERT_TRUE(response_.Read(sockets_[0]));
107
108 Close();
109
110 EXPECT_EQ(kFuseSuccess, response_.header.error);
111 EXPECT_EQ(sizeof(fuse_out_header) + expected_out_size,
112 response_.header.len);
113 EXPECT_EQ(1u, response_.header.unique);
114
115 ASSERT_EQ(1u, callback_.requests.size());
116 EXPECT_EQ(code, callback_.requests[0].code);
117 EXPECT_EQ(10u, callback_.requests[0].inode);
118 }
119
Close()120 void Close() {
121 sockets_[0].reset();
122 sockets_[1].reset();
123 if (thread_.joinable()) {
124 thread_.join();
125 }
126 }
127
TearDown()128 void TearDown() override {
129 Close();
130 }
131 };
132
133 } // namespace
134
TEST_F(FuseAppLoopTest,LookUp)135 TEST_F(FuseAppLoopTest, LookUp) {
136 request_.Reset(3u, FUSE_LOOKUP, 1);
137 request_.header.nodeid = FUSE_ROOT_ID;
138 strcpy(request_.lookup_name, "10");
139
140 ASSERT_TRUE(request_.Write(sockets_[0].get()));
141 ASSERT_TRUE(response_.Read(sockets_[0].get()));
142
143 EXPECT_EQ(kFuseSuccess, response_.header.error);
144 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_entry_out),
145 response_.header.len);
146 EXPECT_EQ(1u, response_.header.unique);
147
148 EXPECT_EQ(10u, response_.entry_out.nodeid);
149 EXPECT_EQ(0u, response_.entry_out.generation);
150 EXPECT_EQ(10u, response_.entry_out.entry_valid);
151 EXPECT_EQ(10u, response_.entry_out.attr_valid);
152 EXPECT_EQ(0u, response_.entry_out.entry_valid_nsec);
153 EXPECT_EQ(0u, response_.entry_out.attr_valid_nsec);
154
155 EXPECT_EQ(10u, response_.entry_out.attr.ino);
156 EXPECT_EQ(kTestFileSize, response_.entry_out.attr.size);
157 EXPECT_EQ(0u, response_.entry_out.attr.blocks);
158 EXPECT_EQ(0u, response_.entry_out.attr.atime);
159 EXPECT_EQ(0u, response_.entry_out.attr.mtime);
160 EXPECT_EQ(0u, response_.entry_out.attr.ctime);
161 EXPECT_EQ(0u, response_.entry_out.attr.atimensec);
162 EXPECT_EQ(0u, response_.entry_out.attr.mtimensec);
163 EXPECT_EQ(0u, response_.entry_out.attr.ctimensec);
164 EXPECT_EQ(S_IFREG | 0777u, response_.entry_out.attr.mode);
165 EXPECT_EQ(0u, response_.entry_out.attr.nlink);
166 EXPECT_EQ(0u, response_.entry_out.attr.uid);
167 EXPECT_EQ(0u, response_.entry_out.attr.gid);
168 EXPECT_EQ(0u, response_.entry_out.attr.rdev);
169 EXPECT_EQ(0u, response_.entry_out.attr.blksize);
170 EXPECT_EQ(0u, response_.entry_out.attr.padding);
171 }
172
TEST_F(FuseAppLoopTest,LookUp_InvalidName)173 TEST_F(FuseAppLoopTest, LookUp_InvalidName) {
174 request_.Reset(3u, FUSE_LOOKUP, 1);
175 request_.header.nodeid = FUSE_ROOT_ID;
176 strcpy(request_.lookup_name, "aa");
177
178 ASSERT_TRUE(request_.Write(sockets_[0].get()));
179 ASSERT_TRUE(response_.Read(sockets_[0].get()));
180
181 EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
182 EXPECT_EQ(-ENOENT, response_.header.error);
183 EXPECT_EQ(1u, response_.header.unique);
184 }
185
TEST_F(FuseAppLoopTest,LookUp_TooLargeName)186 TEST_F(FuseAppLoopTest, LookUp_TooLargeName) {
187 request_.Reset(21u, FUSE_LOOKUP, 1);
188 request_.header.nodeid = FUSE_ROOT_ID;
189 strcpy(request_.lookup_name, "18446744073709551616");
190
191 ASSERT_TRUE(request_.Write(sockets_[0].get()));
192 ASSERT_TRUE(response_.Read(sockets_[0].get()));
193
194 EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
195 EXPECT_EQ(-ENOENT, response_.header.error);
196 EXPECT_EQ(1u, response_.header.unique);
197 }
198
TEST_F(FuseAppLoopTest,GetAttr)199 TEST_F(FuseAppLoopTest, GetAttr) {
200 request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
201 request_.header.nodeid = 10;
202
203 ASSERT_TRUE(request_.Write(sockets_[0].get()));
204 ASSERT_TRUE(response_.Read(sockets_[0].get()));
205
206 EXPECT_EQ(kFuseSuccess, response_.header.error);
207 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
208 response_.header.len);
209 EXPECT_EQ(1u, response_.header.unique);
210
211 EXPECT_EQ(10u, response_.attr_out.attr_valid);
212 EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
213
214 EXPECT_EQ(10u, response_.attr_out.attr.ino);
215 EXPECT_EQ(kTestFileSize, response_.attr_out.attr.size);
216 EXPECT_EQ(0u, response_.attr_out.attr.blocks);
217 EXPECT_EQ(0u, response_.attr_out.attr.atime);
218 EXPECT_EQ(0u, response_.attr_out.attr.mtime);
219 EXPECT_EQ(0u, response_.attr_out.attr.ctime);
220 EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
221 EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
222 EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
223 EXPECT_EQ(S_IFREG | 0777u, response_.attr_out.attr.mode);
224 EXPECT_EQ(0u, response_.attr_out.attr.nlink);
225 EXPECT_EQ(0u, response_.attr_out.attr.uid);
226 EXPECT_EQ(0u, response_.attr_out.attr.gid);
227 EXPECT_EQ(0u, response_.attr_out.attr.rdev);
228 EXPECT_EQ(0u, response_.attr_out.attr.blksize);
229 EXPECT_EQ(0u, response_.attr_out.attr.padding);
230 }
231
TEST_F(FuseAppLoopTest,GetAttr_Root)232 TEST_F(FuseAppLoopTest, GetAttr_Root) {
233 request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
234 request_.header.nodeid = FUSE_ROOT_ID;
235
236 ASSERT_TRUE(request_.Write(sockets_[0].get()));
237 ASSERT_TRUE(response_.Read(sockets_[0].get()));
238
239 EXPECT_EQ(kFuseSuccess, response_.header.error);
240 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
241 response_.header.len);
242 EXPECT_EQ(1u, response_.header.unique);
243
244 EXPECT_EQ(10u, response_.attr_out.attr_valid);
245 EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
246
247 EXPECT_EQ(static_cast<unsigned>(FUSE_ROOT_ID), response_.attr_out.attr.ino);
248 EXPECT_EQ(0u, response_.attr_out.attr.size);
249 EXPECT_EQ(0u, response_.attr_out.attr.blocks);
250 EXPECT_EQ(0u, response_.attr_out.attr.atime);
251 EXPECT_EQ(0u, response_.attr_out.attr.mtime);
252 EXPECT_EQ(0u, response_.attr_out.attr.ctime);
253 EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
254 EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
255 EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
256 EXPECT_EQ(S_IFDIR | 0777u, response_.attr_out.attr.mode);
257 EXPECT_EQ(0u, response_.attr_out.attr.nlink);
258 EXPECT_EQ(0u, response_.attr_out.attr.uid);
259 EXPECT_EQ(0u, response_.attr_out.attr.gid);
260 EXPECT_EQ(0u, response_.attr_out.attr.rdev);
261 EXPECT_EQ(0u, response_.attr_out.attr.blksize);
262 EXPECT_EQ(0u, response_.attr_out.attr.padding);
263 }
264
TEST_F(FuseAppLoopTest,Open)265 TEST_F(FuseAppLoopTest, Open) {
266 CheckCallback(sizeof(fuse_open_in), FUSE_OPEN, sizeof(fuse_open_out));
267 }
268
TEST_F(FuseAppLoopTest,Fsync)269 TEST_F(FuseAppLoopTest, Fsync) {
270 CheckCallback(0u, FUSE_FSYNC, 0u);
271 }
272
TEST_F(FuseAppLoopTest,Release)273 TEST_F(FuseAppLoopTest, Release) {
274 CheckCallback(0u, FUSE_RELEASE, 0u);
275 }
276
TEST_F(FuseAppLoopTest,Read)277 TEST_F(FuseAppLoopTest, Read) {
278 CheckCallback(sizeof(fuse_read_in), FUSE_READ, 0u);
279 }
280
TEST_F(FuseAppLoopTest,Write)281 TEST_F(FuseAppLoopTest, Write) {
282 CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
283 }
284
TEST_F(FuseAppLoopTest,Break)285 TEST_F(FuseAppLoopTest, Break) {
286 // Ensure that the loop started.
287 request_.Reset(sizeof(fuse_open_in), FUSE_OPEN, 1);
288 request_.header.nodeid = 10;
289 ASSERT_TRUE(request_.Write(sockets_[0]));
290 ASSERT_TRUE(response_.Read(sockets_[0]));
291
292 loop_->Break();
293 if (thread_.joinable()) {
294 thread_.join();
295 }
296 }
297
298 } // namespace fuse
299 } // namespace android
300