ui fixes
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good

This commit is contained in:
2025-09-05 08:32:31 -05:00
parent cd28953324
commit f16f6b808e
3 changed files with 533 additions and 6 deletions

View File

@@ -0,0 +1,531 @@
/*
Copyright <2018-2025> <scott.e.graves@protonmail.com>
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.
*/
#ifndef REPERTORY_TEST_INCLUDE_FIXTURES_PLATFORM_FIXTURE_HPP
#define REPERTORY_TEST_INCLUDE_FIXTURES_PLATFORM_FIXTURE_HPP
#include "test_common.hpp"
#include "app_config.hpp"
#include "platform/platform.hpp"
#include "types/repertory.hpp"
#include "utils/file_utils.hpp"
#include "utils/path.hpp"
#include "utils/utils.hpp"
#if defined(_WIN32)
#include "drives/winfsp/remotewinfsp/remote_winfsp_drive.hpp"
#include "drives/winfsp/winfsp_drive.hpp"
#include "providers/i_provider.hpp"
#include "providers/s3/s3_provider.hpp"
#include "providers/sia/sia_provider.hpp"
#else
#include "comm/curl/curl_comm.hpp"
#include "db/i_meta_db.hpp"
#include "db/meta_db.hpp"
#include "drives/fuse/fuse_drive.hpp"
#include "providers/encrypt/encrypt_provider.hpp"
#include "providers/s3/s3_provider.hpp"
#include "providers/sia/sia_provider.hpp"
#if !defined(ACCESSPERMS)
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */
#endif
#endif
namespace {
std::atomic<std::size_t> provider_idx{0U};
constexpr auto SLEEP_SECONDS{1.5s};
} // namespace
namespace repertory {
struct local_s3_no_encryption final {
static constexpr provider_type type{provider_type::s3};
static constexpr provider_type type2{provider_type::s3};
static constexpr std::uint16_t remote_port{41000U};
static constexpr bool force_legacy_encryption{false};
static constexpr std::string_view encryption_token{""};
};
struct local_s3_encryption final {
static constexpr provider_type type{provider_type::s3};
static constexpr provider_type type2{provider_type::s3};
static constexpr std::uint16_t remote_port{41000U};
static constexpr bool force_legacy_encryption{false};
static constexpr std::string_view encryption_token{"encryption_token"};
};
struct local_s3_legacy_encryption final {
static constexpr provider_type type{provider_type::s3};
static constexpr provider_type type2{provider_type::s3};
static constexpr std::uint16_t remote_port{41000U};
static constexpr bool force_legacy_encryption{true};
static constexpr std::string_view encryption_token{"encryption_token"};
};
struct remote_s3_no_encryption final {
static constexpr provider_type type{provider_type::remote};
static constexpr provider_type type2{provider_type::s3};
static constexpr std::uint16_t remote_port{41000U};
static constexpr bool force_legacy_encryption{false};
static constexpr std::string_view encryption_token{""};
};
struct remote_s3_encryption final {
static constexpr provider_type type{provider_type::remote};
static constexpr provider_type type2{provider_type::s3};
static constexpr std::uint16_t remote_port{41000U};
static constexpr bool force_legacy_encryption{false};
static constexpr std::string_view encryption_token{"encryption_token"};
};
struct remote_s3_legacy_encryption final {
static constexpr provider_type type{provider_type::remote};
static constexpr provider_type type2{provider_type::s3};
static constexpr std::uint16_t remote_port{41000U};
static constexpr bool force_legacy_encryption{true};
static constexpr std::string_view encryption_token{"encryption_token"};
};
struct local_sia final {
static constexpr provider_type type{provider_type::sia};
static constexpr provider_type type2{provider_type::sia};
static constexpr std::uint16_t remote_port{41001U};
static constexpr bool force_legacy_encryption{false};
static constexpr std::string_view encryption_token{""};
};
struct remote_sia final {
static constexpr provider_type type{provider_type::remote};
static constexpr provider_type type2{provider_type::sia};
static constexpr std::uint16_t remote_port{41001U};
static constexpr bool force_legacy_encryption{false};
static constexpr std::string_view encryption_token{""};
};
struct remote_winfsp_to_linux final {
static constexpr provider_type type{provider_type::remote};
static constexpr provider_type type2{provider_type::unknown};
static constexpr std::uint16_t remote_port{41002U};
static constexpr bool force_legacy_encryption{false};
static constexpr std::string_view encryption_token{""};
};
struct remote_linux_to_winfsp final {
static constexpr provider_type type{provider_type::remote};
static constexpr provider_type type2{provider_type::unknown};
static constexpr std::uint16_t remote_port{41002U};
static constexpr bool force_legacy_encryption{false};
static constexpr std::string_view encryption_token{""};
};
struct platform_ops {
static void ensure_process_cwd() {
#if !defined(_WIN32)
EXPECT_TRUE(utils::file::change_to_process_directory());
#endif // !defined(_WIN32)
}
static std::string build_cmd(const std::string &args_joined, bool is_mount) {
#if defined(_WIN32)
if (is_mount) {
return "start .\\repertory.exe -f " + args_joined;
}
return ".\\repertory.exe " + args_joined;
#else // !defined(_WIN32)
#if defined(__APPLE__)
constexpr const char *kBin = "./repertory.app/Contents/MacOS/repertory ";
#else // !defined(__APPLE__)
constexpr const char *kBin = "./repertory ";
#endif // defined(__APPLE__)
return std::string(kBin) + args_joined;
#endif // defined(_WIN32)
}
static void execute_mount(std::vector<std::string> args_without_location,
const std::string &location) {
ensure_process_cwd();
args_without_location.emplace_back(location);
const auto cmd = build_cmd(utils::string::join(args_without_location, ' '),
/*is_mount*/ true);
std::cout << "mount command: " << cmd << std::endl;
ASSERT_EQ(0, system(cmd.c_str()));
std::this_thread::sleep_for(5s);
ASSERT_TRUE(utils::file::directory{location}.exists());
}
static void execute_unmount(std::vector<std::string> args_without_unmount,
const std::string &location) {
ensure_process_cwd();
args_without_unmount.emplace_back("-unmount");
const auto cmd = build_cmd(utils::string::join(args_without_unmount, ' '),
/*is_mount*/ false);
std::cout << "unmount command: " << cmd << std::endl;
#if defined(_WIN32)
std::this_thread::sleep_for(10s);
bool unmounted = false;
for (int i = 0; !unmounted && i < 6; ++i) {
(void)system(cmd.c_str());
unmounted = !utils::file::directory{location}.exists();
if (!unmounted)
std::this_thread::sleep_for(5s);
}
ASSERT_TRUE(unmounted);
#else // !defined(_WIN32)
auto res = system(cmd.c_str());
EXPECT_EQ(0, res);
#endif // defined(_WIN32)
}
};
template <typename provider_t> class drive_fixture : public ::testing::Test {
public:
#if !defined(_WIN32)
static std::unique_ptr<app_config> config;
static std::unique_ptr<i_meta_db> meta;
#endif // !defined(_WIN32)
static std::filesystem::path current_directory;
static provider_type current_provider;
static std::vector<std::string> drive_args;
static std::vector<std::string> drive_args2;
static std::string mount_location;
static std::string mount_location2;
protected:
static void SetUpTestCase() {
current_directory = std::filesystem::current_path();
const auto make_test_dir = [](std::string_view suite,
std::string_view sub) {
return utils::path::combine(test::get_test_output_dir(),
{std::string(suite), std::string(sub)});
};
const auto make_cfg_dir = [](const std::string &root,
std::string_view name) {
auto cfg = utils::path::combine(root, {std::string(name)});
ASSERT_TRUE(utils::file::directory(cfg).create_directory());
return cfg;
};
const auto configure_s3 = [](app_config &cfg_obj) {
app_config src_cfg{
provider_type::s3,
utils::path::combine(test::get_test_config_dir(), {"s3"})};
auto cfg = src_cfg.get_s3_config();
cfg.force_legacy_encryption = provider_t::force_legacy_encryption;
cfg.encryption_token = provider_t::encryption_token;
cfg_obj.set_enable_drive_events(true);
cfg_obj.set_event_level(event_level::trace);
cfg_obj.set_s3_config(cfg);
auto r = cfg_obj.get_remote_mount();
r.enable = true;
r.api_port = provider_t::remote_port;
cfg_obj.set_remote_mount(r);
};
const auto configure_sia = [](app_config &cfg_obj) {
app_config src_cfg{
provider_type::sia,
utils::path::combine(test::get_test_config_dir(), {"sia"})};
cfg_obj.set_enable_drive_events(true);
cfg_obj.set_event_level(event_level::trace);
cfg_obj.set_host_config(src_cfg.get_host_config());
cfg_obj.set_sia_config(src_cfg.get_sia_config());
auto r = cfg_obj.get_remote_mount();
r.enable = true;
r.api_port = provider_t::remote_port;
cfg_obj.set_remote_mount(r);
};
const auto mount_local_s3 = [&](bool as_remote) {
const auto test_dir = make_test_dir(
#if defined(_WIN32)
"winfsp_test",
#else // !defined(_WIN32)
"fuse_test",
#endif // defined(_WIN32)
fmt::format("{}_{}", app_config::get_provider_name(current_provider),
as_remote));
#if defined(_WIN32)
mount_location = utils::string::to_lower(std::string{"U:"});
#else // !defined(_WIN32)
mount_location = utils::path::combine(test_dir, {"mount"});
ASSERT_TRUE(utils::file::directory(mount_location).create_directory());
#endif // defined(_WIN32)
auto cfg_dir = make_cfg_dir(test_dir, "cfg");
auto cfg = std::make_unique<app_config>(provider_type::s3, cfg_dir);
configure_s3(*cfg);
drive_args = {"-dd", cfg->get_data_directory(), "-s3", "-na", "s3"};
#if !defined(_WIN32)
cfg->set_database_type(database_type::sqlite);
config = std::move(cfg);
meta = create_meta_db(*config);
#endif // !defined(_WIN32)
platform_ops::execute_mount(drive_args, mount_location);
};
const auto mount_local_sia = [&](bool as_remote) {
const auto test_dir = make_test_dir(
#if defined(_WIN32)
"winfsp_test",
#else // !defined(_WIN32)
"fuse_test",
#endif // defined(_WIN32)
fmt::format("{}_{}", app_config::get_provider_name(current_provider),
as_remote));
#if defined(_WIN32)
mount_location = utils::string::to_lower(std::string{"U:"});
#else // !defined(_WIN32)
mount_location = utils::path::combine(test_dir, {"mount"});
ASSERT_TRUE(utils::file::directory(mount_location).create_directory());
#endif // defined(_WIN32)
auto cfg_dir = make_cfg_dir(test_dir, "cfg");
auto cfg = std::make_unique<app_config>(provider_type::sia, cfg_dir);
configure_sia(*cfg);
drive_args = {"-dd", cfg->get_data_directory(), "-na", "sia"};
#if !defined(_WIN32)
cfg->set_database_type(database_type::sqlite);
config = std::move(cfg);
meta = create_meta_db(*config);
#endif // !defined(_WIN32)
platform_ops::execute_mount(drive_args, mount_location);
};
const auto mount_remote = [&] {
const auto test_dir = make_test_dir(
#if defined(_WIN32)
"winfsp_test",
#else // !defined(_WIN32)
"fuse_test",
#endif // defined(_WIN32)
fmt::format("{}_{}_{}",
app_config::get_provider_name(provider_t::type),
app_config::get_provider_name(provider_t::type2),
provider_t::remote_port));
mount_location2 = mount_location;
#if defined(_WIN32)
mount_location = utils::string::to_lower(std::string{"V:"});
#else // !defined(_WIN32)
mount_location = utils::path::combine(test_dir, {"mount"});
ASSERT_TRUE(utils::file::directory(mount_location).create_directory());
#endif // defined(_WIN32)
auto cfg_dir2 = make_cfg_dir(test_dir, "cfg2");
auto cfg2 = std::make_unique<app_config>(provider_type::remote, cfg_dir2);
cfg2->set_enable_drive_events(true);
cfg2->set_event_level(event_level::trace);
#if !defined(_WIN32)
cfg2->set_database_type(database_type::sqlite);
#endif // !defined(_WIN32)
drive_args2 = {"-dd", cfg2->get_data_directory(), "-rm",
fmt::format("localhost:{}", provider_t::remote_port)};
platform_ops::execute_mount(drive_args2, mount_location);
};
switch (provider_t::type) {
case provider_type::s3: {
mount_local_s3(false);
} break;
case provider_type::sia: {
mount_local_sia(false);
} break;
case provider_type::remote: {
switch (provider_t::type2) {
case provider_type::s3:
mount_local_s3(true);
break;
case provider_type::sia:
mount_local_sia(true);
break;
case provider_type::unknown:
mount_remote();
return;
default:
throw std::runtime_error("remote provider type is not implemented");
}
mount_remote();
} break;
default:
throw std::runtime_error("provider type is not implemented");
}
}
static void TearDownTestCase() {
if (provider_t::type == provider_type::remote) {
platform_ops::execute_unmount(drive_args2, mount_location);
if (provider_t::type2 != provider_type::unknown) {
platform_ops::execute_unmount(drive_args, mount_location2);
}
} else {
platform_ops::execute_unmount(drive_args, mount_location);
}
#if !defined(_WIN32)
meta.reset();
config.reset();
#endif // !defined(_WIN32)
std::filesystem::current_path(current_directory);
}
#if !defined(_WIN32)
public:
static auto create_file_path(std::string &file_name) {
file_name += std::to_string(++provider_idx);
return utils::path::combine(mount_location, {file_name});
}
static auto create_file_and_test(std::string &file_name, mode_t perms)
-> std::string {
file_name += std::to_string(++provider_idx);
auto file_path = utils::path::combine(mount_location, {file_name});
auto handle = open(file_path.c_str(), O_CREAT | O_EXCL | O_RDWR, perms);
EXPECT_LE(1, handle);
auto opt_size = utils::file::file{file_path}.size();
EXPECT_TRUE(opt_size.has_value());
if (opt_size.has_value()) {
EXPECT_EQ(0U, opt_size.value());
}
EXPECT_EQ(0, close(handle));
EXPECT_TRUE(utils::file::file(file_path).exists());
EXPECT_FALSE(utils::file::directory(file_path).exists());
struct stat64 u_stat{};
EXPECT_EQ(0, stat64(file_path.c_str(), &u_stat));
EXPECT_EQ(getgid(), u_stat.st_gid);
EXPECT_EQ(getuid(), u_stat.st_uid);
return file_path;
}
static auto create_file_and_test(std::string &file_name) -> std::string {
return create_file_and_test(file_name, ACCESSPERMS);
}
static auto create_directory_and_test(std::string &dir_name, mode_t perms)
-> std::string {
dir_name += std::to_string(++provider_idx);
auto dir_path = utils::path::combine(mount_location, {dir_name});
mkdir(dir_path.c_str(), perms);
EXPECT_TRUE(utils::file::directory(dir_path).exists());
EXPECT_EQ(0U, utils::file::directory(dir_path).count(false));
EXPECT_EQ(0U, utils::file::directory(dir_path).count(true));
EXPECT_FALSE(utils::file::file(dir_path).exists());
struct stat64 u_stat{};
EXPECT_EQ(0, stat64(dir_path.c_str(), &u_stat));
EXPECT_EQ(getgid(), u_stat.st_gid);
EXPECT_EQ(getuid(), u_stat.st_uid);
return dir_path;
}
static auto create_directory_and_test(std::string &dir_name) -> std::string {
return create_directory_and_test(dir_name, ACCESSPERMS);
}
static auto create_root_file(std::string &file_name) -> std::string {
auto file_path = create_file_and_test(file_name);
auto api_path = utils::path::create_api_path(file_name);
[[maybe_unused]] auto res =
meta->set_item_meta(api_path, {{META_UID, "0"}, {META_GID, "0"}});
std::this_thread::sleep_for(SLEEP_SECONDS);
return file_path;
}
static void rmdir_and_test(std::string_view dir_path) {
EXPECT_TRUE(utils::file::directory(dir_path).remove());
EXPECT_FALSE(utils::file::directory(dir_path).exists());
EXPECT_FALSE(utils::file::file(dir_path).exists());
}
static void unlink_file_and_test(std::string_view file_path) {
EXPECT_TRUE(utils::file::file(file_path).remove());
EXPECT_FALSE(utils::file::file(file_path).exists());
EXPECT_FALSE(utils::file::directory(file_path).exists());
}
static void unlink_root_file(const std::string &file_path) {
auto api_path = utils::path::create_api_path(
utils::path::strip_to_file_name(file_path));
[[maybe_unused]] auto res =
meta->set_item_meta(api_path, {{META_UID, std::to_string(getuid())},
{ META_GID,
std::to_string(getgid()) }});
std::this_thread::sleep_for(SLEEP_SECONDS);
unlink_file_and_test(file_path);
}
#endif // !defined(_WIN32)
};
#if !defined(_WIN32)
template <typename provider_t>
std::unique_ptr<app_config> drive_fixture<provider_t>::config;
template <typename provider_t>
std::unique_ptr<i_meta_db> drive_fixture<provider_t>::meta{};
#endif // !defined(_WIN32)
template <typename provider_t>
std::filesystem::path drive_fixture<provider_t>::current_directory;
template <typename provider_t>
provider_type drive_fixture<provider_t>::current_provider{provider_t::type2};
template <typename provider_t>
std::vector<std::string> drive_fixture<provider_t>::drive_args;
template <typename provider_t>
std::vector<std::string> drive_fixture<provider_t>::drive_args2;
template <typename provider_t>
std::string drive_fixture<provider_t>::mount_location;
template <typename provider_t>
std::string drive_fixture<provider_t>::mount_location2;
using platform_provider_types =
::testing::Types<local_s3_no_encryption, local_s3_encryption,
local_s3_legacy_encryption, remote_s3_no_encryption,
remote_s3_encryption, remote_s3_legacy_encryption,
local_sia, remote_sia>;
#if defined(_WIN32)
using winfsp_test = drive_fixture;
#else
using fuse_test = drive_fixture;
#endif
} // namespace repertory
#endif // REPERTORY_TEST_INCLUDE_FIXTURES_PLATFORM_FIXTURE_HPP

View File

@@ -60,12 +60,7 @@ class _AuthScreenState extends State<AuthScreen> {
return;
}
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Invalid username or password'),
behavior: SnackBarBehavior.floating,
),
);
displayErrorMessage(context, 'Invalid username or password', clear: true);
}
return Scaffold(

View File

@@ -116,6 +116,7 @@ class AppDropdownFormField<T> extends StatelessWidget {
decoration: createCommonDecoration(
scheme,
labelText ?? "",
filled: true,
icon: prefixIcon,
),
dropdownColor: dropdownColor ?? effectiveFill,