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