• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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