From: Thomas Markwalder Date: Thu, 18 Apr 2019 13:53:35 +0000 (-0400) Subject: [#566,!304] Addressed review comments X-Git-Tag: Kea-1.6.0-beta~233 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2e85376f1b57187b822c662144380e04372cffff;p=thirdparty%2Fkea.git [#566,!304] Addressed review comments --- diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am index 313c7bfed1..b5e3349d4a 100644 --- a/src/lib/dhcpsrv/tests/Makefile.am +++ b/src/lib/dhcpsrv/tests/Makefile.am @@ -63,8 +63,7 @@ libdhcpsrv_unittests_SOURCES += alloc_engine_hooks_unittest.cc libdhcpsrv_unittests_SOURCES += alloc_engine4_unittest.cc libdhcpsrv_unittests_SOURCES += alloc_engine6_unittest.cc libdhcpsrv_unittests_SOURCES += callout_handle_store_unittest.cc -libdhcpsrv_unittests_SOURCES += cb_ctl_dhcp4_unittest.cc -libdhcpsrv_unittests_SOURCES += cb_ctl_dhcp6_unittest.cc +libdhcpsrv_unittests_SOURCES += cb_ctl_dhcp_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_db_access_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_duid_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_expiration_unittest.cc diff --git a/src/lib/dhcpsrv/tests/cb_ctl_dhcp6_unittest.cc b/src/lib/dhcpsrv/tests/cb_ctl_dhcp6_unittest.cc deleted file mode 100644 index 48f7956b7d..0000000000 --- a/src/lib/dhcpsrv/tests/cb_ctl_dhcp6_unittest.cc +++ /dev/null @@ -1,764 +0,0 @@ -// Copyright (C) 2019 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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace isc::asiolink; -using namespace isc::db; -using namespace isc::data; -using namespace isc::dhcp; -using namespace isc::dhcp::test; -using namespace isc::process; - -namespace { - -/// @brief Base class for testing derivations of the CBControlDHCP. -class CBControlDHCPTest : public GenericBackendTest { -public: - - /// @brief Constructor. - CBControlDHCPTest() - : timestamp_(), object_timestamp_(), audit_entries_() { - CfgMgr::instance().clear(); - CfgMgr::instance().setFamily(AF_INET6); - initTimestamps(); - } - - /// @brief Destructor. - virtual ~CBControlDHCPTest() { - // Unregister the factory to be tidy. - ConfigBackendDHCPv6Mgr::instance().unregisterBackendFactory("memfile"); - CfgMgr::instance().clear(); - } - - /// @brief Creates new CREATE audit entry. - /// - /// The audit entry is added to the @c audit_entries_ collection. - /// - /// @param object_type Object type to be associated with the audit - /// entry. - void addCreateAuditEntry(const std::string& object_type) { - AuditEntryPtr entry(new AuditEntry(object_type, 1234, - AuditEntry::ModificationType::CREATE, - "some log message")); - audit_entries_.insert(entry); - } - - /// @brief Creates new DELETE audit entry. - /// - /// The audit entry is added to the @c audit_entries_ collection. - /// - /// @param object_type Object type to be associated with the audit - /// entry. - /// @param object_id Identifier of the object to be associated with - /// the audit entry. - void addDeleteAuditEntry(const std::string& object_type, - const uint64_t object_id) { - AuditEntryPtr entry(new AuditEntry(object_type, object_id, - AuditEntry::ModificationType::DELETE, - "some log message")); - audit_entries_.insert(entry); - } - - /// @brief Initializes timestamps used in tests. - void initTimestamps() { - // Get the current timestamp and move it 30 seconds backwards. - auto now = boost::posix_time::second_clock::local_time() - - boost::posix_time::seconds(30); - - // Initialize multiple timestamps from the base timestamp. The - // values with indexes [-5, 0] are in the past. The remaining - // four are in the future. - for (int i = -5; i < 5; ++i) { - timestamp_[i] = now + boost::posix_time::minutes(i); - } - } - - /// @brief Returns timestamp associated with a given index. - /// - /// @param timestamp_index Index of the timestamp to be returned. - boost::posix_time::ptime getTimestamp(const int timestamp_index) { - return (timestamp_[timestamp_index]); - } - - /// @brief Returns timestamp to be associated with a given object type. - /// - /// The object types correspond to the names of the SQL tables holding - /// them, e.g. dhcp6_global_parameter, dhcp6_subnet etc. - /// - /// @param object_type Object type. - boost::posix_time::ptime getTimestamp(const std::string& object_type) { - return (object_timestamp_[object_type]); - } - - /// @brief Associates object type with a timestamp. - /// - /// When adding objects to the database, each one is associated with - /// a modification time value. This value is setup by unit tests - /// via this method. - void setTimestamp(const std::string& object_type, const int timestamp_index) { - object_timestamp_[object_type] = timestamp_[timestamp_index]; - } - - /// @brief Sets timestamps for various object types to the same value. - /// - /// @param timestamp_index Index of the timestamp to be set. - virtual void setAllTimestamps(const int timestamp_index) = 0; - - /// @brief Checks if @c databaseConfigApply should fetch updates for specified - /// object types. - /// - /// @param object_type Object type. - bool fetchConfigElement(const std::string& object_type) const { - if (!audit_entries_.empty()) { - const auto& index = audit_entries_.get(); - auto range = index.equal_range(object_type); - for (auto it = range.first; it != range.second; ++it) { - if (((*it)->getModificationType() != AuditEntry::ModificationType::DELETE)) { - return (true); - } - } - return (false); - } - - return (true); - } - - /// @brief Check if @c databaseConfigApply should delete a given object from the - /// local configuration. - /// - /// @param object_type Object type. - /// @param object_id Object identifier. - bool deleteConfigElement(const std::string& object_type, - const uint64_t object_id) const { - if (!audit_entries_.empty()) { - const auto& index = audit_entries_.get(); - auto range = index.equal_range(boost::make_tuple(object_type, - AuditEntry::ModificationType::DELETE)); - for (auto it = range.first; it != range.second; ++it) { - if ((*it)->getObjectId() == object_id) { - return (true); - } - } - } - return (false); - } - - /// @brief Holds test timestamps. - std::map timestamp_; - - /// @brief Holds mapping of the objects types to their timestamps. - std::map object_timestamp_; - - /// @brief Collection of audit entries used in the unit tests. - AuditEntryCollection audit_entries_; -}; - - -/// @brief Naked @c CBControlDHCPv6 class exposing protected methods. -class TestCBControlDHCPv6 : public CBControlDHCPv6 { -public: - using CBControlDHCPv6::getInitialAuditEntryTime; - using CBControlDHCPv6::databaseConfigApply; -}; - -/// @brief Test fixture class for @c CBControlDHCPv6 unit tests. -class CBControlDHCPv6Test : public CBControlDHCPTest { -public: - - /// @brief Constructor. - CBControlDHCPv6Test() - : CBControlDHCPTest(), ctl_() { - ConfigBackendDHCPv6Mgr::instance().registerBackendFactory("memfile", - [](const DatabaseConnection::ParameterMap& params) - -> ConfigBackendDHCPv6Ptr { - return (TestConfigBackendDHCPv6Ptr(new TestConfigBackendDHCPv6(params))); - }); - ConfigBackendDHCPv6Mgr::instance().addBackend("type=memfile"); - - // By default, set timestamps for all object types to -4. That leaves - // us with the possibility to use index -5 (earlier) to use as lower - // bound modification time so as all objects are fetched. - setAllTimestamps(-4); - } - - /// @brief Sets timestamps of all DHCPv6 specific object types. - /// - /// @param timestamp_index Index of the timestamp to be set. - virtual void setAllTimestamps(const int timestamp_index) { - setTimestamp("dhcp6_global_parameter", timestamp_index); - setTimestamp("dhcp6_option_def", timestamp_index); - setTimestamp("dhcp6_options", timestamp_index); - setTimestamp("dhcp6_shared_network", timestamp_index); - setTimestamp("dhcp6_subnet", timestamp_index); - } - - /// @brief Creates test server configuration and stores it in a test - /// configuration backend. - /// - /// There are pairs of configuration elements stored in the database. - /// For example: two global parameters, two option definitions etc. - /// Having two elements of each type in the database is useful in tests - /// which verify that an element is deleted from the local configuration - /// as a result of being deleted from the configuration backend. In that - /// case the test verifies that one of the elements of the given type - /// is deleted and one is left. - void remoteStoreTestConfiguration() { - auto& mgr = ConfigBackendDHCPv6Mgr::instance(); - - // Insert global parameters into a database. - StampedValuePtr global_parameter = StampedValue::create("foo", "bar"); - global_parameter->setModificationTime(getTimestamp("dhcp6_global_parameter")); - ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - global_parameter)); - - global_parameter = StampedValue::create("bar", "teta"); - global_parameter->setModificationTime(getTimestamp("dhcp6_global_parameter")); - ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - global_parameter)); - - // Insert option definitions into the database. - OptionDefinitionPtr def(new OptionDefinition("one", 101, "uint16")); - def->setId(1); - def->setOptionSpaceName("isc"); - def->setModificationTime(getTimestamp("dhcp6_option_def")); - ASSERT_NO_THROW(mgr.getPool()->createUpdateOptionDef6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - def)); - def.reset(new OptionDefinition("two", 102, "uint16")); - def->setId(2); - def->setOptionSpaceName("isc"); - def->setModificationTime(getTimestamp("dhcp6_option_def")); - ASSERT_NO_THROW(mgr.getPool()->createUpdateOptionDef6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - def)); - - // Insert global options into the database. - OptionDescriptorPtr opt(new OptionDescriptor(createOption - (Option::V6, D6O_BOOTFILE_URL, - true, false, "some.bootfile"))); - opt->setId(1); - opt->space_name_ = DHCP6_OPTION_SPACE; - opt->setModificationTime(getTimestamp("dhcp6_options")); - mgr.getPool()->createUpdateOption6(BackendSelector::UNSPEC(), ServerSelector::ALL(), - opt); - - opt.reset(new OptionDescriptor(createOption - (Option::V6, D6O_AFTR_NAME, - true, true, "some.example.com"))); - opt->setId(2); - opt->space_name_ = DHCP6_OPTION_SPACE; - opt->setModificationTime(getTimestamp("dhcp6_options")); - mgr.getPool()->createUpdateOption6(BackendSelector::UNSPEC(), ServerSelector::ALL(), - opt); - - // Insert shared networks into the database. - SharedNetwork6Ptr network(new SharedNetwork6("one")); - network->setId(1); - network->setModificationTime(getTimestamp("dhcp6_shared_network")); - mgr.getPool()->createUpdateSharedNetwork6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - network); - - network.reset(new SharedNetwork6("two")); - network->setId(2); - network->setModificationTime(getTimestamp("dhcp6_shared_network")); - mgr.getPool()->createUpdateSharedNetwork6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - network); - - // Insert subnets into the database. - Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4, SubnetID(1))); - subnet->setModificationTime(getTimestamp("dhcp6_subnet")); - subnet->setSharedNetworkName("one"); - mgr.getPool()->createUpdateSubnet6(BackendSelector::UNSPEC(), ServerSelector::ALL(), - subnet); - - subnet.reset(new Subnet6(IOAddress("2001:db8:2::"), 64, 1, 2, 3, 4, SubnetID(2))); - subnet->setModificationTime(getTimestamp("dhcp6_subnet")); - mgr.getPool()->createUpdateSubnet6(BackendSelector::UNSPEC(), ServerSelector::ALL(), - subnet); - } - - /// @brief Deletes specified global parameter from the configuration - /// backend and generates audit entry. - /// - /// Note that the current Kea implementation does not track database - /// identifiers of the global parameters. Therefore, the identifier to - /// be used to create the audit entry for the deleted parameter must - /// be explicitly specified. - /// - /// @param parameter_name Parameter name. - /// @param id Parameter id. - void remoteDeleteGlobalParameter(const std::string& parameter_name, - const uint64_t id) { - auto& mgr = ConfigBackendDHCPv6Mgr::instance(); - mgr.getPool()->deleteGlobalParameter6(BackendSelector::UNSPEC(), ServerSelector::ALL(), - parameter_name); - addDeleteAuditEntry("dhcp6_global_parameter", id); - } - - /// @brief Deletes specified option definition from the configuration - /// backend and generates audit entry. - /// - /// @param code Option code. - /// @param space Option space. - void remoteDeleteOptionDef(const uint16_t code, const std::string& space) { - auto& mgr = ConfigBackendDHCPv6Mgr::instance(); - - auto option_def = mgr.getPool()->getOptionDef6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - code, space); - - if (option_def) { - mgr.getPool()->deleteOptionDef6(BackendSelector::UNSPEC(), ServerSelector::ALL(), - code, space); - addDeleteAuditEntry("dhcp6_option_def", option_def->getId()); - } - } - - /// @brief Deletes specified global option from the configuration backend - /// and generates audit entry. - /// - /// @param code Option code. - /// @param space Option space. - void remoteDeleteOption(const uint16_t code, const std::string& space) { - auto& mgr = ConfigBackendDHCPv6Mgr::instance(); - - auto option = mgr.getPool()->getOption6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - code, space); - - if (option) { - mgr.getPool()->deleteOptionDef6(BackendSelector::UNSPEC(), ServerSelector::ALL(), - code, space); - addDeleteAuditEntry("dhcp6_option_def", option->getId()); - } - } - - /// @brief Deletes specified shared network from the configuration backend - /// and generates audit entry. - /// - /// @param name Name of the shared network to be deleted. - void remoteDeleteSharedNetwork(const std::string& name) { - auto& mgr = ConfigBackendDHCPv6Mgr::instance(); - - auto network = mgr.getPool()->getSharedNetwork6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - name); - - if (network) { - mgr.getPool()->deleteSharedNetwork6(BackendSelector::UNSPEC(), - ServerSelector::ALL(), - name); - addDeleteAuditEntry("dhcp6_shared_network", network->getId()); - } - } - - /// @brief Deletes specified subnet from the configuration backend and - /// generates audit entry. - void remoteDeleteSubnet(const SubnetID& id) { - auto& mgr = ConfigBackendDHCPv6Mgr::instance(); - - mgr.getPool()->deleteSubnet6(BackendSelector::UNSPEC(), ServerSelector::ALL(), - id); - addDeleteAuditEntry("dhcp6_subnet", id); - } - - - /// @brief Tests the @c CBControlDHCPv6::databaseConfigApply method. - /// - /// This test inserts configuration elements of each type into the - /// configuration database. Next, it calls the @c databaseConfigApply, - /// which should merge each object from the database for which the - /// CREATE or UPDATE audit entry is found. The test then verifies - /// if the appropriate entries have been merged. - /// - /// @param lb_modification_time Lower bound modification time to be - /// passed to the @c databaseConfigApply. - void testDatabaseConfigApply(const boost::posix_time::ptime& lb_modification_time) { - remoteStoreTestConfiguration(); - - ASSERT_FALSE(audit_entries_.empty()) - << "Require at least one audit entry. The test is broken!"; - - ctl_.databaseConfigApply(BackendSelector::UNSPEC(), ServerSelector::ALL(), - lb_modification_time, audit_entries_); - - // The updates should have been merged into current configuration. - auto srv_cfg = CfgMgr::instance().getCurrentCfg(); - - // If there is an audit entry for global parameter and the parameter - // modification time is later than last audit entry time it should - // be merged. - if (fetchConfigElement("dhcp6_global_parameter") && - (getTimestamp("dhcp6_global_parameter") > lb_modification_time)) { - checkConfiguredGlobal(srv_cfg, "foo", Element::create("bar")); - - } else { - // Otherwise it shouldn't exist. - EXPECT_FALSE(srv_cfg->getConfiguredGlobals()->get("foo")); - } - - // If there is an audit entry for option definition and the definition - // modification time is later than last audit entry time it should - // be merged. - auto found_def = srv_cfg->getCfgOptionDef()->get("isc", "one"); - if (fetchConfigElement("dhcp6_option_def") && - getTimestamp("dhcp6_option_def") > lb_modification_time) { - ASSERT_TRUE(found_def); - EXPECT_EQ(101, found_def->getCode()); - EXPECT_EQ(OptionDataType::OPT_UINT16_TYPE, found_def->getType()); - - } else { - EXPECT_FALSE(found_def); - } - - // If there is an audit entry for an option and the option - // modification time is later than last audit entry time it should - // be merged. - auto options = srv_cfg->getCfgOption(); - auto found_opt = options->get("dhcp6", D6O_BOOTFILE_URL); - if (fetchConfigElement("dhcp6_options") && - (getTimestamp("dhcp6_options") > lb_modification_time)) { - ASSERT_TRUE(found_opt.option_); - EXPECT_EQ("some.bootfile", found_opt.option_->toString()); - - } else { - EXPECT_FALSE(found_opt.option_); - } - - // If there is an audit entry for a shared network and the network - // modification time is later than last audit entry time it should - // be merged. - auto networks = srv_cfg->getCfgSharedNetworks6(); - auto found_network = networks->getByName("one"); - if (fetchConfigElement("dhcp6_shared_network") && - (getTimestamp("dhcp6_shared_network") > lb_modification_time)) { - ASSERT_TRUE(found_network); - EXPECT_TRUE(found_network->hasFetchGlobalsFn()); - - } else { - EXPECT_FALSE(found_network); - } - - // If there is an audit entry for a subnet and the subnet modification - // time is later than last audit entry time it should be merged. - auto subnets = srv_cfg->getCfgSubnets6(); - auto found_subnet = subnets->getSubnet(1); - if (fetchConfigElement("dhcp6_subnet") && - (getTimestamp("dhcp6_subnet") > lb_modification_time)) { - ASSERT_TRUE(found_subnet); - EXPECT_TRUE(found_subnet->hasFetchGlobalsFn()); - - } else { - EXPECT_FALSE(found_subnet); - } - } - - /// @brief Tests deletion of the configuration elements by the - /// @c CBControlDHCPv6::databaseConfigApply method. - /// - /// This test inserts configuration elements of each type into the - /// configuration database and calls the @c databaseConfigApply - /// to fetch this configuration and merge into the local server - /// configuration. - /// - /// Next, the test calls the specified callback function, i.e. - /// @c db_modifications, which deletes selected configuration - /// elements from the database and generates appropriate audit - /// entries. Finally, it calls the @c databaseConfigApply again - /// to process the audit entries and checks if the appropriate - /// configuration elements are deleted from the local configuration - /// - /// @param lb_modification_time Lower bound modification time to be - /// passed to the @c databaseConfigApply. - /// @param db_modifications Pointer to the callback function which - /// applies test specific modifications into the database. - void testDatabaseConfigApplyDelete(const boost::posix_time::ptime& lb_modification_time, - std::function db_modifications) { - // Store initial configuration into the database. - remoteStoreTestConfiguration(); - - // Since we pass an empty audit collection the server treats this - // as if the server is starting up and fetches the entire - // configuration from the database. - ctl_.databaseConfigApply(BackendSelector::UNSPEC(), ServerSelector::ALL(), - ctl_.getInitialAuditEntryTime(), - AuditEntryCollection()); - // Commit the configuration so as it is moved from the staging - // to current. - CfgMgr::instance().commit(); - - // Run user defined callback which should delete selected configuration - // elements from the configuration backend. The appropriate DELETE - // audit entries should now be stored in the audit_entries_ collection. - if (db_modifications) { - db_modifications(); - } - - // Process the DELETE audit entries. - ctl_.databaseConfigApply(BackendSelector::UNSPEC(), ServerSelector::ALL(), - lb_modification_time, audit_entries_); - - // All changes should have been applied in the current configuration. - auto srv_cfg = CfgMgr::instance().getCurrentCfg(); - - { - SCOPED_TRACE("global parameters"); - // One of the global parameters should still be there. - EXPECT_TRUE(srv_cfg->getConfiguredGlobals()->get("bar")); - if (deleteConfigElement("dhcp6_global_parameter", 1)) { - EXPECT_FALSE(srv_cfg->getConfiguredGlobals()->get("foo")); - - } else { - EXPECT_TRUE(srv_cfg->getConfiguredGlobals()->get("foo")); - } - } - - { - SCOPED_TRACE("option definitions"); - // One of the option definitions should still be there. - EXPECT_TRUE(srv_cfg->getCfgOptionDef()->get("isc", "two")); - auto found_def = srv_cfg->getCfgOptionDef()->get("isc", "one"); - if (deleteConfigElement("dhcp6_option_def", 1)) { - EXPECT_FALSE(found_def); - - } else { - EXPECT_TRUE(found_def); - } - } - - { - SCOPED_TRACE("global options"); - // One of the options should still be there. - EXPECT_TRUE(srv_cfg->getCfgOption()->get("dhcp6", D6O_AFTR_NAME).option_); - auto found_opt = srv_cfg->getCfgOption()->get("dhcp6", D6O_AFTR_NAME); - if (deleteConfigElement("dhcp6_options", 1)) { - EXPECT_FALSE(found_opt.option_); - - } else { - EXPECT_TRUE(found_opt.option_); - } - } - - { - SCOPED_TRACE("shared networks"); - // One of the shared networks should still be there. - EXPECT_TRUE(srv_cfg->getCfgSharedNetworks6()->getByName("two")); - auto found_network = srv_cfg->getCfgSharedNetworks6()->getByName("one"); - if (deleteConfigElement("dhcp6_shared_network", 1)) { - EXPECT_FALSE(found_network); - - } else { - EXPECT_TRUE(found_network); - } - } - - { - SCOPED_TRACE("subnets"); - // One of the subnets should still be there. - EXPECT_TRUE(srv_cfg->getCfgSubnets6()->getSubnet(2)); - auto found_subnet = srv_cfg->getCfgSubnets6()->getSubnet(1); - if (deleteConfigElement("dhcp6_subnet", 1)) { - EXPECT_FALSE(found_subnet); - // If the subnet has been deleted, make sure that - // it was detached from the shared network it belonged - // to, if the shared network still exists. - auto found_network = srv_cfg->getCfgSharedNetworks6()->getByName("one"); - if (found_network) { - EXPECT_TRUE(found_network->getAllSubnets()->empty()); - } - - } else { - EXPECT_TRUE(found_subnet); - } - } - } - - /// @brief Instance of the @c CBControlDHCPv6 used for testing. - TestCBControlDHCPv6 ctl_; -}; - - -// This test verifies that the configuration updates for all object -// types are merged into the current configuration. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyAll) { - - addCreateAuditEntry("dhcp6_global_parameter"); - addCreateAuditEntry("dhcp6_option_def"); - addCreateAuditEntry("dhcp6_options"); - addCreateAuditEntry("dhcp6_shared_network"); - addCreateAuditEntry("dhcp6_subnet"); - - testDatabaseConfigApply(getTimestamp(-5)); -} - -// This test verifies that multiple configuration elements are -// deleted from the local configuration as a result of being -// deleted from the database. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteAll) { - testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { - remoteDeleteGlobalParameter("foo", 1); - remoteDeleteOptionDef(101, "isc"); - remoteDeleteOption(D6O_BOOTFILE_URL, DHCP6_OPTION_SPACE); - remoteDeleteSharedNetwork("one"); - remoteDeleteSubnet(SubnetID(1)); - }); -} - -// This test verifies that an attempt to delete non-existing -// configuration element does not cause an error. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteNonExisting) { - testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { - // Add several audit entries instructing to delete the - // non-existing configuration elements. The ids are set - // to 3, but the only existing elements have ids of 1 - // and 2. - addDeleteAuditEntry("dhcp6_global_parameter", 3); - addDeleteAuditEntry("dhcp6_option_def", 3); - addDeleteAuditEntry("dhcp6_options", 3); - addDeleteAuditEntry("dhcp6_shared_network", 3); - addDeleteAuditEntry("dhcp6_subnet", 3); - }); -} - -// This test verifies that only a global parameter is merged into -// the current configuration. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyGlobal) { - addCreateAuditEntry("dhcp6_global_parameter"); - testDatabaseConfigApply(getTimestamp(-5)); -} - -// This test verifies that the global parameter is deleted from -// the local configuration as a result of being deleted from the -// database. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteGlobal) { - testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { - remoteDeleteGlobalParameter("foo", 1); - }); -} - -// This test verifies that global parameter is not fetched from the -// database when the modification time is earlier than the last -// fetched audit entry. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyGlobalNotFetched) { - addCreateAuditEntry("dhcp6_global_parameter"); - testDatabaseConfigApply(getTimestamp(-3)); -} - -// This test verifies that only an option definition is merged into -// the current configuration. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyOptionDef) { - addCreateAuditEntry("dhcp6_option_def"); - testDatabaseConfigApply(getTimestamp(-5)); -} - -// This test verifies that the option definition is deleted from -// the local configuration as a result of being deleted from the -// database. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteOptionDef) { - addDeleteAuditEntry("dhcp6_option_def", 1); - testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { - remoteDeleteOptionDef(101, "isc"); - }); -} - -// This test verifies that option definition is not fetched from the -// database when the modification time is earlier than the last -// fetched audit entry. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyOptionDefNotFetched) { - addCreateAuditEntry("dhcp6_option_def"); - testDatabaseConfigApply(getTimestamp(-3)); -} - -// This test verifies that only a DHCPv6 option is merged into the -// current configuration. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyOption) { - addCreateAuditEntry("dhcp6_options"); - testDatabaseConfigApply(getTimestamp(-5)); -} - -// This test verifies that the global option is deleted from -// the local configuration as a result of being deleted from the -// database. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteOption) { - testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { - remoteDeleteOption(D6O_BOOTFILE_URL, DHCP6_OPTION_SPACE); - }); -} - -// This test verifies that DHCPv6 option is not fetched from the -// database when the modification time is earlier than the last -// fetched audit entry. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyOptionNotFetched) { - addCreateAuditEntry("dhcp6_options"); - testDatabaseConfigApply(getTimestamp(-3)); -} - -// This test verifies that only a shared network is merged into the -// current configuration. -TEST_F(CBControlDHCPv6Test, databaseConfigApplySharedNetwork) { - addCreateAuditEntry("dhcp6_shared_network"); - testDatabaseConfigApply(getTimestamp(-5)); -} - -// This test verifies that the shared network is deleted from -// the local configuration as a result of being deleted from the -// database. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteSharedNetwork) { - testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { - remoteDeleteSharedNetwork("one"); - }); -} - -// This test verifies that shared network is not fetched from the -// database when the modification time is earlier than the last -// fetched audit entry. -TEST_F(CBControlDHCPv6Test, databaseConfigApplySharedNetworkNotFetched) { - addCreateAuditEntry("dhcp6_shared_network"); - testDatabaseConfigApply(getTimestamp(-3)); -} - -// This test verifies that only a subnet is merged into the current -// configuration. -TEST_F(CBControlDHCPv6Test, databaseConfigApplySubnet) { - addCreateAuditEntry("dhcp6_shared_network"); - addCreateAuditEntry("dhcp6_subnet"); - testDatabaseConfigApply(getTimestamp(-5)); -} - -// This test verifies that the subnet is deleted from the local -// configuration as a result of being deleted from the database. -TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteSubnet) { - testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { - remoteDeleteSubnet(SubnetID(1)); - }); -} - -// This test verifies that subnet is not fetched from the database -// when the modification time is earlier than the last fetched audit -// entry. -TEST_F(CBControlDHCPv6Test, databaseConfigApplySubnetNotFetched) { - addCreateAuditEntry("dhcp6_subnet"); - testDatabaseConfigApply(getTimestamp(-3)); -} - -} diff --git a/src/lib/dhcpsrv/tests/cb_ctl_dhcp4_unittest.cc b/src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc similarity index 55% rename from src/lib/dhcpsrv/tests/cb_ctl_dhcp4_unittest.cc rename to src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc index 7dad1b7f35..ff0f8ef362 100644 --- a/src/lib/dhcpsrv/tests/cb_ctl_dhcp4_unittest.cc +++ b/src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc @@ -10,9 +10,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -168,6 +170,8 @@ public: AuditEntryCollection audit_entries_; }; +// ************************ V4 tests ********************* + /// @brief Naked @c CBControlDHCPv4 class exposing protected methods. class TestCBControlDHCPv4 : public CBControlDHCPv4 { public: @@ -760,4 +764,602 @@ TEST_F(CBControlDHCPv4Test, databaseConfigApplySubnetNotFetched) { testDatabaseConfigApply(getTimestamp(-3)); } +// ************************ V6 tests ********************* + +/// @brief Naked @c CBControlDHCPv6 class exposing protected methods. +class TestCBControlDHCPv6 : public CBControlDHCPv6 { +public: + /// @brief Constructor. + TestCBControlDHCPv6() { + CfgMgr::instance().setFamily(AF_INET6); + } + + using CBControlDHCPv6::getInitialAuditEntryTime; + using CBControlDHCPv6::databaseConfigApply; +}; + +/// @brief Test fixture class for @c CBControlDHCPv6 unit tests. +class CBControlDHCPv6Test : public CBControlDHCPTest { +public: + + /// @brief Constructor. + CBControlDHCPv6Test() + : CBControlDHCPTest(), ctl_() { + ConfigBackendDHCPv6Mgr::instance().registerBackendFactory("memfile", + [](const DatabaseConnection::ParameterMap& params) + -> ConfigBackendDHCPv6Ptr { + return (TestConfigBackendDHCPv6Ptr(new TestConfigBackendDHCPv6(params))); + }); + ConfigBackendDHCPv6Mgr::instance().addBackend("type=memfile"); + + // By default, set timestamps for all object types to -4. That leaves + // us with the possibility to use index -5 (earlier) to use as lower + // bound modification time so as all objects are fetched. + setAllTimestamps(-4); + } + + /// @brief Sets timestamps of all DHCPv6 specific object types. + /// + /// @param timestamp_index Index of the timestamp to be set. + virtual void setAllTimestamps(const int timestamp_index) { + setTimestamp("dhcp6_global_parameter", timestamp_index); + setTimestamp("dhcp6_option_def", timestamp_index); + setTimestamp("dhcp6_options", timestamp_index); + setTimestamp("dhcp6_shared_network", timestamp_index); + setTimestamp("dhcp6_subnet", timestamp_index); + } + + /// @brief Creates test server configuration and stores it in a test + /// configuration backend. + /// + /// There are pairs of configuration elements stored in the database. + /// For example: two global parameters, two option definitions etc. + /// Having two elements of each type in the database is useful in tests + /// which verify that an element is deleted from the local configuration + /// as a result of being deleted from the configuration backend. In that + /// case the test verifies that one of the elements of the given type + /// is deleted and one is left. + void remoteStoreTestConfiguration() { + auto& mgr = ConfigBackendDHCPv6Mgr::instance(); + + // Insert global parameters into a database. + StampedValuePtr global_parameter = StampedValue::create("foo", "bar"); + global_parameter->setModificationTime(getTimestamp("dhcp6_global_parameter")); + ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + global_parameter)); + + global_parameter = StampedValue::create("bar", "teta"); + global_parameter->setModificationTime(getTimestamp("dhcp6_global_parameter")); + ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + global_parameter)); + + // Insert option definitions into the database. + OptionDefinitionPtr def(new OptionDefinition("one", 101, "uint16")); + def->setId(1); + def->setOptionSpaceName("isc"); + def->setModificationTime(getTimestamp("dhcp6_option_def")); + ASSERT_NO_THROW(mgr.getPool()->createUpdateOptionDef6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + def)); + def.reset(new OptionDefinition("two", 102, "uint16")); + def->setId(2); + def->setOptionSpaceName("isc"); + def->setModificationTime(getTimestamp("dhcp6_option_def")); + ASSERT_NO_THROW(mgr.getPool()->createUpdateOptionDef6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + def)); + + // Insert global options into the database. + OptionDescriptorPtr opt(new OptionDescriptor(createOption + (Option::V6, D6O_BOOTFILE_URL, + true, false, "some.bootfile"))); + opt->setId(1); + opt->space_name_ = DHCP6_OPTION_SPACE; + opt->setModificationTime(getTimestamp("dhcp6_options")); + mgr.getPool()->createUpdateOption6(BackendSelector::UNSPEC(), ServerSelector::ALL(), + opt); + + opt.reset(new OptionDescriptor(createOption + (Option::V6, D6O_AFTR_NAME, + true, true, "some.example.com"))); + opt->setId(2); + opt->space_name_ = DHCP6_OPTION_SPACE; + opt->setModificationTime(getTimestamp("dhcp6_options")); + mgr.getPool()->createUpdateOption6(BackendSelector::UNSPEC(), ServerSelector::ALL(), + opt); + + // Insert shared networks into the database. + SharedNetwork6Ptr network(new SharedNetwork6("one")); + network->setId(1); + network->setModificationTime(getTimestamp("dhcp6_shared_network")); + mgr.getPool()->createUpdateSharedNetwork6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + network); + + network.reset(new SharedNetwork6("two")); + network->setId(2); + network->setModificationTime(getTimestamp("dhcp6_shared_network")); + mgr.getPool()->createUpdateSharedNetwork6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + network); + + // Insert subnets into the database. + Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4, SubnetID(1))); + subnet->setModificationTime(getTimestamp("dhcp6_subnet")); + subnet->setSharedNetworkName("one"); + mgr.getPool()->createUpdateSubnet6(BackendSelector::UNSPEC(), ServerSelector::ALL(), + subnet); + + subnet.reset(new Subnet6(IOAddress("2001:db8:2::"), 64, 1, 2, 3, 4, SubnetID(2))); + subnet->setModificationTime(getTimestamp("dhcp6_subnet")); + mgr.getPool()->createUpdateSubnet6(BackendSelector::UNSPEC(), ServerSelector::ALL(), + subnet); + } + + /// @brief Deletes specified global parameter from the configuration + /// backend and generates audit entry. + /// + /// Note that the current Kea implementation does not track database + /// identifiers of the global parameters. Therefore, the identifier to + /// be used to create the audit entry for the deleted parameter must + /// be explicitly specified. + /// + /// @param parameter_name Parameter name. + /// @param id Parameter id. + void remoteDeleteGlobalParameter(const std::string& parameter_name, + const uint64_t id) { + auto& mgr = ConfigBackendDHCPv6Mgr::instance(); + mgr.getPool()->deleteGlobalParameter6(BackendSelector::UNSPEC(), ServerSelector::ALL(), + parameter_name); + addDeleteAuditEntry("dhcp6_global_parameter", id); + } + + /// @brief Deletes specified option definition from the configuration + /// backend and generates audit entry. + /// + /// @param code Option code. + /// @param space Option space. + void remoteDeleteOptionDef(const uint16_t code, const std::string& space) { + auto& mgr = ConfigBackendDHCPv6Mgr::instance(); + + auto option_def = mgr.getPool()->getOptionDef6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + code, space); + + if (option_def) { + mgr.getPool()->deleteOptionDef6(BackendSelector::UNSPEC(), ServerSelector::ALL(), + code, space); + addDeleteAuditEntry("dhcp6_option_def", option_def->getId()); + } + } + + /// @brief Deletes specified global option from the configuration backend + /// and generates audit entry. + /// + /// @param code Option code. + /// @param space Option space. + void remoteDeleteOption(const uint16_t code, const std::string& space) { + auto& mgr = ConfigBackendDHCPv6Mgr::instance(); + + auto option = mgr.getPool()->getOption6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + code, space); + + if (option) { + mgr.getPool()->deleteOptionDef6(BackendSelector::UNSPEC(), ServerSelector::ALL(), + code, space); + addDeleteAuditEntry("dhcp6_option_def", option->getId()); + } + } + + /// @brief Deletes specified shared network from the configuration backend + /// and generates audit entry. + /// + /// @param name Name of the shared network to be deleted. + void remoteDeleteSharedNetwork(const std::string& name) { + auto& mgr = ConfigBackendDHCPv6Mgr::instance(); + + auto network = mgr.getPool()->getSharedNetwork6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + name); + + if (network) { + mgr.getPool()->deleteSharedNetwork6(BackendSelector::UNSPEC(), + ServerSelector::ALL(), + name); + addDeleteAuditEntry("dhcp6_shared_network", network->getId()); + } + } + + /// @brief Deletes specified subnet from the configuration backend and + /// generates audit entry. + void remoteDeleteSubnet(const SubnetID& id) { + auto& mgr = ConfigBackendDHCPv6Mgr::instance(); + + mgr.getPool()->deleteSubnet6(BackendSelector::UNSPEC(), ServerSelector::ALL(), + id); + addDeleteAuditEntry("dhcp6_subnet", id); + } + + + /// @brief Tests the @c CBControlDHCPv6::databaseConfigApply method. + /// + /// This test inserts configuration elements of each type into the + /// configuration database. Next, it calls the @c databaseConfigApply, + /// which should merge each object from the database for which the + /// CREATE or UPDATE audit entry is found. The test then verifies + /// if the appropriate entries have been merged. + /// + /// @param lb_modification_time Lower bound modification time to be + /// passed to the @c databaseConfigApply. + void testDatabaseConfigApply(const boost::posix_time::ptime& lb_modification_time) { + remoteStoreTestConfiguration(); + + ASSERT_FALSE(audit_entries_.empty()) + << "Require at least one audit entry. The test is broken!"; + + ctl_.databaseConfigApply(BackendSelector::UNSPEC(), ServerSelector::ALL(), + lb_modification_time, audit_entries_); + + // The updates should have been merged into current configuration. + auto srv_cfg = CfgMgr::instance().getCurrentCfg(); + + // If there is an audit entry for global parameter and the parameter + // modification time is later than last audit entry time it should + // be merged. + if (fetchConfigElement("dhcp6_global_parameter") && + (getTimestamp("dhcp6_global_parameter") > lb_modification_time)) { + checkConfiguredGlobal(srv_cfg, "foo", Element::create("bar")); + + } else { + // Otherwise it shouldn't exist. + EXPECT_FALSE(srv_cfg->getConfiguredGlobals()->get("foo")); + } + + // If there is an audit entry for option definition and the definition + // modification time is later than last audit entry time it should + // be merged. + auto found_def = srv_cfg->getCfgOptionDef()->get("isc", "one"); + if (fetchConfigElement("dhcp6_option_def") && + getTimestamp("dhcp6_option_def") > lb_modification_time) { + ASSERT_TRUE(found_def); + EXPECT_EQ(101, found_def->getCode()); + EXPECT_EQ(OptionDataType::OPT_UINT16_TYPE, found_def->getType()); + + } else { + EXPECT_FALSE(found_def); + } + + // If there is an audit entry for an option and the option + // modification time is later than last audit entry time it should + // be merged. + auto options = srv_cfg->getCfgOption(); + auto found_opt = options->get("dhcp6", D6O_BOOTFILE_URL); + if (fetchConfigElement("dhcp6_options") && + (getTimestamp("dhcp6_options") > lb_modification_time)) { + ASSERT_TRUE(found_opt.option_); + EXPECT_EQ("some.bootfile", found_opt.option_->toString()); + + } else { + EXPECT_FALSE(found_opt.option_); + } + + // If there is an audit entry for a shared network and the network + // modification time is later than last audit entry time it should + // be merged. + auto networks = srv_cfg->getCfgSharedNetworks6(); + auto found_network = networks->getByName("one"); + if (fetchConfigElement("dhcp6_shared_network") && + (getTimestamp("dhcp6_shared_network") > lb_modification_time)) { + ASSERT_TRUE(found_network); + EXPECT_TRUE(found_network->hasFetchGlobalsFn()); + + } else { + EXPECT_FALSE(found_network); + } + + // If there is an audit entry for a subnet and the subnet modification + // time is later than last audit entry time it should be merged. + auto subnets = srv_cfg->getCfgSubnets6(); + auto found_subnet = subnets->getSubnet(1); + if (fetchConfigElement("dhcp6_subnet") && + (getTimestamp("dhcp6_subnet") > lb_modification_time)) { + ASSERT_TRUE(found_subnet); + EXPECT_TRUE(found_subnet->hasFetchGlobalsFn()); + + } else { + EXPECT_FALSE(found_subnet); + } + } + + /// @brief Tests deletion of the configuration elements by the + /// @c CBControlDHCPv6::databaseConfigApply method. + /// + /// This test inserts configuration elements of each type into the + /// configuration database and calls the @c databaseConfigApply + /// to fetch this configuration and merge into the local server + /// configuration. + /// + /// Next, the test calls the specified callback function, i.e. + /// @c db_modifications, which deletes selected configuration + /// elements from the database and generates appropriate audit + /// entries. Finally, it calls the @c databaseConfigApply again + /// to process the audit entries and checks if the appropriate + /// configuration elements are deleted from the local configuration + /// + /// @param lb_modification_time Lower bound modification time to be + /// passed to the @c databaseConfigApply. + /// @param db_modifications Pointer to the callback function which + /// applies test specific modifications into the database. + void testDatabaseConfigApplyDelete(const boost::posix_time::ptime& lb_modification_time, + std::function db_modifications) { + // Store initial configuration into the database. + remoteStoreTestConfiguration(); + + // Since we pass an empty audit collection the server treats this + // as if the server is starting up and fetches the entire + // configuration from the database. + ctl_.databaseConfigApply(BackendSelector::UNSPEC(), ServerSelector::ALL(), + ctl_.getInitialAuditEntryTime(), + AuditEntryCollection()); + // Commit the configuration so as it is moved from the staging + // to current. + CfgMgr::instance().commit(); + + // Run user defined callback which should delete selected configuration + // elements from the configuration backend. The appropriate DELETE + // audit entries should now be stored in the audit_entries_ collection. + if (db_modifications) { + db_modifications(); + } + + // Process the DELETE audit entries. + ctl_.databaseConfigApply(BackendSelector::UNSPEC(), ServerSelector::ALL(), + lb_modification_time, audit_entries_); + + // All changes should have been applied in the current configuration. + auto srv_cfg = CfgMgr::instance().getCurrentCfg(); + + { + SCOPED_TRACE("global parameters"); + // One of the global parameters should still be there. + EXPECT_TRUE(srv_cfg->getConfiguredGlobals()->get("bar")); + if (deleteConfigElement("dhcp6_global_parameter", 1)) { + EXPECT_FALSE(srv_cfg->getConfiguredGlobals()->get("foo")); + + } else { + EXPECT_TRUE(srv_cfg->getConfiguredGlobals()->get("foo")); + } + } + + { + SCOPED_TRACE("option definitions"); + // One of the option definitions should still be there. + EXPECT_TRUE(srv_cfg->getCfgOptionDef()->get("isc", "two")); + auto found_def = srv_cfg->getCfgOptionDef()->get("isc", "one"); + if (deleteConfigElement("dhcp6_option_def", 1)) { + EXPECT_FALSE(found_def); + + } else { + EXPECT_TRUE(found_def); + } + } + + { + SCOPED_TRACE("global options"); + // One of the options should still be there. + EXPECT_TRUE(srv_cfg->getCfgOption()->get("dhcp6", D6O_AFTR_NAME).option_); + auto found_opt = srv_cfg->getCfgOption()->get("dhcp6", D6O_AFTR_NAME); + if (deleteConfigElement("dhcp6_options", 1)) { + EXPECT_FALSE(found_opt.option_); + + } else { + EXPECT_TRUE(found_opt.option_); + } + } + + { + SCOPED_TRACE("shared networks"); + // One of the shared networks should still be there. + EXPECT_TRUE(srv_cfg->getCfgSharedNetworks6()->getByName("two")); + auto found_network = srv_cfg->getCfgSharedNetworks6()->getByName("one"); + if (deleteConfigElement("dhcp6_shared_network", 1)) { + EXPECT_FALSE(found_network); + + } else { + EXPECT_TRUE(found_network); + } + } + + { + SCOPED_TRACE("subnets"); + // One of the subnets should still be there. + EXPECT_TRUE(srv_cfg->getCfgSubnets6()->getSubnet(2)); + auto found_subnet = srv_cfg->getCfgSubnets6()->getSubnet(1); + if (deleteConfigElement("dhcp6_subnet", 1)) { + EXPECT_FALSE(found_subnet); + // If the subnet has been deleted, make sure that + // it was detached from the shared network it belonged + // to, if the shared network still exists. + auto found_network = srv_cfg->getCfgSharedNetworks6()->getByName("one"); + if (found_network) { + EXPECT_TRUE(found_network->getAllSubnets()->empty()); + } + + } else { + EXPECT_TRUE(found_subnet); + } + } + } + + /// @brief Instance of the @c CBControlDHCPv6 used for testing. + TestCBControlDHCPv6 ctl_; +}; + + +// This test verifies that the configuration updates for all object +// types are merged into the current configuration. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyAll) { + + addCreateAuditEntry("dhcp6_global_parameter"); + addCreateAuditEntry("dhcp6_option_def"); + addCreateAuditEntry("dhcp6_options"); + addCreateAuditEntry("dhcp6_shared_network"); + addCreateAuditEntry("dhcp6_subnet"); + + testDatabaseConfigApply(getTimestamp(-5)); +} + +// This test verifies that multiple configuration elements are +// deleted from the local configuration as a result of being +// deleted from the database. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteAll) { + testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { + remoteDeleteGlobalParameter("foo", 1); + remoteDeleteOptionDef(101, "isc"); + remoteDeleteOption(D6O_BOOTFILE_URL, DHCP6_OPTION_SPACE); + remoteDeleteSharedNetwork("one"); + remoteDeleteSubnet(SubnetID(1)); + }); +} + +// This test verifies that an attempt to delete non-existing +// configuration element does not cause an error. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteNonExisting) { + testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { + // Add several audit entries instructing to delete the + // non-existing configuration elements. The ids are set + // to 3, but the only existing elements have ids of 1 + // and 2. + addDeleteAuditEntry("dhcp6_global_parameter", 3); + addDeleteAuditEntry("dhcp6_option_def", 3); + addDeleteAuditEntry("dhcp6_options", 3); + addDeleteAuditEntry("dhcp6_shared_network", 3); + addDeleteAuditEntry("dhcp6_subnet", 3); + }); +} + +// This test verifies that only a global parameter is merged into +// the current configuration. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyGlobal) { + addCreateAuditEntry("dhcp6_global_parameter"); + testDatabaseConfigApply(getTimestamp(-5)); +} + +// This test verifies that the global parameter is deleted from +// the local configuration as a result of being deleted from the +// database. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteGlobal) { + testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { + remoteDeleteGlobalParameter("foo", 1); + }); +} + +// This test verifies that global parameter is not fetched from the +// database when the modification time is earlier than the last +// fetched audit entry. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyGlobalNotFetched) { + addCreateAuditEntry("dhcp6_global_parameter"); + testDatabaseConfigApply(getTimestamp(-3)); +} + +// This test verifies that only an option definition is merged into +// the current configuration. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyOptionDef) { + addCreateAuditEntry("dhcp6_option_def"); + testDatabaseConfigApply(getTimestamp(-5)); +} + +// This test verifies that the option definition is deleted from +// the local configuration as a result of being deleted from the +// database. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteOptionDef) { + addDeleteAuditEntry("dhcp6_option_def", 1); + testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { + remoteDeleteOptionDef(101, "isc"); + }); +} + +// This test verifies that option definition is not fetched from the +// database when the modification time is earlier than the last +// fetched audit entry. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyOptionDefNotFetched) { + addCreateAuditEntry("dhcp6_option_def"); + testDatabaseConfigApply(getTimestamp(-3)); +} + +// This test verifies that only a DHCPv6 option is merged into the +// current configuration. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyOption) { + addCreateAuditEntry("dhcp6_options"); + testDatabaseConfigApply(getTimestamp(-5)); +} + +// This test verifies that the global option is deleted from +// the local configuration as a result of being deleted from the +// database. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteOption) { + testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { + remoteDeleteOption(D6O_BOOTFILE_URL, DHCP6_OPTION_SPACE); + }); +} + +// This test verifies that DHCPv6 option is not fetched from the +// database when the modification time is earlier than the last +// fetched audit entry. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyOptionNotFetched) { + addCreateAuditEntry("dhcp6_options"); + testDatabaseConfigApply(getTimestamp(-3)); +} + +// This test verifies that only a shared network is merged into the +// current configuration. +TEST_F(CBControlDHCPv6Test, databaseConfigApplySharedNetwork) { + addCreateAuditEntry("dhcp6_shared_network"); + testDatabaseConfigApply(getTimestamp(-5)); +} + +// This test verifies that the shared network is deleted from +// the local configuration as a result of being deleted from the +// database. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteSharedNetwork) { + testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { + remoteDeleteSharedNetwork("one"); + }); +} + +// This test verifies that shared network is not fetched from the +// database when the modification time is earlier than the last +// fetched audit entry. +TEST_F(CBControlDHCPv6Test, databaseConfigApplySharedNetworkNotFetched) { + addCreateAuditEntry("dhcp6_shared_network"); + testDatabaseConfigApply(getTimestamp(-3)); +} + +// This test verifies that only a subnet is merged into the current +// configuration. +TEST_F(CBControlDHCPv6Test, databaseConfigApplySubnet) { + addCreateAuditEntry("dhcp6_shared_network"); + addCreateAuditEntry("dhcp6_subnet"); + testDatabaseConfigApply(getTimestamp(-5)); +} + +// This test verifies that the subnet is deleted from the local +// configuration as a result of being deleted from the database. +TEST_F(CBControlDHCPv6Test, databaseConfigApplyDeleteSubnet) { + testDatabaseConfigApplyDelete(getTimestamp(-5), [this]() { + remoteDeleteSubnet(SubnetID(1)); + }); +} + +// This test verifies that subnet is not fetched from the database +// when the modification time is earlier than the last fetched audit +// entry. +TEST_F(CBControlDHCPv6Test, databaseConfigApplySubnetNotFetched) { + addCreateAuditEntry("dhcp6_subnet"); + testDatabaseConfigApply(getTimestamp(-3)); +} + }