| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_installer.h" |
| |
| #include <stdint.h> |
| #include <string.h> |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <utility> |
| |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/test/bind.h" |
| #include "base/test/gmock_callback_support.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_drive_image_download_service.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_image_download_client.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_installer_factory.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_metrics_util.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_pref_names.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_test_helper.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_util.h" |
| #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h" |
| #include "chrome/browser/prefs/browser_prefs.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chromeos/ash/components/dbus/concierge/concierge_client.h" |
| #include "chromeos/ash/components/dbus/concierge/fake_concierge_client.h" |
| #include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h" |
| #include "chromeos/ash/components/dbus/dlcservice/fake_dlcservice_client.h" |
| #include "chromeos/ash/components/dbus/spaced/fake_spaced_client.h" |
| #include "chromeos/ash/components/dbus/vm_plugin_dispatcher/vm_plugin_dispatcher_client.h" |
| #include "components/account_id/account_id.h" |
| #include "components/download/public/background_service/test/test_download_service.h" |
| #include "components/drive/service/dummy_drive_service.h" |
| #include "components/drive/service/fake_drive_service.h" |
| #include "components/prefs/scoped_user_pref_update.h" |
| #include "components/sync_preferences/testing_pref_service_syncable.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "google_apis/common/api_error_codes.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace plugin_vm { |
| |
| namespace { |
| |
| using ::base::test::RunClosure; |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::AtLeast; |
| using ::testing::DoubleEq; |
| using ::testing::Invoke; |
| using ::testing::InvokeWithoutArgs; |
| using ::testing::Mock; |
| using ::testing::StrictMock; |
| |
| using FailureReason = PluginVmInstaller::FailureReason; |
| using InstallingState = PluginVmInstaller::InstallingState; |
| |
| const char kProfileName[] = "p1"; |
| const char kUrl[] = "http://example.com"; |
| const char kDriveUrl[] = "https://drive.google.com/open?id=fakedriveid"; |
| const char kDriveId[] = "fakedriveid"; |
| const char kDriveUrl2[] = "https://drive.google.com/open?id=nonexistantdriveid"; |
| const char kDriveContentType[] = "application/zip"; |
| const char kPluginVmImageFile[] = "plugin_vm_image_file_1.zip"; |
| const char kContent[] = "This is zipped content."; |
| const char kHash[] = |
| "c80344fd4a0e9ee9f803f64edb3ea3ed8b11fe300869817e8fd50898d0663c35"; |
| const char kHashUppercase[] = |
| "C80344FD4A0E9EE9F803F64EDB3EA3ED8B11FE300869817E8FD50898D0663C35"; |
| const char kHash2[] = |
| "02f06421ae27144aacdc598aebcd345a5e2e634405e8578300173628fe1574bd"; |
| // File size set in test_download_service. |
| const int64_t kDefaultRequiredFreeDiskSpaceGB = 20LL; |
| const int kRequiredFreeDiskSpaceGB = 40; |
| const int64_t kBytesPerGigabyte = 1024 * 1024 * 1024; |
| |
| constexpr char kFailureReasonHistogram[] = "PluginVm.SetupFailureReason"; |
| |
| } // namespace |
| |
| class MockObserver : public PluginVmInstaller::Observer { |
| public: |
| MOCK_METHOD1(OnStateUpdated, void(InstallingState)); |
| MOCK_METHOD1(OnProgressUpdated, void(double)); |
| MOCK_METHOD2(OnDownloadProgressUpdated, |
| void(uint64_t bytes_downloaded, int64_t content_length)); |
| MOCK_METHOD0(OnVmExists, void()); |
| MOCK_METHOD0(OnCreated, void()); |
| MOCK_METHOD0(OnImported, void()); |
| MOCK_METHOD1(OnError, void(FailureReason)); |
| MOCK_METHOD0(OnCancelFinished, void()); |
| }; |
| |
| // We are inheriting from DummyDriveService instead of DriveServiceInterface |
| // here since we are only interested in a couple of methods and don't need to |
| // define the rest. |
| class SimpleFakeDriveService : public drive::DummyDriveService { |
| public: |
| using DownloadActionCallback = google_apis::DownloadActionCallback; |
| using GetContentCallback = google_apis::GetContentCallback; |
| using ProgressCallback = google_apis::ProgressCallback; |
| |
| void RunDownloadActionCallback(google_apis::ApiErrorCode error, |
| const base::FilePath& temp_file) { |
| std::move(download_action_callback_).Run(error, temp_file); |
| } |
| |
| void RunGetContentCallback(google_apis::ApiErrorCode error, |
| std::unique_ptr<std::string> content) { |
| get_content_callback_.Run(error, std::move(content), |
| !get_content_callback_called_); |
| get_content_callback_called_ = true; |
| } |
| |
| void RunProgressCallback(int64_t progress, int64_t total) { |
| progress_callback_.Run(progress, total); |
| } |
| |
| bool cancel_callback_called() const { return cancel_callback_called_; } |
| |
| // DriveServiceInterface override. |
| google_apis::CancelCallbackOnce DownloadFile( |
| const base::FilePath& /*cache_path*/, |
| const std::string& /*resource_id*/, |
| DownloadActionCallback download_action_callback, |
| const GetContentCallback& get_content_callback, |
| ProgressCallback progress_callback) override { |
| download_action_callback_ = std::move(download_action_callback); |
| get_content_callback_ = get_content_callback; |
| progress_callback_ = std::move(progress_callback); |
| |
| // It is safe to use base::Unretained as this object will not get deleted |
| // before the end of the test. |
| return base::BindOnce(&SimpleFakeDriveService::CancelCallback, |
| base::Unretained(this)); |
| } |
| |
| private: |
| void CancelCallback() { cancel_callback_called_ = true; } |
| |
| bool cancel_callback_called_{false}; |
| |
| DownloadActionCallback download_action_callback_; |
| GetContentCallback get_content_callback_; |
| ProgressCallback progress_callback_; |
| |
| bool get_content_callback_called_{false}; |
| }; |
| |
| class PluginVmInstallerTestBase : public testing::Test { |
| public: |
| PluginVmInstallerTestBase() = default; |
| |
| PluginVmInstallerTestBase(const PluginVmInstallerTestBase&) = delete; |
| PluginVmInstallerTestBase& operator=(const PluginVmInstallerTestBase&) = |
| delete; |
| |
| ~PluginVmInstallerTestBase() override = default; |
| |
| protected: |
| void SetUp() override { |
| ash::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr); |
| ash::DebugDaemonClient::InitializeFake(); |
| ash::VmPluginDispatcherClient::InitializeFake(); |
| |
| ASSERT_TRUE(profiles_dir_.CreateUniqueTempDir()); |
| CreateProfile(); |
| plugin_vm_test_helper_ = |
| std::make_unique<PluginVmTestHelper>(profile_.get()); |
| plugin_vm_test_helper_->AllowPluginVm(); |
| // Sets new PluginVmImage pref for this test. |
| SetPluginVmImagePref(kUrl, kHash); |
| |
| installer_ = PluginVmInstallerFactory::GetForProfile(profile_.get()); |
| observer_ = std::make_unique<StrictMock<MockObserver>>(); |
| installer_->SetObserver(observer_.get()); |
| installer_->SkipLicenseCheckForTesting(); |
| installer_->SetFreeDiskSpaceForTesting(std::numeric_limits<int64_t>::max()); |
| installer_->SetDownloadedImageForTesting(CreateZipFile()); |
| |
| SetDefaultExpectations(); |
| |
| fake_concierge_client_ = ash::FakeConciergeClient::Get(); |
| |
| ash::FakeSpacedClient::InitializeFake(); |
| } |
| |
| void TearDown() override { |
| observer_.reset(); |
| plugin_vm_test_helper_.reset(); |
| profile_.reset(); |
| observer_.reset(); |
| |
| ash::VmPluginDispatcherClient::Shutdown(); |
| ash::DebugDaemonClient::Shutdown(); |
| ash::ConciergeClient::Shutdown(); |
| ash::FakeSpacedClient::Shutdown(); |
| } |
| |
| void SetPluginVmImagePref(std::string url, std::string hash) { |
| ScopedDictPrefUpdate update(profile_->GetPrefs(), prefs::kPluginVmImage); |
| base::Value::Dict& plugin_vm_image = update.Get(); |
| plugin_vm_image.Set("url", url); |
| plugin_vm_image.Set("hash", hash); |
| } |
| |
| void SetRequiredFreeDiskSpaceGBPref(int required_free_disk_space) { |
| profile_->GetPrefs()->SetInteger(prefs::kPluginVmRequiredFreeDiskSpaceGB, |
| required_free_disk_space); |
| } |
| |
| base::FilePath CreateZipFile() { |
| base::FilePath zip_file_path = |
| profile_->GetPath().AppendASCII(kPluginVmImageFile); |
| base::WriteFile(zip_file_path, kContent); |
| return zip_file_path; |
| } |
| |
| void VerifyExpectations() { |
| Mock::VerifyAndClearExpectations(observer_.get()); |
| SetDefaultExpectations(); |
| } |
| |
| // Set expectations for observer events up to and including |end_state|. |
| void ExpectObserverEventsUntil(InstallingState end_state) { |
| InstallingState states[] = { |
| InstallingState::kCheckingLicense, |
| InstallingState::kCheckingForExistingVm, |
| InstallingState::kCheckingDiskSpace, |
| InstallingState::kDownloadingDlc, |
| InstallingState::kStartingDispatcher, |
| InstallingState::kDownloadingImage, |
| InstallingState::kImporting, |
| }; |
| |
| for (InstallingState state : states) { |
| EXPECT_CALL(*observer_, OnStateUpdated(state)); |
| if (state == end_state) { |
| return; |
| } |
| } |
| |
| NOTREACHED(); |
| } |
| |
| // Helper functions for starting and progressing the installer. |
| |
| void RunUntil(InstallingState state) { |
| base::RunLoop run_loop; |
| ON_CALL(*observer_, OnStateUpdated(state)) |
| .WillByDefault(RunClosure(run_loop.QuitClosure())); |
| run_loop.Run(); |
| } |
| |
| void StartAndRunUntil(InstallingState state) { |
| installer_->Start(); |
| RunUntil(state); |
| } |
| |
| void StartAndRunToCompletion() { |
| installer_->Start(); |
| task_environment_.RunUntilIdle(); |
| } |
| |
| content::BrowserTaskEnvironment task_environment_; |
| std::unique_ptr<TestingProfile> profile_; |
| std::unique_ptr<PluginVmTestHelper> plugin_vm_test_helper_; |
| raw_ptr<PluginVmInstaller, DanglingUntriaged> installer_; |
| std::unique_ptr<MockObserver> observer_; |
| |
| // A pointer to a singleton object which is valid until |
| // ConciergeClient::Shutdown() is called. |
| raw_ptr<ash::FakeConciergeClient, DanglingUntriaged> fake_concierge_client_; |
| ash::FakeDlcserviceClient fake_dlcservice_client_; |
| |
| private: |
| void CreateProfile() { |
| TestingProfile::Builder profile_builder; |
| profile_builder.SetProfileName(kProfileName); |
| profile_builder.SetPath(profiles_dir_.GetPath().AppendASCII(kProfileName)); |
| std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> pref_service = |
| std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); |
| RegisterUserProfilePrefs(pref_service->registry()); |
| profile_builder.SetPrefService(std::move(pref_service)); |
| profile_ = profile_builder.Build(); |
| } |
| |
| void SetDefaultExpectations() { |
| // Suppress progress updates. |
| EXPECT_CALL(*observer_, OnProgressUpdated(_)).Times(AnyNumber()); |
| } |
| |
| base::ScopedTempDir profiles_dir_; |
| }; |
| |
| class PluginVmInstallerDownloadServiceTest : public PluginVmInstallerTestBase { |
| public: |
| PluginVmInstallerDownloadServiceTest() = default; |
| |
| PluginVmInstallerDownloadServiceTest( |
| const PluginVmInstallerDownloadServiceTest&) = delete; |
| PluginVmInstallerDownloadServiceTest& operator=( |
| const PluginVmInstallerDownloadServiceTest&) = delete; |
| |
| ~PluginVmInstallerDownloadServiceTest() override = default; |
| |
| protected: |
| void SetUp() override { |
| PluginVmInstallerTestBase::SetUp(); |
| |
| download_service_ = std::make_unique<download::test::TestDownloadService>(); |
| download_service_->SetIsReady(true); |
| download_service_->SetHash256(kHash); |
| client_ = std::make_unique<PluginVmImageDownloadClient>(profile_.get()); |
| download_service_->set_client(client_.get()); |
| installer_->SetDownloadServiceForTesting(download_service_.get()); |
| histogram_tester_ = std::make_unique<base::HistogramTester>(); |
| } |
| |
| void TearDown() override { |
| histogram_tester_.reset(); |
| download_service_.reset(); |
| client_.reset(); |
| |
| PluginVmInstallerTestBase::TearDown(); |
| } |
| |
| std::unique_ptr<download::test::TestDownloadService> download_service_; |
| std::unique_ptr<base::HistogramTester> histogram_tester_; |
| |
| private: |
| std::unique_ptr<PluginVmImageDownloadClient> client_; |
| }; |
| |
| class PluginVmInstallerDriveTest : public PluginVmInstallerTestBase { |
| public: |
| PluginVmInstallerDriveTest() = default; |
| |
| PluginVmInstallerDriveTest(const PluginVmInstallerDriveTest&) = delete; |
| PluginVmInstallerDriveTest& operator=(const PluginVmInstallerDriveTest&) = |
| delete; |
| |
| ~PluginVmInstallerDriveTest() override = default; |
| |
| protected: |
| void SetUp() override { |
| PluginVmInstallerTestBase::SetUp(); |
| |
| google_apis::ApiErrorCode error = google_apis::OTHER_ERROR; |
| std::unique_ptr<google_apis::FileResource> entry; |
| auto fake_drive_service = std::make_unique<drive::FakeDriveService>(); |
| // We will need to access this object for some tests in the future. |
| fake_drive_service_ = fake_drive_service.get(); |
| fake_drive_service->AddNewFileWithResourceId( |
| kDriveId, kDriveContentType, kContent, |
| "", // parent_resource_id |
| kPluginVmImageFile, |
| true, // shared_with_me |
| base::BindLambdaForTesting( |
| [&](google_apis::ApiErrorCode drive_error, |
| std::unique_ptr<google_apis::FileResource> drive_entry) { |
| error = drive_error; |
| entry = std::move(drive_entry); |
| })); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(google_apis::HTTP_CREATED, error); |
| ASSERT_TRUE(entry); |
| |
| auto drive_download_service = |
| std::make_unique<PluginVmDriveImageDownloadService>(installer_, |
| profile_.get()); |
| // We will need to access this object for some tests in the future. |
| drive_download_service_ = drive_download_service.get(); |
| |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| drive_download_service->SetDownloadDirectoryForTesting(temp_dir.Take()); |
| drive_download_service->SetDriveServiceForTesting( |
| std::move(fake_drive_service)); |
| |
| installer_->SetDriveDownloadServiceForTesting( |
| std::move(drive_download_service)); |
| histogram_tester_ = std::make_unique<base::HistogramTester>(); |
| } |
| |
| void TearDown() override { |
| histogram_tester_.reset(); |
| |
| PluginVmInstallerTestBase::TearDown(); |
| } |
| |
| SimpleFakeDriveService* SetUpSimpleFakeDriveService() { |
| auto fake_drive_service = std::make_unique<SimpleFakeDriveService>(); |
| SimpleFakeDriveService* fake_drive_service_ptr = fake_drive_service.get(); |
| |
| drive_download_service_->SetDriveServiceForTesting( |
| std::move(fake_drive_service)); |
| |
| return fake_drive_service_ptr; |
| } |
| |
| raw_ptr<PluginVmDriveImageDownloadService, DanglingUntriaged> |
| drive_download_service_; |
| raw_ptr<drive::FakeDriveService, DanglingUntriaged> fake_drive_service_; |
| std::unique_ptr<base::HistogramTester> histogram_tester_; |
| }; |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, ProgressUpdates) { |
| SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_); |
| |
| // Override default expectation so unexpected calls will fail the test. |
| EXPECT_CALL(*observer_, OnProgressUpdated(_)).Times(0); |
| |
| EXPECT_CALL(*observer_, OnProgressUpdated(DoubleEq(0.01))); |
| EXPECT_CALL(*observer_, OnProgressUpdated(DoubleEq(0.45))); |
| EXPECT_CALL(*observer_, OnProgressUpdated(DoubleEq(0.725))); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnImported()); |
| StartAndRunToCompletion(); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, InsufficientDisk) { |
| installer_->SetFreeDiskSpaceForTesting( |
| kDefaultRequiredFreeDiskSpaceGB * kBytesPerGigabyte - 1); |
| ExpectObserverEventsUntil(InstallingState::kCheckingDiskSpace); |
| EXPECT_CALL(*observer_, OnError(FailureReason::INSUFFICIENT_DISK_SPACE)); |
| StartAndRunToCompletion(); |
| histogram_tester_->ExpectUniqueSample( |
| kFailureReasonHistogram, FailureReason::INSUFFICIENT_DISK_SPACE, 1); |
| histogram_tester_->ExpectUniqueSample(kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kError, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, InsufficientDiskWhenSetInPolicy) { |
| SetRequiredFreeDiskSpaceGBPref(kRequiredFreeDiskSpaceGB); |
| int64_t requred_free_disk_space_bytes = |
| kRequiredFreeDiskSpaceGB * kBytesPerGigabyte; |
| installer_->SetFreeDiskSpaceForTesting(requred_free_disk_space_bytes - 1); |
| ExpectObserverEventsUntil(InstallingState::kCheckingDiskSpace); |
| EXPECT_CALL(*observer_, OnError(FailureReason::INSUFFICIENT_DISK_SPACE)); |
| StartAndRunToCompletion(); |
| histogram_tester_->ExpectUniqueSample( |
| kFailureReasonHistogram, FailureReason::INSUFFICIENT_DISK_SPACE, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, VmExists) { |
| // This flow works even if the image url is not set. |
| SetPluginVmImagePref("", kHash); |
| |
| vm_tools::concierge::ListVmDisksResponse list_vm_disks_response; |
| list_vm_disks_response.set_success(true); |
| auto* image = list_vm_disks_response.add_images(); |
| image->set_name(kPluginVmName); |
| image->set_storage_location(vm_tools::concierge::STORAGE_CRYPTOHOME_PLUGINVM); |
| fake_concierge_client_->set_list_vm_disks_response(list_vm_disks_response); |
| |
| ExpectObserverEventsUntil(InstallingState::kCheckingForExistingVm); |
| EXPECT_CALL(*observer_, OnVmExists()); |
| StartAndRunToCompletion(); |
| |
| histogram_tester_->ExpectUniqueSample( |
| kPluginVmSetupResultHistogram, PluginVmSetupResult::kVmAlreadyExists, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, InvalidVmExists) { |
| // This flow works even if the image url is not set. |
| SetPluginVmImagePref("", kHash); |
| |
| vm_tools::concierge::ListVmDisksResponse list_vm_disks_response; |
| list_vm_disks_response.set_success(true); |
| auto* image = list_vm_disks_response.add_images(); |
| // Pretend we have a VM with the right name in a wrong location. |
| image->set_name(kPluginVmName); |
| image->set_storage_location(vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT); |
| fake_concierge_client_->set_list_vm_disks_response(list_vm_disks_response); |
| |
| ExpectObserverEventsUntil(InstallingState::kCheckingForExistingVm); |
| EXPECT_CALL(*observer_, OnError(FailureReason::EXISTING_IMAGE_INVALID)); |
| StartAndRunToCompletion(); |
| |
| histogram_tester_->ExpectUniqueSample( |
| kFailureReasonHistogram, FailureReason::EXISTING_IMAGE_INVALID, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, CancelOnVmExistsCheck) { |
| base::RunLoop run_loop; |
| ExpectObserverEventsUntil(InstallingState::kCheckingForExistingVm); |
| ON_CALL(*observer_, OnStateUpdated(InstallingState::kCheckingForExistingVm)) |
| .WillByDefault(RunClosure(run_loop.QuitClosure())); |
| EXPECT_CALL(*observer_, OnCancelFinished()); |
| |
| installer_->Start(); |
| run_loop.Run(); |
| installer_->Cancel(); |
| task_environment_.RunUntilIdle(); |
| |
| histogram_tester_->ExpectUniqueSample( |
| kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kUserCancelledCheckingForExistingVm, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, DownloadPluginVmImageParamsTest) { |
| SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnImported()); |
| |
| StartAndRunUntil(InstallingState::kDownloadingImage); |
| |
| std::string guid = installer_->GetCurrentDownloadGuid(); |
| const std::optional<download::DownloadParams>& params = |
| download_service_->GetDownload(guid); |
| ASSERT_TRUE(params.has_value()); |
| EXPECT_EQ(guid, params->guid); |
| EXPECT_EQ(download::DownloadClient::PLUGIN_VM_IMAGE, params->client); |
| EXPECT_EQ(GURL(kUrl), params->request_params.url); |
| |
| // Finishing image processing. |
| task_environment_.RunUntilIdle(); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, OnlyOneImageIsProcessedTest) { |
| SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnImported()); |
| |
| StartAndRunUntil(InstallingState::kDownloadingImage); |
| |
| EXPECT_TRUE(installer_->IsProcessing()); |
| |
| RunUntil(InstallingState::kImporting); |
| |
| EXPECT_TRUE(installer_->IsProcessing()); |
| |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_FALSE(installer_->IsProcessing()); |
| |
| histogram_tester_->ExpectUniqueSample(kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kSuccess, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, |
| CanProceedWithANewImageWhenSucceededTest) { |
| SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnImported()); |
| StartAndRunToCompletion(); |
| VerifyExpectations(); |
| |
| EXPECT_FALSE(installer_->IsProcessing()); |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnImported()); |
| |
| // As it is deleted after successful importing. |
| installer_->SetDownloadedImageForTesting(CreateZipFile()); |
| StartAndRunToCompletion(); |
| |
| histogram_tester_->ExpectUniqueSample(kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kSuccess, 2); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, |
| CanProceedWithANewImageWhenFailedTest) { |
| SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingImage); |
| EXPECT_CALL(*observer_, OnError(FailureReason::DOWNLOAD_FAILED_ABORTED)); |
| |
| StartAndRunUntil(InstallingState::kDownloadingImage); |
| std::string guid = installer_->GetCurrentDownloadGuid(); |
| download_service_->SetFailedDownload(guid, false); |
| task_environment_.RunUntilIdle(); |
| VerifyExpectations(); |
| |
| EXPECT_FALSE(installer_->IsProcessing()); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnImported()); |
| |
| StartAndRunToCompletion(); |
| |
| histogram_tester_->ExpectBucketCount(kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kError, 1); |
| histogram_tester_->ExpectBucketCount(kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kSuccess, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, CancelledDownloadTest) { |
| ExpectObserverEventsUntil(InstallingState::kDownloadingImage); |
| EXPECT_CALL(*observer_, OnCancelFinished()); |
| |
| StartAndRunUntil(InstallingState::kDownloadingImage); |
| installer_->Cancel(); |
| task_environment_.RunUntilIdle(); |
| |
| histogram_tester_->ExpectTotalCount(kFailureReasonHistogram, 0); |
| histogram_tester_->ExpectUniqueSample( |
| kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kUserCancelledDownloadingPluginVmImage, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, ImportNonExistingImageTest) { |
| SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnError(FailureReason::COULD_NOT_OPEN_IMAGE)); |
| |
| installer_->SetDownloadedImageForTesting(base::FilePath()); |
| StartAndRunToCompletion(); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, ImportFailedOutOfSpaceTest) { |
| SetupConciergeForFailedDiskImageImport( |
| fake_concierge_client_, |
| vm_tools::concierge::DISK_STATUS_NOT_ENOUGH_SPACE); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnError(FailureReason::OUT_OF_DISK_SPACE)); |
| StartAndRunToCompletion(); |
| |
| histogram_tester_->ExpectBucketCount(kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kError, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, CancelledImportTest) { |
| SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_); |
| SetupConciergeForCancelDiskImageOperation(fake_concierge_client_, |
| true /* success */); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| StartAndRunUntil(InstallingState::kImporting); |
| |
| EXPECT_CALL(*observer_, OnCancelFinished()); |
| installer_->Cancel(); |
| task_environment_.RunUntilIdle(); |
| |
| histogram_tester_->ExpectUniqueSample( |
| kPluginVmSetupResultHistogram, |
| PluginVmSetupResult::kUserCancelledImportingPluginVmImage, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, EmptyPluginVmImageUrlTest) { |
| SetPluginVmImagePref("", kHash); |
| ExpectObserverEventsUntil(InstallingState::kDownloadingDlc); |
| EXPECT_CALL(*observer_, OnError(FailureReason::INVALID_IMAGE_URL)); |
| StartAndRunToCompletion(); |
| |
| histogram_tester_->ExpectUniqueSample(kFailureReasonHistogram, |
| FailureReason::INVALID_IMAGE_URL, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, VerifyDownloadTest) { |
| EXPECT_FALSE(installer_->VerifyDownload(kHash2)); |
| EXPECT_TRUE(installer_->VerifyDownload(kHashUppercase)); |
| EXPECT_TRUE(installer_->VerifyDownload(kHash)); |
| EXPECT_FALSE(installer_->VerifyDownload(std::string())); |
| } |
| |
| TEST_F(PluginVmInstallerDownloadServiceTest, CannotStartIfPluginVmIsDisabled) { |
| profile_->ScopedCrosSettingsTestHelper()->SetBoolean(ash::kPluginVmAllowed, |
| false); |
| EXPECT_EQ(FailureReason::NOT_ALLOWED, installer_->Start()); |
| task_environment_.RunUntilIdle(); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, InvalidDriveUrlTest) { |
| SetPluginVmImagePref(kDriveUrl2, kHash); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingImage); |
| EXPECT_CALL(*observer_, OnError(FailureReason::INVALID_IMAGE_URL)); |
| StartAndRunToCompletion(); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, NoConnectionDriveTest) { |
| SetPluginVmImagePref(kDriveUrl, kHash); |
| fake_drive_service_->set_offline(true); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingImage); |
| EXPECT_CALL(*observer_, OnError(FailureReason::DOWNLOAD_FAILED_NETWORK)); |
| StartAndRunToCompletion(); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, WrongHashDriveTest) { |
| SetPluginVmImagePref(kDriveUrl, kHash2); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingImage); |
| EXPECT_CALL(*observer_, OnDownloadProgressUpdated(_, _)).Times(2); |
| EXPECT_CALL(*observer_, OnError(FailureReason::HASH_MISMATCH)); |
| |
| StartAndRunToCompletion(); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, DriveDownloadFailedAfterStartingTest) { |
| SetPluginVmImagePref(kDriveUrl, kHash); |
| SimpleFakeDriveService* fake_drive_service = SetUpSimpleFakeDriveService(); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingImage); |
| EXPECT_CALL(*observer_, OnDownloadProgressUpdated(5, 100)); |
| EXPECT_CALL(*observer_, OnDownloadProgressUpdated(10, 100)); |
| EXPECT_CALL(*observer_, OnError(FailureReason::DOWNLOAD_FAILED_NETWORK)); |
| |
| StartAndRunToCompletion(); |
| |
| fake_drive_service->RunGetContentCallback( |
| google_apis::HTTP_SUCCESS, std::make_unique<std::string>("Part1")); |
| fake_drive_service->RunProgressCallback(5, 100); |
| fake_drive_service->RunGetContentCallback( |
| google_apis::HTTP_SUCCESS, std::make_unique<std::string>("Part2")); |
| fake_drive_service->RunProgressCallback(10, 100); |
| fake_drive_service->RunGetContentCallback(google_apis::NO_CONNECTION, |
| std::unique_ptr<std::string>()); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, CancelledDriveDownloadTest) { |
| SetPluginVmImagePref(kDriveUrl, kHash); |
| SimpleFakeDriveService* fake_drive_service = SetUpSimpleFakeDriveService(); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingImage); |
| EXPECT_CALL(*observer_, OnDownloadProgressUpdated(5, 100)); |
| EXPECT_CALL(*observer_, OnCancelFinished()); |
| |
| StartAndRunToCompletion(); |
| |
| fake_drive_service->RunGetContentCallback( |
| google_apis::HTTP_SUCCESS, std::make_unique<std::string>("Part1")); |
| fake_drive_service->RunProgressCallback(5, 100); |
| installer_->Cancel(); |
| task_environment_.RunUntilIdle(); |
| EXPECT_TRUE(fake_drive_service->cancel_callback_called()); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, SuccessfulDriveDownloadTest) { |
| SetPluginVmImagePref(kDriveUrl, kHash); |
| fake_dlcservice_client_.set_install_error(dlcservice::kErrorNone); |
| |
| ExpectObserverEventsUntil(InstallingState::kImporting); |
| EXPECT_CALL(*observer_, OnDownloadProgressUpdated(_, std::strlen(kContent))) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(*observer_, OnError(_)); |
| |
| StartAndRunToCompletion(); |
| histogram_tester_->ExpectUniqueSample(kPluginVmDlcUseResultHistogram, |
| PluginVmDlcUseResult::kDlcSuccess, 1); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, InstallingPluginVmDlcNeedReboot) { |
| SetPluginVmImagePref(kDriveUrl, kHash); |
| fake_dlcservice_client_.set_install_error(dlcservice::kErrorNeedReboot); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingDlc); |
| EXPECT_CALL(*observer_, OnError(FailureReason::DLC_NEED_REBOOT)); |
| |
| StartAndRunToCompletion(); |
| histogram_tester_->ExpectUniqueSample( |
| kPluginVmDlcUseResultHistogram, PluginVmDlcUseResult::kNeedRebootDlcError, |
| 1); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, InstallingPluginVmDlcNeedSpace) { |
| SetPluginVmImagePref(kDriveUrl, kHash); |
| fake_dlcservice_client_.set_install_error(dlcservice::kErrorAllocation); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingDlc); |
| EXPECT_CALL(*observer_, OnError(FailureReason::DLC_NEED_SPACE)); |
| |
| StartAndRunToCompletion(); |
| histogram_tester_->ExpectUniqueSample( |
| kPluginVmDlcUseResultHistogram, PluginVmDlcUseResult::kNeedSpaceDlcError, |
| 1); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, InstallingPluginVmDlcWhenUnsupported) { |
| SetPluginVmImagePref(kDriveUrl, kHash); |
| fake_dlcservice_client_.set_install_error(dlcservice::kErrorInvalidDlc); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingDlc); |
| EXPECT_CALL(*observer_, OnError(FailureReason::DLC_UNSUPPORTED)); |
| |
| StartAndRunToCompletion(); |
| histogram_tester_->ExpectUniqueSample(kPluginVmDlcUseResultHistogram, |
| PluginVmDlcUseResult::kInvalidDlcError, |
| 1); |
| } |
| |
| TEST_F(PluginVmInstallerDriveTest, InstallingPluginVmDlcWhenNoImageFound) { |
| SetPluginVmImagePref(kDriveUrl, kHash); |
| fake_dlcservice_client_.set_install_error(dlcservice::kErrorNoImageFound); |
| |
| ExpectObserverEventsUntil(InstallingState::kDownloadingDlc); |
| EXPECT_CALL(*observer_, OnError(FailureReason::DLC_INTERNAL)); |
| |
| StartAndRunToCompletion(); |
| histogram_tester_->ExpectUniqueSample( |
| kPluginVmDlcUseResultHistogram, |
| PluginVmDlcUseResult::kNoImageFoundDlcError, 1); |
| } |
| |
| } // namespace plugin_vm |