| // Copyright 2021 The Chromium OS 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 <utility> |
| |
| #include <base/check.h> |
| #include <base/check_op.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/files/file_util.h> |
| #include <chromeos-config/libcros_config/fake_cros_config.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "runtime_probe/probe_config_loader_impl.h" |
| #include "runtime_probe/system_property_impl.h" |
| |
| namespace runtime_probe { |
| |
| namespace { |
| |
| constexpr char kUsrLocal[] = "usr/local"; |
| |
| base::FilePath GetTestDataPath() { |
| char* src_env = std::getenv("SRC"); |
| CHECK_NE(src_env, nullptr) |
| << "Expect to have the envvar |SRC| set when testing."; |
| return base::FilePath(src_env).Append("testdata"); |
| } |
| |
| class MockSystemProperty : public SystemProperty { |
| public: |
| MOCK_METHOD(bool, |
| GetInt, |
| (const std::string& key, int* value_out), |
| (override)); |
| MOCK_METHOD(bool, SetInt, (const std::string& key, int value), (override)); |
| MOCK_METHOD(bool, |
| GetString, |
| (const std::string& key, std::string* value_out), |
| (override)); |
| MOCK_METHOD(bool, |
| SetString, |
| (const std::string& key, const std::string& value), |
| (override)); |
| }; |
| |
| class ProbeConfigLoaderImplTest : public ::testing::Test { |
| protected: |
| void SetUp() { |
| PCHECK(scoped_temp_dir_.CreateUniqueTempDir()); |
| |
| auto cros_config = std::make_unique<brillo::FakeCrosConfig>(); |
| auto mock_system_property = std::make_unique<MockSystemProperty>(); |
| cros_config_ = cros_config.get(); |
| mock_system_property_ = mock_system_property.get(); |
| testdata_root_ = GetTestDataPath(); |
| |
| probe_config_loader_ = std::make_unique<ProbeConfigLoaderImpl>(); |
| probe_config_loader_->SetCrosConfigForTesting(std::move(cros_config)); |
| probe_config_loader_->SetSystemProertyForTesting( |
| std::move(mock_system_property)); |
| probe_config_loader_->SetRootForTest(GetRootDir()); |
| } |
| |
| // Sets model names to the given value. |
| void SetModel(const std::string& val) { |
| cros_config_->SetString(kCrosConfigModelNamePath, kCrosConfigModelNameKey, |
| val); |
| } |
| |
| // Sets cros_debug flag to the given value. |
| void SetCrosDebugFlag(int value) { |
| EXPECT_CALL(*mock_system_property_, |
| GetInt(std::string("cros_debug"), ::testing::_)) |
| .WillRepeatedly(::testing::DoAll(::testing::SetArgPointee<1>(value), |
| ::testing::Return(true))); |
| } |
| |
| // Gets the root directory path used for unit test. |
| const base::FilePath& GetRootDir() const { |
| return scoped_temp_dir_.GetPath(); |
| } |
| |
| // Creates parent directories as needed before copying the file. |
| bool CreateDirectoryAndCopyFile(const base::FilePath& from_path, |
| const base::FilePath& to_path) const { |
| PCHECK(base::CreateDirectoryAndGetError(to_path.DirName(), nullptr)); |
| PCHECK(base::CopyFile(from_path, to_path)); |
| return true; |
| } |
| |
| std::unique_ptr<ProbeConfigLoaderImpl> probe_config_loader_; |
| MockSystemProperty* mock_system_property_; |
| brillo::FakeCrosConfig* cros_config_; |
| base::FilePath testdata_root_; |
| |
| private: |
| base::ScopedTempDir scoped_temp_dir_; |
| }; |
| |
| } // namespace |
| |
| TEST(ProbeConfigLoaderImplTestConstructor, DefaultConstructor) { |
| auto probe_config_loader_ = std::make_unique<ProbeConfigLoaderImpl>(); |
| EXPECT_NE(probe_config_loader_, nullptr); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadFromFile_WithoutCrosDebug) { |
| for (const auto cros_config_flag : {0, 2 /* invalid flags */}) { |
| SetCrosDebugFlag(cros_config_flag); |
| const base::FilePath rel_path{kRuntimeProbeConfigName}; |
| const auto rel_file_path = testdata_root_.Append(kRuntimeProbeConfigName); |
| |
| const auto probe_config = probe_config_loader_->LoadFromFile(rel_file_path); |
| EXPECT_FALSE(probe_config); |
| } |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadFromFile_RelativePath) { |
| SetCrosDebugFlag(1); |
| const base::FilePath rel_path{kRuntimeProbeConfigName}; |
| const auto rel_file_path = testdata_root_.Append(kRuntimeProbeConfigName); |
| const auto abs_file_path = base::MakeAbsoluteFilePath(rel_file_path); |
| |
| const auto probe_config = probe_config_loader_->LoadFromFile(rel_file_path); |
| EXPECT_TRUE(probe_config); |
| EXPECT_EQ(probe_config->path, abs_file_path); |
| EXPECT_FALSE(probe_config->config.DictEmpty()); |
| EXPECT_EQ(probe_config->sha1_hash, |
| "B4B67B8FB7B094783926CC581850C492C5A246A4"); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadFromFile_AbsolutePath) { |
| SetCrosDebugFlag(1); |
| const base::FilePath rel_path{kRuntimeProbeConfigName}; |
| const auto rel_file_path = testdata_root_.Append(kRuntimeProbeConfigName); |
| const auto abs_file_path = base::MakeAbsoluteFilePath(rel_file_path); |
| |
| const auto probe_config = probe_config_loader_->LoadFromFile(abs_file_path); |
| EXPECT_TRUE(probe_config); |
| EXPECT_EQ(probe_config->path, abs_file_path); |
| EXPECT_FALSE(probe_config->config.DictEmpty()); |
| EXPECT_EQ(probe_config->sha1_hash, |
| "B4B67B8FB7B094783926CC581850C492C5A246A4"); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadFromFile_MissingFile) { |
| SetCrosDebugFlag(1); |
| const base::FilePath rel_path{"missing_file.json"}; |
| |
| const auto probe_config = probe_config_loader_->LoadFromFile(rel_path); |
| EXPECT_FALSE(probe_config); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadFromFile_InvalidFile) { |
| SetCrosDebugFlag(1); |
| const base::FilePath rel_path{"invalid_config.json"}; |
| const char invalid_probe_config[] = "foo\nbar"; |
| PCHECK(WriteFile(GetRootDir().Append(rel_path), invalid_probe_config)); |
| |
| const auto probe_config = probe_config_loader_->LoadFromFile(rel_path); |
| EXPECT_FALSE(probe_config); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadFromFile_SymbolicLink) { |
| SetCrosDebugFlag(1); |
| const base::FilePath rel_path{kRuntimeProbeConfigName}; |
| const auto rel_file_path = testdata_root_.Append(kRuntimeProbeConfigName); |
| const auto abs_file_path = base::MakeAbsoluteFilePath(rel_file_path); |
| const auto symlink_config_path = GetRootDir().Append("config.json"); |
| |
| PCHECK(base::CreateSymbolicLink(abs_file_path, symlink_config_path)); |
| auto probe_config = probe_config_loader_->LoadFromFile(symlink_config_path); |
| EXPECT_TRUE(probe_config); |
| EXPECT_EQ(probe_config->path, abs_file_path); |
| EXPECT_FALSE(probe_config->config.DictEmpty()); |
| EXPECT_EQ(probe_config->sha1_hash, |
| "B4B67B8FB7B094783926CC581850C492C5A246A4"); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, GetDefaultPaths_WithoutCrosDebug) { |
| const char model_name[] = "ModelFoo"; |
| SetCrosDebugFlag(0); |
| SetModel(model_name); |
| const auto default_paths = probe_config_loader_->GetDefaultPaths(); |
| EXPECT_THAT(default_paths, ::testing::ElementsAreArray({ |
| GetRootDir() |
| .Append(kRuntimeProbeConfigDir) |
| .Append(model_name) |
| .Append(kRuntimeProbeConfigName), |
| GetRootDir() |
| .Append(kRuntimeProbeConfigDir) |
| .Append(kRuntimeProbeConfigName), |
| })); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, GetDefaultPaths_WithCrosDebug) { |
| const char model_name[] = "ModelFoo"; |
| SetCrosDebugFlag(1); |
| SetModel(model_name); |
| const auto default_paths = probe_config_loader_->GetDefaultPaths(); |
| EXPECT_THAT(default_paths, ::testing::ElementsAreArray({ |
| GetRootDir() |
| .Append(kUsrLocal) |
| .Append(kRuntimeProbeConfigDir) |
| .Append(model_name) |
| .Append(kRuntimeProbeConfigName), |
| GetRootDir() |
| .Append(kUsrLocal) |
| .Append(kRuntimeProbeConfigDir) |
| .Append(kRuntimeProbeConfigName), |
| GetRootDir() |
| .Append(kRuntimeProbeConfigDir) |
| .Append(model_name) |
| .Append(kRuntimeProbeConfigName), |
| GetRootDir() |
| .Append(kRuntimeProbeConfigDir) |
| .Append(kRuntimeProbeConfigName), |
| })); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadDefault_WithoutCrosDebug) { |
| const char model_name[] = "ModelFoo"; |
| SetCrosDebugFlag(0); |
| SetModel(model_name); |
| const base::FilePath config_a_path{"probe_config.json"}; |
| const base::FilePath config_b_path{"probe_config_b.json"}; |
| const base::FilePath rootfs_config_path = |
| GetRootDir().Append(kRuntimeProbeConfigDir); |
| const base::FilePath stateful_partition_config_path = |
| GetRootDir().Append(kUsrLocal).Append(kRuntimeProbeConfigDir); |
| |
| // Copy config_a to rootfs. |
| CreateDirectoryAndCopyFile( |
| testdata_root_.Append(config_a_path), |
| rootfs_config_path.Append(model_name).Append(kRuntimeProbeConfigName)); |
| // Copy config_b to stateful partition. |
| CreateDirectoryAndCopyFile(testdata_root_.Append(config_b_path), |
| stateful_partition_config_path.Append(model_name) |
| .Append(kRuntimeProbeConfigName)); |
| |
| const auto probe_config = probe_config_loader_->LoadDefault(); |
| EXPECT_TRUE(probe_config); |
| EXPECT_EQ( |
| probe_config->path, |
| rootfs_config_path.Append(model_name).Append(kRuntimeProbeConfigName)); |
| EXPECT_FALSE(probe_config->config.DictEmpty()); |
| EXPECT_EQ(probe_config->sha1_hash, |
| "B4B67B8FB7B094783926CC581850C492C5A246A4"); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadDefault_WithCrosDebug) { |
| const char model_name[] = "ModelFoo"; |
| SetCrosDebugFlag(1); |
| SetModel(model_name); |
| const base::FilePath config_a_path{"probe_config.json"}; |
| const base::FilePath config_b_path{"probe_config_b.json"}; |
| const base::FilePath rootfs_config_path = |
| GetRootDir().Append(kRuntimeProbeConfigDir); |
| const base::FilePath stateful_partition_config_path = |
| GetRootDir().Append(kUsrLocal).Append(kRuntimeProbeConfigDir); |
| |
| // Copy config_a to rootfs. |
| CreateDirectoryAndCopyFile( |
| testdata_root_.Append(config_a_path), |
| rootfs_config_path.Append(model_name).Append(kRuntimeProbeConfigName)); |
| // Copy config_b to stateful partition. |
| CreateDirectoryAndCopyFile(testdata_root_.Append(config_b_path), |
| stateful_partition_config_path.Append(model_name) |
| .Append(kRuntimeProbeConfigName)); |
| |
| const auto probe_config = probe_config_loader_->LoadDefault(); |
| EXPECT_TRUE(probe_config); |
| EXPECT_EQ(probe_config->path, |
| stateful_partition_config_path.Append(model_name) |
| .Append(kRuntimeProbeConfigName)); |
| EXPECT_FALSE(probe_config->config.DictEmpty()); |
| EXPECT_EQ(probe_config->sha1_hash, |
| "BC65881109108FB248B76554378AC493CD4D5C6D"); |
| } |
| |
| TEST_F(ProbeConfigLoaderImplTest, LoadDefault_MissingFile) { |
| const char model_name[] = "ModelFoo"; |
| SetCrosDebugFlag(0); |
| SetModel(model_name); |
| |
| const auto probe_config = probe_config_loader_->LoadDefault(); |
| EXPECT_FALSE(probe_config); |
| } |
| |
| } // namespace runtime_probe |