blob: 71ff18ac11ee2f72a5d3220e8c17322018a170ca [file] [log] [blame]
// Copyright 2018 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/components/recovery_component.h"
#include <memory>
#include <string>
#include <utility>
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "chrome/chrome_cleaner/http/mock_http_agent_factory.h"
#include "chrome/chrome_cleaner/test/test_pup_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chrome_cleaner {
namespace {
const UwSId kRemovableUwSId = 42;
const UwSId kReportOnlyUwSId = 21;
} // namespace
class TestRecoveryComponent : public RecoveryComponent {
public:
TestRecoveryComponent() = default;
using RecoveryComponent::WaitForDoneExpandingCrxForTest;
bool run_called() const { return run_called_; }
bool unpack_component_called() const { return unpack_component_called_; }
const std::string& crx_file_contents() const { return crx_file_contents_; }
protected:
// RecoveryComponent.
void Run() override { run_called_ = true; }
void UnpackComponent(const base::FilePath& crx_file) override {
unpack_component_called_ = true;
if (base::PathExists(crx_file)) {
ASSERT_TRUE(base::ReadFileToString(crx_file, &crx_file_contents_));
}
}
private:
bool run_called_{false};
bool unpack_component_called_{false};
std::string crx_file_contents_;
};
class RecoveryComponentTest : public testing::Test {
public:
void SetUp() override {
RecoveryComponent::SetHttpAgentFactoryForTesting(factory_.get());
}
void TearDown() override {
RecoveryComponent::SetHttpAgentFactoryForTesting(nullptr);
}
protected:
RecoveryComponentTest() : task_runner_(new base::TestSimpleTaskRunner) {}
// A message loop is needed for the current task runner to be available.
base::MessageLoopForUI ui_message_loop_;
// The recover component under test. This declaration must be after the
// |ui_message_loop_| because the |RecoveryComponent| constructor needs
// a reference to the current run loop.
TestRecoveryComponent recovery_component_;
// A task runner and a URL fetcher factory are necessary to test URL requests.
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
MockHttpAgentConfig config_;
std::unique_ptr<HttpAgentFactory> factory_{
std::make_unique<MockHttpAgentFactory>(&config_)};
};
TEST_F(RecoveryComponentTest, Success) {
MockHttpAgentConfig::Calls calls(HttpStatus::kOk);
config_.AddCalls(calls);
recovery_component_.PreScan();
recovery_component_.WaitForDoneExpandingCrxForTest();
EXPECT_TRUE(recovery_component_.unpack_component_called());
}
TEST_F(RecoveryComponentTest, Failure) {
MockHttpAgentConfig::Calls calls(HttpStatus::kOk);
calls.request_succeeds = false;
config_.AddCalls(calls);
recovery_component_.PreScan();
recovery_component_.WaitForDoneExpandingCrxForTest();
EXPECT_FALSE(recovery_component_.unpack_component_called());
}
TEST_F(RecoveryComponentTest, CrxDataSavedToDisk) {
const std::string test_data = "test data";
MockHttpAgentConfig::Calls calls(HttpStatus::kOk);
calls.read_data_result = test_data;
config_.AddCalls(calls);
recovery_component_.PreScan();
recovery_component_.WaitForDoneExpandingCrxForTest();
EXPECT_TRUE(recovery_component_.unpack_component_called());
EXPECT_EQ(test_data, recovery_component_.crx_file_contents());
}
TEST_F(RecoveryComponentTest, CrxDataPartiallySavedToDisk) {
// Ensure the buffer is large enough, so a second buffer needs to be read.
const std::string test_data =
std::string(RecoveryComponent::kReadDataFromResponseBufferSize + 1, 'x');
MockHttpAgentConfig::Calls calls(HttpStatus::kOk);
calls.read_data_result = test_data;
calls.read_data_success_sequence.push_back(true);
calls.read_data_success_sequence.push_back(false);
config_.AddCalls(calls);
recovery_component_.PreScan();
recovery_component_.WaitForDoneExpandingCrxForTest();
EXPECT_FALSE(recovery_component_.unpack_component_called());
}
TEST_F(RecoveryComponentTest, RunCalledForRemovablePUP) {
const UwSId kRemovableUwSId = 42;
std::vector<UwSId> found_pups;
TestPUPData test_pup_data;
// When a removable PUP was found, the post scan shouldn't run, it should
// wait for the post-cleanup.
test_pup_data.AddPUP(kRemovableUwSId, PUPData::FLAGS_ACTION_REMOVE, nullptr,
PUPData::kMaxFilesToRemoveSmallUwS);
found_pups.push_back(kRemovableUwSId);
recovery_component_.PostScan(found_pups);
EXPECT_FALSE(recovery_component_.run_called());
recovery_component_.PostCleanup(RESULT_CODE_SUCCESS, nullptr);
EXPECT_TRUE(recovery_component_.run_called());
}
TEST_F(RecoveryComponentTest, RunCalledForNoPUPs) {
std::vector<UwSId> found_pups;
TestPUPData test_pup_data;
// When no PUPs are found, the post scan should run, but not the post-cleanup.
found_pups.clear();
recovery_component_.PostScan(found_pups);
EXPECT_TRUE(recovery_component_.run_called());
}
TEST_F(RecoveryComponentTest, RunCalledForReportOnlyUwS) {
std::vector<UwSId> found_pups;
TestPUPData test_pup_data;
// When only report only PUPs are found, the post scan should run, but not the
// post-cleanup.
test_pup_data.AddPUP(kReportOnlyUwSId, PUPData::FLAGS_NONE, nullptr,
PUPData::kMaxFilesToRemoveSmallUwS);
found_pups.push_back(kReportOnlyUwSId);
recovery_component_.PostScan(found_pups);
EXPECT_TRUE(recovery_component_.run_called());
}
TEST_F(RecoveryComponentTest, RunNotCalledPreReboot) {
std::vector<UwSId> found_pups;
TestPUPData test_pup_data;
// And finally, when a reboot will be needed, none should call run.
test_pup_data.AddPUP(kRemovableUwSId, PUPData::FLAGS_ACTION_REMOVE, nullptr,
PUPData::kMaxFilesToRemoveSmallUwS);
found_pups.push_back(kRemovableUwSId);
recovery_component_.PostScan(found_pups);
EXPECT_FALSE(recovery_component_.run_called());
recovery_component_.PostCleanup(RESULT_CODE_PENDING_REBOOT, nullptr);
EXPECT_FALSE(recovery_component_.run_called());
}
} // namespace chrome_cleaner