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
29namespace android {
30namespace fuse {
31namespace {
32
33constexpr unsigned int kTestFileSize = 1024;
34
35struct CallbackRequest {
36  uint32_t code;
37  uint64_t inode;
38};
39
40class Callback : public FuseAppLoopCallback {
41 public:
42  std::vector<CallbackRequest> requests;
43  FuseAppLoop* loop;
44
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
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
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
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
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
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
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
83class 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
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
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
120  void Close() {
121    sockets_[0].reset();
122    sockets_[1].reset();
123    if (thread_.joinable()) {
124      thread_.join();
125    }
126  }
127
128  void TearDown() override {
129    Close();
130  }
131};
132
133}  // namespace
134
135TEST_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
173TEST_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
186TEST_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
199TEST_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
232TEST_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
265TEST_F(FuseAppLoopTest, Open) {
266  CheckCallback(sizeof(fuse_open_in), FUSE_OPEN, sizeof(fuse_open_out));
267}
268
269TEST_F(FuseAppLoopTest, Fsync) {
270  CheckCallback(0u, FUSE_FSYNC, 0u);
271}
272
273TEST_F(FuseAppLoopTest, Release) {
274  CheckCallback(0u, FUSE_RELEASE, 0u);
275}
276
277TEST_F(FuseAppLoopTest, Read) {
278  CheckCallback(sizeof(fuse_read_in), FUSE_READ, 0u);
279}
280
281TEST_F(FuseAppLoopTest, Write) {
282  CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
283}
284
285TEST_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