From: Francis Dupont Date: Thu, 21 Sep 2017 07:22:54 +0000 (+0200) Subject: [5073a] Added library unit tests X-Git-Tag: trac5363_base~6^2~6 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=9c8fd7fe7f6a4015c059a33cc498612e7d4d1bb0;p=thirdparty%2Fkea.git [5073a] Added library unit tests --- diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc index 3813567c7b..534a1fd967 100644 --- a/src/lib/dhcp/tests/libdhcp++_unittest.cc +++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc @@ -155,19 +155,6 @@ public: end, expected_type, encapsulates); } - /// @brief Create a sample DHCPv4 option 43 with suboptions. - static OptionBuffer createVendorOption() { - const uint8_t opt_data[] = { - 0x2B, 0x0D, // Vendor-Specific Information (CableLabs) - // Suboptions start here... - 0x02, 0x05, // Device Type Option (length = 5) - 'D', 'u', 'm', 'm', 'y', - 0x04, 0x04, // Serial Number Option (length = 4) - 0x42, 0x52, 0x32, 0x32 // Serial number - }; - return (OptionBuffer(opt_data, opt_data + sizeof(opt_data))); - } - /// @brief Create a sample DHCPv4 option 82 with suboptions. static OptionBuffer createAgentInformationOption() { const uint8_t opt_data[] = { @@ -863,23 +850,6 @@ TEST_F(LibDhcpTest, unpackOptions4) { ASSERT_EQ(1, addresses.size()); EXPECT_EQ("10.0.0.10", addresses[0].toText()); -#if 0 - // Vendor Specific Information option - x = options.find(43); - ASSERT_FALSE(x == options.end()); - OptionPtr vsi = x->second; - ASSERT_TRUE(vsi); - EXPECT_EQ(DHO_VENDOR_ENCAPSULATED_OPTIONS, vsi->getType()); - suboptions = vsi->getOptions(); - - // There should be one suboption of VSI. - ASSERT_EQ(1, suboptions.size()); - OptionPtr eso = suboptions.begin()->second; - ASSERT_TRUE(eso); - EXPECT_EQ(0xdc, eso->getType()); - EXPECT_EQ(2, eso->len()); -#endif - // Checking DHCP Relay Agent Information Option. x = options.find(DHO_DHCP_AGENT_OPTIONS); ASSERT_FALSE(x == options.end()); @@ -1180,17 +1150,6 @@ TEST_F(LibDhcpTest, stdOptionDefs4) { LibDhcpTest::testStdOptionDefs4(DHO_NTP_SERVERS, begin, end, typeid(Option4AddrLst)); -#if 0 - // The following option requires well formed buffer to be created from. - // Not just a dummy one. This buffer includes some suboptions. - OptionBuffer vendor_opts_buf = createVendorOption(); - LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_ENCAPSULATED_OPTIONS, - vendor_opts_buf.begin(), - vendor_opts_buf.end(), - typeid(OptionCustom), - "vendor-encapsulated-options-space"); -#endif - LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end, typeid(Option4AddrLst)); @@ -1854,4 +1813,33 @@ TEST_F(LibDhcpTest, setRuntimeOptionDefs) { testRuntimeOptionDefs(5, 100, false); } +// This test verifies the processing of option 43 +TEST_F(LibDhcpTest, option43) { + // Check deferOption() + EXPECT_TRUE(LibDHCP::deferOption(DHCP4_OPTION_SPACE, 43)); + EXPECT_FALSE(LibDHCP::deferOption(DHCP4_OPTION_SPACE, 44)); + EXPECT_FALSE(LibDHCP::deferOption(DHCP6_OPTION_SPACE, 43)); + + // Check last resort + OptionDefinitionPtr def; + def = LibDHCP::getLastResortOptionDef(DHCP6_OPTION_SPACE, 43); + EXPECT_FALSE(def); + def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 44); + EXPECT_FALSE(def); + def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 43); + ASSERT_TRUE(def); + EXPECT_FALSE(def->getArrayType()); + EXPECT_EQ(43, def->getCode()); + EXPECT_EQ("vendor-encapsulated-options-space", def->getEncapsulatedSpace()); + EXPECT_EQ("vendor-encapsulated-options", def->getName()); + EXPECT_EQ(0, def->getRecordFields().size()); + EXPECT_EQ(OptionDataType::OPT_EMPTY_TYPE, def->getType()); + + OptionDefinitionPtr def_by_name = + LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, + "vendor-encapsulated-options"); + EXPECT_TRUE(def_by_name); + EXPECT_EQ(def, def_by_name); +} + } // end of anonymous space diff --git a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc index f2a1b0356d..a630b47c90 100644 --- a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc +++ b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -86,6 +88,12 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary, CfgOptionDefPtr defs(new CfgOptionDef()); ConstElementPtr option_defs = class_def_cfg->get("option-def"); if (option_defs) { + // Apply defaults + SimpleParser::setListDefaults(option_defs, + family == AF_INET ? + SimpleParser4::OPTION4_DEF_DEFAULTS : + SimpleParser6::OPTION6_DEF_DEFAULTS); + OptionDefParser parser; BOOST_FOREACH(ConstElementPtr option_def, option_defs->listValue()) { OptionDefinitionTuple def; diff --git a/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc b/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc index 648b782927..6b82871f49 100644 --- a/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc @@ -480,6 +480,21 @@ TEST_F(ClientClassDefParserTest, invalidExpression) { DhcpConfigError); } +// Verifies that a class with invalid option-def, fails to parse. +TEST_F(ClientClassDefParserTest, invalidOptionDef) { + std::string cfg_text = + "{ \n" + " \"name\": \"one\", \n" + " \"option-def\": [ \n" + " { \"bogus\": \"bad\" } \n" + " ] \n" + "} \n"; + + ClientClassDefPtr cclass; + ASSERT_THROW(cclass = parseClientClassDef(cfg_text, AF_INET), + DhcpConfigError); +} + // Verifies that a class with invalid option-data, fails to parse. TEST_F(ClientClassDefParserTest, invalidOptionData) { std::string cfg_text = @@ -585,8 +600,113 @@ TEST_F(ClientClassDefParserTest, noFixedFields) { EXPECT_EQ(IOAddress("0.0.0.0"), cclass->getNextServer()); EXPECT_EQ(0, cclass->getSname().size()); EXPECT_EQ(0, cclass->getFilename().size()); + + // Nor option definitions + CfgOptionDefPtr cfg = cclass->getCfgOptionDef(); + ASSERT_TRUE(cfg->getAll(DHCP4_OPTION_SPACE)->empty()); +} + +// Test verifies option-def for a bad option fails to parse. +TEST_F(ClientClassDefParserTest, badOptionDef) { + std::string cfg_text = + "{ \n" + " \"name\": \"MICROSOFT\", \n" + " \"option-def\": [ \n" + " { \n" + " \"name\": \"foo\", \n" + " \"code\": 222, \n" + " \"type\": \"uint32\" \n" + " } \n" + " ] \n" + "} \n"; + + ClientClassDefPtr cclass; + ASSERT_THROW(cclass = parseClientClassDef(cfg_text, AF_INET), + DhcpConfigError); +} + +// Test verifies option-def works for private options (224-254). +TEST_F(ClientClassDefParserTest, privateOptionDef) { + std::string cfg_text = + "{ \n" + " \"name\": \"MICROSOFT\", \n" + " \"option-def\": [ \n" + " { \n" + " \"name\": \"foo\", \n" + " \"code\": 232, \n" + " \"type\": \"uint32\" \n" + " } \n" + " ] \n" + "} \n"; + + ClientClassDefPtr cclass; + ASSERT_NO_THROW(cclass = parseClientClassDef(cfg_text, AF_INET)); + + // We should find our class. + ASSERT_TRUE(cclass); + + // And the option definition. + CfgOptionDefPtr cfg = cclass->getCfgOptionDef(); + ASSERT_TRUE(cfg); + EXPECT_TRUE(cfg->get(DHCP4_OPTION_SPACE, 232)); + EXPECT_FALSE(cfg->get(DHCP6_OPTION_SPACE, 232)); + EXPECT_FALSE(cfg->get(DHCP4_OPTION_SPACE, 233)); } +// Test verifies option-def works for option 43. +TEST_F(ClientClassDefParserTest, option43Def) { + std::string cfg_text = + "{ \n" + " \"name\": \"MICROSOFT\", \n" + " \"test\": \"option[60].text == 'MICROSOFT'\", \n" + " \"option-def\": [ \n" + " { \n" + " \"name\": \"vendor-encapsulated-options\", \n" + " \"code\": 43, \n" + " \"space\": \"dhcp4\", \n" + " \"type\": \"empty\", \n" + " \"encapsulate\": \"vsi\" \n" + " } \n" + " ], \n" + " \"option-data\": [ \n" + " { \n" + " \"name\": \"vendor-encapsulated-options\" \n" + " }, \n" + " { \n" + " \"code\": 1, \n" + " \"space\": \"vsi\", \n" + " \"csv-format\": false, \n" + " \"data\": \"C0000200\" \n" + " } \n" + " ] \n" + "} \n"; + + ClientClassDefPtr cclass; + ASSERT_NO_THROW(cclass = parseClientClassDef(cfg_text, AF_INET)); + + // We should find our class. + ASSERT_TRUE(cclass); + + // And the option definition. + CfgOptionDefPtr cfg_def = cclass->getCfgOptionDef(); + ASSERT_TRUE(cfg_def); + EXPECT_TRUE(cfg_def->get(DHCP4_OPTION_SPACE, 43)); + + // Verify the option data. + OptionDescriptor od = cclass->getCfgOption()->get(DHCP4_OPTION_SPACE, 43); + ASSERT_TRUE(od.option_); + EXPECT_EQ(43, od.option_->getType()); + const OptionCollection& oc = od.option_->getOptions(); + ASSERT_EQ(1, oc.size()); + OptionPtr opt = od.option_->getOption(1); + ASSERT_TRUE(opt); + EXPECT_EQ(1, opt->getType()); + ASSERT_EQ(4, opt->getData().size()); + const uint8_t expected[4] = { 0xc0, 0x00, 0x02, 0x00 }; + EXPECT_EQ(0, std::memcmp(expected, &opt->getData()[0], 4)); +} + + // Test verifies that it is possible to define next-server field and it // is actually set in the class properly. TEST_F(ClientClassDefParserTest, nextServer) { diff --git a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc index ffd716cab6..d7dd3ae58e 100644 --- a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc +++ b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ TEST(ClientClassDef, construction) { ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr))); EXPECT_EQ(name, cclass->getName()); ASSERT_FALSE(cclass->getMatchExpr()); + EXPECT_FALSE(cclass->getCfgOptionDef()); // Verify we get an empty collection of cfg_option cfg_option = cclass->getCfgOption(); @@ -168,6 +170,22 @@ TEST(ClientClassDef, copyAndEquality) { EXPECT_FALSE(*cclass == *cclass2); EXPECT_TRUE(*cclass != *cclass2); + // Make a class that with same name, expression and options, but + // different option definitions, verify that the equality tools reflect + // that the equality tools reflect that the classes are not equal. + ASSERT_NO_THROW(cclass2.reset(new ClientClassDef(*cclass))); + EXPECT_TRUE(cclass->equals(*cclass2)); + OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE, 43); + EXPECT_FALSE(def); + def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 43); + EXPECT_TRUE(def); + CfgOptionDefPtr cfg(new CfgOptionDef()); + ASSERT_NO_THROW(cfg->add(def, DHCP4_OPTION_SPACE)); + cclass2->setCfgOptionDef(cfg); + EXPECT_FALSE(cclass->equals(*cclass2)); + EXPECT_FALSE(*cclass == *cclass2); + EXPECT_TRUE(*cclass != *cclass2); + // Make a class with same name and expression, but no options // verify that the equality tools reflect that the classes are not equal. test_options.reset(new CfgOption()); @@ -320,6 +338,7 @@ TEST(ClientClassDef, fixedFieldsDefaults) { ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr))); // Let's checks that it doesn't return any nonsense + EXPECT_FALSE(cclass->getCfgOptionDef()); string empty; ASSERT_EQ(IOAddress("0.0.0.0"), cclass->getNextServer()); EXPECT_EQ(empty, cclass->getSname());