| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/win/conflicts/third_party_conflicts_manager.h" |
| |
| #include <utility> |
| |
| #include "base/base_paths.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/path_service.h" |
| #include "base/run_loop.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "chrome/browser/win/conflicts/module_info.h" |
| #include "chrome/browser/win/conflicts/proto/module_list.pb.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/test/base/scoped_testing_local_state.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| class ThirdPartyConflictsManagerTest : public testing::Test, |
| public ModuleDatabaseEventSource { |
| public: |
| ThirdPartyConflictsManagerTest() |
| : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()) {} |
| |
| ThirdPartyConflictsManagerTest(const ThirdPartyConflictsManagerTest&) = |
| delete; |
| ThirdPartyConflictsManagerTest& operator=( |
| const ThirdPartyConflictsManagerTest&) = delete; |
| |
| void SetUp() override { |
| ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); |
| |
| scoped_feature_list_.InitWithFeatures( |
| // Enabled features. |
| {features::kIncompatibleApplicationsWarning, |
| features::kThirdPartyModulesBlocking}, |
| // Disabled features. |
| {}); |
| } |
| |
| // Returns the path to the module list. |
| base::FilePath GetModuleListPath() const { |
| return scoped_temp_dir_.GetPath().Append(L"ModuleList.bin"); |
| } |
| |
| // Writes an empty serialized ModuleList proto to |GetModuleListPath()|. |
| void CreateModuleList() { |
| chrome::conflicts::ModuleList module_list; |
| // Include an empty blocklist and allowlist. |
| module_list.mutable_blocklist(); |
| module_list.mutable_allowlist(); |
| |
| std::string contents; |
| ASSERT_TRUE(module_list.SerializeToString(&contents)); |
| ASSERT_TRUE(base::WriteFile(GetModuleListPath(), contents)); |
| } |
| |
| void OnManagerInitializationComplete( |
| base::OnceClosure quit_closure, |
| ThirdPartyConflictsManager::State final_state) { |
| final_state_ = final_state; |
| std::move(quit_closure).Run(); |
| } |
| |
| const absl::optional<ThirdPartyConflictsManager::State>& final_state() { |
| return final_state_; |
| } |
| |
| // ModuleDatabaseEventSource: |
| void AddObserver(ModuleDatabaseObserver* observer) override {} |
| void RemoveObserver(ModuleDatabaseObserver* observer) override {} |
| |
| private: |
| content::BrowserTaskEnvironment task_environment_; |
| ScopedTestingLocalState scoped_testing_local_state_; |
| |
| // Temp directory used to host module list. |
| base::ScopedTempDir scoped_temp_dir_; |
| |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| absl::optional<ThirdPartyConflictsManager::State> final_state_; |
| }; |
| |
| std::pair<ModuleInfoKey, ModuleInfoData> CreateExeModuleInfo() { |
| base::FilePath exe_path; |
| base::PathService::Get(base::FILE_EXE, &exe_path); |
| |
| std::pair<ModuleInfoKey, ModuleInfoData> module_info( |
| std::piecewise_construct, |
| std::forward_as_tuple(std::move(exe_path), 0, 0), |
| std::forward_as_tuple()); |
| |
| module_info.second.inspection_result = |
| absl::make_optional<ModuleInspectionResult>(); |
| |
| return module_info; |
| } |
| |
| TEST_F(ThirdPartyConflictsManagerTest, InitializeUpdaters) { |
| ThirdPartyConflictsManager third_party_conflicts_manager(this); |
| |
| // The ThirdPartyConflictsManager class looks for the certificate info of the |
| // current exe via the ModuleDatabaseObserver interface. |
| auto exe_module_info = CreateExeModuleInfo(); |
| third_party_conflicts_manager.OnNewModuleFound(exe_module_info.first, |
| exe_module_info.second); |
| |
| third_party_conflicts_manager.OnModuleDatabaseIdle(); |
| ASSERT_NO_FATAL_FAILURE(CreateModuleList()); |
| third_party_conflicts_manager.LoadModuleList(GetModuleListPath()); |
| |
| base::RunLoop run_loop; |
| third_party_conflicts_manager.ForceInitialization(base::BindRepeating( |
| &ThirdPartyConflictsManagerTest::OnManagerInitializationComplete, |
| base::Unretained(this), run_loop.QuitClosure())); |
| |
| run_loop.Run(); |
| |
| ASSERT_TRUE(final_state().has_value()); |
| |
| EXPECT_EQ(final_state().value(), |
| ThirdPartyConflictsManager::State::kWarningAndBlockingInitialized); |
| } |
| |
| TEST_F(ThirdPartyConflictsManagerTest, InvalidModuleList) { |
| ThirdPartyConflictsManager third_party_conflicts_manager(this); |
| |
| third_party_conflicts_manager.OnModuleDatabaseIdle(); |
| |
| // Pass in an empty path which will ensure that the deserialization will fail. |
| third_party_conflicts_manager.LoadModuleList(GetModuleListPath()); |
| |
| base::RunLoop run_loop; |
| third_party_conflicts_manager.ForceInitialization(base::BindRepeating( |
| &ThirdPartyConflictsManagerTest::OnManagerInitializationComplete, |
| base::Unretained(this), run_loop.QuitClosure())); |
| |
| run_loop.Run(); |
| |
| ASSERT_TRUE(final_state().has_value()); |
| EXPECT_EQ(final_state().value(), |
| ThirdPartyConflictsManager::State::kModuleListInvalidFailure); |
| } |
| |
| TEST_F(ThirdPartyConflictsManagerTest, DestroyManager) { |
| auto third_party_conflicts_manager = |
| std::make_unique<ThirdPartyConflictsManager>(this); |
| |
| third_party_conflicts_manager->OnModuleDatabaseIdle(); |
| ASSERT_NO_FATAL_FAILURE(CreateModuleList()); |
| third_party_conflicts_manager->LoadModuleList(GetModuleListPath()); |
| |
| base::RunLoop run_loop; |
| third_party_conflicts_manager->ForceInitialization(base::BindRepeating( |
| &ThirdPartyConflictsManagerTest::OnManagerInitializationComplete, |
| base::Unretained(this), run_loop.QuitClosure())); |
| |
| // Delete the instance while it is initializing. |
| third_party_conflicts_manager = nullptr; |
| run_loop.Run(); |
| |
| ASSERT_TRUE(final_state().has_value()); |
| EXPECT_EQ(final_state().value(), |
| ThirdPartyConflictsManager::State::kDestroyed); |
| } |