blob: e74d9e700f37079b7fc0d2709f5eb376feea0b39 [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;
35 Callback() : mounted(false) {}
36 void OnMount() override {
37 mounted = true;
38 }
39};
40
41class FuseBridgeLoopTest : public ::testing::Test {
42 protected:
Daichi Hironoa0aecda2016-11-08 10:17:51 +090043 base::unique_fd dev_sockets_[2];
44 base::unique_fd proxy_sockets_[2];
Daichi Hironoc6134762016-10-27 14:57:55 +090045 Callback callback_;
46 std::thread thread_;
47
48 FuseRequest request_;
49 FuseResponse response_;
50
Daichi Hironoa0aecda2016-11-08 10:17:51 +090051 void SetUp() override {
52 base::SetMinimumLogSeverity(base::VERBOSE);
53 int dev_sockets[2];
54 int proxy_sockets[2];
55 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, dev_sockets));
56 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, proxy_sockets));
57 dev_sockets_[0].reset(dev_sockets[0]);
58 dev_sockets_[1].reset(dev_sockets[1]);
59 proxy_sockets_[0].reset(proxy_sockets[0]);
60 proxy_sockets_[1].reset(proxy_sockets[1]);
61
Daichi Hironoc6134762016-10-27 14:57:55 +090062 thread_ = std::thread([this] {
Daichi Hironoa0aecda2016-11-08 10:17:51 +090063 StartFuseBridgeLoop(
64 dev_sockets_[1].release(), proxy_sockets_[0].release(), &callback_);
Daichi Hironoc6134762016-10-27 14:57:55 +090065 });
66 }
67
68 void CheckNotImpl(uint32_t opcode) {
69 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
70
71 memset(&request_, 0, sizeof(FuseRequest));
72 request_.header.opcode = opcode;
73 request_.header.len = sizeof(fuse_in_header);
74 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
75
76 memset(&response_, 0, sizeof(FuseResponse));
77 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
78 EXPECT_EQ(-ENOSYS, response_.header.error);
79 }
80
81 void CheckProxy(uint32_t opcode) {
82 SCOPED_TRACE((std::ostringstream() << "opcode: " << opcode).str());
83
84 memset(&request_, 0, sizeof(FuseRequest));
85 request_.header.opcode = opcode;
86 request_.header.unique = opcode; // Use opcode as unique.
87 request_.header.len = sizeof(fuse_in_header);
88 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
89
90 memset(&request_, 0, sizeof(FuseRequest));
91 ASSERT_TRUE(request_.Read(proxy_sockets_[1]));
92 EXPECT_EQ(opcode, request_.header.opcode);
93 EXPECT_EQ(opcode, request_.header.unique);
94
95 memset(&response_, 0, sizeof(FuseResponse));
96 response_.header.len = sizeof(fuse_out_header);
97 response_.header.unique = opcode; // Use opcode as unique.
98 response_.header.error = kFuseSuccess;
99 ASSERT_TRUE(response_.Write(proxy_sockets_[1]));
100
101 memset(&response_, 0, sizeof(FuseResponse));
102 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
103 EXPECT_EQ(opcode, response_.header.unique);
104 EXPECT_EQ(kFuseSuccess, response_.header.error);
105 }
106
107 void SendInitRequest(uint64_t unique) {
108 memset(&request_, 0, sizeof(FuseRequest));
109 request_.header.opcode = FUSE_INIT;
110 request_.header.unique = unique;
111 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_init_in);
112 request_.init_in.major = FUSE_KERNEL_VERSION;
113 request_.init_in.minor = FUSE_KERNEL_MINOR_VERSION;
114 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
115 }
116
117 void Close() {
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900118 dev_sockets_[0].reset();
119 dev_sockets_[1].reset();
120 proxy_sockets_[0].reset();
121 proxy_sockets_[1].reset();
Daichi Hironoc6134762016-10-27 14:57:55 +0900122 if (thread_.joinable()) {
123 thread_.join();
124 }
125 }
126
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900127 void TearDown() override {
Daichi Hironoc6134762016-10-27 14:57:55 +0900128 Close();
129 }
130};
131
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900132} // namespace
133
Daichi Hironoc6134762016-10-27 14:57:55 +0900134TEST_F(FuseBridgeLoopTest, FuseInit) {
135 SendInitRequest(1u);
136
137 memset(&response_, 0, sizeof(FuseResponse));
138 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
139 EXPECT_EQ(kFuseSuccess, response_.header.error);
140 EXPECT_EQ(1u, response_.header.unique);
141
142 // Unmount.
143 Close();
144 EXPECT_TRUE(callback_.mounted);
145}
146
147TEST_F(FuseBridgeLoopTest, FuseForget) {
148 memset(&request_, 0, sizeof(FuseRequest));
149 request_.header.opcode = FUSE_FORGET;
150 request_.header.unique = 1u;
151 request_.header.len = sizeof(fuse_in_header) + sizeof(fuse_forget_in);
152 ASSERT_TRUE(request_.Write(dev_sockets_[0]));
153
154 SendInitRequest(2u);
155
156 memset(&response_, 0, sizeof(FuseResponse));
157 ASSERT_TRUE(response_.Read(dev_sockets_[0]));
158 EXPECT_EQ(2u, response_.header.unique) <<
159 "The loop must not respond to FUSE_FORGET";
160}
161
162TEST_F(FuseBridgeLoopTest, FuseNotImpl) {
163 CheckNotImpl(FUSE_SETATTR);
164 CheckNotImpl(FUSE_READLINK);
165 CheckNotImpl(FUSE_SYMLINK);
166 CheckNotImpl(FUSE_MKNOD);
167 CheckNotImpl(FUSE_MKDIR);
168 CheckNotImpl(FUSE_UNLINK);
169 CheckNotImpl(FUSE_RMDIR);
170 CheckNotImpl(FUSE_RENAME);
171 CheckNotImpl(FUSE_LINK);
172 CheckNotImpl(FUSE_STATFS);
Daichi Hironoc6134762016-10-27 14:57:55 +0900173 CheckNotImpl(FUSE_SETXATTR);
174 CheckNotImpl(FUSE_GETXATTR);
175 CheckNotImpl(FUSE_LISTXATTR);
176 CheckNotImpl(FUSE_REMOVEXATTR);
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900177 CheckNotImpl(FUSE_FLUSH);
Daichi Hironoc6134762016-10-27 14:57:55 +0900178 CheckNotImpl(FUSE_OPENDIR);
179 CheckNotImpl(FUSE_READDIR);
180 CheckNotImpl(FUSE_RELEASEDIR);
181 CheckNotImpl(FUSE_FSYNCDIR);
182 CheckNotImpl(FUSE_GETLK);
183 CheckNotImpl(FUSE_SETLK);
184 CheckNotImpl(FUSE_SETLKW);
185 CheckNotImpl(FUSE_ACCESS);
186 CheckNotImpl(FUSE_CREATE);
187 CheckNotImpl(FUSE_INTERRUPT);
188 CheckNotImpl(FUSE_BMAP);
189 CheckNotImpl(FUSE_DESTROY);
190 CheckNotImpl(FUSE_IOCTL);
191 CheckNotImpl(FUSE_POLL);
192 CheckNotImpl(FUSE_NOTIFY_REPLY);
193 CheckNotImpl(FUSE_BATCH_FORGET);
194 CheckNotImpl(FUSE_FALLOCATE);
195 CheckNotImpl(FUSE_READDIRPLUS);
196 CheckNotImpl(FUSE_RENAME2);
197 CheckNotImpl(FUSE_LSEEK);
198}
199
200TEST_F(FuseBridgeLoopTest, Proxy) {
201 CheckProxy(FUSE_LOOKUP);
202 CheckProxy(FUSE_GETATTR);
Daichi Hironoc6134762016-10-27 14:57:55 +0900203 CheckProxy(FUSE_READ);
204 CheckProxy(FUSE_WRITE);
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900205 CheckProxy(FUSE_FSYNC);
Daichi Hirono30e68082016-11-15 09:31:21 +0900206
207 // Invoke FUSE_OPEN and FUSE_RELEASE at last as the loop will exit when all files are closed.
208 CheckProxy(FUSE_OPEN);
209 CheckProxy(FUSE_RELEASE);
210
211 // Ensure the loop exits.
212 Close();
Daichi Hironoc6134762016-10-27 14:57:55 +0900213}
214
Daichi Hironoa0aecda2016-11-08 10:17:51 +0900215} // namespace fuse
216} // namespace android