mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 08:47:12 +03:00
255b6777f9
Summary: The use of realpath is needed to resolve a unix-style path to a Windows style one. This helps keep the test generic with no `#ifdef _WIN32` Reviewed By: wez Differential Revision: D21319019 fbshipit-source-id: b8cdd81f0afdd135849a5b850d854399cef8cef8
382 lines
14 KiB
C++
382 lines
14 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This software may be used and distributed according to the terms of the
|
|
* GNU General Public License version 2.
|
|
*/
|
|
|
|
#include "eden/fs/config/EdenConfig.h"
|
|
|
|
#include <folly/experimental/TestUtil.h>
|
|
#include <folly/test/TestUtils.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "eden/fs/utils/PathFuncs.h"
|
|
|
|
using folly::StringPiece;
|
|
|
|
using namespace facebook::eden;
|
|
using namespace folly::string_piece_literals;
|
|
using namespace std::chrono_literals;
|
|
|
|
class ConfigSettingTest : public ::testing::Test {
|
|
protected:
|
|
static constexpr folly::StringPiece defaultDirSp_{"/DEFAULT_DIR"};
|
|
static constexpr folly::StringPiece systemConfigDirSp_{
|
|
"/SYSTEM_CONFIG_SETTING"};
|
|
static constexpr folly::StringPiece userConfigDirSp_{"/USER_CONFIG_SETTING"};
|
|
static constexpr folly::StringPiece otherDirSp_{"/OTHER_DIR"};
|
|
AbsolutePath defaultDir_;
|
|
AbsolutePath systemConfigDir_;
|
|
AbsolutePath userConfigDir_;
|
|
AbsolutePath otherDir_;
|
|
|
|
void SetUp() override {
|
|
defaultDir_ = normalizeBestEffort(defaultDirSp_);
|
|
systemConfigDir_ = normalizeBestEffort(systemConfigDirSp_);
|
|
userConfigDir_ = normalizeBestEffort(userConfigDirSp_);
|
|
otherDir_ = normalizeBestEffort(otherDirSp_);
|
|
}
|
|
};
|
|
|
|
TEST_F(ConfigSettingTest, initStateCheck) {
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
|
|
// Initial should be default
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getConfigKey(), dirKey);
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configSetStringValue) {
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
|
|
std::map<std::string, std::string> attrMap;
|
|
auto rslt = testDir.setStringValue(
|
|
systemConfigDirSp_, attrMap, ConfigSource::UserConfig);
|
|
EXPECT_EQ(rslt.hasError(), false);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::UserConfig);
|
|
EXPECT_EQ(testDir.getValue(), systemConfigDir_);
|
|
EXPECT_EQ(systemConfigDir_, testDir.getStringValue());
|
|
|
|
rslt = testDir.setStringValue(
|
|
userConfigDirSp_, attrMap, ConfigSource::UserConfig);
|
|
EXPECT_EQ(rslt.hasError(), false);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::UserConfig);
|
|
EXPECT_EQ(testDir.getValue(), userConfigDir_);
|
|
EXPECT_EQ(userConfigDir_, testDir.getStringValue());
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configSetAssign) {
|
|
// Setup our target copy
|
|
auto otherKey = "otherKey"_sp;
|
|
ConfigSetting<AbsolutePath> copyOfTestDir{otherKey, otherDir_, nullptr};
|
|
|
|
// Check the copy states first, so we know where starting point is.
|
|
EXPECT_EQ(copyOfTestDir.getConfigKey(), otherKey);
|
|
EXPECT_EQ(copyOfTestDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(copyOfTestDir.getValue(), otherDir_);
|
|
|
|
auto dirKey = "dirKey"_sp;
|
|
{
|
|
// Setup the copy source - sufficiently different
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
|
|
std::map<std::string, std::string> attrMap;
|
|
auto rslt = testDir.setStringValue(
|
|
systemConfigDirSp_, attrMap, ConfigSource::UserConfig);
|
|
EXPECT_EQ(rslt.hasError(), false);
|
|
|
|
EXPECT_EQ(testDir.getConfigKey(), dirKey);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::UserConfig);
|
|
EXPECT_EQ(testDir.getValue(), systemConfigDir_);
|
|
|
|
copyOfTestDir.copyFrom(testDir);
|
|
}
|
|
|
|
// Check all attributes copied.
|
|
EXPECT_EQ(copyOfTestDir.getConfigKey(), dirKey);
|
|
EXPECT_EQ(copyOfTestDir.getSource(), ConfigSource::UserConfig);
|
|
EXPECT_EQ(copyOfTestDir.getValue(), systemConfigDir_);
|
|
|
|
// Check references still valid
|
|
copyOfTestDir.clearValue(ConfigSource::Default);
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configSetInvalidStringValue) {
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
|
|
std::map<std::string, std::string> attrMap;
|
|
auto rslt = testDir.setStringValue(
|
|
systemConfigDirSp_, attrMap, ConfigSource::SystemConfig);
|
|
EXPECT_EQ(rslt.hasError(), false);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getValue(), systemConfigDir_);
|
|
|
|
folly::StringPiece userConfigDir{"INVALID USER_CONFIG_SETTING"};
|
|
rslt =
|
|
testDir.setStringValue(userConfigDir, attrMap, ConfigSource::UserConfig);
|
|
EXPECT_EQ(rslt.hasError(), true);
|
|
EXPECT_EQ(
|
|
rslt.error(),
|
|
"Cannot convert value 'INVALID USER_CONFIG_SETTING' to an absolute path");
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getValue(), systemConfigDir_);
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configSetEnvSubTest) {
|
|
AbsolutePath defaultDir{"/home/bob"};
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir, nullptr};
|
|
|
|
folly::StringPiece userConfigDir{"${HOME}/test_dir"};
|
|
std::map<std::string, std::string> attrMap;
|
|
attrMap["HOME"] = "/home/bob";
|
|
attrMap["USER"] = "bob";
|
|
auto rslt =
|
|
testDir.setStringValue(userConfigDir, attrMap, ConfigSource::UserConfig);
|
|
EXPECT_EQ(rslt.hasError(), false);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::UserConfig);
|
|
AbsolutePath bobTestDir = normalizeBestEffort("/home/bob/test_dir");
|
|
EXPECT_EQ(testDir.getValue(), bobTestDir);
|
|
EXPECT_EQ(bobTestDir, testDir.getStringValue());
|
|
|
|
folly::StringPiece homeUserConfigDir{"/home/${USER}/test_dir"};
|
|
rslt = testDir.setStringValue(
|
|
homeUserConfigDir, attrMap, ConfigSource::UserConfig);
|
|
EXPECT_EQ(rslt.hasError(), false);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::UserConfig);
|
|
EXPECT_EQ(testDir.getValue(), bobTestDir);
|
|
EXPECT_EQ(bobTestDir, testDir.getStringValue());
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configSettingIgnoreDefault) {
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
// Initial should be default
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
|
|
// Setting default value should be ignored
|
|
AbsolutePath notDefaultDir{"/NOT_THE_DEFAULT_DIR"};
|
|
testDir.setValue(notDefaultDir, ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
|
|
// Clearing the default value should be ignored
|
|
testDir.clearValue(ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configSettingClearNonExistingSource) {
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
|
|
// Initially, it should be default value
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
|
|
// Clear unset priorities
|
|
testDir.clearValue(ConfigSource::CommandLine);
|
|
testDir.clearValue(ConfigSource::UserConfig);
|
|
testDir.clearValue(ConfigSource::SystemConfig);
|
|
testDir.clearValue(ConfigSource::Default);
|
|
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configSettingSetAndClearTest) {
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
|
|
AbsolutePath systemEdenDir{"/SYSTEM_DIR"};
|
|
|
|
// Initially, it should be default value
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
|
|
// Over-ride default
|
|
testDir.setValue(systemEdenDir, ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getValue(), systemEdenDir);
|
|
|
|
// Clear the over-ride
|
|
testDir.clearValue(ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configSetOverRiddenSource) {
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
|
|
AbsolutePath cliEdenDir{"/CLI_DIR"};
|
|
AbsolutePath systemEdenDir{"/SYSTEM_DIR"};
|
|
|
|
// Initially, it should be default value
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
|
|
// Set the highest priority item
|
|
testDir.setValue(cliEdenDir, ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getValue(), cliEdenDir);
|
|
|
|
// Set a middle priority item (results same as above)
|
|
testDir.setValue(systemEdenDir, ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getValue(), cliEdenDir);
|
|
|
|
// Clear current highest priority
|
|
testDir.clearValue(ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getValue(), systemEdenDir);
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, configClearOverRiddenSource) {
|
|
auto dirKey = "dirKey"_sp;
|
|
ConfigSetting<AbsolutePath> testDir{dirKey, defaultDir_, nullptr};
|
|
|
|
AbsolutePath cliEdenDir{"/CLI_DIR"};
|
|
AbsolutePath userEdenDir{"/USER_DIR"};
|
|
AbsolutePath systemEdenDir{"/SYSTEM_DIR"};
|
|
|
|
// Initially, it should be default value
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
|
|
// Set next higher over-ride priority
|
|
testDir.setValue(systemEdenDir, ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getValue(), systemEdenDir);
|
|
|
|
// Set next higher over-ride priority
|
|
testDir.setValue(userEdenDir, ConfigSource::UserConfig);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::UserConfig);
|
|
EXPECT_EQ(testDir.getValue(), userEdenDir);
|
|
|
|
// Set next higher over-ride priority
|
|
testDir.setValue(cliEdenDir, ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getValue(), cliEdenDir);
|
|
|
|
// Clear the middle priority item (no effect on source/value)
|
|
testDir.clearValue(ConfigSource::UserConfig);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getValue(), cliEdenDir);
|
|
|
|
// Clear the middle priority item (no effect on source/value)
|
|
testDir.clearValue(ConfigSource::SystemConfig);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getValue(), cliEdenDir);
|
|
|
|
// Clear highest priority - back to default
|
|
testDir.clearValue(ConfigSource::CommandLine);
|
|
EXPECT_EQ(testDir.getSource(), ConfigSource::Default);
|
|
EXPECT_EQ(testDir.getValue(), defaultDir_);
|
|
}
|
|
|
|
namespace {
|
|
|
|
template <typename T, typename FieldConverter, typename ExpectedType = T>
|
|
void checkSet(
|
|
ConfigSetting<T, FieldConverter>& setting,
|
|
ExpectedType expected,
|
|
StringPiece str) {
|
|
SCOPED_TRACE(str.str());
|
|
std::map<std::string, std::string> attrMap;
|
|
auto setResult =
|
|
setting.setStringValue(str, attrMap, ConfigSource::UserConfig);
|
|
ASSERT_FALSE(setResult.hasError()) << setResult.error();
|
|
if constexpr (std::is_floating_point<T>::value) {
|
|
EXPECT_FLOAT_EQ(expected, setting.getValue());
|
|
} else {
|
|
EXPECT_EQ(expected, setting.getValue());
|
|
}
|
|
}
|
|
|
|
template <typename T, typename FieldConverter>
|
|
void checkSetError(
|
|
ConfigSetting<T, FieldConverter>& setting,
|
|
StringPiece expectedError,
|
|
StringPiece str) {
|
|
SCOPED_TRACE(str.str());
|
|
std::map<std::string, std::string> attrMap;
|
|
auto setResult =
|
|
setting.setStringValue(str, attrMap, ConfigSource::UserConfig);
|
|
ASSERT_TRUE(setResult.hasError());
|
|
EXPECT_EQ(expectedError.str(), setResult.error());
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_F(ConfigSettingTest, setBool) {
|
|
ConfigSetting<bool> defaultTrue{"test:value2", true, nullptr};
|
|
EXPECT_EQ(true, defaultTrue.getValue());
|
|
|
|
ConfigSetting<bool> setting{"test:value", false, nullptr};
|
|
EXPECT_EQ(false, setting.getValue());
|
|
|
|
checkSet(setting, true, "true");
|
|
checkSet(setting, true, "1");
|
|
checkSet(setting, true, "y");
|
|
checkSet(setting, true, "yes");
|
|
checkSet(setting, true, "Y");
|
|
checkSet(setting, true, "on");
|
|
EXPECT_EQ("true", setting.getStringValue());
|
|
checkSet(setting, false, "n");
|
|
checkSet(setting, false, "0");
|
|
checkSet(setting, false, "false");
|
|
checkSet(setting, false, "off");
|
|
EXPECT_EQ("false", setting.getStringValue());
|
|
|
|
checkSetError(setting, "Empty input string", "");
|
|
checkSetError(setting, "Invalid value for bool: \"bogus\"", "bogus");
|
|
checkSetError(
|
|
setting,
|
|
"Non-whitespace character found after end of conversion: \"yes_and\"",
|
|
"yes_and");
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, setArithmetic) {
|
|
ConfigSetting<int> intSetting{"test:value", 1, nullptr};
|
|
EXPECT_EQ(1, intSetting.getValue());
|
|
checkSet(intSetting, 9, "9");
|
|
checkSet(intSetting, 1234, "1234");
|
|
checkSetError(intSetting, "Empty input string", "");
|
|
checkSetError(intSetting, "Invalid leading character: \"bogus\"", "bogus");
|
|
// In the future it might be nice to support parsing hexadecimal input.
|
|
checkSetError(
|
|
intSetting,
|
|
"Non-whitespace character found after end of conversion: \"0x15\"",
|
|
"0x15");
|
|
|
|
ConfigSetting<uint8_t> u8Setting{"test:value", 0, nullptr};
|
|
checkSet(u8Setting, 9, "9");
|
|
checkSetError(u8Setting, "Overflow during conversion: \"300\"", "300");
|
|
checkSetError(u8Setting, "Non-digit character found: \"-10\"", "-10");
|
|
|
|
ConfigSetting<float> floatSetting{"test:value", 0, nullptr};
|
|
checkSet(floatSetting, 123.0f, "123");
|
|
checkSet(floatSetting, 0.001f, "0.001");
|
|
checkSetError(
|
|
floatSetting,
|
|
"Non-whitespace character found after end of conversion: \"0.001.9\"",
|
|
"0.001.9");
|
|
}
|
|
|
|
TEST_F(ConfigSettingTest, setDuration) {
|
|
ConfigSetting<std::chrono::nanoseconds> setting{"test:value", 5ms, nullptr};
|
|
EXPECT_EQ(5ms, setting.getValue());
|
|
checkSet(setting, 90s, "1m30s");
|
|
checkSet(setting, -90s, "-1m30s");
|
|
checkSet(setting, 42ns, "42ns");
|
|
checkSet(setting, 300s, "5m");
|
|
checkSetError(setting, "empty input string", "");
|
|
checkSetError(setting, "unknown duration unit specifier", "90");
|
|
checkSetError(setting, "non-digit character found", "bogus");
|
|
}
|