blob: 98e36652aabb1e4dc4d04855bd0f11aa3d24b0d9 [file] [log] [blame]
Daichi Hironoa0aecda2016-11-08 10:17:51 +09001/*
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
Daichi Hironof5d15f92017-03-06 15:23:16 +090026#include "libappfuse/EpollController.h"
27#include "libappfuse/FuseBridgeLoop.h"
28
Daichi Hironoa0aecda2016-11-08 10:17:51 +090029namespace 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;
Daichi Hironof5d15f92017-03-06 15:23:16 +090043 FuseAppLoop* loop;
Daichi Hironoa0aecda2016-11-08 10:17:51 +090044
Daichi Hironof5d15f92017-03-06 15:23:16 +090045 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));
Daichi Hironoa0aecda2016-11-08 10:17:51 +090048 }
49
Daichi Hironof5d15f92017-03-06 15:23:16 +090050 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));
Daichi Hironoa0aecda2016-11-08 10:17:51 +090053 }
54
Daichi Hironof5d15f92017-03-06 15:23:16 +090055 void OnFsync(uint64_t seq, uint64_t inode) override {
56 requests.push_back({.code = FUSE_FSYNC, .inode = inode});
57 loop->ReplySimple(seq, 0);
Daichi Hironoa0aecda2016-11-08 10:17:51 +090058 }
59
Daichi Hironof5d15f92017-03-06 15:23:16 +090060 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);
Daichi Hironoa0aecda2016-11-08 10:17:51 +090064 }
65
Daichi Hironof5d15f92017-03-06 15:23:16 +090066 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);
Daichi Hironoa0aecda2016-11-08 10:17:51 +090070 }
71
Daichi Hironof5d15f92017-03-06 15:23:16 +090072 void OnOpen(uint64_t seq, uint64_t inode) override {
73 requests.push_back({.code = FUSE_OPEN, .inode = inode});
74 loop->ReplyOpen(seq, inode);
Daichi Hironoa0aecda2016-11-08 10:17:51 +090075 }
76
Daichi Hironof5d15f92017-03-06 15:23:16 +090077 void OnRelease(uint64_t seq, uint64_t inode) override {
78 requests.push_back({.code = FUSE_RELEASE, .inode = inode});
79 loop->ReplySimple(seq, 0);
Daichi Hironoa0aecda2016-11-08 10:17:51 +090080 }
81};
82
83class FuseAppLoopTest : public ::testing::Test {
Daichi Hironoa0aecda2016-11-08 10:17:51 +090084 protected:
Daichi Hironof5d15f92017-03-06 15:23:16 +090085 std::thread thread_;
86 base::unique_fd sockets_[2];
87 Callback callback_;
88 FuseRequest request_;
89 FuseResponse response_;
90 std::unique_ptr<FuseAppLoop> loop_;
Daichi Hironoa0aecda2016-11-08 10:17:51 +090091
Daichi Hironof5d15f92017-03-06 15:23:16 +090092 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_); });
Daichi Hironoa0aecda2016-11-08 10:17:51 +090098 }
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
Daichi Hironof5d15f92017-03-06 15:23:16 +0900285TEST_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
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900298} // namespace fuse
299} // namespace android