blob: 0a28451bfc976b8445d5045ca7e5daae6ba5ed4e [file] [log] [blame]
Daichi Hironoc6134762016-10-27 14:57:55 +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/FuseBridgeLoop.h"
18
19#include <sys/socket.h>
20
21#include <sstream>
22#include <thread>
23
Daichi Hironoa0aecda2016-11-08 10:17:51 +090024#include <android-base/logging.h>
25#include <android-base/unique_fd.h>
Daichi Hironoc6134762016-10-27 14:57:55 +090026#include <gtest/gtest.h>
27
28namespace android {
Daichi Hironoa0aecda2016-11-08 10:17:51 +090029namespace fuse {
30namespace {
Daichi Hironoc6134762016-10-27 14:57:55 +090031
Daichi Hironoa0aecda2016-11-08 10:17:51 +090032class Callback : public FuseBridgeLoopCallback {
Daichi Hironoc6134762016-10-27 14:57:55 +090033 public:
34 bool mounted;
Daichi Hirono96c6aa42017-03-06 15:37:20 +090035 bool closed;
36 Callback() : mounted(false), closed(false) {}
37
38 void OnMount(int /*mount_id*/) override { mounted = true; }
39
40 void OnClosed(int /* mount_id */) override { closed = true; }
Daichi Hironoc6134762016-10-27 14:57:55 +090041};
42
43class FuseBridgeLoopTest : public ::testing::Test {
44 protected:
Daichi Hironoa0aecda2016-11-08 10:17:51 +090045 base::unique_fd dev_sockets_[2];
46 base::unique_fd proxy_sockets_[2];
Daichi Hironoc6134762016-10-27 14:57:55 +090047 Callback callback_;
48 std::thread thread_;
49
50 FuseRequest request_;
51 FuseResponse response_;
52
Daichi Hironoa0aecda2016-11-08 10:17:51 +090053 void SetUp() override {
54 base::SetMinimumLogSeverity(base::VERBOSE);
Daichi Hirono57b780f2017-03-06 14:02:42 +090055 ASSERT_TRUE(SetupMessageSockets(&dev_sockets_));
56 ASSERT_TRUE(SetupMessageSockets(&proxy_sockets_));
Daichi Hironoc6134762016-10-27 14:57:55 +090057 thread_ = std::thread([this] {
Daichi Hirono96c6aa42017-03-06 15:37:20 +090058 FuseBridgeLoop loop;
59 loop.AddBridge(1, std::move(dev_sockets_[1]), std::move(proxy_sockets_[0]));
60 loop.Start(&callback_);
Daichi Hironoc6134762016-10-27 14:57:55 +090061 });
62 }
63
64 void CheckNotImpl(uint32_t opcode) {
65 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
66
67 memset(&request_, 0, sizeof(FuseRequest));
68 request_.header.opcode = opcode;
69 request_.header.len = sizeof(fuse_in_header);
Daichi Hironoafa34532017-06-15 15:48:07 +090070 request_.header.unique = 1;
Daichi Hironoc6134762016-10-27 14:57:55 +090071 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
72
73 memset(&response_, 0, sizeof(FuseResponse));
74 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
75 EXPECT_EQ(-ENOSYS, response_.header.error);
76 }
77
78 void CheckProxy(uint32_t opcode) {
79 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
80
81 memset(&request_, 0, sizeof(FuseRequest));
82 request_.header.opcode = opcode;
83 request_.header.unique = opcode; // Use opcode as unique.
84 request_.header.len = sizeof(fuse_in_header);
85 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
86
87 memset(&request_, 0, sizeof(FuseRequest));
88 ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
89 EXPECT_EQ(opcode, request_.header.opcode);
90 EXPECT_EQ(opcode, request_.header.unique);
91
92 memset(&response_, 0, sizeof(FuseResponse));
93 response_.header.len = sizeof(fuse_out_header);
94 response_.header.unique = opcode; // Use opcode as unique.
95 response_.header.error = kFuseSuccess;
96 ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
97
98 memset(&response_, 0, sizeof(FuseResponse));
99 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
100 EXPECT_EQ(opcode, response_.header.unique);
101 EXPECT_EQ(kFuseSuccess, response_.header.error);
102 }
103
104 void SendInitRequest(uint64_t unique) {
105 memset(&request_, 0, sizeof(FuseRequest));
106 request_.header.opcode = FUSE_INIT;
107 request_.header.unique = unique;
108 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
109 request_.init_in.major = FUSE_KERNEL_VERSION;
110 request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
111 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
112 }
113
114 void Close() {
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900115 dev_sockets_[0].reset();
116 dev_sockets_[1].reset();
117 proxy_sockets_[0].reset();
118 proxy_sockets_[1].reset();
Daichi Hironoc6134762016-10-27 14:57:55 +0900119 if (thread_.joinable()) {
120 thread_.join();
121 }
Daichi Hirono96c6aa42017-03-06 15:37:20 +0900122 ASSERT_TRUE(callback_.closed);
Daichi Hironoc6134762016-10-27 14:57:55 +0900123 }
124
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900125 void TearDown() override {
Daichi Hironoc6134762016-10-27 14:57:55 +0900126 Close();
127 }
128};
129
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900130} // namespace
131
Daichi Hironoc6134762016-10-27 14:57:55 +0900132TEST_F(FuseBridgeLoopTest, FuseInit) {
133 SendInitRequest(1u);
134
135 memset(&response_, 0, sizeof(FuseResponse));
136 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
137 EXPECT_EQ(kFuseSuccess, response_.header.error);
138 EXPECT_EQ(1u, response_.header.unique);
139
140 // Unmount.
141 Close();
142 EXPECT_TRUE(callback_.mounted);
143}
144
145TEST_F(FuseBridgeLoopTest, FuseForget) {
146 memset(&request_, 0, sizeof(FuseRequest));
147 request_.header.opcode = FUSE_FORGET;
148 request_.header.unique = 1u;
149 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
150 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
151
152 SendInitRequest(2u);
153
154 memset(&response_, 0, sizeof(FuseResponse));
155 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
156 EXPECT_EQ(2u, response_.header.unique) <<
157 "The loop must not respond to FUSE_FORGET";
158}
159
160TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
161 CheckNotImpl(FUSE_SETATTR);
162 CheckNotImpl(FUSE_READLINK);
163 CheckNotImpl(FUSE_SYMLINK);
164 CheckNotImpl(FUSE_MKNOD);
165 CheckNotImpl(FUSE_MKDIR);
166 CheckNotImpl(FUSE_UNLINK);
167 CheckNotImpl(FUSE_RMDIR);
168 CheckNotImpl(FUSE_RENAME);
169 CheckNotImpl(FUSE_LINK);
170 CheckNotImpl(FUSE_STATFS);
Daichi Hironoc6134762016-10-27 14:57:55 +0900171 CheckNotImpl(FUSE_SETXATTR);
172 CheckNotImpl(FUSE_GETXATTR);
173 CheckNotImpl(FUSE_LISTXATTR);
174 CheckNotImpl(FUSE_REMOVEXATTR);
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900175 CheckNotImpl(FUSE_FLUSH);
Daichi Hironoc6134762016-10-27 14:57:55 +0900176 CheckNotImpl(FUSE_OPENDIR);
177 CheckNotImpl(FUSE_READDIR);
178 CheckNotImpl(FUSE_RELEASEDIR);
179 CheckNotImpl(FUSE_FSYNCDIR);
180 CheckNotImpl(FUSE_GETLK);
181 CheckNotImpl(FUSE_SETLK);
182 CheckNotImpl(FUSE_SETLKW);
183 CheckNotImpl(FUSE_ACCESS);
184 CheckNotImpl(FUSE_CREATE);
185 CheckNotImpl(FUSE_INTERRUPT);
186 CheckNotImpl(FUSE_BMAP);
187 CheckNotImpl(FUSE_DESTROY);
188 CheckNotImpl(FUSE_IOCTL);
189 CheckNotImpl(FUSE_POLL);
190 CheckNotImpl(FUSE_NOTIFY_REPLY);
191 CheckNotImpl(FUSE_BATCH_FORGET);
192 CheckNotImpl(FUSE_FALLOCATE);
193 CheckNotImpl(FUSE_READDIRPLUS);
194 CheckNotImpl(FUSE_RENAME2);
195 CheckNotImpl(FUSE_LSEEK);
196}
197
198TEST_F(FuseBridgeLoopTest, Proxy) {
199 CheckProxy(FUSE_LOOKUP);
200 CheckProxy(FUSE_GETATTR);
Daichi Hironoc6134762016-10-27 14:57:55 +0900201 CheckProxy(FUSE_READ);
202 CheckProxy(FUSE_WRITE);
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900203 CheckProxy(FUSE_FSYNC);
Daichi Hirono30e68082016-11-15 09:31:21 +0900204
205 // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed.
206 CheckProxy(FUSE_OPEN);
207 CheckProxy(FUSE_RELEASE);
208
209 // Ensure the loop exits.
210 Close();
Daichi Hironoc6134762016-10-27 14:57:55 +0900211}
212
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900213} // namespace fuse
214} // namespace android