blob: 0f34328781c27af17d172e45822f7c6630d0efcb [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.h"
#include <memory>
#include <string>
#include <utility>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/optional.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/chromeos/login/users/mock_user_manager.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_image_download_client.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_factory.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_metrics_util.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/test/base/testing_profile.h"
#include "components/account_id/account_id.h"
#include "components/download/public/background_service/test/test_download_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/zlib/google/zip.h"
namespace plugin_vm {
namespace {
const char kProfileName[] = "p1";
const char kUrl[] = "http://example.com";
const char kHash[] =
"842841a4c75a55ad050d686f4ea5f77e83ae059877fe9b6946aa63d3d057ed32";
const char kHashUppercase[] =
"842841A4C75A55AD050D686F4EA5F77E83AE059877FE9B6946AA63D3D057ED32";
const char kHash2[] =
"02f06421ae27144aacdc598aebcd345a5e2e634405e8578300173628fe1574bd";
const char kPluginVmImageUnzipped[] = "plugin_vm_image_unzipped";
const char kPluginVmImageFile1[] = "plugin_vm_image_file_1";
const char kContent1[] = "This is content #1.";
const int kContent1Size = strlen(kContent1);
const char kPluginVmImageFile2[] = "plugin_vm_image_file_2";
const char kContent2[] = "This is content #2.";
const int kContent2Size = strlen(kContent2);
const int kContentSize = kContent1Size + kContent2Size;
const char kLicenseKey[] = "LICENSE_KEY";
// File size set in test_download_service.
const int kDownloadedPluginVmImageSizeInMb = 123456789u / (1024 * 1024);
} // namespace
class MockObserver : public PluginVmImageManager::Observer {
public:
MOCK_METHOD0(OnDownloadStarted, void());
MOCK_METHOD3(OnDownloadProgressUpdated,
void(uint64_t bytes_downloaded,
int64_t content_length,
int64_t download_bytes_per_sec));
MOCK_METHOD0(OnDownloadCompleted, void());
MOCK_METHOD0(OnDownloadCancelled, void());
MOCK_METHOD0(OnDownloadFailed, void());
MOCK_METHOD3(OnUnzippingProgressUpdated,
void(int64_t bytes_unzipped,
int64_t plugin_vm_image_size,
int64_t unzipping_bytes_per_sec));
MOCK_METHOD0(OnUnzipped, void());
MOCK_METHOD0(OnUnzippingFailed, void());
MOCK_METHOD0(OnRegistered, void());
MOCK_METHOD0(OnRegistrationFailed, void());
};
class PluginVmImageManagerTest : public testing::Test {
public:
PluginVmImageManagerTest()
: download_service_(new download::test::TestDownloadService()) {}
protected:
chromeos::MockUserManager user_manager_;
chromeos::ScopedCrosSettingsTestHelper settings_helper_;
content::TestBrowserThreadBundle test_browser_thread_bundle_;
std::unique_ptr<TestingProfile> profile_;
PluginVmImageManager* manager_;
download::test::TestDownloadService* download_service_;
std::unique_ptr<MockObserver> observer_;
base::FilePath fake_downloaded_plugin_vm_image_archive_;
std::unique_ptr<base::HistogramTester> histogram_tester_;
void SetUp() override {
ASSERT_TRUE(profiles_dir_.CreateUniqueTempDir());
CreateProfile();
SetPluginVmImagePref(kUrl, kHash);
manager_ = PluginVmImageManagerFactory::GetForProfile(profile_.get());
download_service_->SetIsReady(true);
download_service_->SetHash256(kHash);
download_service_->set_client(
new PluginVmImageDownloadClient(profile_.get()));
manager_->SetDownloadServiceForTesting(download_service_);
observer_ = std::make_unique<MockObserver>();
manager_->SetObserver(observer_.get());
fake_downloaded_plugin_vm_image_archive_ = CreateZipFile();
SetPluginVmDevicePolicies();
SetUserWithAffiliation();
histogram_tester_ = std::make_unique<base::HistogramTester>();
}
void TearDown() override {
profile_.reset();
observer_.reset();
}
void SetPluginVmDevicePolicies() {
settings_helper_.ReplaceDeviceSettingsProviderWithStub();
settings_helper_.SetBoolean(chromeos::kPluginVmAllowed, true);
settings_helper_.SetString(chromeos::kPluginVmLicenseKey, kLicenseKey);
}
void SetUserWithAffiliation() {
const AccountId account_id(
AccountId::FromUserEmailGaiaId(profile_->GetProfileUserName(), "id"));
user_manager_.AddUserWithAffiliationAndType(
account_id, true, user_manager::USER_TYPE_REGULAR);
chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(
user_manager_.GetActiveUser());
}
void SetPluginVmImagePref(std::string url, std::string hash) {
DictionaryPrefUpdate update(profile_->GetPrefs(),
plugin_vm::prefs::kPluginVmImage);
base::DictionaryValue* plugin_vm_image = update.Get();
plugin_vm_image->SetKey("url", base::Value(url));
plugin_vm_image->SetKey("hash", base::Value(hash));
}
void ProcessImageUntilUnzipping() {
manager_->StartDownload();
test_browser_thread_bundle_.RunUntilIdle();
}
void ProcessImageUntilRegistration() {
ProcessImageUntilUnzipping();
// Faking downloaded file for testing.
manager_->SetDownloadedPluginVmImageArchiveForTesting(
fake_downloaded_plugin_vm_image_archive_);
manager_->StartUnzipping();
test_browser_thread_bundle_.RunUntilIdle();
}
void ProcessImageUntilConfigured() {
ProcessImageUntilRegistration();
manager_->StartRegistration();
test_browser_thread_bundle_.RunUntilIdle();
}
void EnsurePluginVmImageIsRemoved() {
base::FilePath plugin_vm_image_unzipped =
profile_->GetPath()
.AppendASCII(kCrosvmDir)
.AppendASCII(kPvmDir)
.AppendASCII(kPluginVmImageDir);
EXPECT_FALSE(base::DirectoryExists(plugin_vm_image_unzipped));
}
base::FilePath CreateZipFile() {
base::FilePath src_dir = profile_->GetPath().AppendASCII("src");
base::CreateDirectory(src_dir);
base::FilePath dest_dir = profile_->GetPath().AppendASCII("dest");
base::CreateDirectory(dest_dir);
base::FilePath zip_file = dest_dir.Append("out");
base::FilePath plugin_vm_image_unzipped =
src_dir.Append(kPluginVmImageUnzipped);
base::CreateDirectory(plugin_vm_image_unzipped);
base::FilePath plugin_vm_image_file_1 =
plugin_vm_image_unzipped.Append(kPluginVmImageFile1);
base::FilePath plugin_vm_image_file_2 =
plugin_vm_image_unzipped.Append(kPluginVmImageFile2);
base::WriteFile(plugin_vm_image_file_1, kContent1, strlen(kContent1));
base::WriteFile(plugin_vm_image_file_2, kContent2, strlen(kContent2));
zip::Zip(src_dir, zip_file, true /* include_hidden_files */);
return zip_file;
}
private:
base::ScopedTempDir profiles_dir_;
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();
}
DISALLOW_COPY_AND_ASSIGN(PluginVmImageManagerTest);
};
TEST_F(PluginVmImageManagerTest, DownloadPluginVmImageParamsTest) {
EXPECT_CALL(*observer_, OnDownloadCompleted());
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContent1Size,
kContentSize, testing::_));
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContentSize, kContentSize,
testing::_));
EXPECT_CALL(*observer_, OnUnzipped());
EXPECT_CALL(*observer_, OnRegistered());
manager_->StartDownload();
std::string guid = manager_->GetCurrentDownloadGuidForTesting();
base::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.
test_browser_thread_bundle_.RunUntilIdle();
// Faking downloaded file for testing.
manager_->SetDownloadedPluginVmImageArchiveForTesting(
fake_downloaded_plugin_vm_image_archive_);
manager_->StartUnzipping();
test_browser_thread_bundle_.RunUntilIdle();
manager_->StartRegistration();
test_browser_thread_bundle_.RunUntilIdle();
}
TEST_F(PluginVmImageManagerTest, OnlyOneImageIsProcessedTest) {
EXPECT_CALL(*observer_, OnDownloadCompleted());
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContent1Size,
kContentSize, testing::_));
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContentSize, kContentSize,
testing::_));
EXPECT_CALL(*observer_, OnUnzipped());
EXPECT_CALL(*observer_, OnRegistered());
manager_->StartDownload();
EXPECT_TRUE(manager_->IsProcessingImage());
test_browser_thread_bundle_.RunUntilIdle();
// Faking downloaded file for testing.
manager_->SetDownloadedPluginVmImageArchiveForTesting(
fake_downloaded_plugin_vm_image_archive_);
EXPECT_TRUE(manager_->IsProcessingImage());
manager_->StartUnzipping();
EXPECT_TRUE(manager_->IsProcessingImage());
test_browser_thread_bundle_.RunUntilIdle();
EXPECT_TRUE(manager_->IsProcessingImage());
manager_->StartRegistration();
EXPECT_TRUE(manager_->IsProcessingImage());
test_browser_thread_bundle_.RunUntilIdle();
EXPECT_FALSE(manager_->IsProcessingImage());
histogram_tester_->ExpectUniqueSample(kPluginVmImageDownloadedSize,
kDownloadedPluginVmImageSizeInMb, 1);
}
TEST_F(PluginVmImageManagerTest, CanProceedWithANewImageWhenSucceededTest) {
EXPECT_CALL(*observer_, OnDownloadCompleted()).Times(2);
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContent1Size,
kContentSize, testing::_))
.Times(2);
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContentSize, kContentSize,
testing::_))
.Times(2);
EXPECT_CALL(*observer_, OnUnzipped()).Times(2);
EXPECT_CALL(*observer_, OnRegistered()).Times(2);
ProcessImageUntilConfigured();
EXPECT_FALSE(manager_->IsProcessingImage());
// As it is deleted after successful unzipping.
fake_downloaded_plugin_vm_image_archive_ = CreateZipFile();
ProcessImageUntilConfigured();
histogram_tester_->ExpectUniqueSample(kPluginVmImageDownloadedSize,
kDownloadedPluginVmImageSizeInMb, 2);
}
TEST_F(PluginVmImageManagerTest, CanProceedWithANewImageWhenFailedTest) {
EXPECT_CALL(*observer_, OnDownloadFailed());
EXPECT_CALL(*observer_, OnDownloadCompleted());
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContent1Size,
kContentSize, testing::_));
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContentSize, kContentSize,
testing::_));
EXPECT_CALL(*observer_, OnUnzipped());
EXPECT_CALL(*observer_, OnRegistered());
manager_->StartDownload();
std::string guid = manager_->GetCurrentDownloadGuidForTesting();
download_service_->SetFailedDownload(guid, false);
test_browser_thread_bundle_.RunUntilIdle();
EXPECT_FALSE(manager_->IsProcessingImage());
ProcessImageUntilConfigured();
histogram_tester_->ExpectUniqueSample(kPluginVmImageDownloadedSize,
kDownloadedPluginVmImageSizeInMb, 1);
}
TEST_F(PluginVmImageManagerTest, CancelledDownloadTest) {
EXPECT_CALL(*observer_, OnDownloadCompleted()).Times(0);
EXPECT_CALL(*observer_, OnDownloadCancelled());
manager_->StartDownload();
manager_->CancelDownload();
test_browser_thread_bundle_.RunUntilIdle();
// Finishing image processing as it should really happen.
manager_->OnDownloadCancelled();
histogram_tester_->ExpectTotalCount(kPluginVmImageDownloadedSize, 0);
}
TEST_F(PluginVmImageManagerTest, UnzipDownloadedImageTest) {
EXPECT_CALL(*observer_, OnDownloadCompleted());
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContent1Size,
kContentSize, testing::_));
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContentSize, kContentSize,
testing::_));
EXPECT_CALL(*observer_, OnUnzipped());
EXPECT_CALL(*observer_, OnRegistered());
ProcessImageUntilConfigured();
// Checking that all files are in place.
base::FilePath plugin_vm_image_unzipped =
profile_->GetPath()
.AppendASCII(kCrosvmDir)
.AppendASCII(kPvmDir)
.AppendASCII(kPluginVmImageDir)
.AppendASCII(kPluginVmImageUnzipped);
EXPECT_TRUE(base::DirectoryExists(plugin_vm_image_unzipped));
base::FilePath plugin_vm_image_file_1 =
plugin_vm_image_unzipped.AppendASCII(kPluginVmImageFile1);
EXPECT_TRUE(base::PathExists(plugin_vm_image_file_1));
EXPECT_FALSE(base::DirectoryExists(plugin_vm_image_file_1));
std::string plugin_vm_image_file_1_content;
EXPECT_TRUE(base::ReadFileToString(plugin_vm_image_file_1,
&plugin_vm_image_file_1_content));
EXPECT_EQ(kContent1, plugin_vm_image_file_1_content);
base::FilePath plugin_vm_image_file_2 =
plugin_vm_image_unzipped.AppendASCII(kPluginVmImageFile2);
EXPECT_TRUE(base::PathExists(plugin_vm_image_file_2));
EXPECT_FALSE(base::DirectoryExists(plugin_vm_image_file_2));
std::string plugin_vm_image_file_2_content;
EXPECT_TRUE(base::ReadFileToString(plugin_vm_image_file_2,
&plugin_vm_image_file_2_content));
EXPECT_EQ(kContent2, plugin_vm_image_file_2_content);
}
TEST_F(PluginVmImageManagerTest, UnzipNonExistingImageTest) {
EXPECT_CALL(*observer_, OnDownloadCompleted());
EXPECT_CALL(*observer_, OnUnzippingFailed());
ProcessImageUntilUnzipping();
// Should fail as fake downloaded file isn't set.
manager_->StartUnzipping();
test_browser_thread_bundle_.RunUntilIdle();
EnsurePluginVmImageIsRemoved();
}
TEST_F(PluginVmImageManagerTest, CancelUnzippingTest) {
EXPECT_CALL(*observer_, OnDownloadCompleted());
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContent1Size,
kContentSize, testing::_));
EXPECT_CALL(*observer_, OnUnzippingFailed());
ProcessImageUntilUnzipping();
// Faking downloaded file for testing.
manager_->SetDownloadedPluginVmImageArchiveForTesting(
fake_downloaded_plugin_vm_image_archive_);
manager_->StartUnzipping();
manager_->CancelUnzipping();
test_browser_thread_bundle_.RunUntilIdle();
EnsurePluginVmImageIsRemoved();
histogram_tester_->ExpectUniqueSample(kPluginVmImageDownloadedSize,
kDownloadedPluginVmImageSizeInMb, 1);
}
TEST_F(PluginVmImageManagerTest, CancelRegistrationTest) {
EXPECT_CALL(*observer_, OnDownloadCompleted());
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContent1Size,
kContentSize, testing::_));
EXPECT_CALL(*observer_, OnUnzippingProgressUpdated(kContentSize, kContentSize,
testing::_));
EXPECT_CALL(*observer_, OnUnzipped());
EXPECT_CALL(*observer_, OnRegistered()).Times(0);
EXPECT_CALL(*observer_, OnRegistrationFailed()).Times(0);
ProcessImageUntilRegistration();
manager_->StartRegistration();
manager_->CancelRegistration();
test_browser_thread_bundle_.RunUntilIdle();
EnsurePluginVmImageIsRemoved();
histogram_tester_->ExpectUniqueSample(kPluginVmImageDownloadedSize,
kDownloadedPluginVmImageSizeInMb, 1);
}
TEST_F(PluginVmImageManagerTest, EmptyPluginVmImageUrlTest) {
SetPluginVmImagePref("", kHash);
EXPECT_CALL(*observer_, OnDownloadFailed());
ProcessImageUntilUnzipping();
histogram_tester_->ExpectTotalCount(kPluginVmImageDownloadedSize, 0);
}
TEST_F(PluginVmImageManagerTest, VerifyDownloadTest) {
EXPECT_FALSE(manager_->VerifyDownload(kHash2));
EXPECT_TRUE(manager_->VerifyDownload(kHashUppercase));
EXPECT_TRUE(manager_->VerifyDownload(kHash));
EXPECT_FALSE(manager_->VerifyDownload(std::string()));
}
TEST_F(PluginVmImageManagerTest, CannotStartDownloadIfPluginVmGetsDisabled) {
settings_helper_.SetBoolean(chromeos::kPluginVmAllowed, false);
EXPECT_CALL(*observer_, OnDownloadFailed());
ProcessImageUntilUnzipping();
}
} // namespace plugin_vm