From b3624427d5960d406745979a4064b87587ace97b Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Sat, 27 Sep 2025 06:14:52 -0500 Subject: [PATCH] [unit test] Complete FUSE unit tests #22 --- .../src/fuse_drive_directory_test.cpp | 16 +++ .../src/fuse_drive_fsync_test.cpp | 123 ++++++++++++++++++ .../src/fuse_drive_rdrw_test.cpp | 32 +++++ 3 files changed, 171 insertions(+) create mode 100644 repertory/repertory_test/src/fuse_drive_fsync_test.cpp diff --git a/repertory/repertory_test/src/fuse_drive_directory_test.cpp b/repertory/repertory_test/src/fuse_drive_directory_test.cpp index 88e2cdeb..22088085 100644 --- a/repertory/repertory_test/src/fuse_drive_directory_test.cpp +++ b/repertory/repertory_test/src/fuse_drive_directory_test.cpp @@ -113,6 +113,22 @@ TYPED_TEST(fuse_test, directory_can_opendir_after_closedir) { this->rmdir_and_test(dir); } + +TYPED_TEST(fuse_test, directory_rmdir_on_non_empty_directory_should_fail) { + std::string dir_name{"non_empty"}; + auto dir = this->create_directory_and_test(dir_name); + + std::string fname{dir_name + "/child"}; + auto fpath = this->create_file_and_test(fname, 0644); + this->overwrite_text(fpath, "X"); + + errno = 0; + EXPECT_EQ(-1, ::rmdir(dir.c_str())); + EXPECT_EQ(ENOTEMPTY, errno); + + this->unlink_file_and_test(fpath); + this->rmdir_and_test(dir); +} } // namespace repertory #endif // !defined(_WIN32) diff --git a/repertory/repertory_test/src/fuse_drive_fsync_test.cpp b/repertory/repertory_test/src/fuse_drive_fsync_test.cpp new file mode 100644 index 00000000..50a27b42 --- /dev/null +++ b/repertory/repertory_test/src/fuse_drive_fsync_test.cpp @@ -0,0 +1,123 @@ +/* + Copyright <2018-2025> + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#if !defined(_WIN32) + +#include "fixtures/drive_fixture.hpp" + +namespace repertory { +TYPED_TEST_SUITE(fuse_test, platform_provider_types); + +TYPED_TEST(fuse_test, fsync_basic_succeeds_on_dirty_desc) { + std::string name{"fsync_dirty"}; + auto path = this->create_file_and_test(name, 0644); + + auto desc = ::open(path.c_str(), O_RDWR); + ASSERT_NE(desc, -1); + + this->write_all(desc, "ABC"); + errno = 0; + ASSERT_EQ(0, ::fsync(desc)); + ::close(desc); + + EXPECT_EQ("ABC", this->slurp(path)); + this->unlink_file_and_test(path); +} + +TYPED_TEST(fuse_test, fsync_noop_on_clean_desc) { + std::string name{"fsync_clean"}; + auto path = this->create_file_and_test(name, 0644); + + auto desc = ::open(path.c_str(), O_RDONLY); + ASSERT_NE(desc, -1); + + errno = 0; + EXPECT_EQ(0, ::fsync(desc)); + ::close(desc); + + this->unlink_file_and_test(path); +} + +TYPED_TEST(fuse_test, fsync_on_unlinked_file) { + std::string name{"fsync_unlinked"}; + auto path = this->create_file_and_test(name, 0644); + + auto desc = ::open(path.c_str(), O_RDWR); + ASSERT_NE(desc, -1); + + ASSERT_EQ(0, ::unlink(path.c_str())); + + this->write_all(desc, "XYZ"); + errno = 0; + EXPECT_EQ(0, ::fsync(desc)); + ::close(desc); +} + +TYPED_TEST(fuse_test, fsync_after_rename) { + if (this->current_provider != provider_type::sia) { + // TODO finish test + GTEST_SKIP(); + return; + } + + std::string src_name{"fsync_ren_src"}; + auto src = this->create_file_and_test(src_name, 0644); + + auto desc = ::open(src.c_str(), O_RDWR); + ASSERT_NE(desc, -1); + + this->write_all(desc, "AAA"); + + std::string dst_name{"fsync_ren_dst"}; + auto dst = + utils::path::combine(utils::path::get_parent_path(src), {dst_name}); + errno = 0; + ASSERT_EQ(0, ::rename(src.c_str(), dst.c_str())); + + this->write_all(desc, "_BBB"); + errno = 0; + ASSERT_EQ(0, ::fsync(desc)); + ::close(desc); + + EXPECT_EQ("AAA_BBB", this->slurp(dst)); + this->unlink_file_and_test(dst); +} + +#if defined(__linux__) +TYPED_TEST(fuse_test, fsync_fdatasync_behaves_like_fsync_on_linux) { + std::string name{"descatasync_linux"}; + auto path = this->create_file_and_test(name, 0644); + + auto desc = ::open(path.c_str(), O_RDWR); + ASSERT_NE(desc, -1); + + this->write_all(desc, "DATA"); + errno = 0; + ASSERT_EQ(0, ::fdatasync(desc)); + ::close(desc); + + EXPECT_EQ("DATA", this->slurp(path)); + this->unlink_file_and_test(path); +} +#endif // defined(__linux__) +} // namespace repertory + +#endif // !defined(_WIN32) diff --git a/repertory/repertory_test/src/fuse_drive_rdrw_test.cpp b/repertory/repertory_test/src/fuse_drive_rdrw_test.cpp index 8a295845..af832a36 100644 --- a/repertory/repertory_test/src/fuse_drive_rdrw_test.cpp +++ b/repertory/repertory_test/src/fuse_drive_rdrw_test.cpp @@ -205,6 +205,38 @@ TYPED_TEST(fuse_test, rdrw_can_append_to_file) { this->unlink_file_and_test(file_path); } + +TYPED_TEST(fuse_test, rdrw_open_with_o_trunc_resets_size) { + std::string name{"trunc_test"}; + auto path = this->create_file_and_test(name, 0644); + + this->overwrite_text(path, "ABCDEFG"); + EXPECT_GT(this->stat_size(path), 0); + + auto desc = ::open(path.c_str(), O_WRONLY | O_TRUNC); + ASSERT_NE(desc, -1); + ::close(desc); + + EXPECT_EQ(0, this->stat_size(path)); + this->unlink_file_and_test(path); +} + +TYPED_TEST(fuse_test, rdrw_o_append_writes_at_eof) { + std::string name{"append_test"}; + auto path = this->create_file_and_test(name, 0644); + + this->overwrite_text(path, "HEAD"); + + auto desc = ::open(path.c_str(), O_WRONLY | O_APPEND); + ASSERT_NE(desc, -1); + + ASSERT_NE(-1, ::lseek(desc, 0, SEEK_SET)); + this->write_all(desc, "TAIL"); + ::close(desc); + + EXPECT_EQ("HEADTAIL", this->slurp(path)); + this->unlink_file_and_test(path); +} } // namespace repertory #endif // !defined(_WIN32)