Replace config visit pattern with explicit lookups

This is an initial pass at doing explicit value checks when handling
config parsing, as opposed to using a visiting pattern. The latter
made it difficult to check for conditions such as missing required
values, multiple values, etc.

It was also generally less readable (think declarative) which further
made it difficult to get a grasp for what our actual configuration file
requirements were.
pull/1186/head
Stephen Shelton 4 years ago
parent 858e252820
commit 9d71228e74
No known key found for this signature in database
GPG Key ID: EE4BADACCE8B631C

@ -5,6 +5,7 @@
#include <constants/limits.hpp> #include <constants/limits.hpp>
#include <net/net.hpp> #include <net/net.hpp>
#include <router_contact.hpp> #include <router_contact.hpp>
#include <stdexcept>
#include <util/fs.hpp> #include <util/fs.hpp>
#include <util/logging/logger_syslog.hpp> #include <util/logging/logger_syslog.hpp>
#include <util/logging/logger.hpp> #include <util/logging/logger.hpp>
@ -92,138 +93,171 @@ namespace llarp
return {}; return {};
} }
void bool
RouterConfig::fromSection(string_view key, string_view val) RouterConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "job-queue-size") // [router]:job-queue-size
{ auto parsedValue = parser.getSingleSectionValue(values, "router", "job-queue-size", false);
auto sval = svtoi(val); if (not parsedValue.empty())
if (sval >= 1024)
{
m_JobQueueSize = sval;
LogInfo("Set job queue size to ", m_JobQueueSize);
}
}
if (key == "default-protocol")
{ {
m_DefaultLinkProto = str(val); int val = svtoi(parsedValue);
LogInfo("overriding default link protocol to '", val, "'"); if (val < 1024)
} throw std::invalid_argument("invalid value for [router]:job-queue-size, must be 1024 or greater");
if (key == "netid")
{
if (val.size() <= NetID::size())
{
m_netId = str(val);
LogInfo("setting netid to '", val, "'");
}
else else
{ m_JobQueueSize = val;
llarp::LogError("invalid netid '", val, "', is too long");
}
} }
if (key == "max-connections")
// [router]:default-protocol
parsedValue = parser.getSingleSectionValue(values, "router", "default-protocol", false);
if (not parsedValue.empty())
m_DefaultLinkProto = parsedValue;
// [router]:netid
parsedValue = parser.getSingleSectionValue(values, "router", "netid", true);
assert(not parsedValue.empty()); // gauranteed by getSingleSectionValue() with required == true
if(parsedValue.size() > NetID::size())
throw std::invalid_argument("value for [router]:netid is too long");
m_netId = str(parsedValue);
// [router]:max-connections
parsedValue = parser.getSingleSectionValue(values, "router", "max-connections", false);
if (not parsedValue.empty())
{ {
auto ival = svtoi(val); int val = svtoi(parsedValue);
if (ival > 0) if (val < 1)
{ throw std::invalid_argument("invalid value for [router]:max-connections");
m_maxConnectedRouters = ival; else
LogInfo("max connections set to ", m_maxConnectedRouters); m_maxConnectedRouters = val;
}
} }
if (key == "min-connections")
// [router]:min-connections
parsedValue = parser.getSingleSectionValue(values, "router", "min-connections", false);
if (not parsedValue.empty())
{ {
auto ival = svtoi(val); int val = svtoi(parsedValue);
if (ival > 0) if (val < 1)
{ throw std::invalid_argument("invalid value for [router]:min-connections");
m_minConnectedRouters = ival; else
LogInfo("min connections set to ", m_minConnectedRouters); m_minConnectedRouters = val;
}
} }
if (key == "nickname")
// additional check that min <= max
if (m_minConnectedRouters > m_maxConnectedRouters)
throw std::invalid_argument("[router]:min-connections must be less than [router]:max-connections");
// [router]:nickname
parsedValue = parser.getSingleSectionValue(values, "router", "nickname", false);
if (not parsedValue.empty())
{ {
m_nickname = str(val); m_nickname = str(parsedValue);
// set logger name here // TODO: side effect here, no side effects in config parsing!!
LogContext::Instance().nodeName = nickname(); LogContext::Instance().nodeName = nickname();
LogInfo("nickname set");
}
if (key == "encryption-privkey")
{
m_encryptionKeyfile = str(val);
LogDebug("encryption key set to ", m_encryptionKeyfile);
}
if (key == "contact-file")
{
m_ourRcFile = str(val);
LogDebug("rc file set to ", m_ourRcFile);
}
if (key == "transport-privkey")
{
m_transportKeyfile = str(val);
LogDebug("transport key set to ", m_transportKeyfile);
} }
if ((key == "identity-privkey" || key == "ident-privkey"))
{ // [router]:encryption-privkey
m_identKeyfile = str(val); parsedValue = parser.getSingleSectionValue(values, "router", "encryption-privkey", false);
LogDebug("identity key set to ", m_identKeyfile); if (not parsedValue.empty())
} m_encryptionKeyfile = str(parsedValue);
if (key == "public-address" || key == "public-ip")
{ // [router]:contact-file
llarp::LogInfo("public ip ", val, " size ", val.size()); parsedValue = parser.getSingleSectionValue(values, "router", "contact-file", false);
if (val.size() < 17) if (not parsedValue.empty())
m_ourRcFile = str(parsedValue);
// [router]:transport-privkey
parsedValue = parser.getSingleSectionValue(values, "router", "transport-privkey", false);
if (not parsedValue.empty())
m_transportKeyfile = str(parsedValue);
// [router]:identity-privkey OR
// [router]:ident-privkey
// apparently loki-launcher made its own config files at one point and typoed this,
// so we support both
parsedValue = parser.getSingleSectionValue(values, "router", "identity-privkey", false);
if (parsedValue.empty())
parsedValue = parser.getSingleSectionValue(values, "router", "ident-privkey", false);
if (not parsedValue.empty())
m_identKeyfile = str(parsedValue);
// [router]:public-address OR
// [router]:public-ip
// apparently loki-launcher made its own config files at one point and typoed this,
// so we support both
parsedValue = parser.getSingleSectionValue(values, "router", "public-address", false);
if (parsedValue.empty())
parsedValue = parser.getSingleSectionValue(values, "router", "public-ip", false);
if (not parsedValue.empty())
{
llarp::LogInfo("public ip ", parsedValue, " size ", parsedValue.size());
if(parsedValue.size() < 17)
{ {
// assume IPv4 // assume IPv4
llarp::Addr a(val); llarp::Addr a(parsedValue);
llarp::LogInfo("setting public ipv4 ", a); llarp::LogInfo("setting public ipv4 ", a);
m_addrInfo.ip = *a.addr6(); m_addrInfo.ip = *a.addr6();
m_publicOverride = true; m_publicOverride = true;
} }
} }
if (key == "public-port")
// [router]:public-port
parsedValue = parser.getSingleSectionValue(values, "router", "public-port", false);
if (not parsedValue.empty())
{ {
llarp::LogInfo("Setting public port ", val); llarp::LogInfo("Setting public port ", parsedValue);
int p = svtoi(val); int p = svtoi(parsedValue);
// Not needed to flip upside-down - this is done in llarp::Addr(const // Not needed to flip upside-down - this is done in llarp::Addr(const
// AddressInfo&) // AddressInfo&)
m_ip4addr.sin_port = p; m_ip4addr.sin_port = p;
m_addrInfo.port = p; m_addrInfo.port = p;
m_publicOverride = true; m_publicOverride = true;
} }
if (key == "worker-threads" || key == "threads")
// [router]:worker-threads OR
// [router]:threads
// apparently loki-launcher made its own config files at one point and typoed this,
// so we support both
parsedValue = parser.getSingleSectionValue(values, "router", "worker-threads", false);
if (parsedValue.empty())
parsedValue = parser.getSingleSectionValue(values, "router", "threads", false);
if (not parsedValue.empty())
{ {
m_workerThreads = svtoi(val); int val = svtoi(parsedValue);
if (m_workerThreads <= 0) if(val <= 0)
{ throw std::invalid_argument("invalid value for [router]:worker-threads");
LogWarn("worker threads invalid value: '", val, "' defaulting to 1");
m_workerThreads = 1;
}
else else
{ m_workerThreads = val;
LogDebug("set to use ", m_workerThreads, " worker threads");
}
} }
if (key == "net-threads")
// [router]:public-port
parsedValue = parser.getSingleSectionValue(values, "router", "public-port", false);
if (not parsedValue.empty())
{ {
m_numNetThreads = svtoi(val); int val = svtoi(parsedValue);
if (m_numNetThreads <= 0) if (val <= 0)
{ throw std::invalid_argument("invalid value for [router]:public-port");
LogWarn("net threads invalid value: '", val, "' defaulting to 1");
m_numNetThreads = 1;
}
else else
{ m_numNetThreads = val;
LogDebug("set to use ", m_numNetThreads, " net threads");
}
} }
if (key == "block-bogons")
// [router]:block-bogons
parsedValue = parser.getSingleSectionValue(values, "router", "block-bogons", false);
if (not parsedValue.empty())
{ {
m_blockBogons = setOptBool(val); auto val = setOptBool(parsedValue);
if (not val.has_value())
throw std::invalid_argument("invalid value for [router]:block-bogons");
else
m_blockBogons = val;
} }
return true;
} }
void bool
NetworkConfig::fromSection(string_view key, string_view val) NetworkConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "profiling") /*
if(key == "profiling")
{ {
m_enableProfiling = setOptBool(val); m_enableProfiling = setOptBool(val);
} }
@ -240,21 +274,28 @@ namespace llarp
{ {
m_netConfig.emplace(str(key), str(val)); // str()'s here for gcc 5 compat m_netConfig.emplace(str(key), str(val)); // str()'s here for gcc 5 compat
} }
*/
return true;
} }
void bool
NetdbConfig::fromSection(string_view key, string_view val) NetdbConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "dir") /*
if(key == "dir")
{ {
m_nodedbDir = str(val); m_nodedbDir = str(val);
} }
*/
return true;
} }
void bool
DnsConfig::fromSection(string_view key, string_view val) DnsConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "upstream") /*
if(key == "upstream")
{ {
llarp::LogInfo("add upstream resolver ", val); llarp::LogInfo("add upstream resolver ", val);
netConfig.emplace("upstream-dns", str(val)); // str() for gcc 5 compat netConfig.emplace("upstream-dns", str(val)); // str() for gcc 5 compat
@ -264,11 +305,14 @@ namespace llarp
llarp::LogInfo("set local dns to ", val); llarp::LogInfo("set local dns to ", val);
netConfig.emplace("local-dns", str(val)); // str() for gcc 5 compat netConfig.emplace("local-dns", str(val)); // str() for gcc 5 compat
} }
*/
return true;
} }
void bool
LinksConfig::fromSection(string_view key, string_view val) LinksConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
/*
uint16_t proto = 0; uint16_t proto = 0;
std::unordered_set<std::string> parsed_opts; std::unordered_set<std::string> parsed_opts;
@ -317,33 +361,41 @@ namespace llarp
// str() here for gcc 5 compat // str() here for gcc 5 compat
m_InboundLinks.emplace_back(str(key), AF_INET, proto, std::move(opts)); m_InboundLinks.emplace_back(str(key), AF_INET, proto, std::move(opts));
} }
*/
return true;
} }
void bool
ConnectConfig::fromSection(string_view /*key*/, string_view val) ConnectConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
routers.emplace_back(val.begin(), val.end()); // routers.emplace_back(val.begin(), val.end());
return true;
} }
void bool
ServicesConfig::fromSection(string_view key, string_view val) ServicesConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
services.emplace_back(str(key), str(val)); // str()'s here for gcc 5 compat // services.emplace_back(str(key), str(val)); // str()'s here for gcc 5 compat
return true;
} }
void bool
SystemConfig::fromSection(string_view key, string_view val) SystemConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "pidfile") /*
if(key == "pidfile")
{ {
pidfile = str(val); pidfile = str(val);
} }
*/
return true;
} }
void bool
ApiConfig::fromSection(string_view key, string_view val) ApiConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "enabled") /*
if(key == "enabled")
{ {
m_enableRPCServer = IsTrueValue(val); m_enableRPCServer = IsTrueValue(val);
} }
@ -355,12 +407,15 @@ namespace llarp
{ {
// TODO: add pubkey to whitelist // TODO: add pubkey to whitelist
} }
*/
return true;
} }
void bool
LokidConfig::fromSection(string_view key, string_view val) LokidConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "service-node-seed") /*
if(key == "service-node-seed")
{ {
usingSNSeed = true; usingSNSeed = true;
ident_keyfile = std::string{val}; ident_keyfile = std::string{val};
@ -381,21 +436,27 @@ namespace llarp
{ {
lokidRPCPassword = str(val); lokidRPCPassword = str(val);
} }
*/
return true;
} }
void bool
BootstrapConfig::fromSection(string_view key, string_view val) BootstrapConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "add-node") /*
if(key == "add-node")
{ {
routers.emplace_back(val.begin(), val.end()); routers.emplace_back(val.begin(), val.end());
} }
*/
return true;
} }
void bool
LoggingConfig::fromSection(string_view key, string_view val) LoggingConfig::parseSectionValues(const ConfigParser& parser, const SectionValues_t& values)
{ {
if (key == "type" && val == "syslog") /*
if(key == "type" && val == "syslog")
{ {
// TODO(despair): write event log syslog class // TODO(despair): write event log syslog class
#if defined(_WIN32) #if defined(_WIN32)
@ -443,25 +504,26 @@ namespace llarp
::abort(); ::abort();
} }
} }
*/
return true;
} }
template < typename Section > template < typename Section >
Section Section
find_section(const ConfigParser &parser, const std::string &name) find_section(const ConfigParser &parser, const std::string &name)
{ {
Section ret; Section section;
auto visitor = [&ret](const ConfigParser::Section_t& section) -> bool { auto visitor = [&](const ConfigParser::SectionValues_t& sectionValues) {
for (const auto& sec : section) return section.parseSectionValues(parser, sectionValues);
{
ret.fromSection(sec.first, sec.second);
}
return true;
}; };
// TODO: exceptions, please. fuck.
// parser.VisitSection just passes-through the return value of our
// lambda from above
if(parser.VisitSection(name.c_str(), visitor)) if(parser.VisitSection(name.c_str(), visitor))
{ {
return ret; return section;
} }
return {}; return {};

@ -5,6 +5,7 @@
#include <router_contact.hpp> #include <router_contact.hpp>
#include <util/fs.hpp> #include <util/fs.hpp>
#include <util/str.hpp> #include <util/str.hpp>
#include <config/ini.hpp>
#include <cstdlib> #include <cstdlib>
#include <functional> #include <functional>
@ -16,7 +17,8 @@
struct llarp_config; struct llarp_config;
namespace llarp namespace llarp
{ {
struct ConfigParser; using SectionValues_t = llarp::ConfigParser::SectionValues_t;
using Config_impl_t = llarp::ConfigParser::Config_impl_t;
inline const char* inline const char*
lokinetEnv(string_view suffix); lokinetEnv(string_view suffix);
@ -88,8 +90,8 @@ namespace llarp
nonstd::optional< bool > blockBogons() const { return fromEnv(m_blockBogons, "BLOCK_BOGONS"); } nonstd::optional< bool > blockBogons() const { return fromEnv(m_blockBogons, "BLOCK_BOGONS"); }
// clang-format on // clang-format on
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
class NetworkConfig class NetworkConfig
@ -111,8 +113,8 @@ namespace llarp
const NetConfig& netConfig() const { return m_netConfig; } const NetConfig& netConfig() const { return m_netConfig; }
// clang-format on // clang-format on
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
class NetdbConfig class NetdbConfig
@ -125,16 +127,16 @@ namespace llarp
std::string nodedbDir() const { return fromEnv(m_nodedbDir, "NODEDB_DIR"); } std::string nodedbDir() const { return fromEnv(m_nodedbDir, "NODEDB_DIR"); }
// clang-format on // clang-format on
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
struct DnsConfig struct DnsConfig
{ {
std::unordered_multimap<std::string, std::string> netConfig; std::unordered_multimap<std::string, std::string> netConfig;
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
class LinksConfig class LinksConfig
@ -160,31 +162,31 @@ namespace llarp
const Links& inboundLinks() const { return m_InboundLinks; } const Links& inboundLinks() const { return m_InboundLinks; }
// clang-format on // clang-format on
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
struct ConnectConfig struct ConnectConfig
{ {
std::vector<std::string> routers; std::vector<std::string> routers;
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
struct ServicesConfig struct ServicesConfig
{ {
std::vector<std::pair<std::string, std::string>> services; std::vector< std::pair< std::string, std::string > > services;
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
struct SystemConfig struct SystemConfig
{ {
std::string pidfile; std::string pidfile;
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
class ApiConfig class ApiConfig
@ -199,8 +201,8 @@ namespace llarp
std::string rpcBindAddr() const { return fromEnv(m_rpcBindAddr, "RPC_BIND_ADDR"); } std::string rpcBindAddr() const { return fromEnv(m_rpcBindAddr, "RPC_BIND_ADDR"); }
// clang-format on // clang-format on
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
struct LokidConfig struct LokidConfig
@ -212,15 +214,15 @@ namespace llarp
std::string lokidRPCUser; std::string lokidRPCUser;
std::string lokidRPCPassword; std::string lokidRPCPassword;
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
struct BootstrapConfig struct BootstrapConfig
{ {
std::vector<std::string> routers; std::vector< std::string > routers;
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
struct LoggingConfig struct LoggingConfig
@ -228,8 +230,8 @@ namespace llarp
bool m_LogJSON = false; bool m_LogJSON = false;
FILE* m_LogFile = stdout; FILE* m_LogFile = stdout;
void bool
fromSection(string_view key, string_view val); parseSectionValues(const ConfigParser& parser, const SectionValues_t& values);
}; };
struct Config struct Config

@ -1,11 +1,13 @@
#include <config/ini.hpp> #include <config/ini.hpp>
#include <util/logging/logger.hpp> #include <util/logging/logger.hpp>
#include <util/str.hpp>
#include <cctype> #include <cctype>
#include <fstream> #include <fstream>
#include <list> #include <list>
#include <iostream> #include <iostream>
#include <cassert>
namespace llarp namespace llarp
{ {
@ -129,7 +131,7 @@ namespace llarp
LogError(m_FileName, " invalid line (", lineno, "): '", line, "'"); LogError(m_FileName, " invalid line (", lineno, "): '", line, "'");
return false; return false;
} }
Section_t& sect = m_Config[str(sectName)]; SectionValues_t& sect = m_Config[str(sectName)];
LogDebug(m_FileName, ": ", sectName, ".", k, "=", v); LogDebug(m_FileName, ": ", sectName, ".", k, "=", v);
sect.emplace(str(k), str(v)); // str()'s here for gcc 5 compat sect.emplace(str(k), str(v)); // str()'s here for gcc 5 compat
} }
@ -143,16 +145,56 @@ namespace llarp
} }
void void
ConfigParser::IterAll(std::function<void(string_view, const Section_t&)> visit) ConfigParser::IterAll(
std::function< void(string_view, const SectionValues_t&) > visit)
{ {
for (const auto& item : m_Config) for (const auto& item : m_Config)
visit(item.first, item.second); visit(item.first, item.second);
} }
const std::string emptyStr = "";
const std::string&
ConfigParser::getSingleSectionValue(
const SectionValues_t& values,
const std::string& section,
const std::string& key,
bool required,
bool tolerateMultiples) const
{
// section is provided for clarity / sanity check
assert(m_Config.find(section) != m_Config.end());
assert( & m_Config.find(section)->second == &values);
const auto sectionItr = m_Config.find(section);
if (sectionItr == m_Config.end())
throw std::invalid_argument(stringify("could not find section ", section));
const SectionValues_t& sectionValues = sectionItr->second;
if (not tolerateMultiples and sectionValues.count(key) > 1)
throw std::invalid_argument(stringify("config [", section, "]:", key, " cannot have multiple values for ", key));
const auto itr = sectionValues.find(key);
if (itr == sectionValues.end()) {
if (required)
throw std::invalid_argument(stringify("config [", section, "]:", key, " is missing"));
else
return emptyStr;
}
return itr->second;
}
bool bool
ConfigParser::VisitSection( ConfigParser::VisitSection(
const char* name, std::function<bool(const Section_t& sect)> visit) const const char* name,
std::function< bool(const SectionValues_t& sect) > visit) const
{ {
// m_Config is effectively:
// unordered_map< string, unordered_multimap< string, string >>
// in human terms: a map of of sections
// where a section is a multimap of k:v pairs
auto itr = m_Config.find(name); auto itr = m_Config.find(name);
if (itr == m_Config.end()) if (itr == m_Config.end())
return false; return false;

@ -12,8 +12,8 @@ namespace llarp
{ {
struct ConfigParser struct ConfigParser
{ {
using Section_t = std::unordered_multimap<std::string, std::string>; using SectionValues_t = std::unordered_multimap< std::string, std::string >;
using Config_impl_t = std::unordered_map<std::string, Section_t>; using Config_impl_t = std::unordered_map< std::string, SectionValues_t >;
/// clear parser /// clear parser
void void
Clear(); Clear();
@ -32,12 +32,35 @@ namespace llarp
/// iterate all sections and thier values /// iterate all sections and thier values
void void
IterAll(std::function<void(string_view, const Section_t&)> visit); IterAll(std::function< void(string_view, const SectionValues_t&) > visit);
/// visit a section in config read only by name /// visit a section in config read only by name
/// return false if no section or value propagated from visitor /// return false if no section or value propagated from visitor
bool bool
VisitSection(const char* name, std::function<bool(const Section_t&)> visit) const; VisitSection(const char* name,
std::function< bool(const SectionValues_t&) > visit) const;
/// Obtain a section value for the given key, additionally imposing the
/// provided constraints. an `invalid_argument` will be thrown if the
/// constraints aren't met.
///
/// The `section` parameter is redundant and added for readability, but a call to
/// m_Config[section] should result in the same object as `values`.
///
/// @param values is the SectionValues map in which to search for values
/// @param section should correspond to INI section tag related to this config
/// @param key is the key to look up
/// @param bool constrains whether this key must exist
/// @param tolerateMultiples constrains whether multiples are allowed
/// @return the first matching entry if found or empty string if not found
/// @throws std::invalid_argument if constrants aren't met or if `section` is not found
const std::string&
getSingleSectionValue(
const SectionValues_t& values,
const std::string& section,
const std::string& key,
bool required,
bool tolerateMultiples = false) const;
private: private:
bool bool

@ -12,13 +12,14 @@ namespace llarp
ConfigParser parser; ConfigParser parser;
if (!parser.LoadFile(fname)) if (!parser.LoadFile(fname))
return false; return false;
parser.IterAll([&](string_view name, const ConfigParser::Section_t& section) { parser.IterAll(
Config::section_t values; [&](string_view name, const ConfigParser::SectionValues_t& section) {
values.first.assign(name.begin(), name.end()); Config::section_t values;
for (const auto& item : section) values.first.assign(name.begin(), name.end());
values.second.emplace_back(item.first, item.second); for(const auto& item : section)
services.emplace_back(values); values.second.emplace_back(item.first, item.second);
}); services.emplace_back(values);
});
return services.size() > 0; return services.size() > 0;
} }

@ -20,7 +20,7 @@ TEST_F(TestINIParser, TestParseEmpty)
TEST_F(TestINIParser, TestParseOneSection) TEST_F(TestINIParser, TestParseOneSection)
{ {
llarp::ConfigParser::Section_t sect; llarp::ConfigParser::SectionValues_t sect;
// this is an anti pattern don't write this kind of code with configpaser // this is an anti pattern don't write this kind of code with configpaser
auto assertVisit = [&sect](const auto& section) -> bool { auto assertVisit = [&sect](const auto& section) -> bool {
sect = section; sect = section;

@ -63,36 +63,3 @@ TEST_F(LogLevelTest, TestLogLevelToString)
EXPECT_EQ("???", LogLevelToString(llarp::eLogNone)); EXPECT_EQ("???", LogLevelToString(llarp::eLogNone));
} }
TEST_F(LogLevelTest, TestLoggingConfigSideEffects)
{
// restore original runtime level when we're done
llarp::LogContext& logContext = llarp::LogContext::Instance();
auto original = logContext.runtimeLevel;
// LoggingConfig::fromSection updates the runtime level as it reads in conf
// values, so feed it values and ensure that the runtime level is updated
// appropriately
llarp::LoggingConfig config;
config.fromSection("level", "Trace");
EXPECT_EQ(llarp::eLogTrace, logContext.runtimeLevel);
config.fromSection("level", "Debug");
EXPECT_EQ(llarp::eLogDebug, logContext.runtimeLevel);
config.fromSection("level", "Info");
EXPECT_EQ(llarp::eLogInfo, logContext.runtimeLevel);
config.fromSection("level", "Warn");
EXPECT_EQ(llarp::eLogWarn, logContext.runtimeLevel);
config.fromSection("level", "Error");
EXPECT_EQ(llarp::eLogError, logContext.runtimeLevel);
config.fromSection("level", "None");
EXPECT_EQ(llarp::eLogNone, logContext.runtimeLevel);
SetLogLevel(original);
}

Loading…
Cancel
Save