blob: b25152e88f2dbf9aec6dd1575d3a63a056173d72 [file] [log] [blame]
// 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