blob: 3a5f75728b0007fcc03cd5cf47ad43004a2bac4f [file] [log] [blame]
// Copyright 2018 The Chromium OS 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 <utility>
#include <vector>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/test/simple_test_clock.h>
#include <brillo/message_loops/message_loop_utils.h>
#include <dbus/dlcservice/dbus-constants.h>
#include <dlcservice/proto_bindings/dlcservice.pb.h>
#include <update_engine/proto_bindings/update_engine.pb.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "dlcservice/dlc.h"
#include "dlcservice/dlc_service.h"
#include "dlcservice/prefs.h"
#include "dlcservice/test_utils.h"
#include "dlcservice/utils.h"
using brillo::ErrorPtr;
using dlcservice::metrics::InstallResult;
using dlcservice::metrics::UninstallResult;
using std::string;
using std::vector;
using testing::_;
using testing::ElementsAre;
using testing::Invoke;
using testing::Return;
using testing::SetArgPointee;
using testing::StrictMock;
using testing::WithArg;
using testing::WithArgs;
using update_engine::Operation;
using update_engine::StatusResult;
namespace dlcservice {
class DlcServiceTest : public BaseTest {
public:
DlcServiceTest() = default;
void SetUp() override {
BaseTest::SetUp();
InitializeDlcService();
}
void InitializeDlcService() {
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
DoRegisterStatusUpdateAdvancedSignalHandler(_, _))
.Times(1);
EXPECT_CALL(*mock_session_manager_proxy_ptr_,
DoRegisterSessionStateChangedSignalHandler(_, _))
.Times(1);
dlc_service_ = std::make_unique<DlcService>();
dlc_service_->Initialize();
StatusResult status;
status.set_current_operation(Operation::IDLE);
EXPECT_CALL(*mock_update_engine_proxy_ptr_, GetStatusAdvanced(_, _, _))
.WillOnce(DoAll(SetArgPointee<0>(status), Return(true)));
// To set the update_engine status for the first time.
dlc_service_->OnStatusUpdateAdvancedSignalConnected("", "", true);
}
// Successfully install a DLC.
void Install(const DlcId& id) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(DoAll(
WithArg<1>(Invoke(this, &DlcServiceTest::InstallWithUpdateEngine)),
WithArgs<1, 2>(
Invoke(dlc_service_.get(), &DlcService::InstallCompleted)),
Return(true)));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, LoadDlcImage(id, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, id, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessNewInstall));
EXPECT_TRUE(dlc_service_->Install(id, kDefaultOmahaUrl, &err_));
CheckDlcState(id, DlcState::INSTALLING);
StatusResult status_result;
status_result.set_is_install(true);
status_result.set_current_operation(Operation::IDLE);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
CheckDlcState(id, DlcState::INSTALLED);
}
void CheckDlcState(const DlcId& id,
const DlcState::State& expected_state,
const string& error_code = kErrorNone) {
const auto* dlc = dlc_service_->GetDlc(id, &err_);
EXPECT_NE(dlc, nullptr);
EXPECT_EQ(expected_state, dlc->GetState().state());
EXPECT_EQ(dlc->GetState().last_error_code(), error_code.c_str());
}
protected:
std::unique_ptr<DlcService> dlc_service_;
private:
DlcServiceTest(const DlcServiceTest&) = delete;
DlcServiceTest& operator=(const DlcServiceTest&) = delete;
};
TEST_F(DlcServiceTest, GetInstalledTest) {
Install(kFirstDlc);
const auto& dlcs = dlc_service_->GetInstalled();
EXPECT_THAT(dlcs, ElementsAre(kFirstDlc));
EXPECT_FALSE(
dlc_service_->GetDlc(kFirstDlc, &err_)->GetRoot().value().empty());
}
TEST_F(DlcServiceTest, GetExistingDlcs) {
Install(kFirstDlc);
SetUpDlcWithSlots(kSecondDlc);
const auto& dlcs = dlc_service_->GetExistingDlcs();
EXPECT_THAT(dlcs, ElementsAre(kFirstDlc, kSecondDlc));
}
TEST_F(DlcServiceTest, GetDlcsToUpdateTest) {
Install(kFirstDlc);
// Make second DLC marked as verified so we can get it in the list of DLCs
// needed to be updated.
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
const auto& dlcs = dlc_service_->GetDlcsToUpdate();
EXPECT_THAT(dlcs, ElementsAre(kFirstDlc, kSecondDlc));
}
TEST_F(DlcServiceTest, GetInstalledMimicDlcserviceRebootWithoutVerifiedStamp) {
Install(kFirstDlc);
const auto& dlcs_before = dlc_service_->GetInstalled();
EXPECT_THAT(dlcs_before, ElementsAre(kFirstDlc));
EXPECT_FALSE(
dlc_service_->GetDlc(kFirstDlc, &err_)->GetRoot().value().empty());
// Create |kSecondDlc| image, but not verified after device reboot.
SetUpDlcWithSlots(kSecondDlc);
const auto& dlcs_after = dlc_service_->GetInstalled();
EXPECT_THAT(dlcs_after, ElementsAre(kFirstDlc));
}
TEST_F(DlcServiceTest, UninstallTestForUserDlc) {
Install(kFirstDlc);
EXPECT_CALL(*mock_image_loader_proxy_ptr_, UnloadDlcImage(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(true), Return(true)));
// Uninstall should not set the DLC inactive.
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(false, kFirstDlc, _, _))
.Times(0);
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_CALL(*mock_metrics_, SendUninstallResult(UninstallResult::kSuccess));
auto dlc_prefs_path = prefs_path_.Append("dlc").Append(kFirstDlc);
EXPECT_TRUE(base::PathExists(dlc_prefs_path));
EXPECT_TRUE(dlc_service_->Uninstall(kFirstDlc, &err_));
EXPECT_TRUE(err_.get() == nullptr);
// Uninstall should not delete the DLC right away.
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kFirstDlc)));
EXPECT_TRUE(base::PathExists(dlc_prefs_path));
CheckDlcState(kFirstDlc, DlcState::NOT_INSTALLED);
// Uninstall should not change the verified status.
EXPECT_TRUE(dlc_service_->GetDlc(kFirstDlc, &err_)->IsVerified());
}
TEST_F(DlcServiceTest, PurgeTest) {
Install(kFirstDlc);
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(false, kFirstDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, UnloadDlcImage(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(true), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
auto dlc_prefs_path = prefs_path_.Append("dlc").Append(kFirstDlc);
EXPECT_TRUE(base::PathExists(dlc_prefs_path));
EXPECT_TRUE(dlc_service_->Purge(kFirstDlc, &err_));
EXPECT_FALSE(base::PathExists(JoinPaths(content_path_, kFirstDlc)));
EXPECT_FALSE(base::PathExists(dlc_prefs_path));
CheckDlcState(kFirstDlc, DlcState::NOT_INSTALLED);
}
TEST_F(DlcServiceTest, UninstallNotInstalledIsValid) {
EXPECT_CALL(*mock_image_loader_proxy_ptr_, UnloadDlcImage(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(true), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_CALL(*mock_metrics_, SendUninstallResult(UninstallResult::kSuccess));
EXPECT_TRUE(dlc_service_->Uninstall(kSecondDlc, &err_));
EXPECT_TRUE(err_.get() == nullptr);
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED);
}
TEST_F(DlcServiceTest, PurgeNotInstalledIsValid) {
EXPECT_CALL(*mock_image_loader_proxy_ptr_, UnloadDlcImage(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(true), Return(true)));
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(false, kSecondDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_TRUE(dlc_service_->Purge(kSecondDlc, &err_));
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED);
}
TEST_F(DlcServiceTest, PurgeFailToSetDlcActiveValueFalse) {
Install(kFirstDlc);
EXPECT_CALL(*mock_image_loader_proxy_ptr_, UnloadDlcImage(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(true), Return(true)));
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(false, kFirstDlc, _, _))
.WillOnce(Return(false));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_TRUE(dlc_service_->Purge(kFirstDlc, &err_));
EXPECT_FALSE(base::PathExists(JoinPaths(content_path_, kFirstDlc)));
CheckDlcState(kFirstDlc, DlcState::NOT_INSTALLED);
}
TEST_F(DlcServiceTest, UninstallInvalidDlcTest) {
const auto& id = "invalid-dlc-id";
EXPECT_CALL(*mock_metrics_,
SendUninstallResult(UninstallResult::kFailedInvalidDlc));
EXPECT_FALSE(dlc_service_->Uninstall(id, &err_));
EXPECT_EQ(err_->GetCode(), kErrorInvalidDlc);
}
TEST_F(DlcServiceTest, PurgeInvalidDlcTest) {
const auto& id = "invalid-dlc-id";
EXPECT_FALSE(dlc_service_->Purge(id, &err_));
EXPECT_EQ(err_->GetCode(), kErrorInvalidDlc);
}
TEST_F(DlcServiceTest, UninstallImageLoaderFailureTest) {
Install(kFirstDlc);
// |ImageLoader| not available.
EXPECT_CALL(*mock_image_loader_proxy_ptr_, UnloadDlcImage(_, _, _, _, _))
.WillOnce(Return(false));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_CALL(*mock_metrics_, SendUninstallResult(UninstallResult::kSuccess));
EXPECT_TRUE(dlc_service_->Uninstall(kFirstDlc, &err_));
EXPECT_TRUE(err_.get() == nullptr);
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kFirstDlc)));
CheckDlcState(kFirstDlc, DlcState::NOT_INSTALLED, kErrorInternal);
}
TEST_F(DlcServiceTest, PurgeUpdateEngineBusyFailureTest) {
Install(kFirstDlc);
StatusResult status_result;
status_result.set_current_operation(Operation::CHECKING_FOR_UPDATE);
SystemState::Get()->set_update_engine_status(status_result);
EXPECT_FALSE(dlc_service_->Purge(kFirstDlc, &err_));
CheckDlcState(kFirstDlc, DlcState::INSTALLED);
}
// Same behavior should be for purge.
TEST_F(DlcServiceTest, UninstallInstallingFails) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_CALL(*mock_metrics_,
SendUninstallResult(UninstallResult::kFailedUpdateEngineBusy));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
EXPECT_FALSE(dlc_service_->Uninstall(kSecondDlc, &err_));
EXPECT_EQ(err_->GetCode(), kErrorBusy);
}
TEST_F(DlcServiceTest, PurgeInstallingFails) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
EXPECT_FALSE(dlc_service_->Purge(kSecondDlc, &err_));
EXPECT_EQ(err_->GetCode(), kErrorBusy);
}
TEST_F(DlcServiceTest, UninstallInstallingButInstalledFails) {
Install(kFirstDlc);
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, UnloadDlcImage(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(true), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_, SendUninstallResult(UninstallResult::kSuccess));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
// |kFirstDlc| was installed, so there should be no problem uninstalling it
// |even if |kSecondDlc| is installing.
EXPECT_TRUE(dlc_service_->Uninstall(kFirstDlc, &err_));
EXPECT_TRUE(err_.get() == nullptr);
CheckDlcState(kFirstDlc, DlcState::NOT_INSTALLED);
}
TEST_F(DlcServiceTest, InstallInvalidDlcTest) {
const string id = "bad-dlc-id";
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedInvalidDlc));
EXPECT_FALSE(dlc_service_->Install(id, kDefaultOmahaUrl, &err_));
EXPECT_EQ(err_->GetCode(), kErrorInvalidDlc);
}
TEST_F(DlcServiceTest, InstallTest) {
Install(kFirstDlc);
SetMountPath(mount_path_.value());
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_THAT(dlc_service_->GetInstalled(), ElementsAre(kFirstDlc));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
// Should remain same as it's not stamped verified.
EXPECT_THAT(dlc_service_->GetInstalled(), ElementsAre(kFirstDlc));
// TODO(ahassani): Add more install process liked |InstallCompleted|, etc.
}
TEST_F(DlcServiceTest, InstallAlreadyInstalledValid) {
Install(kFirstDlc);
SetMountPath(mount_path_.value());
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, kFirstDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_,
LoadDlcImage(kFirstDlc, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessAlreadyInstalled));
EXPECT_TRUE(dlc_service_->Install(kFirstDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kFirstDlc)));
CheckDlcState(kFirstDlc, DlcState::INSTALLED);
}
TEST_F(DlcServiceTest, InstallAlreadyInstalledWhileAnotherInstalling) {
Install(kFirstDlc);
// Keep |kSecondDlc| installing.
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
// |kFirstDlc| can quickly be installed again even though another install is
// ongoing.
SetMountPath(mount_path_.value());
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, kFirstDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_,
LoadDlcImage(kFirstDlc, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessAlreadyInstalled));
EXPECT_TRUE(dlc_service_->Install(kFirstDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kFirstDlc, DlcState::INSTALLED);
}
TEST_F(DlcServiceTest, InstallCannotSetDlcActiveValue) {
SetMountPath(mount_path_.value());
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, kSecondDlc, _, _))
.WillOnce(Return(false));
EXPECT_CALL(*mock_image_loader_proxy_ptr_,
LoadDlcImage(kSecondDlc, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessNewInstall));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
StatusResult status_result;
status_result.set_is_install(true);
status_result.set_current_operation(Operation::IDLE);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
CheckDlcState(kSecondDlc, DlcState::INSTALLED);
}
TEST_F(DlcServiceTest, PeriodicInstallCheck) {
vector<StatusResult> status_list;
for (const auto& op :
{Operation::CHECKING_FOR_UPDATE, Operation::DOWNLOADING}) {
StatusResult status;
status.set_current_operation(op);
status.set_is_install(true);
status_list.push_back(status);
}
EXPECT_CALL(*mock_update_engine_proxy_ptr_, GetStatusAdvanced(_, _, _))
.WillOnce(DoAll(SetArgPointee<0>(status_list[0]), Return(true)))
.WillOnce(Return(false))
.WillOnce(DoAll(SetArgPointee<0>(status_list[1]), Return(true)));
// We need to make sure the state is intalling so, rescheduling periodic check
// happens.
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
// The first time it should not get the status because enough time hasn't
// passed yet.
dlc_service_->SchedulePeriodicInstallCheck();
EXPECT_EQ(SystemState::Get()->update_engine_status().current_operation(),
Operation::IDLE);
// Now advance clock and make sure that first time we do get status.
clock_.Advance(base::TimeDelta::FromSeconds(11));
loop_.RunOnce(false);
EXPECT_EQ(SystemState::Get()->update_engine_status().current_operation(),
Operation::CHECKING_FOR_UPDATE);
// Now advance the clock even more, this time fail the get status. The status
// should remain same.
clock_.Advance(base::TimeDelta::FromSeconds(11));
loop_.RunOnce(false);
EXPECT_EQ(SystemState::Get()->update_engine_status().current_operation(),
Operation::CHECKING_FOR_UPDATE);
// Now advance a little bit more to see we got the new status.
clock_.Advance(base::TimeDelta::FromSeconds(11));
loop_.RunOnce(false);
EXPECT_EQ(SystemState::Get()->update_engine_status().current_operation(),
Operation::DOWNLOADING);
}
TEST_F(DlcServiceTest, InstallSchedulesPeriodicInstallCheck) {
vector<StatusResult> status_list;
for (const auto& op : {Operation::CHECKING_FOR_UPDATE, Operation::IDLE}) {
StatusResult status;
status.set_current_operation(op);
status.set_is_install(true);
status_list.push_back(status);
}
EXPECT_CALL(*mock_update_engine_proxy_ptr_, GetStatusAdvanced(_, _, _))
.WillOnce(DoAll(SetArgPointee<0>(status_list[1]), Return(true)));
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedToVerifyImage));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
// The checking for update comes from signal.
dlc_service_->OnStatusUpdateAdvancedSignal(status_list[0]);
// Now advance clock and make sure that periodic install check is scheduled
// and eventually called.
clock_.Advance(base::TimeDelta::FromSeconds(11));
loop_.RunOnce(false);
// Since the update_engine status went back to IDLE, the install is complete
// and it should fail.
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED, kErrorInternal);
}
TEST_F(DlcServiceTest, InstallFailureCleansUp) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(false));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedUpdateEngineBusy));
EXPECT_FALSE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_EQ(err_->GetCode(), kErrorBusy);
EXPECT_FALSE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED, kErrorBusy);
}
TEST_F(DlcServiceTest, InstallUrlTest) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
AttemptInstall(kDefaultOmahaUrl, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_);
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
}
TEST_F(DlcServiceTest, InstallAlreadyInstalledThatGotUnmountedTest) {
Install(kFirstDlc);
// TOOD(ahassani): Move these checks to InstallTest.
CheckDlcState(kFirstDlc, DlcState::INSTALLED);
const auto mount_path_root = JoinPaths(mount_path_, "root");
EXPECT_TRUE(base::PathExists(mount_path_root));
EXPECT_TRUE(base::DeletePathRecursively(mount_path_root));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, LoadDlcImage(_, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, kFirstDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessAlreadyInstalled));
EXPECT_TRUE(dlc_service_->Install(kFirstDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kFirstDlc, DlcState::INSTALLED);
}
TEST_F(DlcServiceTest, InstallFailsToCreateDirectory) {
base::SetPosixFilePermissions(content_path_, 0444);
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(1);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedToCreateDirectory));
// Install will fail because DlcBase::CreateDlc() will fail to create
// directories inside |content_path_|, since the permissions don't allow
// writing into |content_path_|.
EXPECT_FALSE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_EQ(err_->GetCode(), kErrorInternal);
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED, kErrorInternal);
}
TEST_F(DlcServiceTest, OnStatusUpdateSignalDlcRootTest) {
Install(kFirstDlc);
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, kSecondDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, LoadDlcImage(_, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessNewInstall));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
StatusResult status_result;
status_result.set_current_operation(Operation::IDLE);
status_result.set_is_install(true);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLED);
const auto& dlcs_after = dlc_service_->GetInstalled();
EXPECT_THAT(dlcs_after, ElementsAre(kFirstDlc, kSecondDlc));
EXPECT_FALSE(
dlc_service_->GetDlc(kFirstDlc, &err_)->GetRoot().value().empty());
EXPECT_FALSE(
dlc_service_->GetDlc(kSecondDlc, &err_)->GetRoot().value().empty());
}
TEST_F(DlcServiceTest, OnStatusUpdateSignalNoRemountTest) {
Install(kFirstDlc);
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, kSecondDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, LoadDlcImage(_, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessNewInstall));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
StatusResult status_result;
status_result.set_current_operation(Operation::IDLE);
status_result.set_is_install(true);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
}
TEST_F(DlcServiceTest, OnStatusUpdateSignalTest) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, kSecondDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, LoadDlcImage(_, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessNewInstall));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
StatusResult status_result;
status_result.set_current_operation(Operation::IDLE);
status_result.set_is_install(true);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLED);
}
TEST_F(DlcServiceTest, MountFailureTest) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, LoadDlcImage(_, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(""), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedToMountImage));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
StatusResult status_result;
status_result.set_current_operation(Operation::IDLE);
status_result.set_is_install(true);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
EXPECT_FALSE(dlc_service_->GetDlc(kSecondDlc, &err_)->IsVerified());
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED, kErrorInternal);
}
TEST_F(DlcServiceTest, ReportingFailureCleanupTest) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedInstallInUpdateEngine));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
{
StatusResult status_result;
status_result.set_current_operation(Operation::REPORTING_ERROR_EVENT);
status_result.set_is_install(true);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
}
{
StatusResult status_result;
status_result.set_current_operation(Operation::IDLE);
status_result.set_is_install(false);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
}
EXPECT_FALSE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED, kErrorInternal);
}
TEST_F(DlcServiceTest, ReportingFailureSignalTest) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedInstallInUpdateEngine));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
{
StatusResult status_result;
status_result.set_current_operation(Operation::REPORTING_ERROR_EVENT);
status_result.set_is_install(true);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
}
{
StatusResult status_result;
status_result.set_current_operation(Operation::IDLE);
status_result.set_is_install(false);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
}
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED, kErrorInternal);
}
TEST_F(DlcServiceTest, ProbableUpdateEngineRestartCleanupTest) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedInstallInUpdateEngine));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
StatusResult status_result;
status_result.set_current_operation(Operation::IDLE);
status_result.set_is_install(false);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
EXPECT_FALSE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED, kErrorInternal);
}
TEST_F(DlcServiceTest, OnStatusUpdateSignalDownloadProgressTest) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_update_engine_proxy_ptr_,
SetDlcActiveValue(true, kSecondDlc, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, LoadDlcImage(_, _, _, _, _, _))
.WillRepeatedly(
DoAll(SetArgPointee<3>(mount_path_.value()), Return(true)));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kSuccessNewInstall));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
StatusResult status_result;
status_result.set_is_install(true);
const vector<Operation> install_operation_sequence = {
Operation::CHECKING_FOR_UPDATE, Operation::UPDATE_AVAILABLE,
Operation::FINALIZING};
for (const auto& op : install_operation_sequence) {
status_result.set_current_operation(op);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
}
status_result.set_current_operation(Operation::DOWNLOADING);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
status_result.set_current_operation(Operation::IDLE);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
CheckDlcState(kSecondDlc, DlcState::INSTALLED);
}
TEST_F(DlcServiceTest,
OnStatusUpdateSignalSubsequentialBadOrNonInstalledDlcsNonBlocking) {
for (int i = 0; i < 5; i++) {
EXPECT_CALL(*mock_update_engine_proxy_ptr_, AttemptInstall(_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(*mock_image_loader_proxy_ptr_, LoadDlcImage(_, _, _, _, _, _))
.WillOnce(Return(false));
EXPECT_CALL(mock_state_change_reporter_, DlcStateChanged(_)).Times(2);
EXPECT_CALL(*mock_metrics_,
SendInstallResult(InstallResult::kFailedToMountImage));
EXPECT_TRUE(dlc_service_->Install(kSecondDlc, kDefaultOmahaUrl, &err_));
CheckDlcState(kSecondDlc, DlcState::INSTALLING);
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
StatusResult status_result;
status_result.set_is_install(true);
status_result.set_current_operation(Operation::IDLE);
dlc_service_->OnStatusUpdateAdvancedSignal(status_result);
EXPECT_TRUE(base::PathExists(JoinPaths(content_path_, kSecondDlc)));
CheckDlcState(kSecondDlc, DlcState::NOT_INSTALLED, kErrorInternal);
}
}
TEST_F(DlcServiceTest, InstallCompleted) {
EXPECT_TRUE(dlc_service_->InstallCompleted({kSecondDlc}, &err_));
EXPECT_TRUE(dlc_service_->GetDlc(kSecondDlc, &err_)->IsVerified());
}
TEST_F(DlcServiceTest, UpdateCompleted) {
auto inactive_boot_slot = SystemState::Get()->inactive_boot_slot();
EXPECT_FALSE(
Prefs(DlcBase(kSecondDlc), inactive_boot_slot).Exists(kDlcPrefVerified));
EXPECT_TRUE(dlc_service_->UpdateCompleted({kFirstDlc, kSecondDlc}, &err_));
EXPECT_TRUE(
Prefs(DlcBase(kSecondDlc), inactive_boot_slot).Exists(kDlcPrefVerified));
}
} // namespace dlcservice