blob: 60a093892e4897edffdd33d0e30e171eb2fb06b1 [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 <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "chrome/chrome_cleaner/engines/broker/engine_client_mock.h"
#include "chrome/chrome_cleaner/engines/common/engine_result_codes.h"
#include "chrome/chrome_cleaner/engines/controllers/engine_cleaner.h"
#include "chrome/chrome_cleaner/logging/logging_service_api.h"
#include "chrome/chrome_cleaner/logging/mock_logging_service.h"
#include "chrome/chrome_cleaner/logging/proto/removal_status.pb.h"
#include "chrome/chrome_cleaner/os/file_removal_status_updater.h"
#include "chrome/chrome_cleaner/pup_data/pup_data.h"
#include "chrome/chrome_cleaner/pup_data/test_uws.h"
#include "chrome/chrome_cleaner/settings/settings.h"
#include "chrome/chrome_cleaner/test/test_file_util.h"
#include "chrome/chrome_cleaner/test/test_pup_data.h"
#include "chrome/chrome_cleaner/test/test_util.h"
#include "chrome/chrome_cleaner/test/test_uws_catalog.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chrome_cleaner {
namespace {
using testing::_;
using testing::DoAll;
using testing::Invoke;
using testing::Return;
using testing::WithArg;
unsigned int kScanOnlyUwS = kGoogleTestAUwSID;
unsigned int kRemovableUwS = kGoogleTestBUwSID;
MATCHER_P(EqPathCaseInsensitive, path, "") {
return base::EqualsCaseInsensitiveASCII(path.value(), arg.value());
}
class EngineCleanerTest : public testing::Test {
public:
EngineCleanerTest() {
test_pup_data_.Reset({&TestUwSCatalog::GetInstance()});
}
void SetUp() override {
LoggingServiceAPI::SetInstanceForTesting(&mock_logging_service_);
engine_cleaner_ =
std::make_unique<EngineCleaner>(mock_engine_client_.get());
ASSERT_TRUE(PUPData::IsKnownPUP(kScanOnlyUwS));
ASSERT_FALSE(PUPData::IsConfirmedUwS(kScanOnlyUwS));
ASSERT_FALSE(PUPData::IsRemovable(kScanOnlyUwS));
ASSERT_TRUE(PUPData::IsKnownPUP(kRemovableUwS));
ASSERT_TRUE(PUPData::IsConfirmedUwS(kRemovableUwS));
ASSERT_TRUE(PUPData::IsRemovable(kRemovableUwS));
}
void TearDown() override {
LoggingServiceAPI::SetInstanceForTesting(nullptr);
Settings::SetInstanceForTesting(nullptr);
}
void RunCleanup(const std::vector<UwSId>& pup_ids) {
engine_cleaner_->Start(pup_ids, base::BindOnce(&EngineCleanerTest::Done,
base::Unretained(this)));
while (!engine_cleaner_->IsCompletelyDone())
base::RunLoop().RunUntilIdle();
}
void RunCleanupAndStop(const std::vector<UwSId>& pup_ids) {
engine_cleaner_->Start(pup_ids, base::BindOnce(&EngineCleanerTest::Done,
base::Unretained(this)));
engine_cleaner_->Stop();
while (!engine_cleaner_->IsCompletelyDone())
base::RunLoop().RunUntilIdle();
}
void Done(ResultCode status) { done_status_ = status; }
protected:
scoped_refptr<StrictMockEngineClient> mock_engine_client_{
base::MakeRefCounted<StrictMockEngineClient>()};
MockLoggingService mock_logging_service_;
TestPUPData test_pup_data_;
std::unique_ptr<EngineCleaner> engine_cleaner_;
base::test::SingleThreadTaskEnvironment task_environment_;
ResultCode done_status_ = RESULT_CODE_INVALID;
};
// Functor to call DoneCallback with predefined arguments.
struct ReportDone {
explicit ReportDone(uint32_t status) : status_(status) {}
void operator()(EngineClient::DoneCallback* done_callback) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(*done_callback), status_));
}
uint32_t status_;
};
} // namespace
TEST_F(EngineCleanerTest, Start_Failure) {
EXPECT_CALL(*mock_engine_client_, MockedStartCleanup(_, _))
.WillOnce(Return(EngineResultCode::kEngineInternal));
EXPECT_CALL(*mock_engine_client_, needs_reboot()).WillOnce(Return(false));
RunCleanup({kRemovableUwS});
EXPECT_EQ(RESULT_CODE_FAILED, done_status_);
}
TEST_F(EngineCleanerTest, Stop) {
EXPECT_CALL(*mock_engine_client_, MockedStartCleanup(_, _))
.WillOnce(Return(EngineResultCode::kSuccess));
EXPECT_CALL(*mock_engine_client_, needs_reboot()).WillOnce(Return(false));
RunCleanupAndStop({kRemovableUwS});
EXPECT_EQ(RESULT_CODE_CANCELED, done_status_);
}
TEST_F(EngineCleanerTest, Clean_Success) {
std::vector<UwSId> saved_enabled_uws;
auto save_enabled_uws =
[&saved_enabled_uws](const std::vector<UwSId>& enabled_uws) {
saved_enabled_uws = enabled_uws;
};
EXPECT_CALL(*mock_engine_client_, MockedStartCleanup(_, _))
.WillOnce(
DoAll(WithArg<0>(Invoke(save_enabled_uws)),
WithArg<1>(Invoke(ReportDone(EngineResultCode::kSuccess))),
Return(EngineResultCode::kSuccess)));
EXPECT_CALL(*mock_engine_client_, needs_reboot()).WillOnce(Return(false));
EXPECT_CALL(mock_logging_service_, AllExpectedRemovalsConfirmed())
.WillOnce(Return(true));
RunCleanup({kRemovableUwS});
EXPECT_THAT(saved_enabled_uws,
::testing::UnorderedElementsAre(kRemovableUwS));
EXPECT_EQ(RESULT_CODE_SUCCESS, done_status_);
}
TEST_F(EngineCleanerTest, Clean_NotAllDetectedFilesRemoved) {
EXPECT_CALL(*mock_engine_client_, MockedStartCleanup(_, _))
.WillOnce(
DoAll(WithArg<1>(Invoke(ReportDone(EngineResultCode::kSuccess))),
Return(EngineResultCode::kSuccess)));
EXPECT_CALL(*mock_engine_client_, needs_reboot()).WillOnce(Return(false));
EXPECT_CALL(mock_logging_service_, AllExpectedRemovalsConfirmed())
.WillOnce(Return(false));
RunCleanup({kRemovableUwS});
EXPECT_EQ(RESULT_CODE_FAILED, done_status_);
}
TEST_F(EngineCleanerTest, Reboot_NotAllDetectedFilesRemoved) {
EXPECT_CALL(*mock_engine_client_, MockedStartCleanup(_, _))
.WillOnce(
DoAll(WithArg<1>(Invoke(ReportDone(EngineResultCode::kSuccess))),
Return(EngineResultCode::kSuccess)));
EXPECT_CALL(*mock_engine_client_, needs_reboot()).WillOnce(Return(true));
EXPECT_CALL(mock_logging_service_, AllExpectedRemovalsConfirmed())
.WillOnce(Return(false));
RunCleanup({kRemovableUwS});
EXPECT_EQ(RESULT_CODE_PENDING_REBOOT, done_status_);
}
TEST_F(EngineCleanerTest, UpdatesRemovalStatusForMissingMatchedFiles) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath missing_file = temp_dir.GetPath().Append(L"missing.exe");
base::FilePath existing_file = temp_dir.GetPath().Append(L"existing.exe");
ASSERT_TRUE(CreateEmptyFile(existing_file));
PUPData::PUP* removable_pup = PUPData::GetPUP(kRemovableUwS);
removable_pup->AddDiskFootprint(missing_file);
removable_pup->AddDiskFootprint(existing_file);
FileRemovalStatusUpdater* removal_status_updater =
FileRemovalStatusUpdater::GetInstance();
removal_status_updater->Clear();
EXPECT_CALL(*mock_engine_client_, MockedStartCleanup(_, _))
.WillOnce(
DoAll(WithArg<1>(Invoke(ReportDone(EngineResultCode::kSuccess))),
Return(EngineResultCode::kSuccess)));
EXPECT_CALL(*mock_engine_client_, needs_reboot()).WillOnce(Return(false));
RunCleanup({kRemovableUwS});
EXPECT_EQ(removal_status_updater->GetRemovalStatus(missing_file),
REMOVAL_STATUS_NOT_FOUND);
EXPECT_EQ(removal_status_updater->GetRemovalStatus(existing_file),
REMOVAL_STATUS_UNSPECIFIED);
}
TEST_F(EngineCleanerTest, Clean_Failure) {
EXPECT_CALL(*mock_engine_client_, MockedStartCleanup(_, _))
.WillOnce(DoAll(
WithArg<1>(Invoke(ReportDone(EngineResultCode::kSandboxUnavailable))),
Return(EngineResultCode::kSuccess)));
EXPECT_CALL(*mock_engine_client_, needs_reboot()).WillOnce(Return(false));
RunCleanup({kRemovableUwS});
EXPECT_EQ(RESULT_CODE_FAILED, done_status_);
}
} // namespace chrome_cleaner