From d34ccc424dcd34aef693ab20b5cd8cae33f7d9ae Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Fri, 18 Oct 2024 14:53:31 -0500 Subject: [PATCH] refactor --- .../repertory_test/src/file_manager_test.cpp | 1709 ++++++++--------- 1 file changed, 770 insertions(+), 939 deletions(-) diff --git a/repertory/repertory_test/src/file_manager_test.cpp b/repertory/repertory_test/src/file_manager_test.cpp index 20a0dc6c..9bb84ca9 100644 --- a/repertory/repertory_test/src/file_manager_test.cpp +++ b/repertory/repertory_test/src/file_manager_test.cpp @@ -91,8 +91,11 @@ TEST_F(file_manager_test, can_start_and_stop) { EXPECT_STREQ("file_manager", ee.get_service().get().c_str()); }); - event_capture ec( - {"service_started", "service_shutdown_begin", "service_shutdown_end"}); + event_capture ec({ + "service_started", + "service_shutdown_begin", + "service_shutdown_end", + }); file_manager fm(*cfg, mp); fm.start(); @@ -102,7 +105,10 @@ TEST_F(file_manager_test, can_start_and_stop) { } TEST_F(file_manager_test, can_create_and_close_file) { + cfg->set_enable_chunk_downloader_timeout(true); + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + polling::instance().start(cfg.get()); file_manager fm(*cfg, mp); @@ -207,6 +213,8 @@ TEST_F(file_manager_test, can_create_and_close_file) { } TEST_F(file_manager_test, can_open_and_close_file) { + cfg->set_enable_chunk_downloader_timeout(true); + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); polling::instance().start(cfg.get()); @@ -388,8 +396,11 @@ TEST_F(file_manager_test, EXPECT_STREQ(source_path.c_str(), ee.get_dest_path().get().c_str()); }); - event_capture ec({"download_resume_added"}, - {"file_upload_completed", "file_upload_queued"}); + + event_capture ec({"download_resume_added"}, { + "file_upload_completed", + "file_upload_queued", + }); const auto now = utils::time::get_time_now(); auto meta = create_meta_attributes( @@ -472,7 +483,10 @@ TEST_F(file_manager_test, ec.wait_for_empty(); event_capture ec2({"download_restored", "download_resume_added"}, - {"file_upload_completed", "file_upload_queued"}); + { + "file_upload_completed", + "file_upload_queued", + }); EXPECT_EQ(std::size_t(0u), fm.get_open_file_count()); EXPECT_EQ(std::size_t(0u), fm.get_open_handle_count()); @@ -515,6 +529,8 @@ TEST_F(file_manager_test, } TEST_F(file_manager_test, upload_occurs_after_write_if_fully_downloaded) { + cfg->set_enable_chunk_downloader_timeout(true); + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); polling::instance().start(cfg.get()); @@ -603,8 +619,11 @@ TEST_F(file_manager_test, upload_occurs_after_write_if_fully_downloaded) { EXPECT_CALL(mp, upload_file("/test_write_full_download.txt", source_path, _)) .WillOnce(Return(api_error::success)); - event_capture ec2( - {"item_timeout", "file_upload_queued", "file_upload_completed"}); + event_capture ec2({ + "item_timeout", + "file_upload_queued", + "file_upload_completed", + }); fm.close(handle); ec2.wait_for_empty(); @@ -772,936 +791,748 @@ TEST_F(file_manager_test, evict_file_fails_if_file_is_open) { fm.close(handle); } -// TEST(file_manager, -// evict_file_fails_if_unable_to_get_source_path_from_item_meta) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// file_manager fm(cfg, mp); -// -// EXPECT_CALL(mp, get_item_meta(_, META_SOURCE, _)) -// .WillOnce([](const std::string &api_path, const std::string &key, -// std::string & /*value*/) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_STREQ(META_SOURCE.c_str(), key.c_str()); -// return api_error::error; -// }); -// -// EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _)) -// .WillOnce([](const std::string &api_path, const std::string &key, -// std::string &value) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_STREQ(META_PINNED.c_str(), key.c_str()); -// value = "0"; -// return api_error::success; -// }); -// -// EXPECT_FALSE(fm.evict_file("/test_open.txt")); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, evict_file_fails_if_source_path_is_empty) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// file_manager fm(cfg, mp); -// -// EXPECT_CALL(mp, get_item_meta(_, META_SOURCE, _)) -// .WillOnce([](const std::string &api_path, const std::string &key, -// std::string &value) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_STREQ(META_SOURCE.c_str(), key.c_str()); -// value = ""; -// return api_error::success; -// }); -// EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _)) -// .WillOnce([](const std::string &api_path, const std::string &key, -// std::string &value) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_STREQ(META_PINNED.c_str(), key.c_str()); -// value = "0"; -// return api_error::success; -// }); -// -// EXPECT_FALSE(fm.evict_file("/test_open.txt")); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, evict_file_fails_if_file_is_uploading) { -// { -// console_consumer c; -// event_system::instance().start(); -// -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// fm.start(); -// -// event_capture capture({ -// "filesystem_item_opened", -// "filesystem_item_handle_opened", -// "filesystem_item_handle_closed", -// "filesystem_item_closed", -// "file_upload_completed", -// }); -// -// const auto source_path = utils::path::combine( -// cfg.get_cache_directory(), {utils::create_uuid_string()}); -// -// const auto now = utils::time::get_time_now(); -// -// auto meta = create_meta_attributes( -// now, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE, now + 1u, now + -// 2u, false, 1, "", 2, now + 3u, 3u, 4u, 0u, source_path, 10, now + -// 4u); -// std::uint64_t handle{}; -// { -// std::shared_ptr f; -// -// EXPECT_CALL(mp, create_file("/test_evict.txt", meta)) -// .WillOnce(Return(api_error::success)); -// EXPECT_CALL(mp, get_filesystem_item) -// .WillRepeatedly([&meta](const std::string &api_path, bool -// directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_evict.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = utils::string::to_uint64(meta[META_SIZE]); -// fsi.source_path = meta[META_SOURCE]; -// return api_error::success; -// }); -// -// #if defined(_WIN32) -// EXPECT_EQ(api_error::success, -// fm.create("/test_evict.txt", meta, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::success, -// fm.create("/test_evict.txt", meta, O_RDWR, handle, f)); -// #endif -// EXPECT_CALL(mp, set_item_meta("/test_evict.txt", _)) -// .Times(2) -// .WillRepeatedly(Return(api_error::success)); -// EXPECT_CALL(mp, upload_file) -// .WillOnce([](const std::string &api_path, -// const std::string &source_path2, -// stop_type & /*stop_requested*/) -> api_error { -// EXPECT_STREQ("/test_evict.txt", api_path.c_str()); -// EXPECT_FALSE(source_path2.empty()); -// std::this_thread::sleep_for(3s); -// return api_error::success; -// }); -// -// data_buffer data{{0, 1, 1}}; -// std::size_t bytes_written{}; -// EXPECT_EQ(api_error::success, f->write(0U, data, bytes_written)); -// -// auto opt_size = utils::file::file{source_path}.size(); -// EXPECT_TRUE(opt_size.has_value()); -// EXPECT_EQ(static_cast(data.size()), opt_size.value()); -// -// fm.close(handle); -// -// EXPECT_TRUE(utils::retry_action( -// [&fm]() -> bool { return fm.is_processing("/test_evict.txt"); })); -// EXPECT_FALSE(fm.evict_file("/test_evict.txt")); -// } -// -// capture.wait_for_empty(); -// -// EXPECT_TRUE(utils::file::file(source_path).exists()); -// -// fm.stop(); -// -// event_system::instance().stop(); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, evict_file_fails_if_file_is_in_upload_queue) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// mock_open_file of{}; -// EXPECT_CALL(of, is_directory).WillRepeatedly(Return(false)); -// EXPECT_CALL(of, get_api_path).WillRepeatedly(Return("/test_evict.txt")); -// EXPECT_CALL(of, -// get_source_path).WillRepeatedly(Return("/test_evict.src")); -// fm.queue_upload(of); -// -// EXPECT_TRUE(fm.is_processing("/test_evict.txt")); -// EXPECT_FALSE(fm.evict_file("/test_evict.txt")); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, evict_file_fails_if_file_is_modified) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, bool directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_evict.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = 1U; -// fsi.source_path = "/test_evict.src"; -// return api_error::success; -// }); -// -// auto of = std::make_shared(); -// EXPECT_CALL(*of, is_directory).WillOnce(Return(false)); -// EXPECT_CALL(*of, add).WillOnce(Return()); -// EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_evict.txt")); -// EXPECT_CALL(*of, -// get_source_path).WillRepeatedly(Return("/test_evict.src")); -// EXPECT_CALL(*of, is_modified).Times(2).WillRepeatedly(Return(true)); -// -// std::uint64_t handle{}; -// std::shared_ptr f; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::success, fm.open(of, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::success, fm.open(of, O_RDWR, handle, f)); -// #endif -// -// EXPECT_TRUE(fm.is_processing("/test_evict.txt")); -// EXPECT_FALSE(fm.evict_file("/test_evict.txt")); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, evict_file_fails_if_file_is_not_complete) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, bool directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_evict.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = 1U; -// return api_error::success; -// }); -// -// auto of = std::make_shared(); -// EXPECT_CALL(*of, is_directory).WillOnce(Return(false)); -// EXPECT_CALL(*of, add).WillOnce(Return()); -// EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_evict.txt")); -// EXPECT_CALL(*of, -// get_source_path).WillRepeatedly(Return("/test_evict.src")); -// EXPECT_CALL(*of, is_modified).Times(2).WillRepeatedly(Return(false)); -// EXPECT_CALL(*of, is_complete).Times(2).WillRepeatedly(Return(false)); -// EXPECT_CALL(mp, set_item_meta("/test_evict.txt", META_SOURCE, _)) -// .WillOnce(Return(api_error::success)); -// -// std::uint64_t handle{}; -// std::shared_ptr f; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::success, fm.open(of, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::success, fm.open(of, O_RDWR, handle, f)); -// #endif -// -// EXPECT_TRUE(fm.is_processing("/test_evict.txt")); -// EXPECT_FALSE(fm.evict_file("/test_evict.txt")); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, can_get_directory_items) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// EXPECT_CALL(mp, get_directory_items) -// .WillOnce([](const std::string &api_path, -// directory_item_list &list) -> api_error { -// EXPECT_STREQ("/", api_path.c_str()); -// list.insert(list.begin(), directory_item{ -// "..", -// "", -// true, -// }); -// list.insert(list.begin(), directory_item{ -// ".", -// "", -// true, -// }); -// return api_error::success; -// }); -// auto list = fm.get_directory_items("/"); -// EXPECT_EQ(std::size_t(2U), list.size()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, file_is_not_opened_if_provider_create_file_fails) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// const auto now = utils::time::get_time_now(); -// auto meta = create_meta_attributes( -// now, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE, now + 1u, now + -// 2u, false, 1, "", 2, now + 3u, 3u, 4u, 0u, "/test_create.src", 10, -// now + 4u); -// file_manager fm(cfg, mp); -// -// EXPECT_CALL(mp, create_file("/test_create.txt", meta)) -// .WillOnce(Return(api_error::error)); -// -// std::uint64_t handle{}; -// std::shared_ptr f; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::error, -// fm.create("/test_create.txt", meta, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::error, -// fm.create("/test_create.txt", meta, O_RDWR, handle, f)); -// #endif -// EXPECT_FALSE(f); -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, create_fails_if_provider_create_is_unsuccessful) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// EXPECT_CALL(mp, create_file("/test_create.txt", _)) -// .WillOnce(Return(api_error::error)); -// -// std::uint64_t handle{}; -// std::shared_ptr f{}; -// api_meta_map meta{}; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::error, -// fm.create("/test_create.txt", meta, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::error, -// fm.create("/test_create.txt", meta, O_RDWR, handle, f)); -// #endif -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, get_open_file_fails_if_file_is_not_open) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// std::shared_ptr f{}; -// EXPECT_FALSE(fm.get_open_file(0U, true, f)); -// EXPECT_FALSE(f); -// -// EXPECT_FALSE(fm.get_open_file(0U, false, f)); -// EXPECT_FALSE(f); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, -// get_open_file_promotes_non_writeable_file_if_writeable_is_specified) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// auto non_writeable = std::make_shared(); -// EXPECT_CALL(*non_writeable, is_directory).WillOnce(Return(false)); -// EXPECT_CALL(*non_writeable, add).WillOnce(Return()); -// EXPECT_CALL(*non_writeable, get_api_path) -// .WillRepeatedly(Return("/test_open.txt")); -// EXPECT_CALL(*non_writeable, get_source_path) -// .WillRepeatedly(Return("/test_open.src")); -// EXPECT_CALL(*non_writeable, is_modified).WillRepeatedly(Return(true)); -// EXPECT_CALL(*non_writeable, is_write_supported) -// .WillRepeatedly(Return(false)); -// EXPECT_CALL(*non_writeable, is_write_supported) -// .WillRepeatedly(Return(false)); -// -// EXPECT_CALL(*non_writeable, get_filesystem_item) -// .WillOnce([api_path = "/test_open.txt"]() -> filesystem_item { -// filesystem_item fsi{}; -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = false; -// fsi.size = 10U; -// fsi.source_path = "/test_open.src"; -// return fsi; -// }); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, bool directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = 10U; -// fsi.source_path = "/test_open.src"; -// return api_error::success; -// }); -// -// std::uint64_t handle{}; -// std::shared_ptr f{}; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::success, fm.open(non_writeable, {}, handle, f)); -// EXPECT_CALL(*non_writeable, get_open_data()) -// .WillOnce([&handle]() -> std::map & { -// static std::map map; -// map[handle] = {}; -// return map; -// }); -// #else -// EXPECT_EQ(api_error::success, fm.open(non_writeable, O_RDWR, handle, f)); -// EXPECT_CALL(*non_writeable, get_open_data()) -// .WillOnce([&handle]() -> std::map & { -// static std::map map; -// map[handle] = O_RDWR; -// return map; -// }); -// #endif -// -// EXPECT_CALL(mp, set_item_meta("/test_open.txt", META_SOURCE, _)) -// .WillOnce(Return(api_error::success)); -// -// EXPECT_CALL(*non_writeable, has_handle(1)).WillOnce([]() -> bool { -// return true; -// }); -// EXPECT_TRUE(fm.get_open_file(handle, true, f)); -// EXPECT_NE(non_writeable.get(), f.get()); -// EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); -// -// std::shared_ptr f2{}; -// EXPECT_TRUE(fm.get_open_file(handle, false, f2)); -// EXPECT_EQ(f.get(), f2.get()); -// EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, open_file_fails_if_file_is_not_found) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// std::shared_ptr f{}; -// EXPECT_FALSE(fm.get_open_file(1U, true, f)); -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// EXPECT_FALSE(f); -// -// EXPECT_FALSE(fm.get_open_file(1U, false, f)); -// EXPECT_FALSE(f); -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, open_file_fails_if_provider_get_filesystem_item_fails) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// auto of = std::make_shared(); -// EXPECT_CALL(*of, is_directory).WillRepeatedly(Return(false)); -// EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_open.txt")); -// EXPECT_CALL(*of, -// get_source_path).WillRepeatedly(Return("/test_open.src")); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, bool directory, -// filesystem_item & /*fsi*/) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// return api_error::error; -// }); -// -// std::uint64_t handle{}; -// std::shared_ptr f{}; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::error, fm.open(of, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::error, fm.open(of, O_RDWR, handle, f)); -// #endif -// EXPECT_FALSE(fm.get_open_file(1U, true, f)); -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// EXPECT_FALSE(f); -// -// EXPECT_FALSE(fm.get_open_file(1U, false, f)); -// EXPECT_FALSE(f); -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, open_file_fails_if_provider_set_item_meta_fails) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// auto of = std::make_shared(); -// EXPECT_CALL(*of, is_directory).WillRepeatedly(Return(false)); -// EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_open.txt")); -// EXPECT_CALL(*of, -// get_source_path).WillRepeatedly(Return("/test_open.src")); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, bool directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = 0U; -// return api_error::success; -// }); -// -// EXPECT_CALL(mp, set_item_meta("/test_open.txt", META_SOURCE, _)) -// .WillOnce(Return(api_error::error)); -// -// std::uint64_t handle{}; -// std::shared_ptr f{}; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::error, fm.open(of, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::error, fm.open(of, O_RDWR, handle, f)); -// #endif -// EXPECT_FALSE(fm.get_open_file(1U, true, f)); -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// EXPECT_FALSE(f); -// -// EXPECT_FALSE(fm.get_open_file(1U, false, f)); -// EXPECT_FALSE(f); -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, open_file_creates_source_path_if_empty) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// auto of = std::make_shared(); -// EXPECT_CALL(*of, add).WillOnce(Return()); -// EXPECT_CALL(*of, is_directory).WillRepeatedly(Return(false)); -// EXPECT_CALL(*of, is_write_supported).WillRepeatedly(Return(true)); -// EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_open.txt")); -// EXPECT_CALL(*of, get_source_path).WillRepeatedly(Return("")); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, bool directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = 0U; -// return api_error::success; -// }); -// -// EXPECT_CALL(mp, set_item_meta("/test_open.txt", _, _)) -// .WillOnce([](const std::string &api_path, const std::string &key, -// const std::string &value) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_STREQ(META_SOURCE.c_str(), key.c_str()); -// EXPECT_FALSE(value.empty()); -// return api_error::success; -// }); -// -// std::uint64_t handle{}; -// std::shared_ptr f{}; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::success, fm.open(of, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::success, fm.open(of, O_RDWR, handle, f)); -// #endif -// EXPECT_CALL(*of, has_handle(1)).Times(2).WillRepeatedly([]() -> bool { -// return true; -// }); -// -// EXPECT_TRUE(fm.get_open_file(1U, true, f)); -// EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); -// EXPECT_TRUE(f); -// -// EXPECT_TRUE(fm.get_open_file(1U, false, f)); -// EXPECT_TRUE(f); -// EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, open_file_first_file_handle_is_not_zero) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// auto of = std::make_shared(); -// EXPECT_CALL(*of, add).WillOnce(Return()); -// EXPECT_CALL(*of, is_directory).WillRepeatedly(Return(false)); -// EXPECT_CALL(*of, is_write_supported).WillRepeatedly(Return(true)); -// EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_open.txt")); -// EXPECT_CALL(*of, -// get_source_path).WillRepeatedly(Return("/test_open.src")); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, bool directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_open.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = 0U; -// fsi.source_path = "/test_open.src"; -// return api_error::success; -// }); -// -// std::uint64_t handle{}; -// std::shared_ptr f{}; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::success, fm.open(of, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::success, fm.open(of, O_RDWR, handle, f)); -// #endif -// EXPECT_CALL(*of, has_handle(1)).WillOnce([]() -> bool { return true; }); -// -// EXPECT_TRUE(fm.get_open_file(1U, true, f)); -// EXPECT_GT(handle, std::uint64_t(0U)); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, can_remove_file) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// { -// auto file = -// utils::file::file::open_or_create_file("./test_remove.txt"); -// EXPECT_TRUE(*file); -// } -// EXPECT_TRUE(utils::file::file("./test_remove.txt").exists()); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, bool directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_remove.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = 0U; -// fsi.source_path = "./test_remove.txt"; -// return api_error::success; -// }); -// EXPECT_CALL(mp, remove_file("/test_remove.txt")) -// .WillOnce(Return(api_error::success)); -// -// EXPECT_EQ(api_error::success, fm.remove_file("/test_remove.txt")); -// -// EXPECT_FALSE(utils::file::file("./test_remove.txt").exists()); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, can_queue_and_remove_upload) { -// { -// console_consumer c; -// event_system::instance().start(); -// event_capture ec({"file_upload_queued", "download_resume_removed"}); -// -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// mock_open_file of{}; -// EXPECT_CALL(of, get_api_path).WillOnce(Return("/test_queue.txt")); -// EXPECT_CALL(of, get_source_path).WillOnce(Return("/test_queue.src")); -// -// EXPECT_FALSE(fm.is_processing("/test_queue.txt")); -// fm.queue_upload(of); -// EXPECT_TRUE(fm.is_processing("/test_queue.txt")); -// -// fm.remove_upload("/test_queue.txt"); -// EXPECT_FALSE(fm.is_processing("/test_queue.txt")); -// -// ec.wait_for_empty(); -// -// event_system::instance().stop(); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, file_is_closed_after_download_timeout) { -// { -// console_consumer c; -// event_system::instance().start(); -// -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_chunk_downloader_timeout_secs(3U); -// polling::instance().start(&cfg); -// -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// fm.start(); -// -// const auto source_path = utils::path::combine( -// cfg.get_cache_directory(), {utils::create_uuid_string()}); -// -// event_consumer es("item_timeout", [](const event &e) { -// const auto &ee = dynamic_cast(e); -// EXPECT_STREQ("/test_download_timeout.txt", -// ee.get_api_path().get().c_str()); -// }); -// -// const auto now = utils::time::get_time_now(); -// auto meta = create_meta_attributes( -// now, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE, now + 1u, now + -// 2u, false, 1, "key", 2, now + 3u, 3u, 4u, -// utils::encryption::encrypting_reader::get_data_chunk_size() * 4u, -// source_path, 10, now + 4u); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillRepeatedly([&meta](const std::string &api_path, bool directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_download_timeout.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = utils::string::to_uint64(meta[META_SIZE]); -// fsi.source_path = meta[META_SOURCE]; -// return api_error::success; -// }); -// -// event_capture ec({"item_timeout"}); -// -// std::uint64_t handle{}; -// std::shared_ptr f; -// #if defined(_WIN32) -// EXPECT_EQ(api_error::success, -// fm.open("/test_download_timeout.txt", false, {}, handle, f)); -// #else -// EXPECT_EQ(api_error::success, -// fm.open("/test_download_timeout.txt", false, O_RDWR, handle, -// f)); -// #endif -// -// EXPECT_CALL(mp, read_file_bytes) -// .WillRepeatedly([](const std::string & /* api_path */, -// std::size_t /*size*/, std::uint64_t offset, -// data_buffer & /*data*/, -// stop_type &stop_requested) -> api_error { -// if (stop_requested) { -// return api_error::download_stopped; -// } -// -// if (offset == 0u) { -// return api_error::success; -// } -// -// while (not stop_requested) { -// std::this_thread::sleep_for(100ms); -// } -// -// return api_error::download_stopped; -// }); -// -// data_buffer data{}; -// EXPECT_EQ(api_error::success, f->read(1U, 0U, data)); -// -// fm.close(handle); -// -// EXPECT_CALL(mp, set_item_meta("/test_download_timeout.txt", META_SOURCE, -// _)) -// .WillOnce(Return(api_error::success)); -// -// EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); -// ec.wait_for_empty(); -// -// EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); -// fm.stop(); -// -// polling::instance().stop(); -// event_system::instance().stop(); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, remove_file_fails_if_file_does_not_exist) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, const bool &directory, -// filesystem_item & /*fsi*/) -> api_error { -// EXPECT_STREQ("/test_remove.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// return api_error::item_not_found; -// }); -// -// EXPECT_EQ(api_error::item_not_found, fm.remove_file("/test_remove.txt")); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } -// -// TEST(file_manager, remove_file_fails_if_provider_remove_file_fails) { -// { -// app_config cfg(provider_type::sia, file_manager_dir); -// cfg.set_enable_chunk_downloader_timeout(false); -// mock_provider mp; -// -// EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); -// -// file_manager fm(cfg, mp); -// -// EXPECT_CALL(mp, get_filesystem_item) -// .WillOnce([](const std::string &api_path, const bool &directory, -// filesystem_item &fsi) -> api_error { -// EXPECT_STREQ("/test_remove.txt", api_path.c_str()); -// EXPECT_FALSE(directory); -// fsi.api_path = api_path; -// fsi.api_parent = utils::path::get_parent_api_path(api_path); -// fsi.directory = directory; -// fsi.size = 0U; -// return api_error::success; -// }); -// EXPECT_CALL(mp, remove_file("/test_remove.txt")) -// .WillOnce(Return(api_error::item_not_found)); -// -// EXPECT_EQ(api_error::item_not_found, fm.remove_file("/test_remove.txt")); -// } -// -// EXPECT_TRUE(utils::file::directory(file_manager_dir).remove_recursively()); -// } +TEST_F(file_manager_test, + evict_file_fails_if_unable_to_get_source_path_from_item_meta) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + file_manager fm(*cfg, mp); + + EXPECT_CALL(mp, get_item_meta(_, META_SOURCE, _)) + .WillOnce([](const std::string &api_path, const std::string &key, + std::string & /*value*/) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_STREQ(META_SOURCE.c_str(), key.c_str()); + return api_error::error; + }); + + EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _)) + .WillOnce([](const std::string &api_path, const std::string &key, + std::string &value) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_STREQ(META_PINNED.c_str(), key.c_str()); + value = "0"; + return api_error::success; + }); + + EXPECT_FALSE(fm.evict_file("/test_open.txt")); +} + +TEST_F(file_manager_test, evict_file_fails_if_source_path_is_empty) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + file_manager fm(*cfg, mp); + + EXPECT_CALL(mp, get_item_meta(_, META_SOURCE, _)) + .WillOnce([](const std::string &api_path, const std::string &key, + std::string &value) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_STREQ(META_SOURCE.c_str(), key.c_str()); + value = ""; + return api_error::success; + }); + EXPECT_CALL(mp, get_item_meta(_, META_PINNED, _)) + .WillOnce([](const std::string &api_path, const std::string &key, + std::string &value) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_STREQ(META_PINNED.c_str(), key.c_str()); + value = "0"; + return api_error::success; + }); + + EXPECT_FALSE(fm.evict_file("/test_open.txt")); +} + +TEST_F(file_manager_test, evict_file_fails_if_file_is_uploading) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + fm.start(); + + event_capture capture({ + "filesystem_item_opened", + "filesystem_item_handle_opened", + "filesystem_item_handle_closed", + "filesystem_item_closed", + "file_upload_completed", + }); + + const auto source_path = utils::path::combine(cfg->get_cache_directory(), + {utils::create_uuid_string()}); + + const auto now = utils::time::get_time_now(); + + auto meta = create_meta_attributes( + now, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE, now + 1u, now + 2u, + false, 1, "", 2, now + 3u, 3u, 4u, 0u, source_path, 10, now + 4u); + std::uint64_t handle{}; + { + std::shared_ptr f; + + EXPECT_CALL(mp, create_file("/test_evict.txt", meta)) + .WillOnce(Return(api_error::success)); + EXPECT_CALL(mp, get_filesystem_item) + .WillRepeatedly([&meta](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_evict.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = utils::string::to_uint64(meta[META_SIZE]); + fsi.source_path = meta[META_SOURCE]; + return api_error::success; + }); + +#if defined(_WIN32) + EXPECT_EQ(api_error::success, + fm.create("/test_evict.txt", meta, {}, handle, f)); +#else + EXPECT_EQ(api_error::success, + fm.create("/test_evict.txt", meta, O_RDWR, handle, f)); +#endif + EXPECT_CALL(mp, set_item_meta("/test_evict.txt", _)) + .Times(2) + .WillRepeatedly(Return(api_error::success)); + EXPECT_CALL(mp, upload_file) + .WillOnce([](const std::string &api_path, + const std::string &source_path2, + stop_type & /*stop_requested*/) -> api_error { + EXPECT_STREQ("/test_evict.txt", api_path.c_str()); + EXPECT_FALSE(source_path2.empty()); + std::this_thread::sleep_for(3s); + return api_error::success; + }); + + data_buffer data{{0, 1, 1}}; + std::size_t bytes_written{}; + EXPECT_EQ(api_error::success, f->write(0U, data, bytes_written)); + + auto opt_size = utils::file::file{source_path}.size(); + EXPECT_TRUE(opt_size.has_value()); + EXPECT_EQ(static_cast(data.size()), opt_size.value()); + + fm.close(handle); + + EXPECT_TRUE(utils::retry_action( + [&fm]() -> bool { return fm.is_processing("/test_evict.txt"); })); + EXPECT_FALSE(fm.evict_file("/test_evict.txt")); + } + + capture.wait_for_empty(); + + EXPECT_TRUE(utils::file::file(source_path).exists()); + + fm.stop(); +} + +TEST_F(file_manager_test, evict_file_fails_if_file_is_in_upload_queue) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + mock_open_file of{}; + EXPECT_CALL(of, is_directory).WillRepeatedly(Return(false)); + EXPECT_CALL(of, get_api_path).WillRepeatedly(Return("/test_evict.txt")); + EXPECT_CALL(of, get_source_path).WillRepeatedly(Return("/test_evict.src")); + fm.queue_upload(of); + + EXPECT_TRUE(fm.is_processing("/test_evict.txt")); + EXPECT_FALSE(fm.evict_file("/test_evict.txt")); +} + +TEST_F(file_manager_test, evict_file_fails_if_file_is_modified) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_evict.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = 1U; + fsi.source_path = "/test_evict.src"; + return api_error::success; + }); + + auto of = std::make_shared(); + EXPECT_CALL(*of, is_directory).WillOnce(Return(false)); + EXPECT_CALL(*of, add).WillOnce(Return()); + EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_evict.txt")); + EXPECT_CALL(*of, get_source_path).WillRepeatedly(Return("/test_evict.src")); + EXPECT_CALL(*of, is_modified).Times(2).WillRepeatedly(Return(true)); + + std::uint64_t handle{}; + std::shared_ptr f; +#if defined(_WIN32) + EXPECT_EQ(api_error::success, fm.open(of, {}, handle, f)); +#else + EXPECT_EQ(api_error::success, fm.open(of, O_RDWR, handle, f)); +#endif + + EXPECT_TRUE(fm.is_processing("/test_evict.txt")); + EXPECT_FALSE(fm.evict_file("/test_evict.txt")); +} + +TEST_F(file_manager_test, evict_file_fails_if_file_is_not_complete) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_evict.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = 1U; + return api_error::success; + }); + + auto of = std::make_shared(); + EXPECT_CALL(*of, is_directory).WillOnce(Return(false)); + EXPECT_CALL(*of, add).WillOnce(Return()); + EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_evict.txt")); + EXPECT_CALL(*of, get_source_path).WillRepeatedly(Return("/test_evict.src")); + EXPECT_CALL(*of, is_modified).Times(2).WillRepeatedly(Return(false)); + EXPECT_CALL(*of, is_complete).Times(2).WillRepeatedly(Return(false)); + EXPECT_CALL(mp, set_item_meta("/test_evict.txt", META_SOURCE, _)) + .WillOnce(Return(api_error::success)); + + std::uint64_t handle{}; + std::shared_ptr f; +#if defined(_WIN32) + EXPECT_EQ(api_error::success, fm.open(of, {}, handle, f)); +#else + EXPECT_EQ(api_error::success, fm.open(of, O_RDWR, handle, f)); +#endif + + EXPECT_TRUE(fm.is_processing("/test_evict.txt")); + EXPECT_FALSE(fm.evict_file("/test_evict.txt")); +} + +TEST_F(file_manager_test, can_get_directory_items) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + EXPECT_CALL(mp, get_directory_items) + .WillOnce([](const std::string &api_path, + directory_item_list &list) -> api_error { + EXPECT_STREQ("/", api_path.c_str()); + list.insert(list.begin(), directory_item{ + "..", + "", + true, + }); + list.insert(list.begin(), directory_item{ + ".", + "", + true, + }); + return api_error::success; + }); + auto list = fm.get_directory_items("/"); + EXPECT_EQ(std::size_t(2U), list.size()); +} + +TEST_F(file_manager_test, file_is_not_opened_if_provider_create_file_fails) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + const auto now = utils::time::get_time_now(); + auto meta = create_meta_attributes( + now, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE, now + 1u, now + 2u, + false, 1, "", 2, now + 3u, 3u, 4u, 0u, "/test_create.src", 10, now + 4u); + file_manager fm(*cfg, mp); + + EXPECT_CALL(mp, create_file("/test_create.txt", meta)) + .WillOnce(Return(api_error::error)); + + std::uint64_t handle{}; + std::shared_ptr f; +#if defined(_WIN32) + EXPECT_EQ(api_error::error, + fm.create("/test_create.txt", meta, {}, handle, f)); +#else + EXPECT_EQ(api_error::error, + fm.create("/test_create.txt", meta, O_RDWR, handle, f)); +#endif + EXPECT_FALSE(f); + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); +} + +TEST_F(file_manager_test, create_fails_if_provider_create_is_unsuccessful) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + EXPECT_CALL(mp, create_file("/test_create.txt", _)) + .WillOnce(Return(api_error::error)); + + std::uint64_t handle{}; + std::shared_ptr f{}; + api_meta_map meta{}; +#if defined(_WIN32) + EXPECT_EQ(api_error::error, + fm.create("/test_create.txt", meta, {}, handle, f)); +#else + EXPECT_EQ(api_error::error, + fm.create("/test_create.txt", meta, O_RDWR, handle, f)); +#endif + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); +} + +TEST_F(file_manager_test, get_open_file_fails_if_file_is_not_open) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + std::shared_ptr f{}; + EXPECT_FALSE(fm.get_open_file(0U, true, f)); + EXPECT_FALSE(f); + + EXPECT_FALSE(fm.get_open_file(0U, false, f)); + EXPECT_FALSE(f); +} + +TEST_F(file_manager_test, + get_open_file_promotes_non_writeable_file_if_writeable_is_specified) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + auto non_writeable = std::make_shared(); + EXPECT_CALL(*non_writeable, is_directory).WillOnce(Return(false)); + EXPECT_CALL(*non_writeable, add).WillOnce(Return()); + EXPECT_CALL(*non_writeable, get_api_path) + .WillRepeatedly(Return("/test_open.txt")); + EXPECT_CALL(*non_writeable, get_source_path) + .WillRepeatedly(Return("/test_open.src")); + EXPECT_CALL(*non_writeable, is_modified).WillRepeatedly(Return(true)); + EXPECT_CALL(*non_writeable, is_write_supported).WillRepeatedly(Return(false)); + EXPECT_CALL(*non_writeable, is_write_supported).WillRepeatedly(Return(false)); + + EXPECT_CALL(*non_writeable, get_filesystem_item) + .WillOnce([api_path = "/test_open.txt"]() -> filesystem_item { + filesystem_item fsi{}; + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = false; + fsi.size = 10U; + fsi.source_path = "/test_open.src"; + return fsi; + }); + + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = 10U; + fsi.source_path = "/test_open.src"; + return api_error::success; + }); + + std::uint64_t handle{}; + std::shared_ptr f{}; +#if defined(_WIN32) + EXPECT_EQ(api_error::success, fm.open(non_writeable, {}, handle, f)); + EXPECT_CALL(*non_writeable, get_open_data()) + .WillOnce([&handle]() -> std::map & { + static std::map map; + map[handle] = {}; + return map; + }); +#else // !defined(_WIN32) + EXPECT_EQ(api_error::success, fm.open(non_writeable, O_RDWR, handle, f)); + EXPECT_CALL(*non_writeable, get_open_data()) + .WillOnce([&handle]() -> std::map & { + static std::map map; + map[handle] = O_RDWR; + return map; + }); +#endif // defined(_WIN32) + + EXPECT_CALL(mp, set_item_meta("/test_open.txt", META_SOURCE, _)) + .WillOnce(Return(api_error::success)); + + EXPECT_CALL(*non_writeable, has_handle(1)).WillOnce([]() -> bool { + return true; + }); + EXPECT_TRUE(fm.get_open_file(handle, true, f)); + EXPECT_NE(non_writeable.get(), f.get()); + EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); + + std::shared_ptr f2{}; + EXPECT_TRUE(fm.get_open_file(handle, false, f2)); + EXPECT_EQ(f.get(), f2.get()); + EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); +} + +TEST_F(file_manager_test, open_file_fails_if_file_is_not_found) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + std::shared_ptr f{}; + EXPECT_FALSE(fm.get_open_file(1U, true, f)); + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); + EXPECT_FALSE(f); + + EXPECT_FALSE(fm.get_open_file(1U, false, f)); + EXPECT_FALSE(f); + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); +} + +TEST_F(file_manager_test, + open_file_fails_if_provider_get_filesystem_item_fails) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + auto of = std::make_shared(); + EXPECT_CALL(*of, is_directory).WillRepeatedly(Return(false)); + EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_open.txt")); + EXPECT_CALL(*of, get_source_path).WillRepeatedly(Return("/test_open.src")); + + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, bool directory, + filesystem_item & /*fsi*/) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_FALSE(directory); + return api_error::error; + }); + + std::uint64_t handle{}; + std::shared_ptr f{}; +#if defined(_WIN32) + EXPECT_EQ(api_error::error, fm.open(of, {}, handle, f)); +#else + EXPECT_EQ(api_error::error, fm.open(of, O_RDWR, handle, f)); +#endif + EXPECT_FALSE(fm.get_open_file(1U, true, f)); + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); + EXPECT_FALSE(f); + + EXPECT_FALSE(fm.get_open_file(1U, false, f)); + EXPECT_FALSE(f); + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); +} + +TEST_F(file_manager_test, open_file_fails_if_provider_set_item_meta_fails) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + auto of = std::make_shared(); + EXPECT_CALL(*of, is_directory).WillRepeatedly(Return(false)); + EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_open.txt")); + EXPECT_CALL(*of, get_source_path).WillRepeatedly(Return("/test_open.src")); + + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = 0U; + return api_error::success; + }); + + EXPECT_CALL(mp, set_item_meta("/test_open.txt", META_SOURCE, _)) + .WillOnce(Return(api_error::error)); + + std::uint64_t handle{}; + std::shared_ptr f{}; +#if defined(_WIN32) + EXPECT_EQ(api_error::error, fm.open(of, {}, handle, f)); +#else + EXPECT_EQ(api_error::error, fm.open(of, O_RDWR, handle, f)); +#endif + EXPECT_FALSE(fm.get_open_file(1U, true, f)); + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); + EXPECT_FALSE(f); + + EXPECT_FALSE(fm.get_open_file(1U, false, f)); + EXPECT_FALSE(f); + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); +} + +TEST_F(file_manager_test, open_file_creates_source_path_if_empty) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + auto of = std::make_shared(); + EXPECT_CALL(*of, add).WillOnce(Return()); + EXPECT_CALL(*of, is_directory).WillRepeatedly(Return(false)); + EXPECT_CALL(*of, is_write_supported).WillRepeatedly(Return(true)); + EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_open.txt")); + EXPECT_CALL(*of, get_source_path).WillRepeatedly(Return("")); + + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = 0U; + return api_error::success; + }); + + EXPECT_CALL(mp, set_item_meta("/test_open.txt", _, _)) + .WillOnce([](const std::string &api_path, const std::string &key, + const std::string &value) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_STREQ(META_SOURCE.c_str(), key.c_str()); + EXPECT_FALSE(value.empty()); + return api_error::success; + }); + + std::uint64_t handle{}; + std::shared_ptr f{}; +#if defined(_WIN32) + EXPECT_EQ(api_error::success, fm.open(of, {}, handle, f)); +#else + EXPECT_EQ(api_error::success, fm.open(of, O_RDWR, handle, f)); +#endif + EXPECT_CALL(*of, has_handle(1)).Times(2).WillRepeatedly([]() -> bool { + return true; + }); + + EXPECT_TRUE(fm.get_open_file(1U, true, f)); + EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); + EXPECT_TRUE(f); + + EXPECT_TRUE(fm.get_open_file(1U, false, f)); + EXPECT_TRUE(f); + EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); +} + +TEST_F(file_manager_test, open_file_first_file_handle_is_not_zero) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + auto of = std::make_shared(); + EXPECT_CALL(*of, add).WillOnce(Return()); + EXPECT_CALL(*of, is_directory).WillRepeatedly(Return(false)); + EXPECT_CALL(*of, is_write_supported).WillRepeatedly(Return(true)); + EXPECT_CALL(*of, get_api_path).WillRepeatedly(Return("/test_open.txt")); + EXPECT_CALL(*of, get_source_path).WillRepeatedly(Return("/test_open.src")); + + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_open.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = 0U; + fsi.source_path = "/test_open.src"; + return api_error::success; + }); + + std::uint64_t handle{}; + std::shared_ptr f{}; +#if defined(_WIN32) + EXPECT_EQ(api_error::success, fm.open(of, {}, handle, f)); +#else + EXPECT_EQ(api_error::success, fm.open(of, O_RDWR, handle, f)); +#endif + EXPECT_CALL(*of, has_handle(1)).WillOnce([]() -> bool { return true; }); + + EXPECT_TRUE(fm.get_open_file(1U, true, f)); + EXPECT_GT(handle, std::uint64_t(0U)); +} + +TEST_F(file_manager_test, can_remove_file) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + { + auto file = utils::file::file::open_or_create_file("./test_remove.txt"); + EXPECT_TRUE(*file); + } + EXPECT_TRUE(utils::file::file("./test_remove.txt").exists()); + + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_remove.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = 0U; + fsi.source_path = "./test_remove.txt"; + return api_error::success; + }); + EXPECT_CALL(mp, remove_file("/test_remove.txt")) + .WillOnce(Return(api_error::success)); + + EXPECT_EQ(api_error::success, fm.remove_file("/test_remove.txt")); + + EXPECT_FALSE(utils::file::file("./test_remove.txt").exists()); +} + +TEST_F(file_manager_test, can_queue_and_remove_upload) { + event_capture ec({ + "file_upload_queued", + "download_resume_removed", + }); + + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + mock_open_file of{}; + EXPECT_CALL(of, get_api_path).WillOnce(Return("/test_queue.txt")); + EXPECT_CALL(of, get_source_path).WillOnce(Return("/test_queue.src")); + + EXPECT_FALSE(fm.is_processing("/test_queue.txt")); + fm.queue_upload(of); + EXPECT_TRUE(fm.is_processing("/test_queue.txt")); + + fm.remove_upload("/test_queue.txt"); + EXPECT_FALSE(fm.is_processing("/test_queue.txt")); + + ec.wait_for_empty(); +} + +TEST_F(file_manager_test, file_is_closed_after_download_timeout) { + cfg->set_enable_chunk_downloader_timeout(true); + cfg->set_chunk_downloader_timeout_secs(3U); + + polling::instance().start(cfg.get()); + + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + fm.start(); + + const auto source_path = utils::path::combine(cfg->get_cache_directory(), + {utils::create_uuid_string()}); + + event_consumer es("item_timeout", [](const event &e) { + const auto &ee = dynamic_cast(e); + EXPECT_STREQ("/test_download_timeout.txt", + ee.get_api_path().get().c_str()); + }); + + const auto now = utils::time::get_time_now(); + auto meta = create_meta_attributes( + now, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE, now + 1u, now + 2u, + false, 1, "key", 2, now + 3u, 3u, 4u, + utils::encryption::encrypting_reader::get_data_chunk_size() * 4u, + source_path, 10, now + 4u); + + EXPECT_CALL(mp, get_filesystem_item) + .WillRepeatedly([&meta](const std::string &api_path, bool directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_download_timeout.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = utils::string::to_uint64(meta[META_SIZE]); + fsi.source_path = meta[META_SOURCE]; + return api_error::success; + }); + + event_capture ec({"item_timeout"}); + + std::uint64_t handle{}; + std::shared_ptr f; +#if defined(_WIN32) + EXPECT_EQ(api_error::success, + fm.open("/test_download_timeout.txt", false, {}, handle, f)); +#else + EXPECT_EQ(api_error::success, + fm.open("/test_download_timeout.txt", false, O_RDWR, handle, f)); +#endif + + EXPECT_CALL(mp, read_file_bytes) + .WillRepeatedly([](const std::string & /* api_path */, + std::size_t /*size*/, std::uint64_t offset, + data_buffer & /*data*/, + stop_type &stop_requested) -> api_error { + if (stop_requested) { + return api_error::download_stopped; + } + + if (offset == 0u) { + return api_error::success; + } + + while (not stop_requested) { + std::this_thread::sleep_for(100ms); + } + + return api_error::download_stopped; + }); + + data_buffer data{}; + EXPECT_EQ(api_error::success, f->read(1U, 0U, data)); + + fm.close(handle); + + EXPECT_CALL(mp, set_item_meta("/test_download_timeout.txt", META_SOURCE, _)) + .WillOnce(Return(api_error::success)); + + EXPECT_EQ(std::size_t(1U), fm.get_open_file_count()); + ec.wait_for_empty(); + + EXPECT_EQ(std::size_t(0U), fm.get_open_file_count()); + fm.stop(); + + polling::instance().stop(); +} + +TEST_F(file_manager_test, remove_file_fails_if_file_does_not_exist) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, const bool &directory, + filesystem_item & /*fsi*/) -> api_error { + EXPECT_STREQ("/test_remove.txt", api_path.c_str()); + EXPECT_FALSE(directory); + return api_error::item_not_found; + }); + + EXPECT_EQ(api_error::item_not_found, fm.remove_file("/test_remove.txt")); +} + +TEST_F(file_manager_test, remove_file_fails_if_provider_remove_file_fails) { + EXPECT_CALL(mp, is_direct_only()).WillRepeatedly(Return(false)); + + file_manager fm(*cfg, mp); + + EXPECT_CALL(mp, get_filesystem_item) + .WillOnce([](const std::string &api_path, const bool &directory, + filesystem_item &fsi) -> api_error { + EXPECT_STREQ("/test_remove.txt", api_path.c_str()); + EXPECT_FALSE(directory); + fsi.api_path = api_path; + fsi.api_parent = utils::path::get_parent_api_path(api_path); + fsi.directory = directory; + fsi.size = 0U; + return api_error::success; + }); + EXPECT_CALL(mp, remove_file("/test_remove.txt")) + .WillOnce(Return(api_error::item_not_found)); + + EXPECT_EQ(api_error::item_not_found, fm.remove_file("/test_remove.txt")); +} } // namespace repertory