blob: ca5fe4acd8f93bd306eb8f0d78e22e442b70d198 [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/chrome_cleaner/engines/controllers/main_controller.h"
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/chrome_cleaner/components/component_api.h"
#include "chrome/chrome_cleaner/components/component_manager.h"
#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
#include "chrome/chrome_cleaner/ipc/chrome_prompt_ipc.h"
#include "chrome/chrome_cleaner/ipc/mock_chrome_prompt_ipc.h"
#include "chrome/chrome_cleaner/logging/logging_service_api.h"
#include "chrome/chrome_cleaner/logging/registry_logger.h"
#include "chrome/chrome_cleaner/os/file_remover_api.h"
#include "chrome/chrome_cleaner/os/rebooter_api.h"
#include "chrome/chrome_cleaner/scanner/signature_matcher_api.h"
#include "chrome/chrome_cleaner/test/test_component.h"
#include "chrome/chrome_cleaner/test/test_pup_data.h"
#include "chrome/chrome_cleaner/test/test_settings_util.h"
#include "chrome/chrome_cleaner/test/test_signature_matcher.h"
#include "chrome/chrome_cleaner/test/test_util.h"
#include "chrome/chrome_cleaner/ui/main_dialog_api.h"
#include "components/chrome_cleaner/test/test_name_helper.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
namespace chrome_cleaner {
namespace {
const UwSId kFakePupId = 0;
class TestEngineFacade : public EngineFacadeInterface {
public:
class TestCleaner : public Cleaner {
public:
TestCleaner()
: start_called_(false),
clean_result_(RESULT_CODE_SUCCESS),
stop_called_(false),
is_completely_done_(true),
get_cleanup_requirements_called_(false),
get_cleanup_requirements_return_value_(true),
post_reboot_clean_called_(false),
post_reboot_clean_return_value_(RESULT_CODE_SUCCESS) {}
// Cleaner.
void Start(const std::vector<UwSId>& pup_ids,
DoneCallback done_callback) override {
start_called_ = true;
pups_to_remove_ = pup_ids;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindOnce(std::move(done_callback), clean_result_),
delay_before_done_);
}
void StartPostReboot(const std::vector<UwSId>& pup_ids,
DoneCallback done_callback) override {
pups_to_remove_ = pup_ids;
post_reboot_clean_called_ = true;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(std::move(done_callback),
post_reboot_clean_return_value_),
delay_before_done_);
}
void Stop() override { stop_called_ = true; }
bool IsCompletelyDone() const override { return is_completely_done_; }
bool CanClean(const std::vector<UwSId>& pup_ids) override {
get_cleanup_requirements_called_ = true;
return get_cleanup_requirements_return_value_;
}
base::TimeDelta delay_before_done_;
bool start_called_;
ResultCode clean_result_;
bool stop_called_;
bool is_completely_done_;
bool get_cleanup_requirements_called_;
bool get_cleanup_requirements_return_value_;
bool post_reboot_clean_called_;
ResultCode post_reboot_clean_return_value_;
std::vector<UwSId> pups_to_remove_;
} test_cleaner_;
class TestScanner : public Scanner {
public:
TestScanner()
: scan_result_(RESULT_CODE_SUCCESS), is_completely_done_(true) {}
bool Start(const FoundUwSCallback& found_uws_callback,
DoneCallback done_callback) override {
for (UwSId pup_id : found_pups_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(found_uws_callback, pup_id));
}
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(std::move(done_callback), scan_result_, found_pups_),
delay_before_done_);
return true;
}
void Stop() override {}
bool IsCompletelyDone() const override { return is_completely_done_; }
std::vector<UwSId> found_pups_;
base::TimeDelta delay_before_done_;
ResultCode scan_result_;
bool is_completely_done_;
} test_scanner_;
Scanner* GetScanner() override { return &test_scanner_; }
Cleaner* GetCleaner() override { return &test_cleaner_; }
base::TimeDelta GetScanningWatchdogTimeout() const override {
return base::TimeDelta::FromMilliseconds(150);
}
};
class TestMainController : public MainController {
public:
explicit TestMainController(ChromePromptIPC* chrome_prompt_ipc)
: MainController(&test_rebooter_,
&test_registry_logger_,
chrome_prompt_ipc),
test_registry_logger_(RegistryLogger::Mode::NOOP_FOR_TESTING),
test_main_dialog_(this) {}
MainDialogAPI* main_dialog() override { return &test_main_dialog_; }
void set_scanning_watchdog_timeout(base::TimeDelta timeout) {
scanning_watchdog_timeout_ = timeout;
}
void set_user_response_watchdog_timeout(base::TimeDelta timeout) {
user_response_watchdog_timeout_ = timeout;
}
void set_user_response_delay(base::TimeDelta delay) {
test_main_dialog_.set_user_response_delay(delay);
}
void set_cleaning_watchdog_timeout(base::TimeDelta timeout) {
cleaning_watchdog_timeout_ = timeout;
}
// TODO(joenotcharles): See about testing log uploads in these tests.
RegistryLogger test_registry_logger_;
class TestMainDialog : public MainDialogAPI {
public:
explicit TestMainDialog(MainDialogDelegate* delegate)
: MainDialogAPI(delegate),
no_pups_found_called_(false),
confirm_cleanup_called_(false),
accept_cleanup_(true),
cleanup_done_called_(false) {}
bool Create() override { return true; }
void NoPUPsFound() override {
no_pups_found_called_ = true;
delegate()->OnClose();
}
void ConfirmCleanup(
const std::vector<UwSId>& found_pups,
const FilePathSet& files_to_remove,
const std::vector<base::string16>& registry_keys) override {
confirm_cleanup_called_ = true;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&MainDialogDelegate::AcceptedCleanup,
base::Unretained(delegate()), accept_cleanup_),
user_response_delay_);
}
void CleanupDone(ResultCode cleanup_result) override {
cleanup_done_called_ = true;
delegate()->OnClose();
}
void Close() override { delegate()->OnClose(); }
void DisableExtensions(const std::vector<base::string16>& extensions,
base::OnceCallback<void(bool)> on_disable) override {
std::move(on_disable).Run(true);
}
void set_user_response_delay(base::TimeDelta delay) {
user_response_delay_ = delay;
}
bool no_pups_found_called_;
bool confirm_cleanup_called_;
bool accept_cleanup_;
bool cleanup_done_called_;
base::TimeDelta user_response_delay_;
} test_main_dialog_;
class TestRebooter : public RebooterAPI {
public:
TestRebooter() {}
void AppendPostRebootSwitch(const std::string& unused) override {}
void AppendPostRebootSwitchASCII(const std::string& unused1,
const std::string& unused2) override {}
bool RegisterPostRebootRun(const base::CommandLine* current_command_line,
const std::string& cleanup_id,
ExecutionMode execution_mode,
bool logs_uploads_allowed) override {
post_reboot_registered_ = true;
return true;
}
void UnregisterPostRebootRun() override { post_reboot_registered_ = false; }
bool post_reboot_registered_ = false;
} test_rebooter_;
};
class MainControllerTest : public testing::TestWithParam<ExecutionMode> {
public:
MainControllerTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
TestMainController* test_main_controller() {
return test_main_controller_.get();
}
void SetUp() override {
execution_mode_ = GetParam();
EXPECT_CALL(mock_settings_, execution_mode())
.WillRepeatedly(testing::Return(GetParam()));
EXPECT_CALL(mock_settings_, logs_upload_allowed())
.WillRepeatedly(testing::Return(false));
Settings::SetInstanceForTesting(&mock_settings_);
if (scanning_mode())
EXPECT_CALL(mock_chrome_prompt_ipc_, Initialize(_));
test_main_controller_ = std::make_unique<TestMainController>(
scanning_mode() ? &mock_chrome_prompt_ipc_ : nullptr);
test_main_controller_->SetEngineFacade(&test_engine_facade_);
// There is a ScopedLoggingService over this scope. To avoid keeping
// any global logging state information, we close the current session
// and initialize a new one.
LoggingServiceAPI::GetInstance()->Terminate();
LoggingServiceAPI::GetInstance()->Initialize(
&test_main_controller_->test_registry_logger_);
}
void TearDown() override {
// There is a ScopedLoggingService over this scope. The temporary session
// is closed and a new one is started.
LoggingServiceAPI::GetInstance()->Terminate();
LoggingServiceAPI::GetInstance()->Initialize(nullptr);
test_main_controller_.reset();
Settings::SetInstanceForTesting(nullptr);
}
TestEngineFacade::TestScanner* test_scanner() {
return &test_engine_facade_.test_scanner_;
}
TestEngineFacade::TestCleaner* test_cleaner() {
return &test_engine_facade_.test_cleaner_;
}
protected:
bool scanning_mode() { return execution_mode_ == ExecutionMode::kScanning; }
bool cleanup_mode() { return execution_mode_ == ExecutionMode::kCleanup; }
MockSettings mock_settings_;
// Use StrictMock to be sure no unexpected IPC messages are sent.
testing::StrictMock<MockChromePromptIPC> mock_chrome_prompt_ipc_;
private:
TestEngineFacade test_engine_facade_;
std::unique_ptr<TestMainController> test_main_controller_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
ExecutionMode execution_mode_;
};
class SimpleTestPUPData : public TestPUPData {
public:
SimpleTestPUPData(UwSId pup_id, PUPData::Flags flags) {
AddPUP(pup_id, flags, nullptr, PUPData::kMaxFilesToRemoveSmallUwS);
// For removable UwS, include an active file so there's something to delete.
if (flags & PUPData::FLAGS_ACTION_REMOVE) {
constexpr wchar_t kActiveFileName[] = L"C:\\active_file_name.bin";
AddDiskFootprint(pup_id, CSIDL_STARTUP, kActiveFileName,
PUPData::DISK_MATCH_ANY_FILE);
PUPData::PUP* pup = PUPData::GetPUP(pup_id);
DCHECK(pup);
pup->AddDiskFootprint(base::FilePath(kActiveFileName));
pup->expanded_registry_footprints.push_back(PUPData::RegistryFootprint(
RegKeyPath(HKEY_USERS, L"Software\\bad-software\\bad-key"),
base::string16(), base::string16(), REGISTRY_VALUE_MATCH_KEY));
}
}
};
ExecutionMode kExecutionModes[] = {ExecutionMode::kScanning,
ExecutionMode::kCleanup};
} // namespace
TEST_P(MainControllerTest, PostRebootValidateCleanup_ScanSuccessNothingFound) {
ScopedIsPostReboot is_post_reboot;
test_scanner()->scan_result_ = RESULT_CODE_SUCCESS;
EXPECT_EQ(RESULT_CODE_POST_REBOOT_SUCCESS,
test_main_controller()->ValidateCleanup());
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_FALSE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
}
TEST_P(MainControllerTest, PostRebootValidateCleanup_ScanNoPupsFound) {
ScopedIsPostReboot is_post_reboot;
test_scanner()->scan_result_ = RESULT_CODE_NO_PUPS_FOUND;
EXPECT_EQ(RESULT_CODE_POST_REBOOT_SUCCESS,
test_main_controller()->ValidateCleanup());
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_FALSE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
}
TEST_P(MainControllerTest, PostRebootValidateCleanup_ScanReportOnlyFound) {
ScopedIsPostReboot is_post_reboot;
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_NONE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_scanner()->scan_result_ = RESULT_CODE_REPORT_ONLY_PUPS_FOUND;
EXPECT_EQ(RESULT_CODE_POST_REBOOT_SUCCESS,
test_main_controller()->ValidateCleanup());
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
}
TEST_P(MainControllerTest, PostRebootValidateCleanup_RemainingSuccess) {
ScopedIsPostReboot is_post_reboot;
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_cleaner()->post_reboot_clean_return_value_ = RESULT_CODE_SUCCESS;
EXPECT_EQ(RESULT_CODE_POST_REBOOT_SUCCESS,
test_main_controller()->ValidateCleanup());
EXPECT_TRUE(test_cleaner()->post_reboot_clean_called_);
EXPECT_THAT(test_cleaner()->pups_to_remove_,
testing::ElementsAre(kFakePupId));
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_FALSE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
}
TEST_P(MainControllerTest, PostRebootValidateCleanup_RemainingFailed) {
ScopedIsPostReboot is_post_reboot;
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_cleaner()->post_reboot_clean_return_value_ = RESULT_CODE_FAILED;
EXPECT_EQ(RESULT_CODE_POST_CLEANUP_VALIDATION_FAILED,
test_main_controller()->ValidateCleanup());
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_TRUE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
}
TEST_P(MainControllerTest, PostRebootValidateCleanup_EngineFailedOnScan) {
ScopedIsPostReboot is_post_reboot;
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_scanner()->scan_result_ = RESULT_CODE_SCANNING_ENGINE_ERROR;
EXPECT_EQ(RESULT_CODE_POST_CLEANUP_VALIDATION_FAILED,
test_main_controller()->ValidateCleanup());
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
}
TEST_P(MainControllerTest, PostRebootValidateCleanup_EngineFailedInCleanup) {
ScopedIsPostReboot is_post_reboot;
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_cleaner()->post_reboot_clean_return_value_ =
RESULT_CODE_SCANNING_ENGINE_ERROR;
EXPECT_EQ(RESULT_CODE_POST_CLEANUP_VALIDATION_FAILED,
test_main_controller()->ValidateCleanup());
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_TRUE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
}
TEST_P(MainControllerTest, PostRebootValidateCleanup_RequestedAnotherReboot) {
ScopedIsPostReboot is_post_reboot;
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_cleaner()->post_reboot_clean_return_value_ = RESULT_CODE_PENDING_REBOOT;
EXPECT_EQ(RESULT_CODE_POST_CLEANUP_VALIDATION_FAILED,
test_main_controller()->ValidateCleanup());
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_TRUE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
}
TEST_P(MainControllerTest, ScanningNothingSuccess) {
ResultCode result = test_main_controller()->ScanAndClean();
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_TRUE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
EXPECT_EQ(RESULT_CODE_NO_PUPS_FOUND, result);
}
TEST_P(MainControllerTest, ScanningReportOnlySuccess) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_NONE);
test_scanner()->found_pups_.push_back(kFakePupId);
ResultCode result = test_main_controller()->ScanAndClean();
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_TRUE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
EXPECT_EQ(RESULT_CODE_REPORT_ONLY_PUPS_FOUND, result);
}
TEST_P(MainControllerTest, ScanningEngineFailed) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_scanner()->scan_result_ = RESULT_CODE_SCANNING_ENGINE_ERROR;
ResultCode result = test_main_controller()->ScanAndClean();
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_TRUE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_EQ(RESULT_CODE_SCANNING_ENGINE_ERROR, result);
}
TEST_P(MainControllerTest, GetCleanupRequirementsFailed) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_cleaner()->get_cleanup_requirements_return_value_ = false;
ResultCode result = test_main_controller()->ScanAndClean();
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_TRUE(test_cleaner()->get_cleanup_requirements_called_);
EXPECT_TRUE(test_main_controller()->test_main_dialog_.no_pups_found_called_);
EXPECT_EQ(RESULT_CODE_CLEANUP_REQUIREMENTS_FAILED, result);
}
TEST_P(MainControllerTest, CleanupDenied) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_main_controller()->test_main_dialog_.accept_cleanup_ = false;
ResultCode result = test_main_controller()->ScanAndClean();
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_FALSE(test_cleaner()->start_called_);
EXPECT_TRUE(test_cleaner()->get_cleanup_requirements_called_);
EXPECT_TRUE(
test_main_controller()->test_main_dialog_.confirm_cleanup_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
EXPECT_EQ(RESULT_CODE_CLEANUP_PROMPT_DENIED, result);
}
TEST_P(MainControllerTest, CleanupAcceptedAndSucceeded) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
ResultCode result = test_main_controller()->ScanAndClean();
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_TRUE(test_cleaner()->get_cleanup_requirements_called_);
EXPECT_TRUE(
test_main_controller()->test_main_dialog_.confirm_cleanup_called_);
EXPECT_TRUE(test_cleaner()->start_called_);
EXPECT_THAT(test_cleaner()->pups_to_remove_,
testing::ElementsAre(kFakePupId));
EXPECT_TRUE(test_main_controller()->test_main_dialog_.cleanup_done_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
EXPECT_EQ(RESULT_CODE_SUCCESS, result);
}
TEST_P(MainControllerTest, CleanupAcceptedButFailed) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_cleaner()->clean_result_ = RESULT_CODE_FAILED;
ResultCode result = test_main_controller()->ScanAndClean();
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_TRUE(test_cleaner()->get_cleanup_requirements_called_);
EXPECT_TRUE(
test_main_controller()->test_main_dialog_.confirm_cleanup_called_);
EXPECT_TRUE(test_cleaner()->start_called_);
EXPECT_TRUE(test_main_controller()->test_main_dialog_.cleanup_done_called_);
EXPECT_FALSE(test_main_controller()->test_rebooter_.post_reboot_registered_);
EXPECT_EQ(RESULT_CODE_FAILED, result);
}
TEST_P(MainControllerTest, CleanupEngineFailed) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_cleaner()->clean_result_ = RESULT_CODE_SCANNING_ENGINE_ERROR;
ResultCode result = test_main_controller()->ScanAndClean();
EXPECT_FALSE(test_cleaner()->post_reboot_clean_called_);
EXPECT_TRUE(test_cleaner()->get_cleanup_requirements_called_);
EXPECT_TRUE(
test_main_controller()->test_main_dialog_.confirm_cleanup_called_);
EXPECT_TRUE(test_cleaner()->start_called_);
EXPECT_TRUE(test_main_controller()->test_main_dialog_.cleanup_done_called_);
EXPECT_EQ(RESULT_CODE_SCANNING_ENGINE_ERROR, result);
}
TEST_P(MainControllerTest, ComponentsWhenPUPFound) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
TestComponent::Calls calls = {};
test_main_controller()->AddComponent(std::make_unique<TestComponent>(&calls));
test_main_controller()->ScanAndClean();
EXPECT_TRUE(calls.pre_scan);
EXPECT_TRUE(calls.post_scan);
EXPECT_THAT(calls.post_scan_found_pups, testing::ElementsAre(kFakePupId));
EXPECT_TRUE(calls.pre_cleanup);
EXPECT_TRUE(calls.post_cleanup);
EXPECT_FALSE(calls.post_validation);
EXPECT_TRUE(calls.on_close);
}
TEST_P(MainControllerTest, ComponentsWhenNoPUPFound) {
TestComponent::Calls calls = {};
test_main_controller()->AddComponent(std::make_unique<TestComponent>(&calls));
test_main_controller()->ScanAndClean();
EXPECT_TRUE(calls.pre_scan);
EXPECT_TRUE(calls.post_scan);
EXPECT_TRUE(calls.post_scan_found_pups.empty());
EXPECT_FALSE(calls.pre_cleanup);
EXPECT_FALSE(calls.post_cleanup);
EXPECT_FALSE(calls.post_validation);
EXPECT_TRUE(calls.on_close);
}
TEST_P(MainControllerTest, ComponentsOnValidateCleanup) {
ScopedIsPostReboot is_post_reboot;
TestComponent::Calls calls = {};
test_main_controller()->AddComponent(std::make_unique<TestComponent>(&calls));
test_main_controller()->ValidateCleanup();
EXPECT_FALSE(calls.pre_scan);
EXPECT_FALSE(calls.post_scan);
EXPECT_TRUE(calls.post_scan_found_pups.empty());
EXPECT_FALSE(calls.pre_cleanup);
EXPECT_FALSE(calls.post_cleanup);
EXPECT_TRUE(calls.post_validation);
EXPECT_TRUE(calls.on_close);
}
// TODO(joenotcharles): add test to make sure that the waits in the
// SafeBrowsingReporter code are only canceled when an explicit reboot is
// requested.
INSTANTIATE_TEST_SUITE_P(All,
MainControllerTest,
testing::ValuesIn(kExecutionModes),
GetParamNameForTest());
class MainControllerWatchdogTest : public MainControllerTest {
public:
void ExpectSuccess(ResultCode expected_result) {
EXPECT_EQ(expected_result, test_main_controller()->ScanAndClean());
}
void ExpectDeath(int expected_exit_code) {
EXPECT_EXIT({ test_main_controller()->ScanAndClean(); },
::testing::ExitedWithCode(expected_exit_code), "");
}
};
TEST_P(MainControllerWatchdogTest, Success) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_main_controller()->set_scanning_watchdog_timeout(
base::TimeDelta::FromMilliseconds(500));
test_scanner()->delay_before_done_ = base::TimeDelta::FromMilliseconds(50);
test_main_controller()->set_user_response_watchdog_timeout(
base::TimeDelta::FromMilliseconds(500));
test_main_controller()->set_user_response_delay(
base::TimeDelta::FromMilliseconds(50));
test_main_controller()->set_cleaning_watchdog_timeout(
base::TimeDelta::FromMilliseconds(500));
test_cleaner()->delay_before_done_ = base::TimeDelta::FromMilliseconds(50);
test_scanner()->found_pups_.push_back(kFakePupId);
ExpectSuccess(RESULT_CODE_SUCCESS);
}
TEST_P(MainControllerWatchdogTest, ScannerHangsNoRemovableUwS) {
SimpleTestPUPData test_pup_data(kFakePupId, 0);
test_scanner()->found_pups_.push_back(kFakePupId);
test_scanner()->delay_before_done_ = base::TimeDelta::FromMilliseconds(300);
// Note: There is a single timeout for the process running in cleanup
// execution mode, that will include both the scanner and the cleaner steps.
// This test simulates the scanner hanging in that scenario to make sure that
// the watchdog timeout is triggered.
test_main_controller()->set_cleaning_watchdog_timeout(
base::TimeDelta::FromMilliseconds(200));
if (scanning_mode()) {
ExpectDeath(RESULT_CODE_WATCHDOG_TIMEOUT_WITHOUT_REMOVABLE_UWS);
} else if (cleanup_mode()) {
ExpectDeath(RESULT_CODE_WATCHDOG_TIMEOUT_CLEANING);
} else {
ExpectSuccess(RESULT_CODE_REPORT_ONLY_PUPS_FOUND);
}
}
TEST_P(MainControllerWatchdogTest, ScannerHangsWithRemovableUwS) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_scanner()->delay_before_done_ = base::TimeDelta::FromMilliseconds(300);
// Note: There is a single timeout for the process running in cleanup
// execution mode, that will include both the scanner and the cleaner steps.
// This test simulates the scanner hanging in that scenario, to make sure that
// the watchdog timeout is triggered.
test_main_controller()->set_cleaning_watchdog_timeout(
base::TimeDelta::FromMilliseconds(200));
if (scanning_mode()) {
ExpectDeath(RESULT_CODE_WATCHDOG_TIMEOUT_WITH_REMOVABLE_UWS);
} else if (cleanup_mode()) {
ExpectDeath(RESULT_CODE_WATCHDOG_TIMEOUT_CLEANING);
} else {
ExpectSuccess(RESULT_CODE_SUCCESS);
}
}
TEST_P(MainControllerWatchdogTest, ScannerHangsWaitingForUserResponse) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_main_controller()->set_user_response_watchdog_timeout(
base::TimeDelta::FromMilliseconds(50));
test_main_controller()->set_user_response_delay(
base::TimeDelta::FromMilliseconds(500));
// Note: There is a single timeout for the process running in cleanup
// execution mode, that will include both the scanner and the cleaner steps.
// Even though the process in cleanup execution mode doesn't wait for a user
// response, we still want to test that scenario in case requirements change
// in the future.
test_main_controller()->set_cleaning_watchdog_timeout(
base::TimeDelta::FromMilliseconds(200));
// Only scanning mode should set a user-response watchdog.
if (scanning_mode()) {
ExpectDeath(RESULT_CODE_WATCHDOG_TIMEOUT_WAITING_FOR_PROMPT_RESPONSE);
} else if (cleanup_mode()) {
ExpectDeath(RESULT_CODE_WATCHDOG_TIMEOUT_CLEANING);
} else {
ExpectSuccess(RESULT_CODE_SUCCESS);
}
}
TEST_P(MainControllerWatchdogTest, CleanerHangs) {
SimpleTestPUPData test_pup_data(kFakePupId, PUPData::FLAGS_ACTION_REMOVE);
test_scanner()->found_pups_.push_back(kFakePupId);
test_main_controller()->set_cleaning_watchdog_timeout(
base::TimeDelta::FromMilliseconds(50));
test_cleaner()->delay_before_done_ = base::TimeDelta::FromMilliseconds(500);
if (cleanup_mode()) {
ExpectDeath(RESULT_CODE_WATCHDOG_TIMEOUT_CLEANING);
} else {
ExpectSuccess(RESULT_CODE_SUCCESS);
}
}
INSTANTIATE_TEST_SUITE_P(All,
MainControllerWatchdogTest,
testing::ValuesIn(kExecutionModes),
GetParamNameForTest());
} // namespace chrome_cleaner