summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv/tests/sanity_checks_unittest.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:15:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:15:43 +0000
commitf5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch)
tree49e44c6f87febed37efb953ab5485aa49f6481a7 /src/lib/dhcpsrv/tests/sanity_checks_unittest.cc
parentInitial commit. (diff)
downloadisc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.tar.xz
isc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.zip
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/dhcpsrv/tests/sanity_checks_unittest.cc')
-rw-r--r--src/lib/dhcpsrv/tests/sanity_checks_unittest.cc1614
1 files changed, 1614 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/tests/sanity_checks_unittest.cc b/src/lib/dhcpsrv/tests/sanity_checks_unittest.cc
new file mode 100644
index 0000000..7185b93
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/sanity_checks_unittest.cc
@@ -0,0 +1,1614 @@
+// Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// 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/.
+
+#include <config.h>
+#include <dhcpsrv/cfg_consistency.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/parsers/sanity_checks_parser.h>
+#include <dhcpsrv/srv_config.h>
+#include <dhcpsrv/lease.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/subnet.h>
+#include <dhcpsrv/sanity_checker.h>
+#include <dhcpsrv/testutils/test_utils.h>
+#include <testutils/log_utils.h>
+#include <util/range_utilities.h>
+#include <cc/data.h>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::data;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+
+class SanityChecksTest : public ::testing::Test {
+public:
+
+ SanityChecksTest() {
+ LeaseMgrFactory::destroy();
+ }
+
+ void startLeaseBackend(bool v6) {
+ std::ostringstream s;
+ s << "type=memfile " << (v6 ? "universe=6 " : "universe=4 ")
+ << "persist=false lfc-interval=0";
+ LeaseMgrFactory::create(s.str());
+ }
+
+ void setLeaseCheck(CfgConsistency::LeaseSanity sanity) {
+ CfgMgr::instance().getCurrentCfg()->getConsistency()->setLeaseSanityCheck(sanity);
+ }
+
+ ~SanityChecksTest() {
+ CfgMgr::instance().clear();
+ LeaseMgrFactory::destroy();
+ }
+
+ /// @brief Generates a simple IPv4 lease.
+ ///
+ /// The HW address is randomly generated, subnet_id is specified.
+ ///
+ /// @param address Lease address.
+ /// @param subnet_id ID of the subnet to use.
+ ///
+ /// @return new lease with random content
+ Lease4Ptr newLease4(const IOAddress& address, SubnetID subnet_id) {
+
+ // Randomize HW address.
+ vector<uint8_t> mac(6);
+ isc::util::fillRandom(mac.begin(), mac.end());
+ HWAddrPtr hwaddr(new HWAddr(mac, HTYPE_ETHER));
+
+ vector<uint8_t> clientid(1);
+
+ time_t timestamp = time(0) - 86400 + random() % 86400;
+
+ // Return created lease.
+ return (Lease4Ptr(new Lease4(address, hwaddr,
+ &clientid[0], 0, // no client-id
+ 1200, // valid
+ timestamp, subnet_id, false, false, "")));
+ }
+
+ /// @brief Generates a simple IPv6 lease.
+ ///
+ /// The DUID and IAID are randomly generated, subnet_id is specified.
+ ///
+ /// @param address Lease address.
+ /// @param subnet_id ID of the subnet to use.
+ ///
+ /// @return new lease with random content
+ Lease6Ptr newLease6(const IOAddress& address, SubnetID subnet_id) {
+ // Let's generate DUID of random length.
+ std::vector<uint8_t> duid_vec(8 + random()%20);
+ // And then fill it with random value.
+ isc::util::fillRandom(duid_vec.begin(), duid_vec.end());
+ DuidPtr duid(new DUID(duid_vec));
+
+ Lease::Type lease_type = Lease::TYPE_NA;
+ uint32_t iaid = 1 + random()%100;
+
+ std::ostringstream hostname;
+ hostname << "hostname" << (random() % 2048);
+
+ // Return created lease.
+ Lease6Ptr lease(new Lease6(lease_type, address, duid, iaid,
+ 1000, 1200, // pref, valid
+ subnet_id,
+ false, false, "")); // fqdn fwd, rev, hostname
+ return (lease);
+ }
+
+ Subnet4Ptr createSubnet4(string subnet_txt, SubnetID id) {
+ size_t pos = subnet_txt.find("/");
+ isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos));
+ size_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
+
+ return (Subnet4Ptr(new Subnet4(addr, len, 1000, 2000, 3000, id)));
+ }
+
+ Subnet6Ptr createSubnet6(string subnet_txt, SubnetID id) {
+ size_t pos = subnet_txt.find("/");
+ isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos));
+ size_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
+
+ return (Subnet6Ptr(new Subnet6(addr, len, 1000, 2000, 3000, 4000, id)));
+ }
+
+ void
+ parserCheck(SrvConfig& cfg, const string& txt, bool exp_throw,
+ CfgConsistency::LeaseSanity exp_sanity,
+ CfgConsistency::ExtendedInfoSanity exp_sanity2) {
+
+ // Reset to defaults.
+ cfg.getConsistency()->setLeaseSanityCheck(CfgConsistency::LEASE_CHECK_NONE);
+ cfg.getConsistency()->setExtendedInfoSanityCheck(CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+
+ SanityChecksParser parser;
+
+ ElementPtr json;
+ EXPECT_NO_THROW(json = Element::fromJSON(txt));
+
+ if (exp_throw) {
+ // Should throw DhcpConfigError.
+ try {
+ parser.parse(cfg, json);
+ ADD_FAILURE() << "should throw not did not throw";
+ return;
+ } catch (const DhcpConfigError&) {
+ return;
+ } catch (const exception& ex) {
+ ADD_FAILURE() << "throw another exception with " << ex.what();
+ }
+ } else {
+ // Should not throw.
+ try {
+ parser.parse(cfg, json);
+ } catch (const exception& ex) {
+ ADD_FAILURE() << "throw an exception with " << ex.what();
+ }
+ }
+
+ EXPECT_EQ(cfg.getConsistency()->getLeaseSanityCheck(), exp_sanity);
+ EXPECT_EQ(cfg.getConsistency()->getExtendedInfoSanityCheck(), exp_sanity2);
+ }
+
+};
+
+// Verify whether configuration parser is able to understand the values
+// that are valid and reject those that are not.
+TEST_F(SanityChecksTest, leaseCheck) {
+
+ // These are valid and should be accepted.
+ string valid1 = "{ \"lease-checks\": \"none\" }";
+ string valid2 = "{ \"lease-checks\": \"warn\" }";
+ string valid3 = "{ \"lease-checks\": \"fix\" }";
+ string valid4 = "{ \"lease-checks\": \"fix-del\" }";
+ string valid5 = "{ \"lease-checks\": \"del\" }";
+
+ // These are not valid values or types.
+ string bogus1 = "{ \"lease-checks\": \"sanitize\" }";
+ string bogus2 = "{ \"lease-checks\": \"ignore\" }";
+ string bogus3 = "{ \"lease-checks\": true }";
+ string bogus4 = "{ \"lease-checks\": 42 }";
+
+ // These are valid and should be accepted.
+ string valid6 = "{ \"extended-info-checks\": \"none\" }";
+ string valid7 = "{ \"extended-info-checks\": \"fix\" }";
+ string valid8 = "{ \"extended-info-checks\": \"strict\" }";
+ string valid9 = "{ \"extended-info-checks\": \"pedantic\" }";
+ string valid10 = "{ \"lease-checks\": \"fix\",\n"
+ " \"extended-info-checks\": \"fix\" }";
+
+ string bogus5 = "{ \"extended-info-checks\": \"sanitize\" }";
+ string bogus6 = "{ \"extended-info-checks\": \"ignore\" }";
+ string bogus7 = "{ \"extended-info-checks\": true }";
+ string bogus8 = "{ \"extended-info-checks\": 42 }";
+
+ SrvConfig cfg;
+
+ // The lease default should be to none.
+ EXPECT_EQ(cfg.getConsistency()->getLeaseSanityCheck(),
+ CfgConsistency::LEASE_CHECK_NONE);
+
+ // The extended info default should be to fix.
+ EXPECT_EQ(cfg.getConsistency()->getExtendedInfoSanityCheck(),
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+
+ parserCheck(cfg, valid1, false, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, valid2, false, CfgConsistency::LEASE_CHECK_WARN,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, valid3, false, CfgConsistency::LEASE_CHECK_FIX,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, valid4, false, CfgConsistency::LEASE_CHECK_FIX_DEL,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, valid5, false, CfgConsistency::LEASE_CHECK_DEL,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+
+ parserCheck(cfg, bogus1, true, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, bogus2, true, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, bogus3, true, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, bogus4, true, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+
+ parserCheck(cfg, valid6, false, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+ parserCheck(cfg, valid7, false, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, valid8, false, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT);
+ parserCheck(cfg, valid9, false, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC);
+ parserCheck(cfg, valid10, false, CfgConsistency::LEASE_CHECK_FIX,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+
+ parserCheck(cfg, bogus5, true, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, bogus6, true, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, bogus7, true, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+ parserCheck(cfg, bogus8, true, CfgConsistency::LEASE_CHECK_NONE,
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// Verify whether sanity checker works as expected (valid v4).
+TEST_F(SanityChecksTest, valid4) {
+ // Create network and lease.
+ CfgMgr::instance().setFamily(AF_INET);
+ Subnet4Ptr subnet = createSubnet4("192.168.1.0/24", 1);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet);
+ IOAddress addr("192.168.1.1");
+ Lease4Ptr lease = newLease4(addr, 1);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease is still here in the same subnet.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(subnet->getID(), lease->subnet_id_);
+}
+
+// Verify whether sanity checker works as expected (valid v6).
+TEST_F(SanityChecksTest, valid6) {
+ // Create network and lease.
+ CfgMgr::instance().setFamily(AF_INET6);
+ Subnet6Ptr subnet = createSubnet6("2001:db8:1::/64", 1);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet);
+ IOAddress addr("2001:db8:1::1");
+ Lease6Ptr lease = newLease6(addr, 1);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease is still here in the same subnet.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(subnet->getID(), lease->subnet_id_);
+}
+
+// Verify whether sanity checker works as expected (wrong subnet v4).
+TEST_F(SanityChecksTest, wrongSubnet4) {
+ // Create networks and lease in the second and wrong subnet.
+ CfgMgr::instance().setFamily(AF_INET);
+ Subnet4Ptr subnet1 = createSubnet4("192.168.1.0/24", 1);
+ Subnet4Ptr subnet2 = createSubnet4("192.168.2.0/24", 2);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet1);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet2);
+ IOAddress addr("192.168.1.1");
+ Lease4Ptr lease = newLease4(addr, 2);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease is still here but was moved to the first and right subnet.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(subnet1->getID(), lease->subnet_id_);
+}
+
+// Verify whether sanity checker works as expected (wrong subnet v6).
+TEST_F(SanityChecksTest, wrongSubnet6) {
+ // Create networks and lease in the second and wrong subnet.
+ CfgMgr::instance().setFamily(AF_INET6);
+ Subnet6Ptr subnet1 = createSubnet6("2001:db8:1::/64", 1);
+ Subnet6Ptr subnet2 = createSubnet6("2001:db8:2::/64", 2);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet1);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet2);
+ IOAddress addr("2001:db8:1::1");
+ Lease6Ptr lease = newLease6(addr, 2);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease is still here but was moved to the first and right subnet.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(subnet1->getID(), lease->subnet_id_);
+}
+
+// Verify whether sanity checker works as expected (no subnet v4).
+TEST_F(SanityChecksTest, noSubnet4) {
+ // Create network and lease in a wrong subnet.
+ CfgMgr::instance().setFamily(AF_INET);
+ Subnet4Ptr subnet = createSubnet4("192.168.2.0/24", 1);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet);
+ IOAddress addr("192.168.1.1");
+ Lease4Ptr lease = newLease4(addr, 1);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease was removed because its subnet does not exist,
+ EXPECT_FALSE(lease);
+}
+
+// Verify whether sanity checker works as expected (no subnet v6).
+TEST_F(SanityChecksTest, noSubnet6) {
+ // Create network and lease in a wrong subnet.
+ CfgMgr::instance().setFamily(AF_INET6);
+ Subnet6Ptr subnet = createSubnet6("2001:db8:2::/64", 1);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet);
+ IOAddress addr("2001:db8:1::1");
+ Lease6Ptr lease = newLease6(addr, 1);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease was removed because its subnet does not exist,
+ EXPECT_FALSE(lease);
+}
+
+// Verify whether sanity checker works as expected (guard v4).
+TEST_F(SanityChecksTest, guard4) {
+ // Create networks and lease in the first and guarded subnet.
+ CfgMgr::instance().setFamily(AF_INET);
+ Subnet4Ptr subnet1 = createSubnet4("192.168.1.0/24", 1);
+ subnet1->allowClientClass("foo");
+ Subnet4Ptr subnet2 = createSubnet4("192.168.1.100/24", 2);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet1);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet2);
+ IOAddress addr("192.168.1.1");
+ Lease4Ptr lease = newLease4(addr, 1);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease is still here and in the guarded subnet.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(subnet1->getID(), lease->subnet_id_);
+}
+
+// Verify whether sanity checker works as expected (guard v6).
+TEST_F(SanityChecksTest, guard6) {
+ // Create networks and lease in the first and guarded subnet.
+ CfgMgr::instance().setFamily(AF_INET6);
+ Subnet6Ptr subnet1 = createSubnet6("2001:db8:1::/64", 1);
+ subnet1->allowClientClass("foo");
+ Subnet6Ptr subnet2 = createSubnet6("2001:db8:2::100/64", 2);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet1);
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet2);
+ IOAddress addr("2001:db8:1::1");
+ Lease6Ptr lease = newLease6(addr, 1);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease is still here and in the guarded subnet.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(subnet1->getID(), lease->subnet_id_);
+}
+
+// Verify whether sanity checker works as expected (guard only v4).
+TEST_F(SanityChecksTest, guardOnly4) {
+ // Create guarded network and lease.
+ CfgMgr::instance().setFamily(AF_INET);
+ Subnet4Ptr subnet = createSubnet4("192.168.1.0/24", 1);
+ subnet->allowClientClass("foo");
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->add(subnet);
+ IOAddress addr("192.168.1.1");
+ Lease4Ptr lease = newLease4(addr, 1);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease is still here in the same subnet.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(subnet->getID(), lease->subnet_id_);
+}
+
+// Verify whether sanity checker works as expected (valid v6).
+TEST_F(SanityChecksTest, guardOnly6) {
+ // Create guarded network and lease.
+ CfgMgr::instance().setFamily(AF_INET6);
+ Subnet6Ptr subnet = createSubnet6("2001:db8:1::/64", 1);
+ subnet->allowClientClass("foo");
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->add(subnet);
+ IOAddress addr("2001:db8:1::1");
+ Lease6Ptr lease = newLease6(addr, 1);
+
+ // Check the lease.
+ setLeaseCheck(CfgConsistency::LEASE_CHECK_FIX_DEL);
+ SanityChecker checker;
+ checker.checkLease(lease);
+
+ // Verify the lease is still here in the same subnet.
+ ASSERT_TRUE(lease);
+ EXPECT_EQ(subnet->getID(), lease->subnet_id_);
+}
+
+class ExtendedInfoChecksTest : public LogContentTest {
+public:
+
+ /// @brief Generates a simple IPv4 lease.
+ ///
+ /// The HW address is randomly generated, user context is specified.
+ ///
+ /// @param address Lease address.
+ /// @param user_context User context to use.
+ ///
+ /// @return new lease with random content.
+ Lease4Ptr newLease4(const IOAddress& address,
+ ConstElementPtr user_context) {
+
+ // Randomize HW address.
+ vector<uint8_t> mac(6);
+ isc::util::fillRandom(mac.begin(), mac.end());
+ HWAddrPtr hwaddr(new HWAddr(mac, HTYPE_ETHER));
+
+ vector<uint8_t> clientid(1);
+
+ time_t timestamp = time(0) - 86400 + random() % 86400;
+
+ // Return created lease.
+ Lease4Ptr lease(new Lease4(address, hwaddr,
+ &clientid[0], 0, // no client-id
+ 1200, // valid
+ timestamp, 1, false, false, ""));
+ lease->setContext(user_context);
+ return(lease);
+ }
+
+ /// @brief Generates a simple IPv6 lease.
+ ///
+ /// The DUID and IAID are randomly generated, user context is specified.
+ ///
+ /// @param address Lease address.
+ /// @param user_context User context to use.
+ ///
+ /// @return new lease with random content.
+ Lease6Ptr newLease6(const IOAddress& address,
+ ConstElementPtr user_context) {
+ // Let's generate DUID of random length.
+ std::vector<uint8_t> duid_vec(8 + random()%20);
+ // And then fill it with random value.
+ isc::util::fillRandom(duid_vec.begin(), duid_vec.end());
+ DuidPtr duid(new DUID(duid_vec));
+
+ Lease::Type lease_type = Lease::TYPE_NA;
+ uint32_t iaid = 1 + random()%100;
+
+ std::ostringstream hostname;
+ hostname << "hostname" << (random() % 2048);
+
+ // Return created lease.
+ Lease6Ptr lease(new Lease6(lease_type, address, duid, iaid,
+ 1000, 1200, // pref, valid
+ 1, false, false, ""));
+ lease->setContext(user_context);
+ return(lease);
+ }
+
+ /// @brief Check IPv4 scenario.
+ ///
+ /// @brief original Original user context.
+ /// @brief expected Expected user context.
+ /// @brief sanity Extended info sanity level.
+ /// @break logs Expected log messages.
+ void check4(string description, string original, string expected,
+ CfgConsistency::ExtendedInfoSanity sanity,
+ vector<string> logs = {}) {
+ ElementPtr orig_context;
+ if (!original.empty()) {
+ ASSERT_NO_THROW(orig_context = Element::fromJSON(original))
+ << "invalid original user context, test " << description
+ << " is broken";
+ }
+ ElementPtr exp_context;
+ if (!expected.empty()) {
+ ASSERT_NO_THROW(exp_context = Element::fromJSON(expected))
+ << "invalid expected user context, test " << description
+ << " is broken";
+ }
+
+ Lease4Ptr lease = newLease4(IOAddress("192.168.1.1"), orig_context);
+ ConstElementPtr before;
+ if (orig_context) {
+ before = isc::data::copy(orig_context);
+ }
+ for (const string& log : logs) {
+ addString(log);
+ }
+
+ bool ret = LeaseMgr::upgradeLease4ExtendedInfo(lease, sanity);
+ ConstElementPtr after = lease->getContext();
+ if (!before && !after) {
+ EXPECT_FALSE(ret) << "null before and null after";
+ } else if ((before && !after) || (!before && after)) {
+ EXPECT_TRUE(ret) << "only one of before and after is null";
+ } else if (before->equals(*after)) {
+ EXPECT_FALSE(ret) << "before == after";
+ } else {
+ EXPECT_TRUE(ret) << "before != after";
+ }
+ if (!exp_context) {
+ EXPECT_FALSE(after) << "expected null, got " << *after;
+ } else {
+ ASSERT_TRUE(after) << "expected not null, got null";
+ EXPECT_TRUE(exp_context->equals(*after))
+ << "expected: " << *exp_context << std::endl
+ << "actual: " << *after << std::endl;
+ }
+ EXPECT_TRUE(checkFile());
+ }
+
+ /// @brief Check IPv6 scenario.
+ ///
+ /// @brief original Original user context.
+ /// @brief expected Expected user context.
+ /// @brief sanity Extended info sanity level.
+ /// @break logs Expected log messages.
+ void check6(string description, string original, string expected,
+ CfgConsistency::ExtendedInfoSanity sanity,
+ vector<string> logs = {}) {
+ ElementPtr orig_context;
+ if (!original.empty()) {
+ ASSERT_NO_THROW(orig_context = Element::fromJSON(original))
+ << "invalid original user context, test " << description
+ << " is broken";
+ }
+ ElementPtr exp_context;
+ if (!expected.empty()) {
+ ASSERT_NO_THROW(exp_context = Element::fromJSON(expected))
+ << "invalid expected user context, test " << description
+ << " is broken";
+ }
+
+ Lease6Ptr lease = newLease6(IOAddress("2001::1"), orig_context);
+ ConstElementPtr before;
+ if (orig_context) {
+ before = isc::data::copy(orig_context);
+ }
+ for (const string& log : logs) {
+ addString(log);
+ }
+
+ bool ret = LeaseMgr::upgradeLease6ExtendedInfo(lease, sanity);
+ ConstElementPtr after = lease->getContext();
+ if (!before && !after) {
+ EXPECT_FALSE(ret) << "null before and null after";
+ } else if ((before && !after) || (!before && after)) {
+ EXPECT_TRUE(ret) << "only one of before and after is null";
+ } else if (before->equals(*after)) {
+ EXPECT_FALSE(ret) << "before == after";
+ } else {
+ EXPECT_TRUE(ret) << "before != after";
+ }
+ if (!exp_context) {
+ EXPECT_FALSE(after) << "expected null, got " << *after;
+ } else {
+ ASSERT_TRUE(after) << "expected not null, got null";
+ EXPECT_TRUE(exp_context->equals(*after))
+ << "expected: " << *exp_context << std::endl
+ << "actual: " << *after << std::endl;
+ }
+ EXPECT_TRUE(checkFile());
+ }
+};
+
+// No user context is right for any sanity check level including the highest.
+TEST_F(ExtendedInfoChecksTest, noUserContext4) {
+ string description = "no user context, pedantic";
+ check4(description, "", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC);
+}
+
+// User context with a bad type is right only when no check is done.
+TEST_F(ExtendedInfoChecksTest, badTypeUserContext4none) {
+ string description = "user context not a map, none";
+ check4(description, "1", "1", CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// User context with a bad type is refused by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeUserContext4) {
+ string description = "user context not a map, fix";
+ check4(description, "1", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in user context a problem was found:"
+ " user context is not a map)" });
+}
+
+// Empty user context is right only when no check is done.
+TEST_F(ExtendedInfoChecksTest, emptyTypeUserContext4none) {
+ string description = "empty user context, none";
+ check4(description, "{ }", "{ }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// Empty user context is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, emptyTypeUserContext4) {
+ string description = "empty user context, fix";
+ check4(description, "{ }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// No ISC entry is right in all cases.
+TEST_F(ExtendedInfoChecksTest, noISC4) {
+ string description = "no ISC entry, pedantic";
+ check4(description, "{ \"foo\": 1 }", "{ \"foo\": 1 }",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC);
+}
+
+// ISC entry with a bad type is right only when no check is done.
+TEST_F(ExtendedInfoChecksTest, badTypeISC4none) {
+ string description = "ISC entry no a map, none";
+ check4(description, "{ \"ISC\": 1 }", "{ \"ISC\": 1 }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// ISC entry with a bad type is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeISC4) {
+ string description = "ISC entry no a map, fix";
+ check4(description, "{ \"ISC\": 1 }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in isc a problem was found:"
+ " ISC entry is not a map)" });
+}
+
+// When the ISC entry is dropped other entries are kept.
+TEST_F(ExtendedInfoChecksTest, badTypeISC4other) {
+ string description = "ISC entry no a map with others, fix";
+ check4(description, "{ \"ISC\": 1, \"foo\": 2 }", "{ \"foo\": 2 }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in isc a problem was found:"
+ " ISC entry is not a map)" });
+}
+
+// Empty ISC entry is kept only when no check is done.
+TEST_F(ExtendedInfoChecksTest, emptyISC4none) {
+ string description = "empty ISC entry, none";
+ check4(description, "{ \"ISC\": { } }", "{ \"ISC\": { } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// Empty ISC entry is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, emptyISC4) {
+ string description = "empty ISC entry, fix";
+ check4(description, "{ \"ISC\": { } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// No relay-agent-info entry is right at all sanity levels.
+TEST_F(ExtendedInfoChecksTest, noRAI) {
+ string description = "no RAI, pedantic";
+ check4(description, "{ \"ISC\": { \"foo\": 1 } }",
+ "{ \"ISC\": { \"foo\": 1 } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC);
+}
+
+// relay-agent-info entry with a bad type is right only when no check is done.
+TEST_F(ExtendedInfoChecksTest, badTypeRAInone) {
+ string description = "RAI is not a string or a map, none";
+ check4(description, "{ \"ISC\": { \"relay-agent-info\": true } }",
+ "{ \"ISC\": { \"relay-agent-info\": true } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// relay-agent-info entry with a bad type is dropped by all not none sanity
+// check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRAI) {
+ string description = "RAI is not a string or a map, fix";
+ check4(description, "{ \"ISC\": { \"relay-agent-info\": true } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in relay-agent-info a problem was found:"
+ " relay-agent-info is not a map or a string)" });
+}
+
+// When relay-agent-info entry is dropped other entries are kept.
+TEST_F(ExtendedInfoChecksTest, badTypeRAIother) {
+ string description = "RAI is not a string or a map with others, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": true, \"foo\": 1 } }",
+ "{ \"ISC\": { \"foo\": 1 } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in relay-agent-info a problem was found:"
+ " relay-agent-info is not a map or a string)" });
+}
+
+// String relay-agent-info entry which can't be decoded is right
+// only when no check is done.
+TEST_F(ExtendedInfoChecksTest, badEncodingStringRAInone) {
+ string description = "string RAI with a junk value, none";
+ check4(description, "{ \"ISC\": { \"relay-agent-info\": \"foo\" } }",
+ "{ \"ISC\": { \"relay-agent-info\": \"foo\" } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// String relay-agent-info entry which can't be decoded is dropped
+// by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badEncodingStringRAI) {
+ string description = "string RAI with a junk value, fix";
+ check4(description, "{ \"ISC\": { \"relay-agent-info\": \"foo\" } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in rai a problem was found:"
+ " 'foo' is not a valid string of hexadecimal digits)" });
+}
+
+// String relay-agent-info entry for an empty option is dropped
+// by all not none sanity check levels (this should not happen).
+TEST_F(ExtendedInfoChecksTest, emptyStringRAI) {
+ string description = "string RAI with empty content, fix";
+ check4(description, "{ \"ISC\": { \"relay-agent-info\": \"0x\" } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in rai a problem was found:"
+ " '0x' is not a valid string of hexadecimal digits)" });
+}
+
+// Valid string relay-agent-info entry is upgraded by all not none
+// sanity check levels.
+TEST_F(ExtendedInfoChecksTest, upgradedRAI) {
+ string description = "valid string RAI, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": \"0x0104AABBCCDD\" } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"0x0104AABBCCDD\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED"
+ " extended info for lease 192.168.1.1 was upgraded" });
+}
+
+// Upgraded string relay-agent-info entry with ids.
+TEST_F(ExtendedInfoChecksTest, upgradedRAIwithIds) {
+ string description = "valid string RAI with ids, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": \"0x02030102030C03AABBCC\" } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"0x02030102030C03AABBCC\", \"remote-id\": \"010203\","
+ " \"relay-id\": \"AABBCC\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_UPGRADED"
+ " extended info for lease 192.168.1.1 was upgraded" });
+}
+
+// sub-options entry with a bad type is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, badTypeSubOptionsfix) {
+ string description = "sub-options not a string, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\": 1 } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\": 1 } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// sub-options entry with a bad type is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badTypeSubOptionsstrict) {
+ string description = "sub-options not a string, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\": 1 } } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in sub-options a problem was found:"
+ " sub-options is not a string)" });
+}
+
+// sub-options entry which can't be decoded is right up to the fix
+// sanity level.
+TEST_F(ExtendedInfoChecksTest, badEncodingSubOptionsfix) {
+ string description = "sub-options with a junk value, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"foo\" } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"foo\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// sub-options entry which can't be decoded is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badEncodingSubOptionsstrict) {
+ string description = "sub-options with a junk value, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"foo\" } } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in sub-options a problem was found:"
+ " 'foo' is not a valid string of hexadecimal digits)" });
+}
+
+// remote-id entry with a bad type is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, badTypeRemoteId4fix) {
+ string description = "remote-id not a string, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": 1 } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": 1 } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// remote-id entry with a bad type is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRemoteId4strict) {
+ string description = "remote-id not a string, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": 1 } } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in remote-id a problem was found:"
+ " remote-id is not a string)" });
+}
+
+// remote-id entry which can't be decoded is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, badEncodingRemoteId4fix) {
+ string description = "remote-id with a junk value, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":"
+ " \"foo\" } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":"
+ " \"foo\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// remote-id entry which can't be decoded is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badEncodingRemoteId4strict) {
+ string description = "remote-id with a junk value, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":"
+ " \"foo\" } } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in remote-id a problem was found:"
+ " attempt to decode a value not in base16 char set)" });
+}
+
+// Empty remote-id entry is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, emptyRemoteId4fix) {
+ string description = "empty remote-id, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": \"\" } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": \"\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// Empty remote-id entry is dropped at strict or higher sanity levels.
+TEST_F(ExtendedInfoChecksTest, emptyRemoteId4strict) {
+ string description = "empty remote-id, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\": \"\" } } }",
+ "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in remote-id a problem was found:"
+ " remote-id is empty)" });
+}
+
+// Valid remote-id entry is right for all sanity levels.
+TEST_F(ExtendedInfoChecksTest, validRemoteId4strict) {
+ string description = "valid remote-id, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":"
+ " \"AABB\" } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"remote-id\":"
+ " \"AABB\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT);
+}
+
+// relay-id entry with a bad type is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, badTypeRelayId4fix) {
+ string description = "relay-id not a string, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": 1 } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": 1 } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// relay-id entry with a bad type is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRelayId4strict) {
+ string description = "relay-id not a string, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": 1 } } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in relay-id a problem was found:"
+ " relay-id is not a string)" });
+}
+
+// relay-id entry which can't be decoded is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, badEncodingRelayId4fix) {
+ string description = "relay-id with a junk value, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":"
+ " \"foo\" } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":"
+ " \"foo\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// relay-id entry which can't be decoded is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badEncodingRelayId4strict) {
+ string description = "relay-id with a junk value, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":"
+ " \"foo\" } } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in relay-id a problem was found:"
+ " attempt to decode a value not in base16 char set)" });
+}
+
+// Empty relay-id entry is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, emptyRelayId4fix) {
+ string description = "empty relay-id, fix";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": \"\" } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": \"\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// Empty relay-id entry is dropped at strict or higher sanity levels.
+TEST_F(ExtendedInfoChecksTest, emptyRelayId4strict) {
+ string description = "empty relay-id, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\": \"\" } } }",
+ "", CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in relay-id a problem was found:"
+ " relay-id is empty)" });
+}
+
+// Valid relay-id entry is right for all sanity levels.
+TEST_F(ExtendedInfoChecksTest, validRelayId4strict) {
+ string description = "valid relay-id, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":"
+ " \"AABB\" } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"relay-id\":"
+ " \"AABB\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT);
+}
+
+// Junk entries are right up to the strict sanity level.
+TEST_F(ExtendedInfoChecksTest, junk4strict) {
+ string description = "junk entry, strict";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"foo\": 1 } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"foo\": 1 } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT);
+}
+
+// Junk entries are dropped at the pedantic level.
+TEST_F(ExtendedInfoChecksTest, junk4pedantic) {
+ string description = "junk entry, pedantic";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"foo\": 1 } } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE4_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 192.168.1.1 failed checks"
+ " (in relay-agent-info a problem was found:"
+ " spurious 'foo' entry in relay-agent-info)" });
+}
+
+// comment is not considered as a junk entry.
+TEST_F(ExtendedInfoChecksTest, comment4) {
+ string description = "comment entry, pedantic";
+ check4(description,
+ "{ \"ISC\": { \"relay-agent-info\": { \"comment\": \"good\" } } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"comment\": \"good\" } } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC);
+}
+
+// No user context is right for any sanity check level including the highest.
+TEST_F(ExtendedInfoChecksTest, noUserContext6) {
+ string description = "no user context, pedantic";
+ check6(description, "", "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC);
+}
+
+// User context with a bad type is right only when no check is done.
+TEST_F(ExtendedInfoChecksTest, badTypeUserContext6none) {
+ string description = "user context not a map, none";
+ check6(description, "1", "1", CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// User context with a bad type is refused by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeUserContext6) {
+ string description = "user context not a map, fix";
+ check6(description, "1", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in user context a problem was found:"
+ " user context is not a map)" });
+}
+
+// Empty user context is right only when no check is done.
+TEST_F(ExtendedInfoChecksTest, emptyTypeUserContext6none) {
+ string description = "empty user context, none";
+ check6(description, "{ }", "{ }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// Empty user context is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, emptyTypeUserContext6) {
+ string description = "empty user context, fix";
+ check6(description, "{ }", "", CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// No ISC entry is right in all cases.
+TEST_F(ExtendedInfoChecksTest, noISC6) {
+ string description = "no ISC entry, pedantic";
+ check6(description, "{ \"foo\": 1 }", "{ \"foo\": 1 }",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC);
+}
+
+// ISC entry with a bad type is right only when no check is done.
+TEST_F(ExtendedInfoChecksTest, badTypeISC6none) {
+ string description = "ISC entry no a map, none";
+ check6(description, "{ \"ISC\": 1 }", "{ \"ISC\": 1 }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// ISC entry with a bad type is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeISC6) {
+ string description = "ISC entry no a map, fix";
+ check6(description, "{ \"ISC\": 1 }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in isc a problem was found:"
+ " ISC entry is not a map)" });
+}
+
+// When the ISC entry is dropped other entries are kept.
+TEST_F(ExtendedInfoChecksTest, badTypeISC6other) {
+ string description = "ISC entry no a map with others, fix";
+ check6(description, "{ \"ISC\": 1, \"foo\": 2 }", "{ \"foo\": 2 }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in isc a problem was found:"
+ " ISC entry is not a map)" });
+}
+
+// Empty ISC entry is kept only when no check is done.
+TEST_F(ExtendedInfoChecksTest, emptyISC6none) {
+ string description = "empty ISC entry, none";
+ check6(description, "{ \"ISC\": { } }", "{ \"ISC\": { } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// Empty ISC entry is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, emptyISC6) {
+ string description = "empty ISC entry, fix";
+ check6(description, "{ \"ISC\": { } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// relays is not upgraded when no check is done.
+TEST_F(ExtendedInfoChecksTest, relaysnone) {
+ string description = "relays, none";
+ check6(description, "{ \"ISC\": { \"relays\": true } }",
+ "{ \"ISC\": { \"relays\": true } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_NONE);
+}
+
+// relays is dropped when relay-info is present by all not none sanity
+// check levels.
+TEST_F(ExtendedInfoChecksTest, relaysAndRelayInfo) {
+ string description = "relays and relay-info, fix";
+ check6(description,
+ "{ \"ISC\": { \"relays\": true, \"relay-info\":"
+ " [ { \"foo\": 1 } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"foo\": 1 } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// relays with bad type is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRelays) {
+ string description = "relays is not a list, fix";
+ check6(description, "{ \"ISC\": { \"relays\": true } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relays a problem was found:"
+ " relays is not a list)" });
+}
+
+// Empty relays is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, emptyRelays) {
+ string description = "empty relays, fix";
+ check6(description, "{ \"ISC\": { \"relays\": [ ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relays a problem was found:"
+ " relays is empty)" });
+}
+
+// Relay (element of relays) with bad type is dropped by all not none
+// sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRelay) {
+ string description = "relay is not a map, fix";
+ check6(description, "{ \"ISC\": { \"relays\": [ 1 ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relay [relay#0] a problem was found:"
+ " relay#0 is not a map)" });
+}
+
+// options with bad type is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeOptions) {
+ string description = "options is not a string, fix";
+ check6(description, "{ \"ISC\": { \"relays\": [ { \"options\": 1 } ] } }",
+ "", CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in options [relay#0] a problem was found:"
+ " options is not a string)" });
+}
+
+// options which can't be decoded is dropped by all not none sanity
+// check levels.
+TEST_F(ExtendedInfoChecksTest, badEncodingOptions) {
+ string description = "options with junk value, fix";
+ check6(description,
+ "{ \"ISC\": { \"relays\": [ { \"options\": \"foo\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in options [relay#0] a problem was found:"
+ " 'foo' is not a valid string of hexadecimal digits)" });
+}
+
+// Valid relays is upgraded by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, upgradedRelays) {
+ string description = "upgraded relays, fix";
+ check6(description,
+ "{ \"ISC\": { \"relays\": [ { \"hop\": 33,"
+ " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\","
+ " \"options\": \"0x00C800080102030405060708\" } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"hop\": 33,"
+ " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\","
+ " \"options\": \"0x00C800080102030405060708\" } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED"
+ " extended info for lease 2001::1 was upgraded" });
+}
+
+// Valid relays with ids is upgraded by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, upgradedRelaysWithIds) {
+ string description = "upgraded relays with ids, fix";
+ check6(description,
+ "{ \"ISC\": { \"relays\": [ { \"hop\": 100,"
+ " \"options\": \"0x00250006010203040506003500086464646464646464\","
+ " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\" } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"hop\": 100,"
+ " \"options\": \"0x00250006010203040506003500086464646464646464\","
+ " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\","
+ " \"remote-id\": \"010203040506\","
+ " \"relay-id\": \"6464646464646464\" } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED"
+ " extended info for lease 2001::1 was upgraded" });
+}
+
+// Valid relays with 2 relays is upgraded by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, upgradedRelays2) {
+ string description = "upgraded relays with 2 relays, fix";
+ check6(description,
+ "{ \"ISC\": { \"relays\": [ { \"hop\": 33,"
+ " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\","
+ " \"options\": \"0x00C800080102030405060708\" }, { \"hop\": 100,"
+ " \"options\": \"0x00250006010203040506003500086464646464646464\","
+ " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\" } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"hop\": 33,"
+ " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\","
+ " \"options\": \"0x00C800080102030405060708\" }, { \"hop\": 100,"
+ " \"options\": \"0x00250006010203040506003500086464646464646464\","
+ " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\","
+ " \"remote-id\": \"010203040506\","
+ " \"relay-id\": \"6464646464646464\" } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_UPGRADED"
+ " extended info for lease 2001::1 was upgraded" });
+}
+
+// relayinfo with bad type is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRelayInfo) {
+ string description = "relayinfo is not a list, fix";
+ check6(description, "{ \"ISC\": { \"relay-info\": true } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relay-info a problem was found:"
+ " relay-info is not a list)" });
+}
+
+// Empty relay-info is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, emptyRelayInfo) {
+ string description = "empty relay-info, fix";
+ check6(description, "{ \"ISC\": { \"relay-info\": [ ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relay-info a problem was found:"
+ " relay-info is empty)" });
+}
+
+// Relay (element of relay-info) with bad type is dropped by all not none
+// sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRelay2) {
+ string description = "relay is not a map, fix";
+ check6(description, "{ \"ISC\": { \"relay-info\": [ 1 ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relay [relay#0] a problem was found:"
+ " relay#0 is not a map)" });
+}
+
+// options with bad type is dropped by all not none sanity check levels.
+TEST_F(ExtendedInfoChecksTest, badTypeOptions2) {
+ string description = "options is not a string, fix";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"options\": 1 } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in options [relay#0] a problem was found:"
+ " options is not a string)" });
+}
+
+// options which can't be decoded is dropped by all not none sanity
+// check levels.
+TEST_F(ExtendedInfoChecksTest, badEncodingOptions2) {
+ string description = "options with junk value, fix";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"options\": \"foo\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in options [relay#0] a problem was found:"
+ " 'foo' is not a valid string of hexadecimal digits)" });
+}
+
+// Relay without a link entry is right up to fix sanity check level.
+TEST_F(ExtendedInfoChecksTest, noLinkfix) {
+ string description = "no link, fix";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"foo\": 1 } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"foo\": 1 } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// Relay without a link entry is dropped by strict sanity check level and
+// higher.
+TEST_F(ExtendedInfoChecksTest, noLinkstrict) {
+ string description = "no link, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"foo\": 1 } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in link [relay#0] a problem was found:"
+ " no link)" });
+}
+
+// link entry with bad type is dropped by strict sanity check level and higher.
+TEST_F(ExtendedInfoChecksTest, badTypeLink) {
+ string description = "link is not a string, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": 1 } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in link [relay#0] a problem was found:"
+ " link is not a string)" });
+}
+
+// link entry which is not an address is dropped by strict sanity check level
+// and higher.
+TEST_F(ExtendedInfoChecksTest, notAddressLink) {
+ string description = "link is not an address, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"foo\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in link [relay#0] a problem was found:"
+ " Failed to convert string to address 'foo':"
+ " Invalid argument)" });
+}
+
+// link entry which is an IPv4 (vs IPv6) address is dropped by strict sanity
+// check level and higher.
+TEST_F(ExtendedInfoChecksTest, notV6Link) {
+ string description = "link is v4, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\":"
+ " \"192.128.1.1\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in link [relay#0] a problem was found:"
+ " link is not an IPv6 address)" });
+}
+
+// Valid link entry is right for all sanity levels.
+TEST_F(ExtendedInfoChecksTest, validLink) {
+ string description = "valid link, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\" } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\" } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT);
+}
+
+// remote-id entry with a bad type is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, badTypeRemoteId6fix) {
+ string description = "remote-id not a string, fix";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": 1 } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": 1 } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// remote-id entry with a bad type is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRemoteId6strict) {
+ string description = "remote-id not a string, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": 1,"
+ " \"link\": \"2001::2\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in remote-id [relay#0] a problem was found:"
+ " remote-id is not a string)" });
+}
+
+// remote-id entry which can't be decoded is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badEncodingRemoteId6strict) {
+ string description = "remote-id with a junk value, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": \"foo\","
+ " \"link\": \"2001::2\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in remote-id [relay#0] a problem was found:"
+ " attempt to decode a value not in base16 char set)" });
+}
+
+// Empty remote-id entry is dropped at strict or higher sanity levels.
+TEST_F(ExtendedInfoChecksTest, emptyRemoteId6strict) {
+ string description = "empty remote-id, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": \"\","
+ " \"link\": \"2001::2\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in remote-id [relay#0] a problem was found:"
+ " remote-id is empty)" });
+}
+
+// Valid remote-id entry is right at all sanity levels.
+TEST_F(ExtendedInfoChecksTest, validRemoteId6strict) {
+ string description = "valid remote-id, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": \"AABB\","
+ " \"link\": \"2001::2\" } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"remote-id\": \"AABB\","
+ " \"link\": \"2001::2\" } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT);
+}
+
+// relay-id entry with a bad type is right up to the fix sanity level.
+TEST_F(ExtendedInfoChecksTest, badTypeRelayId6fix) {
+ string description = "relay-id not a string, fix";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": 1 } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": 1 } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_FIX);
+}
+
+// relay-id entry with a bad type is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badTypeRelayId6strict) {
+ string description = "relay-id not a string, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": 1,"
+ " \"link\": \"2001::2\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relay-id [relay#0] a problem was found:"
+ " relay-id is not a string)" });
+}
+
+// relay-id entry which can't be decoded is dropped at strict or higher
+// sanity levels.
+TEST_F(ExtendedInfoChecksTest, badEncodingRelayId6strict) {
+ string description = "relay-id with a junk value, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": \"foo\","
+ " \"link\": \"2001::2\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relay-id [relay#0] a problem was found:"
+ " attempt to decode a value not in base16 char set)" });
+}
+
+// Empty relay-id entry is dropped at strict or higher sanity levels.
+TEST_F(ExtendedInfoChecksTest, emptyRelayId6strict) {
+ string description = "empty relay-id, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": \"\","
+ " \"link\": \"2001::2\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relay-id [relay#0] a problem was found:"
+ " relay-id is empty)" });
+}
+
+// Valid relay-id entry is right at all sanity levels.
+TEST_F(ExtendedInfoChecksTest, validRelayId6strict) {
+ string description = "valid relay-id, strict";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": \"AABB\","
+ " \"link\": \"2001::2\" } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"relay-id\": \"AABB\","
+ " \"link\": \"2001::2\" } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_STRICT);
+}
+
+// Pedantic requires a peer entry.
+TEST_F(ExtendedInfoChecksTest, noPeerpedantic) {
+ string description = "no peer, pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\" } ] } }",
+ "", CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in peer [relay#0] a problem was found:"
+ " no peer)" });
+}
+
+// peer entry with bad type is dropped by pedantic sanity check level.
+TEST_F(ExtendedInfoChecksTest, badTypePeer) {
+ string description = "peer is not a string, pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\","
+ " \"peer\": 1 } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in peer [relay#0] a problem was found:"
+ " peer is not a string)" });
+}
+
+// peer entry which is not an address is dropped by pedantic sanity check level.
+TEST_F(ExtendedInfoChecksTest, notAddressPeer) {
+ string description = "peer is not an address, pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\","
+ " \"peer\": \"foo\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in peer [relay#0] a problem was found:"
+ " Failed to convert string to address 'foo':"
+ " Invalid argument)" });
+}
+
+// peer entry which is an IPv4 (vs IPv6) address is dropped by pedantic sanity
+// check level.
+TEST_F(ExtendedInfoChecksTest, notV6Peer) {
+ string description = "peer is v4, pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\","
+ " \"peer\": \"192.128.1.1\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in peer [relay#0] a problem was found:"
+ " peer is not an IPv6 address)" });
+}
+
+// Pedantic requires a hop entry.
+TEST_F(ExtendedInfoChecksTest, noHop) {
+ string description = "no hop, pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\","
+ " \"peer\": \"2001::3\" } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in hop [relay#0] a problem was found:"
+ " no hop)" });
+}
+
+// hop entry with bad type is dropped by pedantic sanity check level.
+TEST_F(ExtendedInfoChecksTest, badTypeHop) {
+ string description = "hop is not an integer pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\","
+ " \"peer\": \"2001::3\", \"hop\": false } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in hop [relay#0] a problem was found:"
+ " hop is not an integer)" });
+}
+
+// Valid relay.
+TEST_F(ExtendedInfoChecksTest, valid6Pedantic) {
+ string description = "valid, pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\","
+ " \"peer\": \"2001::3\", \"hop\": 10 } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\","
+ " \"peer\": \"2001::3\", \"hop\": 10 } ] } }",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC);
+}
+
+// Junk entries are dropped at the pedantic level.
+TEST_F(ExtendedInfoChecksTest, junk6pedantic) {
+ string description = "junk entry, pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relay-info\": [ { \"link\": \"2001::2\","
+ " \"peer\": \"2001::3\", \"hop\": 10, \"foo\": 1 } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relay-info [relay#0] a problem was found:"
+ " spurious 'foo' entry)" });
+}
+
+// Same with relays post upgrade checks.
+TEST_F(ExtendedInfoChecksTest, junkRelayspedantic) {
+ string description = "junk entry, pedantic";
+ check6(description,
+ "{ \"ISC\": { \"relays\": [ { \"link\": \"2001::2\","
+ " \"peer\": \"2001::3\", \"hop\": 10, \"foo\": 1 } ] } }", "",
+ CfgConsistency::EXTENDED_INFO_CHECK_PEDANTIC,
+ { "DHCPSRV_LEASE6_EXTENDED_INFO_SANITY_FAIL"
+ " extended info for lease 2001::1 failed checks"
+ " (in relays [relay#0] a problem was found:"
+ " spurious 'foo' entry)" });
+}