Commit c3b15298 authored by Julian Watson's avatar Julian Watson Committed by Commit Bot

Crostini backup restore: Display failed space info in notification

Bug: 932339
Change-Id: Ib835835ac8e58262091232be7ba285c2901f3746
Cq-Depend: chromium:1630343,chromium:1630135
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1631157
Commit-Queue: Julian Watson <juwa@google.com>
Reviewed-by: default avatarJoel Hockey <joelhockey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#669104}
parent e9ec579c
......@@ -3713,6 +3713,9 @@
<message name="IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_ARCHITECTURE" desc="Message displayed in the notification when import (restore) of the Linux container fails due to architecture mismatch.">
Cannot import container architecture type <ph name="ARCHITECTURE_CONTAINER">$1<ex>arm64</ex></ph> with this device which is <ph name="ARCHITECTURE_DEVICE">$2<ex>x86_64</ex></ph>. You can try restoring this container into a different device, or you can access the files inside this container image by opening in Files app.
</message>
<message name="IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_SPACE" desc="Message displayed in the notification when import (restore) of the Linux container fails due to insufficient space.">
Cannot restore due to lack of storage space. Free up <ph name="SPACE_REQUIRED">$1<ex>10Gb</ex></ph> from the device and try again.
</message>
<!-- Time limit notification -->
<message name="IDS_SCREEN_TIME_NOTIFICATION_TITLE" desc="The title of the notification when screen usage limit reaches before locking the device.">
......
......@@ -24,6 +24,7 @@
#include "components/prefs/pref_service.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/text/bytes_formatting.h"
namespace crostini {
......@@ -324,6 +325,9 @@ void CrostiniExportImport::OnImportComplete(
CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE:
enum_hist_result = ImportContainerResult::kFailedArchitecture;
break;
case crostini::CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_SPACE:
enum_hist_result = ImportContainerResult::kFailedSpace;
break;
default:
enum_hist_result = ImportContainerResult::kFailed;
}
......@@ -345,7 +349,9 @@ void CrostiniExportImport::OnImportContainerProgress(
int progress_percent,
uint64_t progress_speed,
const std::string& architecture_device,
const std::string& architecture_container) {
const std::string& architecture_container,
uint64_t available_space,
uint64_t minimum_required_space) {
ContainerId container_id(vm_name, container_name);
auto it = notifications_.find(container_id);
DCHECK(it != notifications_.end())
......@@ -371,6 +377,12 @@ void CrostiniExportImport::OnImportContainerProgress(
base::ASCIIToUTF16(architecture_container),
base::ASCIIToUTF16(architecture_device)));
break;
case ImportContainerProgressStatus::FAILURE_SPACE:
DCHECK_GE(minimum_required_space, available_space);
it->second->set_message_failed(l10n_util::GetStringFUTF16(
IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_SPACE,
ui::FormatBytes(minimum_required_space - available_space)));
break;
default:
LOG(WARNING) << "Unknown Export progress status " << int(status);
}
......
......@@ -45,7 +45,8 @@ enum class ImportContainerResult {
kFailedVmStopped = 2,
kFailedVmStarted = 3,
kFailedArchitecture = 4,
kMaxValue = kFailedArchitecture,
kFailedSpace = 5,
kMaxValue = kFailedSpace,
};
// CrostiniExportImport is a keyed profile service to manage exporting and
......@@ -94,6 +95,7 @@ class CrostiniExportImport : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFail);
FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
TestImportFailArchitecture);
FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFailSpace);
// ui::SelectFileDialog::Listener implementation.
void FileSelected(const base::FilePath& path,
......@@ -113,14 +115,15 @@ class CrostiniExportImport : public KeyedService,
uint64_t progress_speed) override;
// crostini::ImportContainerProgressObserver implementation.
void OnImportContainerProgress(
const std::string& vm_name,
const std::string& container_name,
crostini::ImportContainerProgressStatus status,
int progress_percent,
uint64_t progress_speed,
const std::string& architecture_device,
const std::string& architecture_container) override;
void OnImportContainerProgress(const std::string& vm_name,
const std::string& container_name,
crostini::ImportContainerProgressStatus status,
int progress_percent,
uint64_t progress_speed,
const std::string& architecture_device,
const std::string& architecture_container,
uint64_t available_space,
uint64_t minimum_required_space) override;
void ExportAfterSharing(const ContainerId& container_id,
const base::FilePath& filename,
......
......@@ -21,6 +21,12 @@
namespace crostini {
struct ImportProgressOptionalArguments {
int progress_percent{};
uint64_t available_space{};
uint64_t min_required_space{};
};
class CrostiniExportImportTest : public testing::Test {
public:
void SendExportProgress(
......@@ -37,16 +43,17 @@ class CrostiniExportImportTest : public testing::Test {
void SendImportProgress(
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status status,
int progress_percent) {
const ImportProgressOptionalArguments& arguments = {}) {
vm_tools::cicerone::ImportLxdContainerProgressSignal signal;
signal.set_owner_id(CryptohomeIdForProfile(profile()));
signal.set_vm_name(kCrostiniDefaultVmName);
signal.set_container_name(kCrostiniDefaultContainerName);
signal.set_status(status);
signal.set_progress_percent(progress_percent);
signal.set_progress_percent(progress_percent);
signal.set_progress_percent(arguments.progress_percent);
signal.set_architecture_device("arch_dev");
signal.set_architecture_container("arch_con");
signal.set_available_space(arguments.available_space);
signal.set_min_required_space(arguments.min_required_space);
fake_cicerone_client_->NotifyImportLxdContainerProgress(signal);
}
......@@ -184,7 +191,7 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) {
SendImportProgress(
vm_tools::cicerone::
ImportLxdContainerProgressSignal_Status_IMPORTING_UPLOAD,
20);
{.progress_percent = 20});
EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::RUNNING);
EXPECT_EQ(notification->get_notification()->progress(), 10);
......@@ -193,7 +200,7 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) {
SendImportProgress(
vm_tools::cicerone::
ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK,
20);
{.progress_percent = 20});
EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::RUNNING);
EXPECT_EQ(notification->get_notification()->progress(), 60);
......@@ -203,14 +210,14 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) {
SendImportProgress(
vm_tools::cicerone::
ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK,
40);
{.progress_percent = 40});
EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::RUNNING);
EXPECT_EQ(notification->get_notification()->progress(), 60);
// Done.
SendImportProgress(
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_DONE, 0);
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_DONE);
EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::DONE);
}
......@@ -224,7 +231,7 @@ TEST_F(CrostiniExportImportTest, TestImportFail) {
// Failed.
SendImportProgress(
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED, 0);
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED);
EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::FAILED);
std::string msg("Restoring couldn't be completed due to an error");
......@@ -242,8 +249,7 @@ TEST_F(CrostiniExportImportTest, TestImportFailArchitecture) {
// Failed Architecture.
SendImportProgress(
vm_tools::cicerone::
ImportLxdContainerProgressSignal_Status_FAILED_ARCHITECTURE,
0);
ImportLxdContainerProgressSignal_Status_FAILED_ARCHITECTURE);
EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::FAILED);
std::string msg(
......@@ -254,4 +260,28 @@ TEST_F(CrostiniExportImportTest, TestImportFailArchitecture) {
EXPECT_EQ(notification->get_notification()->message(),
base::UTF8ToUTF16(msg));
}
TEST_F(CrostiniExportImportTest, TestImportFailSpace) {
crostini_export_import()->FileSelected(
tarball_, 0, reinterpret_cast<void*>(ExportImportType::IMPORT));
run_loop_->RunUntilIdle();
CrostiniExportImportNotification* notification =
crostini_export_import()->GetNotificationForTesting(container_id_);
// Failed Space.
SendImportProgress(
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED_SPACE,
{
.available_space = 20ul * 1'024 * 1'024 * 1'024, // 20Gb
.min_required_space = 35ul * 1'024 * 1'024 * 1'024 // 35Gb
});
EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::FAILED);
std::string msg =
"Cannot restore due to lack of storage space. Free up 15.0 GB from the "
"device and try again.";
EXPECT_EQ(notification->get_notification()->message(),
base::UTF8ToUTF16(msg));
}
} // namespace crostini
......@@ -2615,6 +2615,12 @@ void CrostiniManager::OnImportLxdContainerProgress(
call_original_callback = true;
result = CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE;
break;
case vm_tools::cicerone::ImportLxdContainerProgressSignal::FAILED_SPACE:
call_observers = true;
status = ImportContainerProgressStatus::FAILURE_SPACE;
call_original_callback = true;
result = CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_SPACE;
break;
default:
call_original_callback = true;
result = CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED;
......@@ -2628,7 +2634,8 @@ void CrostiniManager::OnImportLxdContainerProgress(
observer.OnImportContainerProgress(
signal.vm_name(), signal.container_name(), status,
signal.progress_percent(), signal.progress_speed(),
signal.architecture_device(), signal.architecture_container());
signal.architecture_device(), signal.architecture_container(),
signal.available_space(), signal.min_required_space());
}
}
......
......@@ -72,6 +72,7 @@ enum class CrostiniResult {
CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED,
CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE,
NOT_ALLOWED,
CONTAINER_EXPORT_IMPORT_FAILED_SPACE,
};
enum class InstallLinuxPackageProgressStatus {
......@@ -102,6 +103,7 @@ enum class ImportContainerProgressStatus {
UPLOAD,
UNPACK,
FAILURE_ARCHITECTURE,
FAILURE_SPACE,
};
struct VmInfo {
......@@ -199,7 +201,9 @@ class ImportContainerProgressObserver {
int progress_percent,
uint64_t progress_speed,
const std::string& architecture_device,
const std::string& architecture_container) = 0;
const std::string& architecture_container,
uint64_t available_space,
uint64_t minimum_required_space) = 0;
};
class InstallerViewStatusObserver : public base::CheckedObserver {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment