Parcourir la source

[5073a] Added library unit tests

Francis Dupont il y a 7 ans
Parent
commit
9c8fd7fe7f

+ 29 - 41
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

+ 8 - 0
src/lib/dhcpsrv/parsers/client_class_def_parser.cc

@@ -11,6 +11,8 @@
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <dhcpsrv/parsers/client_class_def_parser.h>
 #include <dhcpsrv/parsers/option_data_parser.h>
+#include <dhcpsrv/parsers/simple_parser4.h>
+#include <dhcpsrv/parsers/simple_parser6.h>
 #include <eval/eval_context.h>
 #include <asiolink/io_address.h>
 #include <asiolink/io_error.h>
@@ -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;

+ 120 - 0
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) {

+ 19 - 0
src/lib/dhcpsrv/tests/client_class_def_unittest.cc

@@ -7,6 +7,7 @@
 #include <config.h>
 #include <dhcpsrv/client_class_def.h>
 #include <dhcpsrv/cfgmgr.h>
+#include <dhcp/libdhcp++.h>
 #include <dhcp/option_space.h>
 #include <testutils/test_to_element.h>
 #include <exceptions/exceptions.h>
@@ -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());