| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <fuchsia/io/cpp/fidl.h> |
| #include <lib/fdio/vfs.h> |
| #include <lib/fidl/cpp/interface_request.h> |
| #include <lib/vfs/cpp/pseudo_dir.h> |
| #include <lib/vfs/cpp/pseudo_file.h> |
| #include <lib/vfs/cpp/remote_dir.h> |
| #include <lib/vfs/cpp/testing/dir_test_util.h> |
| |
| #include <memory> |
| |
| namespace { |
| |
| class RemoteDirConnection : public vfs_tests::DirConnection { |
| public: |
| RemoteDirConnection() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) { |
| AddFileToPseudoDir("file1"); |
| AddFileToPseudoDir("file2"); |
| AddFileToPseudoDir("file3"); |
| loop_.StartThread("vfs test thread"); |
| } |
| |
| protected: |
| vfs::internal::Directory* GetDirectoryNode() override { return dir_.get(); } |
| |
| fuchsia::io::DirectoryPtr GetPseudoDirConnection() { |
| fuchsia::io::DirectoryPtr ptr; |
| pseudo_dir_.Serve(fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE, |
| ptr.NewRequest().TakeChannel(), loop_.dispatcher()); |
| return ptr; |
| } |
| |
| void ReadDir(vfs::internal::Directory* dir, std::vector<uint8_t>* dirents, |
| uint64_t buffer_size = 1024) { |
| fuchsia::io::DirectorySyncPtr ptr; |
| dir->Serve(fuchsia::io::OPEN_RIGHT_READABLE, ptr.NewRequest().TakeChannel(), |
| loop_.dispatcher()); |
| zx_status_t status; |
| ptr->ReadDirents(buffer_size, &status, dirents); |
| ASSERT_EQ(ZX_OK, status); |
| ASSERT_GT(dirents->size(), 0u); |
| } |
| |
| void CompareReadDirs() { |
| std::vector<uint8_t> remote_dir_dirents; |
| std::vector<uint8_t> pseudo_dir_dirents; |
| ReadDir(&pseudo_dir_, &pseudo_dir_dirents); |
| ReadDir(dir_.get(), &remote_dir_dirents); |
| ASSERT_EQ(remote_dir_dirents, pseudo_dir_dirents); |
| } |
| |
| vfs::PseudoDir pseudo_dir_; |
| std::shared_ptr<vfs::RemoteDir> dir_; |
| async::Loop loop_; |
| |
| private: |
| void AddFileToPseudoDir(const std::string& name) { |
| pseudo_dir_.AddEntry( |
| name, std::make_unique<vfs::PseudoFile>( |
| name.length(), [name](std::vector<uint8_t>* output, size_t max_file_size) { |
| output->resize(name.length()); |
| std::copy(name.begin(), name.end(), output->begin()); |
| return ZX_OK; |
| })); |
| } |
| }; |
| |
| TEST_F(RemoteDirConnection, ConstructorWithChannel) { |
| auto connection = GetPseudoDirConnection(); |
| dir_ = std::make_shared<vfs::RemoteDir>(connection.Unbind().TakeChannel()); |
| CompareReadDirs(); |
| } |
| |
| TEST_F(RemoteDirConnection, ConstructorWithInterfaceHandle) { |
| auto connection = GetPseudoDirConnection(); |
| dir_ = std::make_shared<vfs::RemoteDir>(connection.Unbind()); |
| CompareReadDirs(); |
| } |
| |
| TEST_F(RemoteDirConnection, ConstructorWithDirPtr) { |
| dir_ = std::make_shared<vfs::RemoteDir>(GetPseudoDirConnection()); |
| CompareReadDirs(); |
| } |
| |
| class RemoteDirContained : public RemoteDirConnection { |
| protected: |
| RemoteDirContained() { |
| dir_ = std::make_shared<vfs::RemoteDir>(GetPseudoDirConnection()); |
| parent_pseudo_dir_.AddSharedEntry("remote_dir", dir_); |
| parent_pseudo_dir_.Serve(fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE, |
| ptr_.NewRequest().TakeChannel(), loop_.dispatcher()); |
| } |
| |
| ~RemoteDirContained() { loop_.Shutdown(); } |
| |
| vfs::PseudoDir parent_pseudo_dir_; |
| fuchsia::io::DirectorySyncPtr ptr_; |
| }; |
| |
| TEST_F(RemoteDirContained, RemoteDirContainedInPseudoDir) { |
| std::vector<vfs_tests::Dirent> expected = {vfs_tests::Dirent::DirentForDot(), |
| vfs_tests::Dirent::DirentForDirectory("remote_dir")}; |
| AssertReadDirents(ptr_, 1024, expected); |
| } |
| |
| TEST_F(RemoteDirContained, OpenAndReadFile) { |
| fuchsia::io::FileSyncPtr file_ptr; |
| std::string paths[] = {"remote_dir/file1", "remote_dir//file1", "remote_dir/./file1"}; |
| for (auto& path : paths) { |
| SCOPED_TRACE(path); |
| AssertOpenPath(ptr_, path, file_ptr, fuchsia::io::OPEN_RIGHT_READABLE); |
| AssertRead(file_ptr, 1024, "file1"); |
| } |
| } |
| |
| TEST_F(RemoteDirContained, OpenRemoteDirAndRead) { |
| std::string paths[] = {"remote_dir", "remote_dir/", "remote_dir/.", |
| "remote_dir/./", "remote_dir//", "remote_dir//."}; |
| for (auto& path : paths) { |
| SCOPED_TRACE(path); |
| fuchsia::io::DirectorySyncPtr remote_ptr; |
| AssertOpenPath(ptr_, path, remote_ptr, |
| fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE); |
| fuchsia::io::FileSyncPtr file_ptr; |
| AssertOpenPath(remote_ptr, "file1", file_ptr, fuchsia::io::OPEN_RIGHT_READABLE); |
| AssertRead(file_ptr, 1024, "file1"); |
| } |
| } |
| |
| } // namespace |