diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
commit | f5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch) | |
tree | 49e44c6f87febed37efb953ab5485aa49f6481a7 /src/lib/dhcpsrv/tests/lease_mgr_unittest.cc | |
parent | Initial commit. (diff) | |
download | isc-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.cc | 1038 |
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 |