blob: 7ed34d3f2689145be5528bd31c88c307610ce64a [file] [log] [blame]
// Copyright 2020 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/browser/component_updater/floc_component_installer.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
#include "base/test/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/component_updater/mock_component_updater_service.h"
#include "components/federated_learning/floc_constants.h"
#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock-actions.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
namespace component_updater {
namespace {
ACTION_P(QuitMessageLoop, loop) {
loop->Quit();
return true;
}
// This class monitors the OnSortingLshClustersFileReady method calls.
class MockFlocSortingLshClustersService
: public federated_learning::FlocSortingLshClustersService {
public:
MockFlocSortingLshClustersService() = default;
MockFlocSortingLshClustersService(const MockFlocSortingLshClustersService&) =
delete;
MockFlocSortingLshClustersService& operator=(
const MockFlocSortingLshClustersService&) = delete;
~MockFlocSortingLshClustersService() override = default;
void OnSortingLshClustersFileReady(const base::FilePath& file_path,
const base::Version& version) override {
file_paths_.push_back(file_path);
versions_.push_back(version);
}
const std::vector<base::FilePath>& file_paths() const { return file_paths_; }
const std::vector<base::Version>& versions() const { return versions_; }
private:
std::vector<base::FilePath> file_paths_;
std::vector<base::Version> versions_;
};
} // namespace
class FlocComponentInstallerTest : public PlatformTest {
public:
FlocComponentInstallerTest() = default;
FlocComponentInstallerTest(const FlocComponentInstallerTest&) = delete;
FlocComponentInstallerTest& operator=(const FlocComponentInstallerTest&) =
delete;
~FlocComponentInstallerTest() override = default;
void SetUp() override {
PlatformTest::SetUp();
ASSERT_TRUE(component_install_dir_.CreateUniqueTempDir());
auto test_floc_sorting_lsh_clusters_service =
std::make_unique<MockFlocSortingLshClustersService>();
test_floc_sorting_lsh_clusters_service->SetBackgroundTaskRunnerForTesting(
base::SequencedTaskRunnerHandle::Get());
test_floc_sorting_lsh_clusters_service_ =
test_floc_sorting_lsh_clusters_service.get();
TestingBrowserProcess::GetGlobal()->SetFlocSortingLshClustersService(
std::move(test_floc_sorting_lsh_clusters_service));
policy_ = std::make_unique<FlocComponentInstallerPolicy>(
test_floc_sorting_lsh_clusters_service_);
}
void TearDown() override {
TestingBrowserProcess::GetGlobal()->SetFlocSortingLshClustersService(
nullptr);
PlatformTest::TearDown();
}
MockFlocSortingLshClustersService* sorting_lsh_clusters_service() {
return test_floc_sorting_lsh_clusters_service_;
}
void WriteStringToFile(const std::string& data, const base::FilePath& path) {
ASSERT_EQ(base::WriteFile(path, data.data(), data.length()),
static_cast<int32_t>(data.length()));
}
base::FilePath component_install_dir() {
return component_install_dir_.GetPath();
}
void CreateTestFlocComponentFiles(const std::string& sorting_lsh_content) {
base::FilePath sorting_lsh_file_path = component_install_dir().Append(
federated_learning::kSortingLshClustersFileName);
ASSERT_NO_FATAL_FAILURE(
WriteStringToFile(sorting_lsh_content, sorting_lsh_file_path));
}
void LoadFlocComponent(const std::string& content_version,
int format_version) {
auto manifest = std::make_unique<base::DictionaryValue>();
manifest->SetInteger(federated_learning::kManifestFlocComponentFormatKey,
format_version);
if (!policy_->VerifyInstallation(*manifest, component_install_dir()))
return;
policy_->ComponentReady(base::Version(content_version),
component_install_dir(), std::move(manifest));
}
protected:
content::BrowserTaskEnvironment task_environment_;
base::ScopedTempDir component_install_dir_;
std::unique_ptr<FlocComponentInstallerPolicy> policy_;
MockFlocSortingLshClustersService* test_floc_sorting_lsh_clusters_service_ =
nullptr;
};
TEST_F(FlocComponentInstallerTest, TestComponentRegistration) {
auto component_updater =
std::make_unique<component_updater::MockComponentUpdateService>();
base::RunLoop run_loop;
EXPECT_CALL(*component_updater, RegisterComponent(testing::_))
.Times(1)
.WillOnce(QuitMessageLoop(&run_loop));
RegisterFlocComponent(component_updater.get(),
sorting_lsh_clusters_service());
run_loop.Run();
}
TEST_F(FlocComponentInstallerTest, LoadFlocComponent) {
ASSERT_TRUE(sorting_lsh_clusters_service());
std::string contents = "abcd";
ASSERT_NO_FATAL_FAILURE(CreateTestFlocComponentFiles(contents));
ASSERT_NO_FATAL_FAILURE(LoadFlocComponent(
"1.0.1", federated_learning::kCurrentFlocComponentFormatVersion));
ASSERT_EQ(sorting_lsh_clusters_service()->file_paths().size(), 1u);
ASSERT_EQ(sorting_lsh_clusters_service()->versions().size(), 1u);
// Assert that the file path is the concatenation of |component_install_dir_|
// and the corresponding file name, which implies that the |version| argument
// has no impact. In reality, though, the |component_install_dir_| and the
// |version| should always match.
ASSERT_EQ(sorting_lsh_clusters_service()->file_paths()[0].AsUTF8Unsafe(),
component_install_dir()
.Append(federated_learning::kSortingLshClustersFileName)
.AsUTF8Unsafe());
EXPECT_EQ(sorting_lsh_clusters_service()->versions()[0].GetString(), "1.0.1");
std::string actual_contents;
ASSERT_TRUE(base::ReadFileToString(
sorting_lsh_clusters_service()->file_paths()[0], &actual_contents));
EXPECT_EQ(actual_contents, contents);
}
TEST_F(FlocComponentInstallerTest, UnsupportedFormatVersionIgnored) {
ASSERT_TRUE(sorting_lsh_clusters_service());
const std::string contents = "future stuff";
ASSERT_NO_FATAL_FAILURE(CreateTestFlocComponentFiles(contents));
ASSERT_NO_FATAL_FAILURE(LoadFlocComponent(
"1.0.0", federated_learning::kCurrentFlocComponentFormatVersion + 1));
EXPECT_EQ(sorting_lsh_clusters_service()->file_paths().size(), 0u);
}
} // namespace component_updater