2017-01-18 01:08:28 +01:00
|
|
|
// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
|
2016-12-22 11:57:32 +01:00
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
2017-01-18 01:08:28 +01:00
|
|
|
#include <stdint.h>
|
2016-12-22 11:57:32 +01:00
|
|
|
#include <cc/simple_parser.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
using namespace isc::data;
|
2017-01-26 20:34:45 +01:00
|
|
|
using isc::dhcp::DhcpConfigError;
|
2016-12-22 11:57:32 +01:00
|
|
|
|
|
|
|
/// This table defines sample default values. Although these are DHCPv6
|
|
|
|
/// specific, the mechanism is generic and can be used by any other component.
|
|
|
|
const SimpleDefaults SAMPLE_DEFAULTS = {
|
|
|
|
{ "renew-timer", Element::integer, "900" },
|
|
|
|
{ "rebind-timer", Element::integer, "1800" },
|
|
|
|
{ "preferred-lifetime", Element::integer, "3600" },
|
|
|
|
{ "valid-lifetime", Element::integer, "7200" }
|
|
|
|
};
|
|
|
|
|
|
|
|
/// This list defines parameters that can be inherited from one scope
|
|
|
|
/// to another. Although these are DHCPv6 specific, the mechanism is generic and
|
|
|
|
/// can be used by any other component.
|
|
|
|
const ParamsList SAMPLE_INHERITS = {
|
|
|
|
"renew-timer",
|
|
|
|
"rebind-timer",
|
|
|
|
"preferred-lifetime",
|
|
|
|
"valid-lifetime"
|
|
|
|
};
|
|
|
|
|
|
|
|
/// @brief Simple Parser test fixture class
|
|
|
|
class SimpleParserTest : public ::testing::Test {
|
|
|
|
public:
|
|
|
|
/// @brief Checks if specified map has an integer parameter with expected value
|
|
|
|
///
|
|
|
|
/// @param map map to be checked
|
|
|
|
/// @param param_name name of the parameter to be checked
|
|
|
|
/// @param exp_value expected value of the parameter.
|
|
|
|
void checkIntegerValue(const ConstElementPtr& map, const std::string& param_name,
|
|
|
|
int64_t exp_value) {
|
|
|
|
|
|
|
|
// First check if the passed element is a map.
|
|
|
|
ASSERT_EQ(Element::map, map->getType());
|
|
|
|
|
|
|
|
// Now try to get the element being checked
|
|
|
|
ConstElementPtr elem = map->get(param_name);
|
|
|
|
ASSERT_TRUE(elem);
|
|
|
|
|
|
|
|
// Now check if it's indeed integer
|
|
|
|
ASSERT_EQ(Element::integer, elem->getType());
|
|
|
|
|
|
|
|
// Finally, check if its value meets expectation.
|
|
|
|
EXPECT_EQ(exp_value, elem->intValue());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-18 01:08:28 +01:00
|
|
|
class SimpleParserClassTest : public SimpleParser {
|
|
|
|
public:
|
2017-03-04 21:57:52 +01:00
|
|
|
/// @brief Instantiation of getIntType for uint8_t
|
|
|
|
///
|
|
|
|
/// @param scope specified parameter will be extracted from this scope
|
|
|
|
/// @param name name of the parameter for error report
|
|
|
|
/// @return an uint8_t value
|
|
|
|
uint8_t getUint8(ConstElementPtr scope, const std::string& name) {
|
|
|
|
return (getIntType<uint8_t>(scope, name));
|
|
|
|
}
|
2017-01-18 01:08:28 +01:00
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
/// @brief Instantiation of getAndConvert
|
2017-01-18 12:01:15 +01:00
|
|
|
///
|
2017-01-26 20:34:45 +01:00
|
|
|
/// @param scope specified parameter will be extracted from this scope
|
2017-01-18 12:01:15 +01:00
|
|
|
/// @param name name of the parameter for error report
|
|
|
|
/// @return a bool value
|
2017-01-26 20:34:45 +01:00
|
|
|
bool getAsBool(ConstElementPtr scope, const std::string& name) {
|
|
|
|
return (getAndConvert<bool, toBool>(scope, name, "boolean"));
|
2017-01-18 12:01:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Convert to boolean
|
|
|
|
///
|
|
|
|
/// @param str the string "false" or "true"
|
|
|
|
/// @return false for "false" and true for "true"
|
|
|
|
/// @thrown isc::OutOfRange if not "false" or "true'
|
|
|
|
static bool toBool(const std::string& str) {
|
|
|
|
if (str == "false") {
|
|
|
|
return (false);
|
|
|
|
} else if (str == "true") {
|
|
|
|
return (true);
|
|
|
|
} else {
|
|
|
|
isc_throw(TypeError, "not a boolean: " << str);
|
|
|
|
}
|
|
|
|
}
|
2017-01-18 01:08:28 +01:00
|
|
|
};
|
|
|
|
|
2016-12-22 11:57:32 +01:00
|
|
|
// This test checks if the parameters can be inherited from the global
|
|
|
|
// scope to the subnet scope.
|
|
|
|
TEST_F(SimpleParserTest, deriveParams) {
|
|
|
|
ElementPtr global = Element::fromJSON("{ \"renew-timer\": 1,"
|
|
|
|
" \"rebind-timer\": 2,"
|
|
|
|
" \"preferred-lifetime\": 3,"
|
|
|
|
" \"valid-lifetime\": 4"
|
|
|
|
"}");
|
|
|
|
ElementPtr subnet = Element::fromJSON("{ \"renew-timer\": 100 }");
|
|
|
|
|
|
|
|
// we should inherit 3 parameters. Renew-timer should remain intact,
|
|
|
|
// as it was already defined in the subnet scope.
|
|
|
|
size_t num;
|
|
|
|
EXPECT_NO_THROW(num = SimpleParser::deriveParams(global, subnet,
|
|
|
|
SAMPLE_INHERITS));
|
|
|
|
EXPECT_EQ(3, num);
|
|
|
|
|
2016-12-24 14:01:50 +01:00
|
|
|
// Check the values. 3 of them are inherited, while the fourth one
|
2016-12-22 11:57:32 +01:00
|
|
|
// was already defined in the subnet, so should not be inherited.
|
|
|
|
checkIntegerValue(subnet, "renew-timer", 100);
|
|
|
|
checkIntegerValue(subnet, "rebind-timer", 2);
|
|
|
|
checkIntegerValue(subnet, "preferred-lifetime", 3);
|
|
|
|
checkIntegerValue(subnet, "valid-lifetime", 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This test checks if global defaults are properly set for DHCPv6.
|
|
|
|
TEST_F(SimpleParserTest, setDefaults) {
|
|
|
|
|
|
|
|
ElementPtr empty = Element::fromJSON("{ }");
|
|
|
|
size_t num = 0;
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(num = SimpleParser::setDefaults(empty, SAMPLE_DEFAULTS));
|
|
|
|
|
|
|
|
// We expect at least 4 parameters to be inserted.
|
|
|
|
EXPECT_GE(num, 3);
|
|
|
|
|
|
|
|
checkIntegerValue(empty, "valid-lifetime", 7200);
|
|
|
|
checkIntegerValue(empty, "preferred-lifetime", 3600);
|
|
|
|
checkIntegerValue(empty, "rebind-timer", 1800);
|
|
|
|
checkIntegerValue(empty, "renew-timer", 900);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This test checks if global defaults are properly set for DHCPv6.
|
|
|
|
TEST_F(SimpleParserTest, setListDefaults) {
|
|
|
|
|
|
|
|
ElementPtr empty = Element::fromJSON("[{}, {}, {}]");
|
|
|
|
size_t num;
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(num = SimpleParser::setListDefaults(empty, SAMPLE_DEFAULTS));
|
|
|
|
|
|
|
|
// We expect at least 12 parameters to be inserted (3 entries, with
|
|
|
|
// 4 parameters inserted in each)
|
|
|
|
EXPECT_EQ(12, num);
|
|
|
|
|
|
|
|
ASSERT_EQ(Element::list, empty->getType());
|
|
|
|
ASSERT_EQ(3, empty->size());
|
|
|
|
|
|
|
|
ConstElementPtr first = empty->get(0);
|
|
|
|
ConstElementPtr second = empty->get(1);
|
|
|
|
ConstElementPtr third = empty->get(2);
|
|
|
|
|
|
|
|
checkIntegerValue(first, "valid-lifetime", 7200);
|
|
|
|
checkIntegerValue(first, "preferred-lifetime", 3600);
|
|
|
|
checkIntegerValue(first, "rebind-timer", 1800);
|
|
|
|
checkIntegerValue(first, "renew-timer", 900);
|
|
|
|
|
|
|
|
checkIntegerValue(second, "valid-lifetime", 7200);
|
|
|
|
checkIntegerValue(second, "preferred-lifetime", 3600);
|
|
|
|
checkIntegerValue(second, "rebind-timer", 1800);
|
|
|
|
checkIntegerValue(second, "renew-timer", 900);
|
|
|
|
|
|
|
|
checkIntegerValue(third, "valid-lifetime", 7200);
|
|
|
|
checkIntegerValue(third, "preferred-lifetime", 3600);
|
|
|
|
checkIntegerValue(third, "rebind-timer", 1800);
|
|
|
|
checkIntegerValue(third, "renew-timer", 900);
|
|
|
|
}
|
2017-01-18 01:08:28 +01:00
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
// This test exercises the getIntType template
|
|
|
|
TEST_F(SimpleParserTest, getIntType) {
|
2017-01-18 01:08:28 +01:00
|
|
|
|
|
|
|
SimpleParserClassTest parser;
|
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
// getIntType checks it can be found
|
|
|
|
ElementPtr not_found = Element::fromJSON("{ \"bar\": 1 }");
|
|
|
|
EXPECT_THROW(parser.getUint8(not_found, "foo"), DhcpConfigError);
|
2017-01-18 01:08:28 +01:00
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
// getIntType checks if it is an integer
|
|
|
|
ElementPtr not_int = Element::fromJSON("{ \"foo\": \"xyz\" }");
|
|
|
|
EXPECT_THROW(parser.getUint8(not_int, "foo"), DhcpConfigError);
|
2017-01-18 01:08:28 +01:00
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
// getIntType checks bounds
|
|
|
|
ElementPtr negative = Element::fromJSON("{ \"foo\": -1 }");
|
|
|
|
EXPECT_THROW(parser.getUint8(negative, "foo"), DhcpConfigError);
|
|
|
|
ElementPtr too_large = Element::fromJSON("{ \"foo\": 1024 }");
|
|
|
|
EXPECT_THROW(parser.getUint8(too_large, "foo"), DhcpConfigError);
|
|
|
|
|
|
|
|
// checks if getIntType can return the expected value
|
|
|
|
ElementPtr hundred = Element::fromJSON("{ \"foo\": 100 }");
|
2017-01-18 01:08:28 +01:00
|
|
|
uint8_t val = 0;
|
2017-01-26 20:34:45 +01:00
|
|
|
EXPECT_NO_THROW(val = parser.getUint8(hundred, "foo"));
|
2017-01-18 01:08:28 +01:00
|
|
|
EXPECT_EQ(100, val);
|
|
|
|
}
|
2017-01-18 12:01:15 +01:00
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
// This test exercises the getAndConvert template
|
|
|
|
TEST_F(SimpleParserTest, getAndConvert) {
|
2017-01-18 12:01:15 +01:00
|
|
|
|
|
|
|
SimpleParserClassTest parser;
|
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
// getAndConvert checks it can be found
|
|
|
|
ElementPtr not_found = Element::fromJSON("{ \"bar\": \"true\" }");
|
|
|
|
EXPECT_THROW(parser.getAsBool(not_found, "foo"), DhcpConfigError);
|
|
|
|
|
|
|
|
// getAndConvert checks if it is a string
|
|
|
|
ElementPtr not_bool = Element::fromJSON("{ \"foo\": 1 }");
|
|
|
|
EXPECT_THROW(parser.getAsBool(not_bool, "foo"), DhcpConfigError);
|
2017-01-18 12:01:15 +01:00
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
// checks if getAndConvert can return the expected value
|
|
|
|
ElementPtr a_bool = Element::fromJSON("{ \"foo\": \"false\" }");
|
2017-01-18 12:01:15 +01:00
|
|
|
bool val = true;
|
2017-01-26 20:34:45 +01:00
|
|
|
EXPECT_NO_THROW(val = parser.getAsBool(a_bool, "foo"));
|
2017-01-18 12:01:15 +01:00
|
|
|
EXPECT_FALSE(val);
|
|
|
|
|
2017-01-26 20:34:45 +01:00
|
|
|
// getAndConvert checks convertion
|
|
|
|
ElementPtr bad_bool = Element::fromJSON("{ \"foo\": \"bar\" }");
|
|
|
|
EXPECT_THROW(parser.getAsBool(bad_bool, "bar"), DhcpConfigError);
|
2017-01-18 12:01:15 +01:00
|
|
|
}
|
|
|
|
|