blob: 64dd8133025ef69b21db7acc5235a30090881c49 [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
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);
Daichi Hirono57b780f2017-03-06 14:02:42 +0900112 ASSERT_TRUE(SetupMessageSockets(&sockets_));
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900113 thread_ = std::thread([this] {
114 StartFuseAppLoop(sockets_[1].release(), &callback_);
115 });
116 }
117
118 void CheckCallback(
119 size_t data_size, uint32_t code, size_t expected_out_size) {
120 request_.Reset(data_size, code, 1);
121 request_.header.nodeid = 10;
122
123 ASSERT_TRUE(request_.Write(sockets_[0]));
124 ASSERT_TRUE(response_.Read(sockets_[0]));
125
126 Close();
127
128 EXPECT_EQ(kFuseSuccess, response_.header.error);
129 EXPECT_EQ(sizeof(fuse_out_header) + expected_out_size,
130 response_.header.len);
131 EXPECT_EQ(1u, response_.header.unique);
132
133 ASSERT_EQ(1u, callback_.requests.size());
134 EXPECT_EQ(code, callback_.requests[0].code);
135 EXPECT_EQ(10u, callback_.requests[0].inode);
136 }
137
138 void Close() {
139 sockets_[0].reset();
140 sockets_[1].reset();
141 if (thread_.joinable()) {
142 thread_.join();
143 }
144 }
145
146 void TearDown() override {
147 Close();
148 }
149};
150
151} // namespace
152
153TEST_F(FuseAppLoopTest, LookUp) {
154 request_.Reset(3u, FUSE_LOOKUP, 1);
155 request_.header.nodeid = FUSE_ROOT_ID;
156 strcpy(request_.lookup_name, "10");
157
158 ASSERT_TRUE(request_.Write(sockets_[0].get()));
159 ASSERT_TRUE(response_.Read(sockets_[0].get()));
160
161 EXPECT_EQ(kFuseSuccess, response_.header.error);
162 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_entry_out),
163 response_.header.len);
164 EXPECT_EQ(1u, response_.header.unique);
165
166 EXPECT_EQ(10u, response_.entry_out.nodeid);
167 EXPECT_EQ(0u, response_.entry_out.generation);
168 EXPECT_EQ(10u, response_.entry_out.entry_valid);
169 EXPECT_EQ(10u, response_.entry_out.attr_valid);
170 EXPECT_EQ(0u, response_.entry_out.entry_valid_nsec);
171 EXPECT_EQ(0u, response_.entry_out.attr_valid_nsec);
172
173 EXPECT_EQ(10u, response_.entry_out.attr.ino);
174 EXPECT_EQ(kTestFileSize, response_.entry_out.attr.size);
175 EXPECT_EQ(0u, response_.entry_out.attr.blocks);
176 EXPECT_EQ(0u, response_.entry_out.attr.atime);
177 EXPECT_EQ(0u, response_.entry_out.attr.mtime);
178 EXPECT_EQ(0u, response_.entry_out.attr.ctime);
179 EXPECT_EQ(0u, response_.entry_out.attr.atimensec);
180 EXPECT_EQ(0u, response_.entry_out.attr.mtimensec);
181 EXPECT_EQ(0u, response_.entry_out.attr.ctimensec);
182 EXPECT_EQ(S_IFREG | 0777u, response_.entry_out.attr.mode);
183 EXPECT_EQ(0u, response_.entry_out.attr.nlink);
184 EXPECT_EQ(0u, response_.entry_out.attr.uid);
185 EXPECT_EQ(0u, response_.entry_out.attr.gid);
186 EXPECT_EQ(0u, response_.entry_out.attr.rdev);
187 EXPECT_EQ(0u, response_.entry_out.attr.blksize);
188 EXPECT_EQ(0u, response_.entry_out.attr.padding);
189}
190
191TEST_F(FuseAppLoopTest, LookUp_InvalidName) {
192 request_.Reset(3u, FUSE_LOOKUP, 1);
193 request_.header.nodeid = FUSE_ROOT_ID;
194 strcpy(request_.lookup_name, "aa");
195
196 ASSERT_TRUE(request_.Write(sockets_[0].get()));
197 ASSERT_TRUE(response_.Read(sockets_[0].get()));
198
199 EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
200 EXPECT_EQ(-ENOENT, response_.header.error);
201 EXPECT_EQ(1u, response_.header.unique);
202}
203
204TEST_F(FuseAppLoopTest, LookUp_TooLargeName) {
205 request_.Reset(21u, FUSE_LOOKUP, 1);
206 request_.header.nodeid = FUSE_ROOT_ID;
207 strcpy(request_.lookup_name, "18446744073709551616");
208
209 ASSERT_TRUE(request_.Write(sockets_[0].get()));
210 ASSERT_TRUE(response_.Read(sockets_[0].get()));
211
212 EXPECT_EQ(sizeof(fuse_out_header), response_.header.len);
213 EXPECT_EQ(-ENOENT, response_.header.error);
214 EXPECT_EQ(1u, response_.header.unique);
215}
216
217TEST_F(FuseAppLoopTest, GetAttr) {
218 request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
219 request_.header.nodeid = 10;
220
221 ASSERT_TRUE(request_.Write(sockets_[0].get()));
222 ASSERT_TRUE(response_.Read(sockets_[0].get()));
223
224 EXPECT_EQ(kFuseSuccess, response_.header.error);
225 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
226 response_.header.len);
227 EXPECT_EQ(1u, response_.header.unique);
228
229 EXPECT_EQ(10u, response_.attr_out.attr_valid);
230 EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
231
232 EXPECT_EQ(10u, response_.attr_out.attr.ino);
233 EXPECT_EQ(kTestFileSize, response_.attr_out.attr.size);
234 EXPECT_EQ(0u, response_.attr_out.attr.blocks);
235 EXPECT_EQ(0u, response_.attr_out.attr.atime);
236 EXPECT_EQ(0u, response_.attr_out.attr.mtime);
237 EXPECT_EQ(0u, response_.attr_out.attr.ctime);
238 EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
239 EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
240 EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
241 EXPECT_EQ(S_IFREG | 0777u, response_.attr_out.attr.mode);
242 EXPECT_EQ(0u, response_.attr_out.attr.nlink);
243 EXPECT_EQ(0u, response_.attr_out.attr.uid);
244 EXPECT_EQ(0u, response_.attr_out.attr.gid);
245 EXPECT_EQ(0u, response_.attr_out.attr.rdev);
246 EXPECT_EQ(0u, response_.attr_out.attr.blksize);
247 EXPECT_EQ(0u, response_.attr_out.attr.padding);
248}
249
250TEST_F(FuseAppLoopTest, GetAttr_Root) {
251 request_.Reset(sizeof(fuse_getattr_in), FUSE_GETATTR, 1);
252 request_.header.nodeid = FUSE_ROOT_ID;
253
254 ASSERT_TRUE(request_.Write(sockets_[0].get()));
255 ASSERT_TRUE(response_.Read(sockets_[0].get()));
256
257 EXPECT_EQ(kFuseSuccess, response_.header.error);
258 EXPECT_EQ(sizeof(fuse_out_header) + sizeof(fuse_attr_out),
259 response_.header.len);
260 EXPECT_EQ(1u, response_.header.unique);
261
262 EXPECT_EQ(10u, response_.attr_out.attr_valid);
263 EXPECT_EQ(0u, response_.attr_out.attr_valid_nsec);
264
265 EXPECT_EQ(static_cast<unsigned>(FUSE_ROOT_ID), response_.attr_out.attr.ino);
266 EXPECT_EQ(0u, response_.attr_out.attr.size);
267 EXPECT_EQ(0u, response_.attr_out.attr.blocks);
268 EXPECT_EQ(0u, response_.attr_out.attr.atime);
269 EXPECT_EQ(0u, response_.attr_out.attr.mtime);
270 EXPECT_EQ(0u, response_.attr_out.attr.ctime);
271 EXPECT_EQ(0u, response_.attr_out.attr.atimensec);
272 EXPECT_EQ(0u, response_.attr_out.attr.mtimensec);
273 EXPECT_EQ(0u, response_.attr_out.attr.ctimensec);
274 EXPECT_EQ(S_IFDIR | 0777u, response_.attr_out.attr.mode);
275 EXPECT_EQ(0u, response_.attr_out.attr.nlink);
276 EXPECT_EQ(0u, response_.attr_out.attr.uid);
277 EXPECT_EQ(0u, response_.attr_out.attr.gid);
278 EXPECT_EQ(0u, response_.attr_out.attr.rdev);
279 EXPECT_EQ(0u, response_.attr_out.attr.blksize);
280 EXPECT_EQ(0u, response_.attr_out.attr.padding);
281}
282
283TEST_F(FuseAppLoopTest, Open) {
284 CheckCallback(sizeof(fuse_open_in), FUSE_OPEN, sizeof(fuse_open_out));
285}
286
287TEST_F(FuseAppLoopTest, Fsync) {
288 CheckCallback(0u, FUSE_FSYNC, 0u);
289}
290
291TEST_F(FuseAppLoopTest, Release) {
292 CheckCallback(0u, FUSE_RELEASE, 0u);
293}
294
295TEST_F(FuseAppLoopTest, Read) {
296 CheckCallback(sizeof(fuse_read_in), FUSE_READ, 0u);
297}
298
299TEST_F(FuseAppLoopTest, Write) {
300 CheckCallback(sizeof(fuse_write_in), FUSE_WRITE, sizeof(fuse_write_out));
301}
302
303} // namespace fuse
304} // namespace android