HDFS-9117. Config file reader / options classes for libhdfs++. Contributed by Bob Hansen.
This commit is contained in:
parent
a38703fdfc
commit
87362b1c17
|
@ -49,7 +49,9 @@ include_directories(
|
|||
lib
|
||||
${PROJECT_BINARY_DIR}/lib/proto
|
||||
third_party/asio-1.10.2/include
|
||||
third_party/rapidxml-1.13
|
||||
third_party/gmock-1.7.0
|
||||
third_party/tr2
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
../libhdfs/include
|
||||
)
|
||||
|
|
|
@ -1 +1 @@
|
|||
add_library(common base64.cc options.cc status.cc sasl_digest_md5.cc hdfs_public_api.cc)
|
||||
add_library(common base64.cc status.cc sasl_digest_md5.cc hdfs_public_api.cc options.cc configuration.cc)
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following features are not currently implemented
|
||||
* - Deprecated values
|
||||
* - Make filename and config file contents unicode-safe
|
||||
* - Config redirection/environment substitution
|
||||
*
|
||||
* - getInts (comma separated))
|
||||
* - getStrings (comma separated))
|
||||
* - getIntegerRange
|
||||
* - getSocketAddr
|
||||
* - getTimeDuration
|
||||
* - getBytes (e.g. 1M or 1G)
|
||||
* - hex values
|
||||
*/
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include <strings.h>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <rapidxml/rapidxml.hpp>
|
||||
#include <rapidxml/rapidxml_utils.hpp>
|
||||
|
||||
namespace hdfs {
|
||||
|
||||
/*
|
||||
* Configuration class
|
||||
*/
|
||||
|
||||
Configuration::Configuration() {}
|
||||
|
||||
bool is_valid_bool(const std::string& raw) {
|
||||
if (!strcasecmp(raw.c_str(), "true")) {
|
||||
return true;
|
||||
}
|
||||
if (!strcasecmp(raw.c_str(), "false")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool str_to_bool(const std::string& raw) {
|
||||
if (!strcasecmp(raw.c_str(), "true")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
optional<Configuration> Configuration::Load(const std::string& xmlData) {
|
||||
Configuration result;
|
||||
return result.OverlayResourceString(xmlData);
|
||||
}
|
||||
|
||||
optional<Configuration> Configuration::OverlayResourceString(
|
||||
const std::string& xmlData) const {
|
||||
if (xmlData.size() == 0) {
|
||||
return optional<Configuration>();
|
||||
}
|
||||
|
||||
int length = xmlData.size();
|
||||
std::vector<char> raw_bytes;
|
||||
raw_bytes.reserve(length + 1);
|
||||
std::copy(xmlData.begin(), xmlData.end(), std::back_inserter(raw_bytes));
|
||||
raw_bytes.push_back('\0');
|
||||
|
||||
ConfigMap map(raw_values_);
|
||||
bool success = UpdateMapWithResource(map, raw_bytes);
|
||||
|
||||
if (success) {
|
||||
return optional<Configuration>(Configuration(map));
|
||||
} else {
|
||||
return optional<Configuration>();
|
||||
}
|
||||
}
|
||||
|
||||
bool Configuration::UpdateMapWithResource(ConfigMap& map,
|
||||
std::vector<char>& raw_bytes) {
|
||||
rapidxml::xml_document<> dom;
|
||||
dom.parse<rapidxml::parse_trim_whitespace>(&raw_bytes[0]);
|
||||
|
||||
/* File must contain a single <configuration> stanza */
|
||||
auto config_node = dom.first_node("configuration", 0, false);
|
||||
if (!config_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Walk all of the <property> nodes, ignoring the rest */
|
||||
for (auto property_node = config_node->first_node("property", 0, false);
|
||||
property_node;
|
||||
property_node = property_node->next_sibling("property", 0, false)) {
|
||||
auto name_node = property_node->first_node("name", 0, false);
|
||||
auto value_node = property_node->first_node("value", 0, false);
|
||||
|
||||
if (name_node && value_node) {
|
||||
auto mapValue = map.find(name_node->value());
|
||||
if (mapValue != map.end() && mapValue->second.final) {
|
||||
continue;
|
||||
}
|
||||
|
||||
map[name_node->value()] = value_node->value();
|
||||
auto final_node = property_node->first_node("final", 0, false);
|
||||
if (final_node && is_valid_bool(final_node->value())) {
|
||||
map[name_node->value()].final = str_to_bool(final_node->value());
|
||||
}
|
||||
}
|
||||
|
||||
auto name_attr = property_node->first_attribute("name", 0, false);
|
||||
auto value_attr = property_node->first_attribute("value", 0, false);
|
||||
|
||||
if (name_attr && value_attr) {
|
||||
auto mapValue = map.find(name_attr->value());
|
||||
if (mapValue != map.end() && mapValue->second.final) {
|
||||
continue;
|
||||
}
|
||||
|
||||
map[name_attr->value()] = value_attr->value();
|
||||
auto final_attr = property_node->first_attribute("final", 0, false);
|
||||
if (final_attr && is_valid_bool(final_attr->value())) {
|
||||
map[name_attr->value()].final = str_to_bool(final_attr->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
optional<std::string> Configuration::Get(const std::string& key) const {
|
||||
auto found = raw_values_.find(key);
|
||||
if (found != raw_values_.end()) {
|
||||
return std::experimental::make_optional(found->second.value);
|
||||
} else {
|
||||
return optional<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
std::string Configuration::GetWithDefault(
|
||||
const std::string& key, const std::string& default_value) const {
|
||||
return Get(key).value_or(default_value);
|
||||
}
|
||||
|
||||
optional<int64_t> Configuration::GetInt(const std::string& key) const {
|
||||
auto raw = Get(key);
|
||||
if (raw) {
|
||||
errno = 0;
|
||||
char* end = nullptr;
|
||||
auto result =
|
||||
std::experimental::make_optional(strtol(raw->c_str(), &end, 10));
|
||||
if (end == raw->c_str()) {
|
||||
/* strtoll will set end to input if no conversion was done */
|
||||
return optional<int64_t>();
|
||||
}
|
||||
if (errno == ERANGE) {
|
||||
return optional<int64_t>();
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return optional<int64_t>();
|
||||
}
|
||||
}
|
||||
|
||||
int64_t Configuration::GetIntWithDefault(const std::string& key,
|
||||
int64_t default_value) const {
|
||||
return GetInt(key).value_or(default_value);
|
||||
}
|
||||
|
||||
optional<double> Configuration::GetDouble(const std::string& key) const {
|
||||
auto raw = Get(key);
|
||||
if (raw) {
|
||||
errno = 0;
|
||||
char* end = nullptr;
|
||||
auto result = std::experimental::make_optional(strtod(raw->c_str(), &end));
|
||||
if (end == raw->c_str()) {
|
||||
/* strtod will set end to input if no conversion was done */
|
||||
return optional<double>();
|
||||
}
|
||||
if (errno == ERANGE) {
|
||||
return optional<double>();
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return optional<double>();
|
||||
}
|
||||
}
|
||||
|
||||
double Configuration::GetDoubleWithDefault(const std::string& key,
|
||||
double default_value) const {
|
||||
return GetDouble(key).value_or(default_value);
|
||||
}
|
||||
|
||||
optional<bool> Configuration::GetBool(const std::string& key) const {
|
||||
auto raw = Get(key);
|
||||
if (!raw) {
|
||||
return optional<bool>();
|
||||
}
|
||||
|
||||
if (!strcasecmp(raw->c_str(), "true")) {
|
||||
return std::experimental::make_optional(true);
|
||||
}
|
||||
if (!strcasecmp(raw->c_str(), "false")) {
|
||||
return std::experimental::make_optional(false);
|
||||
}
|
||||
|
||||
return optional<bool>();
|
||||
}
|
||||
|
||||
bool Configuration::GetBoolWithDefault(const std::string& key,
|
||||
bool default_value) const {
|
||||
return GetBool(key).value_or(default_value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_CONFIGURATION_H_
|
||||
#define COMMON_CONFIGURATION_H_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <istream>
|
||||
#include <stdint.h>
|
||||
#include <optional.hpp>
|
||||
|
||||
namespace hdfs {
|
||||
|
||||
template <class T>
|
||||
using optional = std::experimental::optional<T>;
|
||||
|
||||
/**
|
||||
* Configuration class that parses XML.
|
||||
*
|
||||
* Files should be an XML file of the form
|
||||
* <configuration>
|
||||
* <property>
|
||||
* <name>Name</name>
|
||||
* <value>Value</value>
|
||||
* </property>
|
||||
* <configuration>
|
||||
*
|
||||
* This class is not thread-safe.
|
||||
*/
|
||||
class Configuration {
|
||||
public:
|
||||
/* Creates a new Configuration from input xml */
|
||||
static optional<Configuration> Load(const std::string &xml_data);
|
||||
|
||||
/* Constructs a configuration with no resources loaded */
|
||||
Configuration();
|
||||
|
||||
/* Loads resources from a file or a stream */
|
||||
optional<Configuration> OverlayResourceString(
|
||||
const std::string &xml_data) const;
|
||||
|
||||
// Gets values
|
||||
std::string GetWithDefault(const std::string &key,
|
||||
const std::string &default_value) const;
|
||||
optional<std::string> Get(const std::string &key) const;
|
||||
int64_t GetIntWithDefault(const std::string &key, int64_t default_value) const;
|
||||
optional<int64_t> GetInt(const std::string &key) const;
|
||||
double GetDoubleWithDefault(const std::string &key,
|
||||
double default_value) const;
|
||||
optional<double> GetDouble(const std::string &key) const;
|
||||
bool GetBoolWithDefault(const std::string &key, bool default_value) const;
|
||||
optional<bool> GetBool(const std::string &key) const;
|
||||
|
||||
private:
|
||||
/* Transparent data holder for property values */
|
||||
struct ConfigData {
|
||||
std::string value;
|
||||
bool final;
|
||||
ConfigData() : final(false){};
|
||||
ConfigData(const std::string &value) : value(value), final(false) {}
|
||||
void operator=(const std::string &new_value) {
|
||||
value = new_value;
|
||||
final = false;
|
||||
}
|
||||
};
|
||||
typedef std::map<std::string, ConfigData> ConfigMap;
|
||||
|
||||
Configuration(ConfigMap &src_map) : raw_values_(src_map){};
|
||||
static bool UpdateMapWithResource(ConfigMap &map,
|
||||
std::vector<char> &raw_bytes);
|
||||
|
||||
const ConfigMap raw_values_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -68,6 +68,10 @@ add_executable(node_exclusion_test node_exclusion_test.cc)
|
|||
target_link_libraries(node_exclusion_test fs gmock_main common ${PROTOBUF_LIBRARIES} ${OPENSSL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
add_test(node_exclusion node_exclusion_test)
|
||||
|
||||
add_executable(configuration_test configuration_test.cc)
|
||||
target_link_libraries(configuration_test common gmock_main ${CMAKE_THREAD_LIBS_INIT})
|
||||
add_test(configuration configuration_test)
|
||||
|
||||
build_libhdfs_test(libhdfs_threaded hdfspp_test_shim_static expect.c test_libhdfs_threaded.c ${OS_DIR}/thread.c)
|
||||
link_libhdfs_test(libhdfs_threaded hdfspp_test_shim_static fs reader rpc proto common ${PROTOBUF_LIBRARIES} ${OPENSSL_LIBRARIES} native_mini_dfs ${JAVA_JVM_LIBRARY})
|
||||
add_libhdfs_test(libhdfs_threaded hdfspp_test_shim_static)
|
||||
|
|
|
@ -0,0 +1,363 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "configuration_test.h"
|
||||
#include "common/configuration.h"
|
||||
#include <gmock/gmock.h>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
using namespace hdfs;
|
||||
|
||||
namespace hdfs {
|
||||
|
||||
TEST(ConfigurationTest, TestDegenerateInputs) {
|
||||
/* Completely empty stream */
|
||||
{
|
||||
std::stringstream stream;
|
||||
optional<Configuration> config = Configuration::Load("");
|
||||
EXPECT_FALSE(config && "Empty stream");
|
||||
}
|
||||
|
||||
/* No values */
|
||||
{
|
||||
std::string data = "<configuration></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(data);
|
||||
EXPECT_TRUE(config && "Blank config");
|
||||
}
|
||||
|
||||
/* Extraneous values */
|
||||
{
|
||||
std::string data = "<configuration><spam></spam></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(data);
|
||||
EXPECT_TRUE(config && "Extraneous values");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConfigurationTest, TestBasicOperations) {
|
||||
/* Single value */
|
||||
{
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, "key1", "value1");
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse single value");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
}
|
||||
|
||||
/* Multiple values */
|
||||
{
|
||||
optional<Configuration> config =
|
||||
simpleConfig("key1", "value1", "key2", "value2");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
EXPECT_EQ("value2", config->GetWithDefault("key2", ""));
|
||||
}
|
||||
|
||||
/* No defaults */
|
||||
{
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, "key1", "value1");
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse single value");
|
||||
optional<std::string> value = config->Get("key1");
|
||||
EXPECT_TRUE((bool)value);
|
||||
EXPECT_EQ("value1", *value);
|
||||
EXPECT_FALSE(config->Get("key2"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConfigurationTest, TestCompactValues) {
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << "<configuration><property name=\"key1\" "
|
||||
"value=\"value1\"/></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Compact value parse");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConfigurationTest, TestMultipleResources) {
|
||||
/* Single value */
|
||||
{
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, "key1", "value1");
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse first stream");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
|
||||
std::stringstream stream2;
|
||||
simpleConfigStream(stream2, "key2", "value2");
|
||||
optional<Configuration> config2 =
|
||||
config->OverlayResourceString(stream2.str());
|
||||
EXPECT_TRUE(config2 && "Parse second stream");
|
||||
EXPECT_EQ("value1", config2->GetWithDefault("key1", ""));
|
||||
EXPECT_EQ("value2", config2->GetWithDefault("key2", ""));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConfigurationTest, TestStringResource) {
|
||||
/* Single value */
|
||||
{
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, "key1", "value1");
|
||||
std::string str = stream.str();
|
||||
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse single value");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConfigurationTest, TestFinal) {
|
||||
{
|
||||
/* Explicitly non-final non-compact value */
|
||||
std::stringstream stream;
|
||||
stream << "<configuration><property><name>key1</name><value>value1</"
|
||||
"value><final>false</final></property></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse first stream");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
|
||||
std::stringstream stream2;
|
||||
simpleConfigStream(stream2, "key1", "value2");
|
||||
optional<Configuration> config2 =
|
||||
config->OverlayResourceString(stream2.str());
|
||||
EXPECT_TRUE(config2 && "Parse second stream");
|
||||
EXPECT_EQ("value2", config2->GetWithDefault("key1", ""));
|
||||
}
|
||||
{
|
||||
/* Explicitly final non-compact value */
|
||||
std::stringstream stream;
|
||||
stream << "<configuration><property><name>key1</name><value>value1</"
|
||||
"value><final>true</final></property></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse first stream");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
|
||||
std::stringstream stream2;
|
||||
simpleConfigStream(stream2, "key1", "value2");
|
||||
optional<Configuration> config2 =
|
||||
config->OverlayResourceString(stream2.str());
|
||||
EXPECT_TRUE(config2 && "Parse second stream");
|
||||
EXPECT_EQ("value1", config2->GetWithDefault("key1", ""));
|
||||
}
|
||||
{
|
||||
/* Explicitly non-final compact value */
|
||||
std::stringstream stream;
|
||||
stream << "<configuration><property name=\"key1\" value=\"value1\" "
|
||||
"final=\"false\"/></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse first stream");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
|
||||
std::stringstream stream2;
|
||||
simpleConfigStream(stream2, "key1", "value2");
|
||||
optional<Configuration> config2 =
|
||||
config->OverlayResourceString(stream2.str());
|
||||
EXPECT_TRUE(config2 && "Parse second stream");
|
||||
EXPECT_EQ("value2", config2->GetWithDefault("key1", ""));
|
||||
}
|
||||
{
|
||||
/* Explicitly final compact value */
|
||||
std::stringstream stream;
|
||||
stream << "<configuration><property name=\"key1\" value=\"value1\" "
|
||||
"final=\"true\"/></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse first stream");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
|
||||
std::stringstream stream2;
|
||||
simpleConfigStream(stream2, "key1", "value2");
|
||||
optional<Configuration> config2 =
|
||||
config->OverlayResourceString(stream2.str());
|
||||
EXPECT_TRUE(config2 && "Parse second stream");
|
||||
EXPECT_EQ("value1", config2->GetWithDefault("key1", ""));
|
||||
}
|
||||
{
|
||||
/* Bogus final value */
|
||||
std::stringstream stream;
|
||||
stream << "<configuration><property><name>key1</name><value>value1</"
|
||||
"value><final>spam</final></property></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse first stream");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
|
||||
std::stringstream stream2;
|
||||
simpleConfigStream(stream2, "key1", "value2");
|
||||
optional<Configuration> config2 =
|
||||
config->OverlayResourceString(stream2.str());
|
||||
EXPECT_TRUE(config2 && "Parse second stream");
|
||||
EXPECT_EQ("value2", config2->GetWithDefault("key1", ""));
|
||||
}
|
||||
{
|
||||
/* Blank final value */
|
||||
std::stringstream stream;
|
||||
stream << "<configuration><property><name>key1</name><value>value1</"
|
||||
"value><final></final></property></configuration>";
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse first stream");
|
||||
EXPECT_EQ("value1", config->GetWithDefault("key1", ""));
|
||||
|
||||
std::stringstream stream2;
|
||||
simpleConfigStream(stream2, "key1", "value2");
|
||||
optional<Configuration> config2 =
|
||||
config->OverlayResourceString(stream2.str());
|
||||
EXPECT_TRUE(config2 && "Parse second stream");
|
||||
EXPECT_EQ("value2", config2->GetWithDefault("key1", ""));
|
||||
}
|
||||
}
|
||||
TEST(ConfigurationTest, TestIntConversions) {
|
||||
/* No defaults */
|
||||
{
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, "key1", "1");
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse single value");
|
||||
optional<int64_t> value = config->GetInt("key1");
|
||||
EXPECT_TRUE((bool)value);
|
||||
EXPECT_EQ(1, *value);
|
||||
EXPECT_FALSE(config->GetInt("key2"));
|
||||
}
|
||||
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "1");
|
||||
EXPECT_EQ(1, config->GetIntWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "-100");
|
||||
EXPECT_EQ(-100, config->GetIntWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", " 1 ");
|
||||
EXPECT_EQ(1, config->GetIntWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "");
|
||||
EXPECT_EQ(-1, config->GetIntWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "spam");
|
||||
EXPECT_EQ(-1, config->GetIntWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key2", "");
|
||||
EXPECT_EQ(-1, config->GetIntWithDefault("key1", -1));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConfigurationTest, TestDoubleConversions) {
|
||||
/* No defaults */
|
||||
{
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, "key1", "1");
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse single value");
|
||||
optional<double> value = config->GetDouble("key1");
|
||||
EXPECT_TRUE((bool)value);
|
||||
EXPECT_EQ(1, *value);
|
||||
EXPECT_FALSE(config->GetDouble("key2"));
|
||||
}
|
||||
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "1");
|
||||
EXPECT_EQ(1, config->GetDoubleWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "-100");
|
||||
EXPECT_EQ(-100, config->GetDoubleWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", " 1 ");
|
||||
EXPECT_EQ(1, config->GetDoubleWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "");
|
||||
EXPECT_EQ(-1, config->GetDoubleWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "spam");
|
||||
EXPECT_EQ(-1, config->GetDoubleWithDefault("key1", -1));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key2", "");
|
||||
EXPECT_EQ(-1, config->GetDoubleWithDefault("key1", -1));
|
||||
}
|
||||
{ /* Out of range */
|
||||
optional<Configuration> config = simpleConfig("key2", "1e9999");
|
||||
EXPECT_EQ(-1, config->GetDoubleWithDefault("key1", -1));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConfigurationTest, TestBoolConversions) {
|
||||
/* No defaults */
|
||||
{
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, "key1", "true");
|
||||
optional<Configuration> config = Configuration::Load(stream.str());
|
||||
EXPECT_TRUE(config && "Parse single value");
|
||||
optional<bool> value = config->GetBool("key1");
|
||||
EXPECT_TRUE((bool)value);
|
||||
EXPECT_EQ(true, *value);
|
||||
EXPECT_FALSE(config->GetBool("key2"));
|
||||
}
|
||||
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "true");
|
||||
EXPECT_EQ(true, config->GetBoolWithDefault("key1", false));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "tRuE");
|
||||
EXPECT_EQ(true, config->GetBoolWithDefault("key1", false));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "false");
|
||||
EXPECT_FALSE(config->GetBoolWithDefault("key1", true));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "FaLsE");
|
||||
EXPECT_FALSE(config->GetBoolWithDefault("key1", true));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", " FaLsE ");
|
||||
EXPECT_FALSE(config->GetBoolWithDefault("key1", true));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "");
|
||||
EXPECT_EQ(true, config->GetBoolWithDefault("key1", true));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "spam");
|
||||
EXPECT_EQ(true, config->GetBoolWithDefault("key1", true));
|
||||
}
|
||||
{
|
||||
optional<Configuration> config = simpleConfig("key1", "");
|
||||
EXPECT_EQ(true, config->GetBoolWithDefault("key2", true));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* The following line must be executed to initialize Google Mock
|
||||
* (and Google Test) before running the tests.
|
||||
*/
|
||||
::testing::InitGoogleMock(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef TESTS_CONFIGURATION_H_
|
||||
#define TESTS_CONFIGURATION_H_
|
||||
|
||||
#include "common/configuration.h"
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
namespace hdfs {
|
||||
|
||||
template <typename T, typename U>
|
||||
void simpleConfigStreamProperty(std::stringstream& out, T key, U value) {
|
||||
out << "<property>"
|
||||
<< "<name>" << key << "</name>"
|
||||
<< "<value>" << value << "</value>"
|
||||
<< "</property>";
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename... Args>
|
||||
void simpleConfigStreamProperty(std::stringstream& out, T key, U value,
|
||||
Args... args) {
|
||||
simpleConfigStreamProperty(out, key, value);
|
||||
simpleConfigStreamProperty(out, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void simpleConfigStream(std::stringstream& out, Args... args) {
|
||||
out << "<configuration>";
|
||||
simpleConfigStreamProperty(out, args...);
|
||||
out << "</configuration>";
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
optional<Configuration> simpleConfig(Args... args) {
|
||||
Configuration result;
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, args...);
|
||||
optional<Configuration> parse = result.Load(stream.str());
|
||||
EXPECT_TRUE((bool)parse);
|
||||
|
||||
return parse;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void writeSimpleConfig(const std::string& filename, Args... args) {
|
||||
std::stringstream stream;
|
||||
simpleConfigStream(stream, args...);
|
||||
|
||||
std::ofstream out;
|
||||
out.open(filename);
|
||||
out << stream.rdbuf();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue