summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv/tests/lease_mgr_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/lease_mgr_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/lease_mgr_unittest.cc')
-rw-r--r--src/lib/dhcpsrv/tests/lease_mgr_unittest.cc1038
1 files changed, 1038 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
new file mode 100644
index 0000000..54c9332
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
@@ -0,0 +1,1038 @@
+// Copyright (C) 2012-2023 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 <asiolink/io_address.h>
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/memfile_lease_mgr.h>
+#include <dhcpsrv/testutils/test_utils.h>
+#include <dhcpsrv/testutils/concrete_lease_mgr.h>
+#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
+#include <testutils/gtest_utils.h>
+
+#include <iostream>
+#include <list>
+#include <sstream>
+
+#include <time.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::db;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+
+class LeaseMgrTest : public GenericLeaseMgrTest {
+public:
+ LeaseMgrTest() {
+ }
+
+ /// @brief Reopen the database
+ ///
+ /// No-op implementation. We need to provide concrete implementation,
+ /// as this is a pure virtual method in GenericLeaseMgrTest.
+ virtual void reopen(Universe) {
+ }
+
+};
+
+namespace {
+
+// This test checks if getLease6() method is working properly for 0 (NULL),
+// 1 (return the lease) and more than 1 leases (throw).
+TEST_F(LeaseMgrTest, getLease6) {
+
+ DatabaseConnection::ParameterMap pmap;
+ boost::scoped_ptr<ConcreteLeaseMgr> mgr(new ConcreteLeaseMgr(pmap));
+
+ vector<Lease6Ptr> leases = createLeases6();
+
+ mgr->leases6_.clear();
+ // For no leases, the function should return NULL pointer
+ Lease6Ptr lease;
+
+ // the getLease6() is calling getLeases6(), which is a dummy. It returns
+ // whatever is there in leases6_ field.
+ EXPECT_NO_THROW(lease = mgr->getLease6(leasetype6_[1], *leases[1]->duid_,
+ leases[1]->iaid_,
+ leases[1]->subnet_id_));
+ EXPECT_FALSE(lease);
+
+ // For a single lease, the function should return that lease
+ mgr->leases6_.push_back(leases[1]);
+ EXPECT_NO_THROW(lease = mgr->getLease6(leasetype6_[1], *leases[1]->duid_,
+ leases[1]->iaid_,
+ leases[1]->subnet_id_));
+ EXPECT_TRUE(lease);
+
+ EXPECT_NO_THROW(detailCompareLease(lease, leases[1]));
+
+ // Add one more lease. There are 2 now. It should throw
+ mgr->leases6_.push_back(leases[2]);
+
+ EXPECT_THROW(lease = mgr->getLease6(leasetype6_[1], *leases[1]->duid_,
+ leases[1]->iaid_,
+ leases[1]->subnet_id_),
+ MultipleRecords);
+}
+
+// Verify LeaseStatsQuery default construction
+TEST (LeaseStatsQueryTest, defaultCtor) {
+ LeaseStatsQueryPtr qry;
+
+ // Valid construction, verifiy member values.
+ ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery()));
+ ASSERT_EQ(0, qry->getFirstSubnetID());
+ ASSERT_EQ(0, qry->getLastSubnetID());
+ ASSERT_EQ(LeaseStatsQuery::ALL_SUBNETS, qry->getSelectMode());
+}
+
+// Verify LeaseStatsQuery single-subnet construction
+TEST (LeaseStatsQueryTest, singleSubnetCtor) {
+ LeaseStatsQueryPtr qry;
+
+ // Invalid values for subnet_id
+ ASSERT_THROW(qry.reset(new LeaseStatsQuery(0)), BadValue);
+
+ // Valid values should work and set mode accordingly.
+ ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery(77)));
+ ASSERT_EQ(77, qry->getFirstSubnetID());
+ ASSERT_EQ(0, qry->getLastSubnetID());
+ ASSERT_EQ(LeaseStatsQuery::SINGLE_SUBNET, qry->getSelectMode());
+}
+
+// Verify LeaseStatsQuery subnet-range construction
+TEST (LeaseStatsQueryTest, subnetRangeCtor) {
+ LeaseStatsQueryPtr qry;
+
+ // Either ID set to 0, or a backward range should throw
+ ASSERT_THROW(qry.reset(new LeaseStatsQuery(0,1)), BadValue);
+ ASSERT_THROW(qry.reset(new LeaseStatsQuery(1,0)), BadValue);
+ ASSERT_THROW(qry.reset(new LeaseStatsQuery(2,1)), BadValue);
+
+ // Valid values should work and set mode accordingly.
+ ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery(1,2)));
+ ASSERT_EQ(1, qry->getFirstSubnetID());
+ ASSERT_EQ(2, qry->getLastSubnetID());
+ ASSERT_EQ(LeaseStatsQuery::SUBNET_RANGE, qry->getSelectMode());
+}
+
+// Verify Lease4 user context upgrade basic operations.
+TEST(Lease4ExtendedInfoTest, basic) {
+ Lease4Ptr lease;
+
+ // No Lease.
+ ASSERT_FALSE(lease);
+ EXPECT_FALSE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+
+ // No user context.
+ lease.reset(new Lease4());
+ ASSERT_TRUE(lease);
+ ASSERT_FALSE(lease->getContext());
+ EXPECT_FALSE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+
+ // Not map user context.
+ ElementPtr user_context = Element::createList();
+ lease->setContext(user_context);
+ EXPECT_TRUE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+ EXPECT_FALSE(lease->getContext());
+
+ // No ISC.
+ user_context = Element::createMap();
+ user_context->set("foo", Element::create(string("bar")));
+ lease->setContext(user_context);
+ EXPECT_FALSE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+
+ // Not a map ISC.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ ElementPtr isc = Element::create(string("..."));
+ user_context->set("ISC", isc);
+ EXPECT_TRUE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+ EXPECT_FALSE(lease->getContext());
+
+ // No relay agent info.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ isc->set("foo", Element::create(string("bar")));
+ EXPECT_FALSE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+
+ // Not string or map relay agent info.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ ElementPtr rai = Element::createMap();
+ rai->set("foo", Element::create(string("bar")));
+ isc->set("relay-agent-info", rai);
+ EXPECT_FALSE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+
+ // Positive case.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ rai = Element::create(string("0xAA01BB"));
+ isc->set("relay-agent-info", rai);
+ EXPECT_TRUE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+
+ ConstElementPtr new_user_context = lease->getContext();
+ ASSERT_TRUE(new_user_context);
+ ConstElementPtr new_isc = new_user_context->get("ISC");
+ ASSERT_TRUE(new_isc);
+ ConstElementPtr new_rai = new_isc->get("relay-agent-info");
+ ASSERT_TRUE(new_rai);
+ ASSERT_EQ(Element::map, new_rai->getType());
+ ASSERT_EQ("{ \"sub-options\": \"0xAA01BB\" }", new_rai->str());
+}
+
+// Verify Lease4 user context upgrade complex operations.
+TEST(Lease4ExtendedInfoTest, upgradeLease4ExtendedInfo) {
+ // Structure that defines a test scenario.
+ struct Scenario {
+ string description_; // test description.
+ string orig_; // original user context.
+ string expected_; // expected user context.
+ };
+
+ // Test scenarios.
+ vector<Scenario> scenarios {
+ {
+ "no user context",
+ "",
+ ""
+ },
+ {
+ "user context is not a map",
+ "[ ]",
+ ""
+ },
+ {
+ "no ISC entry",
+ "{ }",
+ ""
+ },
+ {
+ "no ISC entry but not empty",
+ "{ \"foo\": true }",
+ "{ \"foo\": true }"
+ },
+ {
+ "ISC entry is not a map",
+ "{ \"ISC\": true }",
+ ""
+ },
+ {
+ "ISC entry is not a map, user context not empty",
+ "{ \"foo\": true, \"ISC\": true }",
+ "{ \"foo\": true }"
+ },
+ {
+ "no relay agent info",
+ "{ \"ISC\": { } }",
+ ""
+ },
+ {
+ "no relay agent info, ISC not empty",
+ "{ \"ISC\": { \"foo\": true } }",
+ "{ \"ISC\": { \"foo\": true } }"
+ },
+ {
+ "relay agent info is not a string or a map",
+ "{ \"ISC\": { \"relay-agent-info\": false } }",
+ ""
+ },
+ {
+ "relay agent info is not a string or a map, ISC not empty",
+ "{ \"ISC\": { \"foo\": true, \"relay-agent-info\": false } }",
+ "{ \"ISC\": { \"foo\": true } }"
+ },
+ {
+ "relay agent info has a junk value",
+ "{ \"ISC\": { \"relay-agent-info\": \"foobar\" } }",
+ ""
+ },
+ {
+ "relay agent info has a junk value, ISC not empty",
+ "{ \"ISC\": { \"foo\": true, \"relay-agent-info\": \"foobar\" } }",
+ "{ \"ISC\": { \"foo\": true } }"
+ },
+ {
+ "relay agent info has a rai without ids",
+ "{ \"ISC\": { \"relay-agent-info\": \"0x0104AABBCCDD\" } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"0x0104AABBCCDD\" } } }"
+ },
+ {
+ "relay agent info with other entries",
+ "{ \"foo\": 123, \"ISC\": { \"bar\": 456,"
+ " \"relay-agent-info\": \"0x0104AABBCCDD\" } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"0x0104AABBCCDD\" }, \"bar\": 456 }, \"foo\": 123 }"
+ },
+ {
+ "relay agent info has a rai with ids",
+ "{ \"ISC\": { \"relay-agent-info\": \"0x02030102030C03AABBCC\" } }",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"0x02030102030C03AABBCC\", \"remote-id\": \"010203\","
+ " \"relay-id\": \"AABBCC\" } } }"
+ }
+ };
+
+ Lease4Ptr lease(new Lease4());
+ ElementPtr orig_context;
+ ElementPtr exp_context;
+ for (auto scenario : scenarios) {
+ SCOPED_TRACE(scenario.description_);
+
+ // Create the original user context from JSON.
+ if (scenario.orig_.empty()) {
+ orig_context.reset();
+ } else {
+ ASSERT_NO_THROW(orig_context = Element::fromJSON(scenario.orig_))
+ << "invalid original context, test " << scenario.description_
+ << " is broken";
+ }
+
+ // Create the expected user context from JSON.
+ if (scenario.expected_.empty()) {
+ exp_context.reset();
+ } else {
+ ASSERT_NO_THROW(exp_context = Element::fromJSON(scenario.expected_))
+ << "invalid expected context, test is broken";
+ }
+
+ // Perform the test.
+ lease->setContext(orig_context);
+ ConstElementPtr before;
+ if (orig_context) {
+ before = isc::data::copy(orig_context);
+ }
+ bool ret = LeaseMgr::upgradeLease4ExtendedInfo(lease);
+ 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;
+ }
+ }
+}
+
+// Verify Lease4 user context extract basic operations.
+TEST(Lease4ExtendedInfoTest, extract) {
+ Lease4Ptr lease;
+
+ // No Lease.
+ ASSERT_FALSE(lease);
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease, false));
+
+ // No user context.
+ lease.reset(new Lease4());
+ ASSERT_TRUE(lease);
+ ASSERT_FALSE(lease->getContext());
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease, false));
+
+ // Not map user context.
+ ElementPtr user_context = Element::createList();
+ lease->setContext(user_context);
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+
+ // No ISC.
+ user_context = Element::createMap();
+ user_context->set("foo", Element::create(string("bar")));
+ lease->setContext(user_context);
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease, false));
+
+ // Not a map ISC.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ ElementPtr isc = Element::create(string("..."));
+ user_context->set("ISC", isc);
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+
+ // No relay agent info.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ isc->set("foo", Element::create(string("bar")));
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease, false));
+
+ // Not a map relay agent info.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ ElementPtr rai = Element::createMap();
+ rai->set("foo", Element::create(string("bar")));
+ isc->set("relay-agent-info", rai);
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+
+ // No upgraded.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ rai = Element::create(string("0x02030102030C03AABBCC"));
+ isc->set("relay-agent-info", rai);
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+ EXPECT_TRUE(lease->relay_id_.empty());
+ EXPECT_TRUE(lease->remote_id_.empty());
+
+ // Upgraded.
+ EXPECT_TRUE(LeaseMgr::upgradeLease4ExtendedInfo(lease));
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease, false));
+ const vector<uint8_t> relay_id = { 0xaa, 0xbb, 0xcc };
+ EXPECT_EQ(relay_id, lease->relay_id_);
+ const vector<uint8_t> remote_id = { 1, 2, 3 };
+ EXPECT_EQ(remote_id, lease->remote_id_);
+}
+
+// Verify Lease4 user context extract complex operations.
+TEST(Lease4ExtendedInfoTest, extractLease4ExtendedInfo) {
+ struct Scenario {
+ string description_; // test description.
+ string context_; // user context.
+ string msg_; // error message.
+ };
+
+ // Test scenarios.
+ vector<Scenario> scenarios {
+ {
+ "no user context",
+ "",
+ ""
+ },
+ {
+ "user context is not a map",
+ "[ ]",
+ "user context is not a map"
+ },
+ {
+ "no ISC entry",
+ "{ }",
+ ""
+ },
+ {
+ "no ISC entry but not empty",
+ "{ \"foo\": true }",
+ ""
+ },
+ {
+ "ISC entry is not a map",
+ "{ \"ISC\": true }",
+ "ISC entry is not a map"
+ },
+ {
+ "ISC entry is not a map, user context not empty",
+ "{ \"foo\": true, \"ISC\": true }",
+ "ISC entry is not a map"
+ },
+ {
+ "no relay agent info",
+ "{ \"ISC\": { } }",
+ ""
+ },
+ {
+ "no relay agent info, ISC not empty",
+ "{ \"ISC\": { \"foo\": true } }",
+ ""
+ },
+ {
+ "relay agent info is not a string or a map",
+ "{ \"ISC\": { \"relay-agent-info\": false } }",
+ "relay-agent-info is not a map"
+ },
+ {
+ "relay agent info is not a string or a map, ISC not empty",
+ "{ \"ISC\": { \"foo\": true, \"relay-agent-info\": false } }",
+ "relay-agent-info is not a map"
+ },
+ {
+ "relay agent info has a junk value",
+ "{ \"ISC\": { \"relay-agent-info\": \"foobar\" } }",
+ "relay-agent-info is not a map"
+ },
+ {
+ "relay agent info has a junk value, ISC not empty",
+ "{ \"ISC\": { \"foo\": true, \"relay-agent-info\": \"foobar\" } }",
+ "relay-agent-info is not a map"
+ },
+ {
+ "relay agent info has a rai without ids",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"0x0104AABBCCDD\" } } }",
+ ""
+ },
+ {
+ "relay agent info with other entries",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"0x0104AABBCCDD\" }, \"bar\": 456 }, \"foo\": 123 }",
+ ""
+ },
+ {
+ "relay agent info has a rai with ids",
+ "{ \"ISC\": { \"relay-agent-info\": { \"sub-options\":"
+ " \"0x02030102030C03AABBCC\", \"remote-id\": \"010203\","
+ " \"relay-id\": \"AABBCC\" } } }",
+ ""
+ }
+ };
+
+ Lease4Ptr lease(new Lease4());
+ ElementPtr user_context;
+ for (auto scenario : scenarios) {
+ SCOPED_TRACE(scenario.description_);
+
+ // Create the original user context from JSON.
+ if (scenario.context_.empty()) {
+ user_context.reset();
+ } else {
+ ASSERT_NO_THROW(user_context = Element::fromJSON(scenario.context_))
+ << "invalid user context, test " << scenario.description_
+ << " is broken";
+ }
+
+ // Perform the test.
+ lease->setContext(user_context);
+ if (scenario.msg_.empty()) {
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease, false));
+ } else {
+ EXPECT_NO_THROW(LeaseMgr::extractLease4ExtendedInfo(lease));
+ EXPECT_THROW_MSG(LeaseMgr::extractLease4ExtendedInfo(lease, false),
+ BadValue, scenario.msg_);
+ }
+ }
+ // Last scenario sets relay and remote ids.
+ const vector<uint8_t> relay_id = { 0xaa, 0xbb, 0xcc };
+ EXPECT_EQ(relay_id, lease->relay_id_);
+ const vector<uint8_t> remote_id = { 1, 2, 3 };
+ EXPECT_EQ(remote_id, lease->remote_id_);
+}
+
+// Verify Lease6 user context upgrade basic operations.
+TEST(Lease6ExtendedInfoTest, basic) {
+ Lease6Ptr lease;
+
+ // No Lease.
+ ASSERT_FALSE(lease);
+ EXPECT_FALSE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+
+ // No user context.
+ lease.reset(new Lease6());
+ ASSERT_TRUE(lease);
+ ASSERT_FALSE(lease->getContext());
+ EXPECT_FALSE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+
+ // Not map user context.
+ ElementPtr user_context = Element::createList();
+ lease->setContext(user_context);
+ EXPECT_TRUE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+ EXPECT_FALSE(lease->getContext());
+
+ // No ISC.
+ user_context = Element::createMap();
+ user_context->set("foo", Element::create(string("bar")));
+ lease->setContext(user_context);
+ EXPECT_FALSE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+
+ // Not map ISC.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ ElementPtr isc = Element::create(string("..."));
+ user_context->set("ISC", isc);
+ EXPECT_TRUE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+ EXPECT_FALSE(lease->getContext());
+
+ // No relays.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ isc->set("foo", Element::create(string("bar")));
+ EXPECT_FALSE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+
+ // Not list relays.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ ElementPtr relays = Element::create(string("foo"));
+ isc->set("relays", relays);
+ EXPECT_TRUE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+ EXPECT_FALSE(lease->getContext());
+
+ // Empty relays.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ relays = Element::createList();
+ isc->set("relays", relays);
+ EXPECT_TRUE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+ EXPECT_FALSE(lease->getContext());
+
+ // Not map relay.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ relays = Element::createList();
+ isc->set("relays", relays);
+ relays->add(Element::create(string("foo")));
+ EXPECT_TRUE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+ EXPECT_FALSE(lease->getContext());
+
+ // Positive case.
+ user_context = Element::createMap();
+ lease->setContext(user_context);
+ isc = Element::createMap();
+ user_context->set("ISC", isc);
+ relays = Element::createList();
+ isc->set("relays", relays);
+ ElementPtr relay = Element::createMap();
+ relays->add(relay);
+ relay->set("foo", Element::create(string("bar")));
+ EXPECT_TRUE(LeaseMgr::upgradeLease6ExtendedInfo(lease));
+
+ ConstElementPtr new_user_context = lease->getContext();
+ ASSERT_TRUE(new_user_context);
+ ASSERT_EQ(Element::map, new_user_context->getType());
+ ConstElementPtr new_isc = new_user_context->get("ISC");
+ ASSERT_TRUE(new_isc);
+ ASSERT_EQ(Element::map, new_isc->getType());
+ ConstElementPtr relay_info = new_isc->get("relay-info");
+ ASSERT_TRUE(relay_info);
+ ASSERT_EQ(Element::list, relay_info->getType());
+ ASSERT_EQ("[ { \"foo\": \"bar\" } ]", relay_info->str());
+}
+
+// Verify Lease6 user context upgrade complex operations.
+TEST(Lease6ExtendedInfoTest, upgradeLease6ExtendedInfo) {
+ // Structure that defines a test scenario.
+ struct Scenario {
+ string description_; // test description.
+ string orig_; // original user context.
+ string expected_; // expected user context.
+ };
+
+ // Test scenarios.
+ vector<Scenario> scenarios {
+ {
+ "no user context",
+ "",
+ ""
+ },
+ {
+ "user context is not a map",
+ "[ ]",
+ ""
+ },
+ {
+ "no ISC entry",
+ "{ }",
+ ""
+ },
+ {
+ "no ISC entry but not empty",
+ "{ \"foo\": true }",
+ "{ \"foo\": true }"
+ },
+ {
+ "ISC entry is not a map",
+ "{ \"ISC\": true }",
+ ""
+ },
+ {
+ "ISC entry is not a map, user context not empty",
+ "{ \"foo\": true, \"ISC\": true }",
+ "{ \"foo\": true }"
+ },
+ {
+ "no relays",
+ "{ \"ISC\": { } }",
+ ""
+ },
+ {
+ "no relays, ISC not empty",
+ "{ \"ISC\": { \"foo\": true } }",
+ "{ \"ISC\": { \"foo\": true } }"
+ },
+ {
+ "relays is not a list",
+ "{ \"ISC\": { \"relays\": { } } }",
+ ""
+ },
+ {
+ "relays is not a list, ISC not empty",
+ "{ \"ISC\": { \"foo\": true, \"relays\": { } } }",
+ "{ \"ISC\": { \"foo\": true } }"
+ },
+ {
+ "relays is empty",
+ "{ \"ISC\": { \"relays\": [ ] } }",
+ ""
+ },
+ {
+ "relays is empty, ISC not empty",
+ "{ \"ISC\": { \"foo\": true, \"relays\": [ ] } }",
+ "{ \"ISC\": { \"foo\": true } }"
+ },
+ {
+ "relay is not a map",
+ "{ \"ISC\": { \"relays\": [ \"foobar\" ] } }",
+ ""
+ },
+ {
+ "relay has other values",
+ "{ \"ISC\": { \"relays\": [ { \"foo\": \"bar\" } ] } }",
+ "{ \"ISC\": { \"relay-info\": [ { \"foo\": \"bar\" } ] } }"
+ },
+ {
+ "one relay with no ids",
+ "{ \"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\" } ] } }"
+ },
+ {
+ "one relay with remote and relay ids",
+ "{ \"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\" } ] } }"
+ },
+ {
+ "two relays",
+ "{ \"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\" } ] } }"
+ }
+ };
+
+ Lease6Ptr lease(new Lease6());
+ ElementPtr orig_context;
+ ElementPtr exp_context;
+ for (auto scenario : scenarios) {
+ SCOPED_TRACE(scenario.description_);
+
+ // Create the original user context from JSON.
+ if (scenario.orig_.empty()) {
+ orig_context.reset();
+ } else {
+ ASSERT_NO_THROW(orig_context = Element::fromJSON(scenario.orig_))
+ << "invalid original context, test " << scenario.description_
+ << " is broken";
+ }
+
+ // Create the expected user context from JSON.
+ if (scenario.expected_.empty()) {
+ exp_context.reset();
+ } else {
+ ASSERT_NO_THROW(exp_context = Element::fromJSON(scenario.expected_))
+ << "invalid expected context, test is broken";
+ }
+
+ // Perform the test.
+ lease->setContext(orig_context);
+ ConstElementPtr before;
+ if (orig_context) {
+ before = isc::data::copy(orig_context);
+ }
+ bool ret = LeaseMgr::upgradeLease6ExtendedInfo(lease);
+ 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;
+ }
+ }
+}
+
+/// Verify setExtendedInfoTablesEnabled without valid extended info.
+TEST(Lease6ExtendedInfoTest, invalidSetExtendedInfoTablesEnabled) {
+
+ DatabaseConnection::ParameterMap pmap;
+ boost::scoped_ptr<ConcreteLeaseMgr> mgr(new ConcreteLeaseMgr(pmap));
+
+ // Structure that defines a test scenario.
+ struct Scenario {
+ string description_; // test description.
+ string user_context_txt_; // user context.
+ };
+
+ // Test scenarios.
+ vector<Scenario> scenarios {
+ {
+ "no user context",
+ ""
+ },
+ {
+ "user context is not a map",
+ "[ ]"
+ },
+ {
+ "no ISC entry",
+ "{ }"
+ },
+ {
+ "no ISC entry but not empty",
+ "{ \"foo\": true }"
+ },
+ {
+ "ISC entry is not a map",
+ "{ \"ISC\": true }"
+ },
+ {
+ "ISC entry is not a map, user context not empty",
+ "{ \"foo\": true, \"ISC\": true }"
+ },
+ {
+ "no relay-info",
+ "{ \"ISC\": { } }"
+ },
+ {
+ "no relay-info, ISC not empty",
+ "{ \"ISC\": { \"foo\": true } }"
+ },
+ {
+ "relay-info is not a list",
+ "{ \"ISC\": { \"relay-info\": { } } }"
+ },
+ {
+ "relay-info is not a list, ISC not empty",
+ "{ \"ISC\": { \"foo\": true, \"relay-info\": { } } }"
+ },
+ {
+ "relay-info is empty",
+ "{ \"ISC\": { \"relay-info\": [ ] } }"
+ },
+ {
+ "relay-info is empty, ISC not empty",
+ "{ \"ISC\": { \"foo\": true, \"relay-info\": [ ] } }"
+ },
+ {
+ "relay is not a map",
+ "{ \"ISC\": { \"relay-info\": [ \"foobar\" ] } }"
+ },
+ {
+ "relay has other values",
+ "{ \"ISC\": { \"relay-info\": [ { \"foo\": \"bar\" } ] } }"
+ }
+ };
+
+ Lease6Ptr lease(new Lease6());
+ ElementPtr user_context;
+ for (auto scenario : scenarios) {
+ SCOPED_TRACE(scenario.description_);
+
+ // Create the user context from JSON.
+ if (scenario.user_context_txt_.empty()) {
+ user_context.reset();
+ } else {
+ ASSERT_NO_THROW(user_context = Element::fromJSON(scenario.user_context_txt_))
+ << "invalid user context, test " << scenario.description_
+ << " is broken";
+ }
+
+ // Perform the test.
+ lease->setContext(user_context);
+ mgr->relay_id6_.clear();
+ mgr->remote_id6_.clear();
+ EXPECT_NO_THROW(mgr->addExtendedInfo6(lease));
+ EXPECT_TRUE(mgr->relay_id6_.empty());
+ EXPECT_TRUE(mgr->remote_id6_.empty());
+ }
+}
+
+/// Verify setExtendedInfoTablesEnabled with one relay without ids.
+TEST(Lease6ExtendedInfoTest, noIdSetExtendedInfoTablesEnabled) {
+
+ string user_context_txt =
+ "{ \"ISC\": { \"relay-info\": [ { \"hop\": 33,"
+ " \"link\": \"2001:db8::1\", \"peer\": \"2001:db8::2\","
+ " \"options\": \"0x00C800080102030405060708\" } ] } }";
+
+ DatabaseConnection::ParameterMap pmap;
+ boost::scoped_ptr<ConcreteLeaseMgr> mgr(new ConcreteLeaseMgr(pmap));
+
+ Lease6Ptr lease(new Lease6());
+ lease->addr_ = IOAddress("2001:db8::100");
+ ElementPtr user_context;
+ ASSERT_NO_THROW(user_context = Element::fromJSON(user_context_txt));
+ lease->setContext(user_context);
+ EXPECT_NO_THROW(mgr->addExtendedInfo6(lease));
+ EXPECT_TRUE(mgr->relay_id6_.empty());
+ EXPECT_TRUE(mgr->remote_id6_.empty());
+}
+
+/// Verify setExtendedInfoTablesEnabled with one relay with ids.
+TEST(Lease6ExtendedInfoTest, idsSetExtendedInfoTablesEnabled) {
+
+ string user_context_txt =
+ "{ \"ISC\": { \"relay-info\": [ { \"hop\": 100,"
+ " \"options\": \"0x00250006010203040506003500086464646464646464\","
+ " \"link\": \"2001:db8::5\", \"peer\": \"2001:db8::6\","
+ " \"remote-id\": \"010203040506\","
+ " \"relay-id\": \"6464646464646464\" } ] } }";
+
+ DatabaseConnection::ParameterMap pmap;
+ boost::scoped_ptr<ConcreteLeaseMgr> mgr(new ConcreteLeaseMgr(pmap));
+
+ Lease6Ptr lease(new Lease6());
+ lease->addr_ = IOAddress("2001:db8::100");
+ ElementPtr user_context;
+ ASSERT_NO_THROW(user_context = Element::fromJSON(user_context_txt));
+ lease->setContext(user_context);
+ EXPECT_NO_THROW(mgr->addExtendedInfo6(lease));
+
+ EXPECT_EQ(1, mgr->relay_id6_.size());
+ Lease6ExtendedInfoPtr ex_info = mgr->relay_id6_.front();
+ ASSERT_TRUE(ex_info);
+ EXPECT_EQ("2001:db8::100", ex_info->lease_addr_.toText());
+ const vector<uint8_t>& relay_id = ex_info->id_;
+ const vector<uint8_t>& exp_relay_id = vector<uint8_t>(8, 0x64);
+ EXPECT_EQ(exp_relay_id, relay_id);
+
+ EXPECT_EQ(1, mgr->remote_id6_.size());
+ ex_info = mgr->remote_id6_.front();
+ ASSERT_TRUE(ex_info);
+ EXPECT_EQ("2001:db8::100", ex_info->lease_addr_.toText());
+ const vector<uint8_t>& remote_id = ex_info->id_;
+ const vector<uint8_t>& exp_remote_id = { 1, 2, 3, 4, 5, 6 };
+ EXPECT_EQ(exp_remote_id, remote_id);
+}
+
+/// Verify setExtendedInfoTablesEnabled with one relay with ids but
+/// :: link address.
+TEST(Lease6ExtendedInfoTest, linkZeroSetExtendedInfoTablesEnabled) {
+
+ string user_context_txt =
+ "{ \"ISC\": { \"relay-info\": [ { \"hop\": 100,"
+ " \"options\": \"0x00250006010203040506003500086464646464646464\","
+ " \"link\": \"::\", \"peer\": \"2001:db8::6\","
+ " \"remote-id\": \"010203040506\","
+ " \"relay-id\": \"6464646464646464\" } ] } }";
+
+ DatabaseConnection::ParameterMap pmap;
+ boost::scoped_ptr<ConcreteLeaseMgr> mgr(new ConcreteLeaseMgr(pmap));
+
+ Lease6Ptr lease(new Lease6());
+ lease->addr_ = IOAddress("2001:db8::100");
+ ElementPtr user_context;
+ ASSERT_NO_THROW(user_context = Element::fromJSON(user_context_txt));
+ lease->setContext(user_context);
+ EXPECT_NO_THROW(mgr->addExtendedInfo6(lease));
+
+ EXPECT_EQ(1, mgr->relay_id6_.size());
+ Lease6ExtendedInfoPtr ex_info = mgr->relay_id6_.front();
+ ASSERT_TRUE(ex_info);
+ EXPECT_EQ("2001:db8::100", ex_info->lease_addr_.toText());
+ const vector<uint8_t>& relay_id = ex_info->id_;
+ const vector<uint8_t>& exp_relay_id = vector<uint8_t>(8, 0x64);
+ EXPECT_EQ(exp_relay_id, relay_id);
+
+ EXPECT_EQ(1, mgr->remote_id6_.size());
+ ex_info = mgr->remote_id6_.front();
+ ASSERT_TRUE(ex_info);
+ EXPECT_EQ("2001:db8::100", ex_info->lease_addr_.toText());
+ const vector<uint8_t>& remote_id = ex_info->id_;
+ const vector<uint8_t>& exp_remote_id = { 1, 2, 3, 4, 5, 6 };
+ EXPECT_EQ(exp_remote_id, remote_id);
+}
+
+/// Verify setExtendedInfoTablesEnabled with two relays.
+TEST(Lease6ExtendedInfoTest, twoSetExtendedInfoTablesEnabled) {
+
+ string user_context_txt =
+ "{ \"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\" } ] } }";
+
+ DatabaseConnection::ParameterMap pmap;
+ boost::scoped_ptr<ConcreteLeaseMgr> mgr(new ConcreteLeaseMgr(pmap));
+
+ Lease6Ptr lease(new Lease6());
+ lease->addr_ = IOAddress("2001:db8::100");
+ ElementPtr user_context;
+ ASSERT_NO_THROW(user_context = Element::fromJSON(user_context_txt));
+ lease->setContext(user_context);
+ EXPECT_NO_THROW(mgr->addExtendedInfo6(lease));
+
+ EXPECT_EQ(1, mgr->relay_id6_.size());
+ Lease6ExtendedInfoPtr ex_info = mgr->relay_id6_.front();
+ ASSERT_TRUE(ex_info);
+ EXPECT_EQ("2001:db8::100", ex_info->lease_addr_.toText());
+ const vector<uint8_t>& relay_id = ex_info->id_;
+ const vector<uint8_t>& exp_relay_id = vector<uint8_t>(8, 0x64);
+ EXPECT_EQ(exp_relay_id, relay_id);
+
+ EXPECT_EQ(1, mgr->remote_id6_.size());
+ ex_info = mgr->remote_id6_.front();
+ ASSERT_TRUE(ex_info);
+ EXPECT_EQ("2001:db8::100", ex_info->lease_addr_.toText());
+ const vector<uint8_t>& remote_id = ex_info->id_;
+ const vector<uint8_t>& exp_remote_id = { 1, 2, 3, 4, 5, 6 };
+ EXPECT_EQ(exp_remote_id, remote_id);
+}
+
+// There's no point in calling any other methods in LeaseMgr, as they
+// are purely virtual, so we would only call ConcreteLeaseMgr methods.
+// Those methods are just stubs that do not return anything.
+
+} // namespace