From 7af15d32f3b1e69e95f827f7230e8cbff731f57a Mon Sep 17 00:00:00 2001 From: sharder996 Date: Mon, 19 Jun 2023 03:49:19 -0700 Subject: [PATCH] [image vault] have image vault reference factory for instance directories --- include/multipass/vm_image_vault.h | 2 +- src/daemon/daemon.cpp | 18 ++- src/daemon/default_vm_image_vault.cpp | 37 +++-- src/daemon/default_vm_image_vault.h | 12 +- .../backends/lxd/lxd_vm_image_vault.cpp | 3 +- .../backends/lxd/lxd_vm_image_vault.h | 4 +- .../qemu/qemu_virtual_machine_factory.cpp | 11 +- .../qemu/qemu_virtual_machine_factory.h | 2 + .../shared/base_virtual_machine_factory.h | 4 +- tests/blueprint_test_lambdas.cpp | 8 +- tests/blueprint_test_lambdas.h | 2 +- tests/lxd/test_lxd_image_vault.cpp | 75 +++++----- tests/mock_vm_image_vault.h | 8 +- tests/stub_vm_image_vault.h | 4 +- tests/test_alias_dict.cpp | 2 +- tests/test_daemon.cpp | 26 ++-- tests/test_daemon_launch.cpp | 4 +- tests/test_image_vault.cpp | 137 ++++++++++-------- 18 files changed, 191 insertions(+), 168 deletions(-) diff --git a/include/multipass/vm_image_vault.h b/include/multipass/vm_image_vault.h index 6f31f54faea..f6977697e2c 100644 --- a/include/multipass/vm_image_vault.h +++ b/include/multipass/vm_image_vault.h @@ -82,7 +82,7 @@ class VMImageVault : private DisabledCopyMove virtual ~VMImageVault() = default; virtual VMImage fetch_image(const FetchType& fetch_type, const Query& query, const PrepareAction& prepare, const ProgressMonitor& monitor, const bool unlock, - const std::optional& checksum) = 0; + const std::optional& checksum, const Path& download_dir) = 0; virtual void remove(const std::string& name) = 0; virtual bool has_record_for(const std::string& name) = 0; virtual void prune_expired_images() = 0; diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index ee8226edc84..17dd0453514 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -449,14 +449,15 @@ QJsonObject vm_spec_to_json(const mp::VMSpecs& specs) return json; } -auto fetch_image_for(const std::string& name, const mp::FetchType& fetch_type, mp::VMImageVault& vault) +auto fetch_image_for(const std::string& name, mp::VirtualMachineFactory& factory, mp::VMImageVault& vault) { auto stub_prepare = [](const mp::VMImage&) -> mp::VMImage { return {}; }; auto stub_progress = [](int download_type, int progress) { return true; }; mp::Query query{name, "", false, "", mp::Query::Type::Alias, false}; - return vault.fetch_image(fetch_type, query, stub_prepare, stub_progress, false, std::nullopt); + return vault.fetch_image(factory.fetch_type(), query, stub_prepare, stub_progress, false, std::nullopt, + factory.get_instance_directory_name(name)); } auto try_mem_size(const std::string& val) -> std::optional @@ -1286,7 +1287,7 @@ mp::Daemon::Daemon(std::unique_ptr the_config) continue; } - auto vm_image = fetch_image_for(name, config->factory->fetch_type(), *config->vault); + auto vm_image = fetch_image_for(name, *config->factory, *config->vault); if (!vm_image.image_path.isEmpty() && !QFile::exists(vm_image.image_path)) { mpl::log(mpl::Level::warning, category, @@ -1629,7 +1630,7 @@ try // clang-format on info->mutable_instance_status()->set_status(grpc_instance_status_for(present_state)); } - auto vm_image = fetch_image_for(name, config->factory->fetch_type(), *config->vault); + auto vm_image = fetch_image_for(name, *config->factory, *config->vault); auto original_release = vm_image.original_release; if (!vm_image.id.empty() && original_release.empty()) @@ -1817,7 +1818,7 @@ try // clang-format on entry->mutable_instance_status()->set_status(grpc_instance_status_for(present_state)); // FIXME: Set the release to the cached current version when supported - auto vm_image = fetch_image_for(name, config->factory->fetch_type(), *config->vault); + auto vm_image = fetch_image_for(name, *config->factory, *config->vault); auto current_release = vm_image.original_release; if (!vm_image.id.empty() && current_release.empty()) @@ -2912,8 +2913,9 @@ void mp::Daemon::create_vm(const CreateRequest* request, if (!vm_desc.image.id.empty()) checksum = vm_desc.image.id; - auto vm_image = config->vault->fetch_image(fetch_type, query, prepare_action, progress_monitor, - launch_from_blueprint, checksum); + auto vm_image = + config->vault->fetch_image(fetch_type, query, prepare_action, progress_monitor, launch_from_blueprint, + checksum, config->factory->get_instance_directory_name(name)); const auto image_size = config->vault->minimum_image_size_for(vm_image.id); vm_desc.disk_space = compute_final_image_size( @@ -3354,7 +3356,7 @@ grpc::Status mp::Daemon::migrate_from_hyperkit(grpc::ServerReaderWriterInterface qemu_instances_json.contains(key) || qemu_instance_images_json.contains(key)) reply_msg(server, fmt::format("Cannot migrate {}: name already taken by a qemu instance", vm_name), /* sticky = */ true); - else if (const auto vm_image = fetch_image_for(vm_name, config->factory->fetch_type(), *config->vault); + else if (const auto vm_image = fetch_image_for(vm_name, *config->factory, *config->vault); vm_image.original_release.find("16.04") != std::string::npos && !vm_image.image_path.contains("uefi", Qt::CaseInsensitive)) reply_msg(server, diff --git a/src/daemon/default_vm_image_vault.cpp b/src/daemon/default_vm_image_vault.cpp index 890fc137e95..7ccabaf0097 100644 --- a/src/daemon/default_vm_image_vault.cpp +++ b/src/daemon/default_vm_image_vault.cpp @@ -247,7 +247,6 @@ mp::DefaultVMImageVault::DefaultVMImageVault(std::vector image_hos url_downloader{downloader}, cache_dir{QDir(cache_dir_path).filePath("vault")}, data_dir{QDir(data_dir_path).filePath("vault")}, - instances_dir(data_dir.filePath("instances")), images_dir(cache_dir.filePath("images")), days_to_expire{days_to_expire}, prepared_image_records{load_db(cache_dir.filePath(image_db_name))}, @@ -262,7 +261,8 @@ mp::DefaultVMImageVault::~DefaultVMImageVault() mp::VMImage mp::DefaultVMImageVault::fetch_image(const FetchType& fetch_type, const Query& query, const PrepareAction& prepare, const ProgressMonitor& monitor, - const bool unlock, const std::optional& checksum) + const bool unlock, const std::optional& checksum, + const mp::Path& download_dir) { { std::lock_guard lock{fetch_mutex}; @@ -290,11 +290,11 @@ mp::VMImage mp::DefaultVMImageVault::fetch_image(const FetchType& fetch_type, co if (source_image.image_path.endsWith(".xz")) { - source_image.image_path = extract_image_from(query.name, source_image, monitor); + source_image.image_path = extract_image_from(query.name, source_image, monitor, download_dir); } else { - source_image = image_instance_from(query.name, source_image); + source_image = image_instance_from(query.name, source_image, download_dir); } if (fetch_type == FetchType::ImageKernelAndInitrd) @@ -343,7 +343,7 @@ mp::VMImage mp::DefaultVMImageVault::fetch_image(const FetchType& fetch_type, co if (last_modified.isValid() && (last_modified.toString().toStdString() == record.image.release_date)) { - return finalize_image_records(query, record.image, id); + return finalize_image_records(query, record.image, id, download_dir); } } @@ -408,7 +408,7 @@ mp::VMImage mp::DefaultVMImageVault::fetch_image(const FetchType& fetch_type, co const auto prepared_image = record.second.image; try { - return finalize_image_records(query, prepared_image, record.first); + return finalize_image_records(query, prepared_image, record.first, download_dir); } catch (const std::exception& e) { @@ -446,7 +446,7 @@ mp::VMImage mp::DefaultVMImageVault::fetch_image(const FetchType& fetch_type, co auto prepared_image = future.result(); std::lock_guard lock{fetch_mutex}; in_progress_image_fetches.erase(id); - return finalize_image_records(query, prepared_image, id); + return finalize_image_records(query, prepared_image, id, download_dir); } catch (const std::exception&) { @@ -551,7 +551,8 @@ void mp::DefaultVMImageVault::update_images(const FetchType& fetch_type, const P mpl::log(mpl::Level::info, category, fmt::format("Updating {} source image to latest", record.query.release)); try { - fetch_image(fetch_type, record.query, prepare, monitor, false, std::nullopt); + fetch_image(fetch_type, record.query, prepare, monitor, false, std::nullopt, + QFileInfo{record.image.image_path}.absolutePath()); // Remove old image std::lock_guard lock{fetch_mutex}; @@ -654,26 +655,22 @@ mp::VMImage mp::DefaultVMImageVault::download_and_prepare_source_image( } QString mp::DefaultVMImageVault::extract_image_from(const std::string& instance_name, const VMImage& source_image, - const ProgressMonitor& monitor) + const ProgressMonitor& monitor, const mp::Path& dest_dir) { const auto name = QString::fromStdString(instance_name); - const QDir output_dir{MP_UTILS.make_dir(instances_dir, name)}; QFileInfo file_info{source_image.image_path}; const auto image_name = file_info.fileName().remove(".xz"); - const auto image_path = output_dir.filePath(image_name); + const auto image_path = QDir(dest_dir).filePath(image_name); return mp::vault::extract_image(image_path, monitor); } mp::VMImage mp::DefaultVMImageVault::image_instance_from(const std::string& instance_name, - const VMImage& prepared_image) + const VMImage& prepared_image, const mp::Path& dest_dir) { - auto name = QString::fromStdString(instance_name); - auto output_dir = MP_UTILS.make_dir(instances_dir, name); - - return {mp::vault::copy(prepared_image.image_path, output_dir), - mp::vault::copy(prepared_image.kernel_path, output_dir), - mp::vault::copy(prepared_image.initrd_path, output_dir), + return {mp::vault::copy(prepared_image.image_path, dest_dir), + mp::vault::copy(prepared_image.kernel_path, dest_dir), + mp::vault::copy(prepared_image.initrd_path, dest_dir), prepared_image.id, prepared_image.original_release, prepared_image.current_release, @@ -708,13 +705,13 @@ std::optional> mp::DefaultVMImageVault::get_image_future(co } mp::VMImage mp::DefaultVMImageVault::finalize_image_records(const Query& query, const VMImage& prepared_image, - const std::string& id) + const std::string& id, const mp::Path& dest_dir) { VMImage vm_image; if (!query.name.empty()) { - vm_image = image_instance_from(query.name, prepared_image); + vm_image = image_instance_from(query.name, prepared_image, dest_dir); instance_image_records[query.name] = {vm_image, query, std::chrono::system_clock::now()}; } diff --git a/src/daemon/default_vm_image_vault.h b/src/daemon/default_vm_image_vault.h index bb27b5b89f5..a493a92db53 100644 --- a/src/daemon/default_vm_image_vault.h +++ b/src/daemon/default_vm_image_vault.h @@ -51,8 +51,8 @@ class DefaultVMImageVault final : public BaseVMImageVault ~DefaultVMImageVault(); VMImage fetch_image(const FetchType& fetch_type, const Query& query, const PrepareAction& prepare, - const ProgressMonitor& monitor, const bool unlock, - const std::optional& checksum) override; + const ProgressMonitor& monitor, const bool unlock, const std::optional& checksum, + const Path& download_dir) override; void remove(const std::string& name) override; bool has_record_for(const std::string& name) override; void prune_expired_images() override; @@ -61,16 +61,17 @@ class DefaultVMImageVault final : public BaseVMImageVault MemorySize minimum_image_size_for(const std::string& id) override; private: - VMImage image_instance_from(const std::string& name, const VMImage& prepared_image); + VMImage image_instance_from(const std::string& name, const VMImage& prepared_image, const Path& dest_dir); VMImage download_and_prepare_source_image(const VMImageInfo& info, std::optional& existing_source_image, const QDir& image_dir, const FetchType& fetch_type, const PrepareAction& prepare, const ProgressMonitor& monitor); QString extract_image_from(const std::string& instance_name, const VMImage& source_image, - const ProgressMonitor& monitor); + const ProgressMonitor& monitor, const Path& dest_dir); VMImage fetch_kernel_and_initrd(const VMImageInfo& info, const VMImage& source_image, const QDir& image_dir, const ProgressMonitor& monitor); std::optional> get_image_future(const std::string& id); - VMImage finalize_image_records(const Query& query, const VMImage& prepared_image, const std::string& id); + VMImage finalize_image_records(const Query& query, const VMImage& prepared_image, const std::string& id, + const Path& dest_dir); VMImageInfo get_kernel_query_info(const std::string& name); void persist_image_records(); void persist_instance_records(); @@ -78,7 +79,6 @@ class DefaultVMImageVault final : public BaseVMImageVault URLDownloader* const url_downloader; const QDir cache_dir; const QDir data_dir; - const QDir instances_dir; const QDir images_dir; const days days_to_expire; std::mutex fetch_mutex; diff --git a/src/platform/backends/lxd/lxd_vm_image_vault.cpp b/src/platform/backends/lxd/lxd_vm_image_vault.cpp index 9cec1363f6a..3a922c3c6ce 100644 --- a/src/platform/backends/lxd/lxd_vm_image_vault.cpp +++ b/src/platform/backends/lxd/lxd_vm_image_vault.cpp @@ -159,7 +159,8 @@ mp::LXDVMImageVault::LXDVMImageVault(std::vector image_hosts, URLD mp::VMImage mp::LXDVMImageVault::fetch_image(const FetchType& fetch_type, const Query& query, const PrepareAction& prepare, const ProgressMonitor& monitor, - const bool unlock, const std::optional& checksum) + const bool unlock, const std::optional& checksum, + const mp::Path&) { // Look for an already existing instance and get its image info try diff --git a/src/platform/backends/lxd/lxd_vm_image_vault.h b/src/platform/backends/lxd/lxd_vm_image_vault.h index fe6ade82713..ced3654ea7a 100644 --- a/src/platform/backends/lxd/lxd_vm_image_vault.h +++ b/src/platform/backends/lxd/lxd_vm_image_vault.h @@ -40,8 +40,8 @@ class LXDVMImageVault final : public BaseVMImageVault const QUrl& base_url, const QString& cache_dir_path, const multipass::days& days_to_expire); VMImage fetch_image(const FetchType& fetch_type, const Query& query, const PrepareAction& prepare, - const ProgressMonitor& monitor, const bool unlock, - const std::optional& checksum) override; + const ProgressMonitor& monitor, const bool unlock, const std::optional& checksum, + const Path&) override; void remove(const std::string& name) override; bool has_record_for(const std::string& name) override; void prune_expired_images() override; diff --git a/src/platform/backends/qemu/qemu_virtual_machine_factory.cpp b/src/platform/backends/qemu/qemu_virtual_machine_factory.cpp index 16cbd457ac2..7c322ce01fd 100644 --- a/src/platform/backends/qemu/qemu_virtual_machine_factory.cpp +++ b/src/platform/backends/qemu/qemu_virtual_machine_factory.cpp @@ -37,10 +37,9 @@ constexpr auto category = "qemu factory"; } // namespace mp::QemuVirtualMachineFactory::QemuVirtualMachineFactory(const mp::Path& data_dir) - : BaseVirtualMachineFactory( - MP_UTILS.make_dir(QDir(data_dir, get_backend_directory_name()).filePath("vault"), "instances")), - qemu_platform{MP_QEMU_PLATFORM_FACTORY.make_qemu_platform(data_dir)} + : BaseVirtualMachineFactory(QString{}), qemu_platform{MP_QEMU_PLATFORM_FACTORY.make_qemu_platform(data_dir)} { + instances_dir = MP_UTILS.make_dir(QDir(data_dir, get_backend_directory_name()).filePath("vault"), "instances"); } mp::VirtualMachine::UPtr mp::QemuVirtualMachineFactory::create_virtual_machine(const VirtualMachineDescription& desc, @@ -124,3 +123,9 @@ auto mp::QemuVirtualMachineFactory::networks() const -> std::vectornetworks(); } + +mp::Path mp::QemuVirtualMachineFactory::make_qemu_platform_and_resolve_instances_dir(const mp::Path& data_dir) +{ + qemu_platform = MP_QEMU_PLATFORM_FACTORY.make_qemu_platform(data_dir); + return MP_UTILS.make_dir(QDir(data_dir, get_backend_directory_name()).filePath("vault"), "instances"); +} diff --git a/src/platform/backends/qemu/qemu_virtual_machine_factory.h b/src/platform/backends/qemu/qemu_virtual_machine_factory.h index f11de47c6d2..75869ed8709 100644 --- a/src/platform/backends/qemu/qemu_virtual_machine_factory.h +++ b/src/platform/backends/qemu/qemu_virtual_machine_factory.h @@ -44,6 +44,8 @@ class QemuVirtualMachineFactory final : public BaseVirtualMachineFactory std::vector networks() const override; private: + Path make_qemu_platform_and_resolve_instances_dir(const Path& data_dir); + QemuPlatform::UPtr qemu_platform; }; } // namespace multipass diff --git a/src/platform/backends/shared/base_virtual_machine_factory.h b/src/platform/backends/shared/base_virtual_machine_factory.h index 334509c3809..936174bf28f 100644 --- a/src/platform/backends/shared/base_virtual_machine_factory.h +++ b/src/platform/backends/shared/base_virtual_machine_factory.h @@ -49,7 +49,7 @@ class BaseVirtualMachineFactory : public VirtualMachineFactory QString get_instance_directory_name(const std::string& name) const override { - return multipass::utils::backend_directory_path(instances_dir, QString::fromStdString(name)); + return MP_UTILS.make_dir(multipass::utils::backend_directory_path(instances_dir, QString::fromStdString(name))); } void prepare_networking(std::vector& /*extra_interfaces*/) override @@ -84,7 +84,7 @@ class BaseVirtualMachineFactory : public VirtualMachineFactory virtual void prepare_interface(NetworkInterface& net, std::vector& host_nets, const std::string& bridge_type); - const Path instances_dir; + Path instances_dir; }; } // namespace multipass diff --git a/tests/blueprint_test_lambdas.cpp b/tests/blueprint_test_lambdas.cpp index 0ea7bb8ede7..542ba9d9f01 100644 --- a/tests/blueprint_test_lambdas.cpp +++ b/tests/blueprint_test_lambdas.cpp @@ -29,17 +29,19 @@ #include "common.h" #include "stub_virtual_machine.h" #include "stub_vm_image_vault.h" +#include "temp_dir.h" namespace mp = multipass; namespace mpt = multipass::test; std::function)> + const mp::ProgressMonitor&, const bool, const std::optional, const mp::Path&)> mpt::fetch_image_lambda(const std::string& release, const std::string& remote, const bool must_have_checksum) { return [&release, &remote, must_have_checksum]( const mp::FetchType& fetch_type, const mp::Query& query, const mp::VMImageVault::PrepareAction& prepare, - const mp::ProgressMonitor& monitor, const bool unlock, const std::optional& checksum) { + const mp::ProgressMonitor& monitor, const bool unlock, const std::optional& checksum, + const mp::Path& download_dir) { EXPECT_EQ(query.release, release); if (remote.empty()) { @@ -55,7 +57,7 @@ mpt::fetch_image_lambda(const std::string& release, const std::string& remote, c EXPECT_NE(checksum, std::nullopt); } - return mpt::StubVMImageVault().fetch_image(fetch_type, query, prepare, monitor, unlock, checksum); + return mpt::StubVMImageVault().fetch_image(fetch_type, query, prepare, monitor, unlock, checksum, download_dir); }; } diff --git a/tests/blueprint_test_lambdas.h b/tests/blueprint_test_lambdas.h index 345b38846b2..8deb2952a9f 100644 --- a/tests/blueprint_test_lambdas.h +++ b/tests/blueprint_test_lambdas.h @@ -39,7 +39,7 @@ namespace test { std::function)> + const bool, const std::optional, const multipass::Path&)> fetch_image_lambda(const std::string& release, const std::string& remote, const bool must_have_checksum = false); std::function diff --git a/tests/lxd/test_lxd_image_vault.cpp b/tests/lxd/test_lxd_image_vault.cpp index 79e5bd0b127..f98af001b97 100644 --- a/tests/lxd/test_lxd_image_vault.cpp +++ b/tests/lxd/test_lxd_image_vault.cpp @@ -70,6 +70,7 @@ struct LXDImageVault : public Test mp::Query default_query{instance_name, "xenial", false, "", mp::Query::Type::Alias}; mpt::StubURLDownloader stub_url_downloader; mpt::TempDir cache_dir; + mpt::TempDir download_dir; }; } // namespace @@ -95,7 +96,7 @@ TEST_F(LXDImageVault, instance_exists_fetch_returns_expected_image_info) mp::VMImage image; EXPECT_NO_THROW(image = image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, - false, std::nullopt)); + false, std::nullopt, download_dir.path())); EXPECT_EQ(image.id, mpt::default_id); EXPECT_EQ(image.original_release, "18.04 LTS"); @@ -123,7 +124,7 @@ TEST_F(LXDImageVault, instance_exists_custom_image_returns_expected_image_info) mp::VMImage image; EXPECT_NO_THROW(image = image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, - false, std::nullopt)); + false, std::nullopt, download_dir.path())); EXPECT_EQ(image.id, "6937ddd3f4c3329182855843571fc91ae4fee24e8e0eb0f7cdcf2c22feed4dab"); EXPECT_EQ(image.original_release, "Snapcraft builder for Core 20"); @@ -152,7 +153,7 @@ TEST_F(LXDImageVault, instance_exists_uses_cached_release_title) mp::VMImage image; EXPECT_NO_THROW(image = image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, - false, std::nullopt)); + false, std::nullopt, download_dir.path())); EXPECT_EQ(image.id, mpt::default_id); EXPECT_EQ(image.original_release, "Fake Title"); @@ -182,7 +183,7 @@ TEST_F(LXDImageVault, instance_exists_no_cached_release_title_info_for_fails) mp::VMImage image; EXPECT_NO_THROW(image = image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, - false, std::nullopt)); + false, std::nullopt, download_dir.path())); EXPECT_EQ(image.id, mpt::default_id); EXPECT_EQ(image.original_release, ""); @@ -212,7 +213,7 @@ TEST_F(LXDImageVault, returns_expected_info_with_valid_remote) mp::VMImage image; EXPECT_NO_THROW(image = image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, - std::nullopt)); + std::nullopt, download_dir.path())); EXPECT_EQ(image.id, mpt::default_id); EXPECT_EQ(image.original_release, "18.04 LTS"); @@ -240,11 +241,11 @@ TEST_F(LXDImageVault, throws_with_invalid_alias) mp::LXDVMImageVault image_vault{hosts, &stub_url_downloader, mock_network_access_manager.get(), base_url, cache_dir.path(), mp::days{0}}; - MP_EXPECT_THROW_THAT( - image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt), - std::runtime_error, - mpt::match_what( - StrEq(fmt::format("Unable to find an image matching \"{}\" in remote \"{}\".", alias, "release")))); + MP_EXPECT_THROW_THAT(image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()), + std::runtime_error, + mpt::match_what(StrEq(fmt::format("Unable to find an image matching \"{}\" in remote \"{}\".", + alias, "release")))); } TEST_F(LXDImageVault, throws_with_invalid_remote) @@ -259,9 +260,10 @@ TEST_F(LXDImageVault, throws_with_invalid_remote) mp::LXDVMImageVault image_vault{hosts, &stub_url_downloader, mock_network_access_manager.get(), base_url, cache_dir.path(), mp::days{0}}; - MP_EXPECT_THROW_THAT( - image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt), - std::runtime_error, mpt::match_what(HasSubstr(fmt::format("Remote \'{}\' is not found.", remote)))); + MP_EXPECT_THROW_THAT(image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()), + std::runtime_error, + mpt::match_what(HasSubstr(fmt::format("Remote \'{}\' is not found.", remote)))); } TEST_F(LXDImageVault, does_not_download_if_image_exists) @@ -289,7 +291,7 @@ TEST_F(LXDImageVault, does_not_download_if_image_exists) base_url, cache_dir.path(), mp::days{0}}; EXPECT_NO_THROW(image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, - std::nullopt)); + std::nullopt, download_dir.path())); } TEST_F(LXDImageVault, instance_exists_missing_image_does_not_download_image) @@ -326,7 +328,7 @@ TEST_F(LXDImageVault, instance_exists_missing_image_does_not_download_image) mp::VMImage image; EXPECT_NO_THROW(image = image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, - false, std::nullopt)); + false, std::nullopt, download_dir.path())); EXPECT_FALSE(download_requested); EXPECT_EQ(image.original_release, mpt::default_release_info); } @@ -353,7 +355,7 @@ TEST_F(LXDImageVault, requests_download_if_image_does_not_exist) base_url, cache_dir.path(), mp::days{0}}; EXPECT_NO_THROW(image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, - std::nullopt)); + std::nullopt, download_dir.path())); EXPECT_TRUE(download_requested); } @@ -380,8 +382,8 @@ TEST_F(LXDImageVault, sets_fingerprint_with_hash_query) base_url, cache_dir.path(), mp::days{0}}; const mp::Query query{"", "e3b0c44298fc1c1", false, "release", mp::Query::Type::Alias}; - EXPECT_NO_THROW( - image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt)); + EXPECT_NO_THROW(image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path())); } TEST_F(LXDImageVault, download_deletes_and_throws_on_cancel) @@ -419,9 +421,9 @@ TEST_F(LXDImageVault, download_deletes_and_throws_on_cancel) mp::LXDVMImageVault image_vault{hosts, &stub_url_downloader, mock_network_access_manager.get(), base_url, cache_dir.path(), mp::days{0}}; - EXPECT_THROW( - image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, monitor, false, std::nullopt), - mp::AbortedDownloadException); + EXPECT_THROW(image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, monitor, false, + std::nullopt, download_dir.path()), + mp::AbortedDownloadException); EXPECT_TRUE(delete_requested); } @@ -457,9 +459,9 @@ TEST_F(LXDImageVault, percent_complete_returns_negative_on_metadata_download) mp::LXDVMImageVault image_vault{hosts, &stub_url_downloader, mock_network_access_manager.get(), base_url, cache_dir.path(), mp::days{0}}; - EXPECT_THROW( - image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, monitor, false, std::nullopt), - mp::AbortedDownloadException); + EXPECT_THROW(image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, monitor, false, + std::nullopt, download_dir.path()), + mp::AbortedDownloadException); } TEST_F(LXDImageVault, delete_requested_on_instance_remove) @@ -832,8 +834,8 @@ TEST_F(LXDImageVault, custom_image_found_returns_expected_info) base_url, cache_dir.path(), mp::days{0}}; const mp::Query query{"", "snapcraft", false, "release", mp::Query::Type::Alias}; - auto image = - image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt); + auto image = image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_EQ(image.id, mpt::lxd_snapcraft_image_id); EXPECT_EQ(image.original_release, mpt::snapcraft_release_info); @@ -890,8 +892,8 @@ TEST_F(LXDImageVault, custom_image_downloads_and_creates_correct_upload) base_url, cache_dir.path(), mp::days{0}}; const mp::Query query{"", "custom", false, "release", mp::Query::Type::Alias}; - auto image = - image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt); + auto image = image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_EQ(image.id, mpt::lxd_custom_image_id); EXPECT_EQ(image.original_release, mpt::custom_release_info); @@ -916,7 +918,7 @@ TEST_F(LXDImageVault, fetch_image_unable_to_connect_logs_error_and_returns_blank StrEq(fmt::format("{} - returning blank image info", exception_message))))); auto image = image_vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, - std::nullopt); + std::nullopt, download_dir.path()); EXPECT_TRUE(image.id.empty()); EXPECT_TRUE(image.original_release.empty()); @@ -1043,8 +1045,8 @@ TEST_F(LXDImageVault, http_based_image_downloads_and_creates_correct_upload) const std::string download_url{"http://www.foo.com/images/foo.img"}; const mp::Query query{"", download_url, false, "", mp::Query::Type::HttpDownload}; - auto image = - image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt); + auto image = image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_EQ(image.id, "bc5a973bd6f2bef30658fb51177cf5e506c1d60958a4c97813ee26416dc368da"); @@ -1109,8 +1111,8 @@ TEST_F(LXDImageVault, file_based_fetch_copies_image_and_returns_expected_info) auto current_time = QDateTime::currentDateTime(); const mp::Query query{"", file.url().toStdString(), false, "", mp::Query::Type::LocalFile}; - auto image = - image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt); + auto image = image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_EQ(image.id, "bc5a973bd6f2bef30658fb51177cf5e506c1d60958a4c97813ee26416dc368da"); @@ -1131,9 +1133,10 @@ TEST_F(LXDImageVault, invalid_local_file_image_throws) const std::string missing_file{"/foo"}; const mp::Query query{"", fmt::format("file://{}", missing_file), false, "", mp::Query::Type::LocalFile}; - MP_EXPECT_THROW_THAT( - image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt), - std::runtime_error, mpt::match_what(StrEq(fmt::format("Custom image `{}` does not exist.", missing_file)))); + MP_EXPECT_THROW_THAT(image_vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()), + std::runtime_error, + mpt::match_what(StrEq(fmt::format("Custom image `{}` does not exist.", missing_file)))); } TEST_F(LXDImageVault, updateImagesThrowsOnMissingImage) diff --git a/tests/mock_vm_image_vault.h b/tests/mock_vm_image_vault.h index 8846d5d2bad..84e475795df 100644 --- a/tests/mock_vm_image_vault.h +++ b/tests/mock_vm_image_vault.h @@ -35,16 +35,16 @@ class MockVMImageVault : public VMImageVault public: MockVMImageVault() { - ON_CALL(*this, fetch_image(_, _, _, _, _, _)) - .WillByDefault([this](auto, auto, const PrepareAction& prepare, auto, auto, auto) { + ON_CALL(*this, fetch_image(_, _, _, _, _, _, _)) + .WillByDefault([this](auto, auto, const PrepareAction& prepare, auto, auto, auto, auto) { return VMImage{dummy_image.name(), dummy_image.name(), dummy_image.name(), {}, {}, {}, {}, {}}; }); ON_CALL(*this, has_record_for(_)).WillByDefault(Return(true)); ON_CALL(*this, minimum_image_size_for(_)).WillByDefault(Return(MemorySize{"1048576"})); }; - MOCK_METHOD6(fetch_image, VMImage(const FetchType&, const Query&, const PrepareAction&, const ProgressMonitor&, - const bool, const std::optional&)); + MOCK_METHOD7(fetch_image, VMImage(const FetchType&, const Query&, const PrepareAction&, const ProgressMonitor&, + const bool, const std::optional&, const mp::Path&)); MOCK_METHOD1(remove, void(const std::string&)); MOCK_METHOD1(has_record_for, bool(const std::string&)); MOCK_METHOD0(prune_expired_images, void()); diff --git a/tests/stub_vm_image_vault.h b/tests/stub_vm_image_vault.h index 48236a612bd..f1fa245ab7c 100644 --- a/tests/stub_vm_image_vault.h +++ b/tests/stub_vm_image_vault.h @@ -29,8 +29,8 @@ namespace test struct StubVMImageVault final : public multipass::VMImageVault { multipass::VMImage fetch_image(const multipass::FetchType&, const multipass::Query&, const PrepareAction& prepare, - const multipass::ProgressMonitor&, const bool, - const std::optional&) override + const multipass::ProgressMonitor&, const bool, const std::optional&, + const multipass::Path&) override { return prepare({dummy_image.name(), dummy_image.name(), dummy_image.name(), {}, {}, {}, {}, {}}); }; diff --git a/tests/test_alias_dict.cpp b/tests/test_alias_dict.cpp index e1de7b30f1d..994c9f6e548 100644 --- a/tests/test_alias_dict.cpp +++ b/tests/test_alias_dict.cpp @@ -461,7 +461,7 @@ TEST_P(DaemonAliasTestsuite, purge_removes_purged_instance_aliases_and_scripts) auto mock_image_vault = std::make_unique>(); EXPECT_CALL(*mock_image_vault, remove(_)).WillRepeatedly(Return()); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillRepeatedly(Return(mp::VMImage{})); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillRepeatedly(Return(mp::VMImage{})); EXPECT_CALL(*mock_image_vault, prune_expired_images()).WillRepeatedly(Return()); EXPECT_CALL(*mock_image_vault, has_record_for(_)).WillRepeatedly(Return(true)); diff --git a/tests/test_daemon.cpp b/tests/test_daemon.cpp index 46c1d18cc8d..82a2c71332b 100644 --- a/tests/test_daemon.cpp +++ b/tests/test_daemon.cpp @@ -662,7 +662,7 @@ TEST_F(DaemonCreateLaunchAliasTestSuite, blueprintFoundPassesExpectedAliases) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); auto alias = std::make_optional(std::make_pair(alias_name, mp::AliasDefinition{name, alias_command, alias_wdir})); @@ -700,7 +700,7 @@ TEST_F(DaemonCreateLaunchAliasTestSuite, blueprintFoundMountsWorkspace) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)) .WillOnce( @@ -734,7 +734,7 @@ TEST_F(DaemonCreateLaunchAliasTestSuite, blueprintFoundMountsWorkspaceConfined) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)) .WillOnce( @@ -772,7 +772,7 @@ TEST_F(DaemonCreateLaunchAliasTestSuite, blueprintFoundMountsWorkspaceInExisting EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)) .WillOnce( @@ -815,7 +815,7 @@ TEST_F(DaemonCreateLaunchAliasTestSuite, blueprintFoundDoesNotMountUnwrittableWo EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)) .WillOnce( @@ -859,7 +859,7 @@ TEST_F(DaemonCreateLaunchAliasTestSuite, blueprintFoundButCannotMount) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)) .WillOnce( @@ -907,7 +907,7 @@ TEST_F(DaemonCreateLaunchAliasTestSuite, blueprintFoundPassesExpectedAliasesWith EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, command_line_name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); auto alias = std::make_optional(std::make_pair(alias_name, mp::AliasDefinition{name, alias_command, alias_wdir})); @@ -952,7 +952,7 @@ TEST_F(DaemonCreateLaunchAliasTestSuite, blueprintFoundDoesNotOverwriteAliases) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); auto alias = std::make_optional(std::make_pair(alias_name, mp::AliasDefinition{name, alias_command, alias_wdir})); @@ -993,7 +993,7 @@ TEST_P(DaemonCreateLaunchTestSuite, blueprint_found_passes_expected_data) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)) .WillOnce(mpt::fetch_blueprint_for_lambda(num_cores, mem_size, disk_space, release, remote)); @@ -1021,7 +1021,7 @@ TEST_P(DaemonCreateLaunchTestSuite, blueprint_not_found_passes_expected_data) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, empty)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, empty)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, empty)); config_builder.vault = std::move(mock_image_vault); mp::Daemon daemon{config_builder.build()}; @@ -1276,7 +1276,7 @@ TEST_F(DaemonCreateLaunchTestSuite, blueprintFromFileCallsCorrectFunction) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)).Times(1); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).Times(1); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).Times(1); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)).Times(0); @@ -1626,9 +1626,9 @@ TEST_F(Daemon, ctor_drops_removed_instances) config_builder.data_directory = temp_dir->path(); auto mock_image_vault = std::make_unique>(); - EXPECT_CALL(*mock_image_vault, fetch_image(_, Field(&mp::Query::name, stayed), _, _, _, _)) + EXPECT_CALL(*mock_image_vault, fetch_image(_, Field(&mp::Query::name, stayed), _, _, _, _, _)) .WillRepeatedly(DoDefault()); // returns an image that can be verified to exist for this instance - EXPECT_CALL(*mock_image_vault, fetch_image(_, Field(&mp::Query::name, gone), _, _, _, _)) + EXPECT_CALL(*mock_image_vault, fetch_image(_, Field(&mp::Query::name, gone), _, _, _, _, _)) .WillOnce( Return(mp::VMImage{"/path/to/nowhere", "", "", "", "", "", "", {}})); // an image that can't be verified to // exist for this instance diff --git a/tests/test_daemon_launch.cpp b/tests/test_daemon_launch.cpp index d9714051894..8ec99d00a26 100644 --- a/tests/test_daemon_launch.cpp +++ b/tests/test_daemon_launch.cpp @@ -73,7 +73,7 @@ TEST_F(TestDaemonLaunch, blueprintFoundMountsWorkspaceWithNameOverride) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, command_line_name)); - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)).WillOnce(mpt::fetch_image_lambda(release, remote)); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)) .WillOnce( @@ -128,7 +128,7 @@ TEST_F(TestDaemonLaunch, v2BlueprintFoundPropagatesSha) .WillOnce(mpt::create_virtual_machine_lambda(num_cores, mem_size, disk_space, command_line_name)); // The expectation of this test is set in fetch_image_lambda(). - EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _)) + EXPECT_CALL(*mock_image_vault, fetch_image(_, _, _, _, _, _, _)) .WillOnce(mpt::fetch_image_lambda(release, remote, true)); EXPECT_CALL(*mock_blueprint_provider, fetch_blueprint_for(_, _, _)) diff --git a/tests/test_image_vault.cpp b/tests/test_image_vault.cpp index 43889bb3109..a0f34caaf1f 100644 --- a/tests/test_image_vault.cpp +++ b/tests/test_image_vault.cpp @@ -168,6 +168,7 @@ struct ImageVault : public testing::Test [](const mp::VMImage& source_image) -> mp::VMImage { return source_image; }}; mpt::TempDir cache_dir; mpt::TempDir data_dir; + mpt::TempDir download_dir; std::string instance_name{"valley-pied-piper"}; mp::Query default_query{instance_name, "xenial", false, "", mp::Query::Type::Alias}; }; @@ -176,8 +177,8 @@ struct ImageVault : public testing::Test TEST_F(ImageVault, downloads_image) { mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_THAT(url_downloader.downloaded_files.size(), Eq(1)); EXPECT_TRUE(url_downloader.downloaded_urls.contains(host.image.url())); @@ -186,8 +187,8 @@ TEST_F(ImageVault, downloads_image) TEST_F(ImageVault, returned_image_contains_instance_name) { mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_TRUE(vm_image.image_path.contains(QString::fromStdString(instance_name))); } @@ -196,7 +197,7 @@ TEST_F(ImageVault, downloads_kernel_and_initrd) { mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; auto vm_image = vault.fetch_image(mp::FetchType::ImageKernelAndInitrd, default_query, stub_prepare, stub_monitor, - false, std::nullopt); + false, std::nullopt, download_dir.path()); EXPECT_THAT(url_downloader.downloaded_files.size(), Eq(3)); EXPECT_TRUE(url_downloader.downloaded_urls.contains(host.image.url())); @@ -216,8 +217,8 @@ TEST_F(ImageVault, calls_prepare) prepare_called = true; return source_image; }; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_TRUE(prepare_called); } @@ -230,10 +231,10 @@ TEST_F(ImageVault, records_instanced_images) ++prepare_called_count; return source_image; }; - auto vm_image1 = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); - auto vm_image2 = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image1 = vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); + auto vm_image2 = vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_THAT(url_downloader.downloaded_files.size(), Eq(1)); EXPECT_THAT(prepare_called_count, Eq(1)); @@ -249,13 +250,13 @@ TEST_F(ImageVault, caches_prepared_images) ++prepare_called_count; return source_image; }; - auto vm_image1 = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image1 = vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); auto another_query = default_query; another_query.name = "valley-pied-piper-chat"; - auto vm_image2 = - vault.fetch_image(mp::FetchType::ImageOnly, another_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image2 = vault.fetch_image(mp::FetchType::ImageOnly, another_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_THAT(url_downloader.downloaded_files.size(), Eq(1)); EXPECT_THAT(prepare_called_count, Eq(1)); @@ -273,12 +274,12 @@ TEST_F(ImageVault, remembers_instance_images) }; mp::DefaultVMImageVault first_vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image1 = - first_vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image1 = first_vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); mp::DefaultVMImageVault another_vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image2 = - another_vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image2 = another_vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_THAT(url_downloader.downloaded_files.size(), Eq(1)); EXPECT_THAT(prepare_called_count, Eq(1)); @@ -294,14 +295,14 @@ TEST_F(ImageVault, remembers_prepared_images) }; mp::DefaultVMImageVault first_vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image1 = - first_vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image1 = first_vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); auto another_query = default_query; another_query.name = "valley-pied-piper-chat"; mp::DefaultVMImageVault another_vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image2 = - another_vault.fetch_image(mp::FetchType::ImageOnly, another_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image2 = another_vault.fetch_image(mp::FetchType::ImageOnly, another_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_THAT(url_downloader.downloaded_files.size(), Eq(1)); EXPECT_THAT(prepare_called_count, Eq(1)); @@ -322,8 +323,8 @@ TEST_F(ImageVault, uses_image_from_prepare) }; mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); const auto image_data = mp::utils::contents_of(vm_image.image_path); EXPECT_THAT(image_data, StrEq(expected_data)); @@ -341,8 +342,8 @@ TEST_F(ImageVault, image_purged_expired) mpt::make_file_with_content(file_name); return {file_name, "", "", source_image.id, "", "", "", {}}; }; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_TRUE(QFileInfo::exists(file_name)); @@ -362,8 +363,8 @@ TEST_F(ImageVault, image_exists_not_expired) mpt::make_file_with_content(file_name); return {file_name, "", "", source_image.id, "", "", "", {}}; }; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, prepare, stub_monitor, false, + std::nullopt, download_dir.path()); EXPECT_TRUE(QFileInfo::exists(file_name)); @@ -398,7 +399,8 @@ TEST_F(ImageVault, DISABLE_ON_WINDOWS_AND_MACOS(file_based_fetch_copies_image_an query.release = file.url().toStdString(); query.query_type = mp::Query::Type::LocalFile; - auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()); EXPECT_TRUE(QFileInfo::exists(vm_image.image_path)); EXPECT_EQ(vm_image.id, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); @@ -412,7 +414,8 @@ TEST_F(ImageVault, invalid_custom_image_file_throws) query.release = "file://foo"; query.query_type = mp::Query::Type::LocalFile; - EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt), + EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()), std::runtime_error); } @@ -424,7 +427,8 @@ TEST_F(ImageVault, DISABLE_ON_WINDOWS_AND_MACOS(custom_image_url_downloads)) query.release = "http://www.foo.com/fake.img"; query.query_type = mp::Query::Type::HttpDownload; - vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt); + vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()); EXPECT_THAT(url_downloader.downloaded_files.size(), Eq(1)); EXPECT_TRUE(url_downloader.downloaded_urls.contains(QString::fromStdString(query.release))); @@ -434,18 +438,18 @@ TEST_F(ImageVault, missing_downloaded_image_throws) { mpt::StubURLDownloader stub_url_downloader; mp::DefaultVMImageVault vault{hosts, &stub_url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - EXPECT_THROW( - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt), - mp::CreateImageException); + EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()), + mp::CreateImageException); } TEST_F(ImageVault, hash_mismatch_throws) { BadURLDownloader bad_url_downloader; mp::DefaultVMImageVault vault{hosts, &bad_url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - EXPECT_THROW( - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt), - mp::CreateImageException); + EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()), + mp::CreateImageException); } TEST_F(ImageVault, invalid_remote_throws) @@ -456,7 +460,8 @@ TEST_F(ImageVault, invalid_remote_throws) query.remote_name = "foo"; - EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt), + EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()), std::runtime_error); } @@ -468,7 +473,8 @@ TEST_F(ImageVault, DISABLE_ON_WINDOWS_AND_MACOS(invalid_image_alias_throw)) query.release = "foo"; - EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt), + EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()), mp::CreateImageException); } @@ -481,8 +487,8 @@ TEST_F(ImageVault, valid_remote_and_alias_returns_valid_image_info) query.remote_name = "release"; mp::VMImage image; - EXPECT_NO_THROW( - image = vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt)); + EXPECT_NO_THROW(image = vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path())); EXPECT_THAT(image.original_release, Eq("18.04 LTS")); EXPECT_THAT(image.id, Eq("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); @@ -497,8 +503,8 @@ TEST_F(ImageVault, DISABLE_ON_WINDOWS_AND_MACOS(http_download_returns_expected_i mp::Query query{instance_name, image_url, false, "", mp::Query::Type::HttpDownload}; mp::VMImage image; - EXPECT_NO_THROW( - image = vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt)); + EXPECT_NO_THROW(image = vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path())); // Hash is based on image url EXPECT_THAT(image.id, Eq("7404f51c9b4f40312fa048a0ad36e07b74b718a2d3a5a08e8cca906c69059ddf")); @@ -508,7 +514,8 @@ TEST_F(ImageVault, DISABLE_ON_WINDOWS_AND_MACOS(http_download_returns_expected_i TEST_F(ImageVault, image_update_creates_new_dir_and_removes_old) { mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{1}}; - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()); auto original_file{url_downloader.downloaded_files[0]}; auto original_absolute_path{QFileInfo(original_file).absolutePath()}; @@ -539,9 +546,9 @@ TEST_F(ImageVault, aborted_download_throws) running_url_downloader.abort_all_downloads(); - EXPECT_THROW( - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt), - mp::AbortedDownloadException); + EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()), + mp::AbortedDownloadException); } TEST_F(ImageVault, minimum_image_size_returns_expected_size) @@ -552,8 +559,8 @@ TEST_F(ImageVault, minimum_image_size_returns_expected_size) auto mock_factory_scope = inject_fake_qemuimg_callback(qemuimg_exit_status, qemuimg_output); mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); const auto size = vault.minimum_image_size_for(vm_image.id); @@ -574,7 +581,8 @@ TEST_F(ImageVault, DISABLE_ON_WINDOWS_AND_MACOS(file_based_minimum_size_returns_ query.release = file.url().toStdString(); query.query_type = mp::Query::Type::LocalFile; - auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()); const auto size = vault.minimum_image_size_for(vm_image.id); @@ -597,8 +605,8 @@ TEST_F(ImageVault, minimum_image_size_throws_when_qemuimg_info_crashes) auto mock_factory_scope = inject_fake_qemuimg_callback(qemuimg_exit_status, qemuimg_output); mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); MP_EXPECT_THROW_THAT(vault.minimum_image_size_for(vm_image.id), std::runtime_error, mpt::match_what(AllOf(HasSubstr("qemu-img failed"), HasSubstr("with output")))); @@ -611,8 +619,8 @@ TEST_F(ImageVault, minimum_image_size_throws_when_qemuimg_info_cannot_find_the_i auto mock_factory_scope = inject_fake_qemuimg_callback(qemuimg_exit_status, qemuimg_output); mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); MP_EXPECT_THROW_THAT(vault.minimum_image_size_for(vm_image.id), std::runtime_error, mpt::match_what(AllOf(HasSubstr("qemu-img failed"), HasSubstr("Could not find")))); @@ -625,8 +633,8 @@ TEST_F(ImageVault, minimum_image_size_throws_when_qemuimg_info_does_not_understa auto mock_factory_scope = inject_fake_qemuimg_callback(qemuimg_exit_status, qemuimg_output); mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{0}}; - auto vm_image = - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + auto vm_image = vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()); MP_EXPECT_THROW_THAT(vault.minimum_image_size_for(vm_image.id), std::runtime_error, mpt::match_what(HasSubstr("Could not obtain image's virtual size"))); @@ -697,7 +705,8 @@ TEST_F(ImageVault, updateImagesLogsWarningOnUnsupportedImage) { mpt::MockLogger::Scope logger_scope = mpt::MockLogger::inject(mpl::Level::warning); mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{1}}; - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()); EXPECT_CALL(host, info_for(_)).WillOnce(Throw(mp::UnsupportedImageException(default_query.release))); @@ -714,7 +723,8 @@ TEST_F(ImageVault, updateImagesLogsWarningOnEmptyVault) { mpt::MockLogger::Scope logger_scope = mpt::MockLogger::inject(mpl::Level::warning); mp::DefaultVMImageVault vault{hosts, &url_downloader, cache_dir.path(), data_dir.path(), mp::days{1}}; - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt); + vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()); EXPECT_CALL(host, info_for(_)).WillOnce(Return(std::nullopt)); @@ -734,9 +744,9 @@ TEST_F(ImageVault, fetchLocalImageThrowsOnEmptyVault) EXPECT_CALL(host, info_for(_)).WillOnce(Return(std::nullopt)); - EXPECT_THROW( - vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, std::nullopt), - mp::ImageNotFoundException); + EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, default_query, stub_prepare, stub_monitor, false, + std::nullopt, download_dir.path()), + mp::ImageNotFoundException); } TEST_F(ImageVault, fetchRemoteImageThrowsOnMissingKernel) @@ -746,6 +756,7 @@ TEST_F(ImageVault, fetchRemoteImageThrowsOnMissingKernel) EXPECT_CALL(host, info_for(_)).WillOnce(Return(std::nullopt)); - EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt), + EXPECT_THROW(vault.fetch_image(mp::FetchType::ImageOnly, query, stub_prepare, stub_monitor, false, std::nullopt, + download_dir.path()), mp::ImageNotFoundException); }