mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 04:57:52 +00:00
[2544] Added test cases covering per subnet option value configuration.
This commit is contained in:
parent
16bdc3898a
commit
4114ac95b5
@ -74,6 +74,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~Dhcp4ParserTest() {
|
~Dhcp4ParserTest() {
|
||||||
|
resetConfiguration();
|
||||||
delete srv_;
|
delete srv_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,6 +118,50 @@ public:
|
|||||||
EXPECT_TRUE(memcmp(expected_data, data, expected_data_len));
|
EXPECT_TRUE(memcmp(expected_data, data, expected_data_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Reset configuration database.
|
||||||
|
///
|
||||||
|
/// This function resets configuration data base by
|
||||||
|
/// removing all subnets and option-data. Reset must
|
||||||
|
/// be performed after each test to make sure that
|
||||||
|
/// contents of the database do not affect result of
|
||||||
|
/// subsequent tests.
|
||||||
|
void resetConfiguration() {
|
||||||
|
ConstElementPtr status;
|
||||||
|
|
||||||
|
string config = "{ \"interface\": [ \"all\" ],"
|
||||||
|
"\"rebind-timer\": 2000, "
|
||||||
|
"\"renew-timer\": 1000, "
|
||||||
|
"\"valid-lifetime\": 4000, "
|
||||||
|
"\"subnet4\": [ ], "
|
||||||
|
"\"option-data\": [ ] }";
|
||||||
|
|
||||||
|
try {
|
||||||
|
ElementPtr json = Element::fromJSON(config);
|
||||||
|
status = configureDhcp4Server(*srv_, json);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
FAIL() << "Fatal error: unable to reset configuration database"
|
||||||
|
<< " after the test. The following configuration was used"
|
||||||
|
<< " to reset database: " << std::endl
|
||||||
|
<< config << std::endl
|
||||||
|
<< " and the following error message was returned:"
|
||||||
|
<< ex.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returned value should be 0 (configuration success)
|
||||||
|
if (!status) {
|
||||||
|
FAIL() << "Fatal error: unable to reset configuration database"
|
||||||
|
<< " after the test. Configuration function returned"
|
||||||
|
<< " NULL pointer" << std::endl;
|
||||||
|
}
|
||||||
|
comment_ = parseAnswer(rcode_, status);
|
||||||
|
if (rcode_ != 0) {
|
||||||
|
FAIL() << "Fatal error: unable to reset configuration database"
|
||||||
|
<< " after the test. Configuration function returned"
|
||||||
|
<< " error code " << rcode_ << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Dhcpv4Srv* srv_;
|
Dhcpv4Srv* srv_;
|
||||||
|
|
||||||
int rcode_;
|
int rcode_;
|
||||||
@ -299,12 +344,12 @@ TEST_F(Dhcp4ParserTest, optionDataDefaults) {
|
|||||||
"\"renew-timer\": 1000,"
|
"\"renew-timer\": 1000,"
|
||||||
"\"option-data\": [ {"
|
"\"option-data\": [ {"
|
||||||
" \"name\": \"option_foo\","
|
" \"name\": \"option_foo\","
|
||||||
" \"code\": 100,"
|
" \"code\": 56,"
|
||||||
" \"data\": \"AB CDEF0105\""
|
" \"data\": \"AB CDEF0105\""
|
||||||
" },"
|
" },"
|
||||||
" {"
|
" {"
|
||||||
" \"name\": \"option_foo2\","
|
" \"name\": \"option_foo2\","
|
||||||
" \"code\": 101,"
|
" \"code\": 23,"
|
||||||
" \"data\": \"01\""
|
" \"data\": \"01\""
|
||||||
" } ],"
|
" } ],"
|
||||||
"\"subnet4\": [ { "
|
"\"subnet4\": [ { "
|
||||||
@ -333,30 +378,164 @@ TEST_F(Dhcp4ParserTest, optionDataDefaults) {
|
|||||||
// code so we get the range.
|
// code so we get the range.
|
||||||
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
|
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
|
||||||
Subnet::OptionContainerTypeIndex::const_iterator> range =
|
Subnet::OptionContainerTypeIndex::const_iterator> range =
|
||||||
idx.equal_range(100);
|
idx.equal_range(56);
|
||||||
|
// Expect single option with the code equal to 56.
|
||||||
|
ASSERT_EQ(1, std::distance(range.first, range.second));
|
||||||
|
const uint8_t foo_expected[] = {
|
||||||
|
0xAB, 0xCD, 0xEF, 0x01, 0x05
|
||||||
|
};
|
||||||
|
// Check if option is valid in terms of code and carried data.
|
||||||
|
testOption(*range.first, 56, foo_expected, sizeof(foo_expected));
|
||||||
|
|
||||||
|
range = idx.equal_range(23);
|
||||||
|
ASSERT_EQ(1, std::distance(range.first, range.second));
|
||||||
|
// Do another round of testing with second option.
|
||||||
|
const uint8_t foo2_expected[] = {
|
||||||
|
0x01
|
||||||
|
};
|
||||||
|
testOption(*range.first, 23, foo2_expected, sizeof(foo2_expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Goal of this test is to verify options configuration
|
||||||
|
// for a single subnet. In particular this test checks
|
||||||
|
// that local options configuration overrides global
|
||||||
|
// option setting.
|
||||||
|
TEST_F(Dhcp4ParserTest, optionDataInSingleSubnet) {
|
||||||
|
ConstElementPtr x;
|
||||||
|
string config = "{ \"interface\": [ \"all\" ],"
|
||||||
|
"\"rebind-timer\": 2000, "
|
||||||
|
"\"renew-timer\": 1000, "
|
||||||
|
"\"option-data\": [ {"
|
||||||
|
" \"name\": \"option_foo\","
|
||||||
|
" \"code\": 56,"
|
||||||
|
" \"data\": \"AB\""
|
||||||
|
" } ],"
|
||||||
|
"\"subnet4\": [ { "
|
||||||
|
" \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
|
||||||
|
" \"subnet\": \"192.0.2.0/24\", "
|
||||||
|
" \"option-data\": [ {"
|
||||||
|
" \"name\": \"option_foo\","
|
||||||
|
" \"code\": 56,"
|
||||||
|
" \"data\": \"AB CDEF0105\""
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"name\": \"option_foo2\","
|
||||||
|
" \"code\": 23,"
|
||||||
|
" \"data\": \"01\""
|
||||||
|
" } ]"
|
||||||
|
" } ],"
|
||||||
|
"\"valid-lifetime\": 4000 }";
|
||||||
|
|
||||||
|
ElementPtr json = Element::fromJSON(config);
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
|
||||||
|
ASSERT_TRUE(x);
|
||||||
|
comment_ = parseAnswer(rcode_, x);
|
||||||
|
ASSERT_EQ(0, rcode_);
|
||||||
|
|
||||||
|
Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.24"));
|
||||||
|
ASSERT_TRUE(subnet);
|
||||||
|
const Subnet::OptionContainer& options = subnet->getOptions();
|
||||||
|
ASSERT_EQ(2, options.size());
|
||||||
|
|
||||||
|
// Get the search index. Index #1 is to search using option code.
|
||||||
|
const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
|
||||||
|
|
||||||
|
// Get the options for specified index. Expecting one option to be
|
||||||
|
// returned but in theory we may have multiple options with the same
|
||||||
|
// code so we get the range.
|
||||||
|
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
|
||||||
|
Subnet::OptionContainerTypeIndex::const_iterator> range =
|
||||||
|
idx.equal_range(56);
|
||||||
// Expect single option with the code equal to 100.
|
// Expect single option with the code equal to 100.
|
||||||
ASSERT_EQ(1, std::distance(range.first, range.second));
|
ASSERT_EQ(1, std::distance(range.first, range.second));
|
||||||
const uint8_t foo_expected[] = {
|
const uint8_t foo_expected[] = {
|
||||||
0xAB, 0xCD, 0xEF, 0x01, 0x05
|
0xAB, 0xCD, 0xEF, 0x01, 0x05
|
||||||
};
|
};
|
||||||
// Check if option is valid in terms of code and carried data.
|
// Check if option is valid in terms of code and carried data.
|
||||||
testOption(*range.first, 100, foo_expected, sizeof(foo_expected));
|
testOption(*range.first, 56, foo_expected, sizeof(foo_expected));
|
||||||
|
|
||||||
range = idx.equal_range(101);
|
range = idx.equal_range(23);
|
||||||
ASSERT_EQ(1, std::distance(range.first, range.second));
|
ASSERT_EQ(1, std::distance(range.first, range.second));
|
||||||
// Do another round of testing with second option.
|
// Do another round of testing with second option.
|
||||||
const uint8_t foo2_expected[] = {
|
const uint8_t foo2_expected[] = {
|
||||||
0x01
|
0x01
|
||||||
};
|
};
|
||||||
testOption(*range.first, 101, foo2_expected, sizeof(foo2_expected));
|
testOption(*range.first, 23, foo2_expected, sizeof(foo2_expected));
|
||||||
|
|
||||||
// Check that options with other option codes are not returned.
|
|
||||||
for (uint16_t code = 102; code < 110; ++code) {
|
|
||||||
range = idx.equal_range(code);
|
|
||||||
EXPECT_EQ(0, std::distance(range.first, range.second));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Goal of this test is to verify options configuration
|
||||||
|
// for multiple subnets.
|
||||||
|
TEST_F(Dhcp4ParserTest, optionDataInMultipleSubnets) {
|
||||||
|
ConstElementPtr x;
|
||||||
|
string config = "{ \"interface\": [ \"all\" ],"
|
||||||
|
"\"rebind-timer\": 2000, "
|
||||||
|
"\"renew-timer\": 1000, "
|
||||||
|
"\"subnet4\": [ { "
|
||||||
|
" \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
|
||||||
|
" \"subnet\": \"192.0.2.0/24\", "
|
||||||
|
" \"option-data\": [ {"
|
||||||
|
" \"name\": \"option_foo\","
|
||||||
|
" \"code\": 56,"
|
||||||
|
" \"data\": \"0102030405060708090A\""
|
||||||
|
" } ]"
|
||||||
|
" },"
|
||||||
|
" {"
|
||||||
|
" \"pool\": [ \"192.0.3.101 - 192.0.3.150\" ],"
|
||||||
|
" \"subnet\": \"192.0.3.0/24\", "
|
||||||
|
" \"option-data\": [ {"
|
||||||
|
" \"name\": \"option_foo2\","
|
||||||
|
" \"code\": 23,"
|
||||||
|
" \"data\": \"FF\""
|
||||||
|
" } ]"
|
||||||
|
" } ],"
|
||||||
|
"\"valid-lifetime\": 4000 }";
|
||||||
|
|
||||||
|
ElementPtr json = Element::fromJSON(config);
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
|
||||||
|
ASSERT_TRUE(x);
|
||||||
|
comment_ = parseAnswer(rcode_, x);
|
||||||
|
ASSERT_EQ(0, rcode_);
|
||||||
|
|
||||||
|
Subnet4Ptr subnet1 = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.100"));
|
||||||
|
ASSERT_TRUE(subnet1);
|
||||||
|
const Subnet::OptionContainer& options1 = subnet1->getOptions();
|
||||||
|
ASSERT_EQ(1, options1.size());
|
||||||
|
|
||||||
|
// Get the search index. Index #1 is to search using option code.
|
||||||
|
const Subnet::OptionContainerTypeIndex& idx1 = options1.get<1>();
|
||||||
|
|
||||||
|
// Get the options for specified index. Expecting one option to be
|
||||||
|
// returned but in theory we may have multiple options with the same
|
||||||
|
// code so we get the range.
|
||||||
|
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
|
||||||
|
Subnet::OptionContainerTypeIndex::const_iterator> range1 =
|
||||||
|
idx1.equal_range(56);
|
||||||
|
// Expect single option with the code equal to 56.
|
||||||
|
ASSERT_EQ(1, std::distance(range1.first, range1.second));
|
||||||
|
const uint8_t foo_expected[] = {
|
||||||
|
0x01, 0x02, 0x03, 0x04, 0x05,
|
||||||
|
0x06, 0x07, 0x08, 0x09, 0x0A
|
||||||
|
};
|
||||||
|
// Check if option is valid in terms of code and carried data.
|
||||||
|
testOption(*range1.first, 56, foo_expected, sizeof(foo_expected));
|
||||||
|
|
||||||
|
// Test another subnet in the same way.
|
||||||
|
Subnet4Ptr subnet2 = CfgMgr::instance().getSubnet4(IOAddress("192.0.3.102"));
|
||||||
|
ASSERT_TRUE(subnet2);
|
||||||
|
const Subnet::OptionContainer& options2 = subnet2->getOptions();
|
||||||
|
ASSERT_EQ(1, options2.size());
|
||||||
|
|
||||||
|
const Subnet::OptionContainerTypeIndex& idx2 = options2.get<1>();
|
||||||
|
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
|
||||||
|
Subnet::OptionContainerTypeIndex::const_iterator> range2 =
|
||||||
|
idx2.equal_range(23);
|
||||||
|
ASSERT_EQ(1, std::distance(range2.first, range2.second));
|
||||||
|
|
||||||
|
const uint8_t foo2_expected[] = { 0xFF };
|
||||||
|
testOption(*range2.first, 23, foo2_expected, sizeof(foo2_expected));
|
||||||
|
}
|
||||||
|
|
||||||
/// This test checks if Uint32Parser can really parse the whole range
|
/// This test checks if Uint32Parser can really parse the whole range
|
||||||
/// and properly err of out of range values. As we can't call Uint32Parser
|
/// and properly err of out of range values. As we can't call Uint32Parser
|
||||||
|
Loading…
x
Reference in New Issue
Block a user