diff --git a/src/bin/dhcp4/dhcp4.spec b/src/bin/dhcp4/dhcp4.spec index 0d8ec185bb..84c28d75fe 100644 --- a/src/bin/dhcp4/dhcp4.spec +++ b/src/bin/dhcp4/dhcp4.spec @@ -43,6 +43,50 @@ } ] }, + + { "item_name": "expired-leases-processing", + "item_type": "map", + "item_optional": false, + "item_default": {}, + "map_item_spec": [ + { + "item_name": "reclaim-timer-wait-time", + "item_type": "integer", + "item_optional": false, + "item_default": 10 + }, + { + "item_name": "flush-reclaimed-timer-wait-time", + "item_type": "integer", + "item_optional": false, + "item_default": 25 + }, + { + "item_name": "hold-reclaimed-time", + "item_type": "integer", + "item_optional": false, + "item_default": 3600 + }, + { + "item_name": "max-reclaim-leases", + "item_type": "integer", + "item_optional": false, + "item_default": 100 + }, + { + "item_name": "max-reclaim-time", + "item_type": "integer", + "item_optional": false, + "item_default": 250 + }, + { + "item_name": "unwarned-reclaim-cycles", + "item_type": "integer", + "item_optional": false, + "item_default": 5 + } + ] + }, { "item_name": "renew-timer", "item_type": "integer", diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc index 22c45fd7c8..d62e03e39b 100644 --- a/src/bin/dhcp4/json_config_parser.cc +++ b/src/bin/dhcp4/json_config_parser.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -405,6 +406,8 @@ namespace dhcp { parser = new BooleanParser(config_id, globalContext()->boolean_values_); } else if (config_id.compare("control-socket") == 0) { parser = new ControlSocketParser(config_id); + } else if (config_id.compare("expired-leases-processing") == 0) { + parser = new ExpirationConfigParser(); } else { isc_throw(DhcpConfigError, "unsupported global configuration parameter: " diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index 4b879efe20..933146facc 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -3712,4 +3713,73 @@ TEST_F(Dhcp4ParserTest, declineTimerError) { EXPECT_TRUE(errorContainsPosition(status, "")); } +// Check that configuration for the expired leases processing may be +// specified. +TEST_F(Dhcp4ParserTest, expiredLeasesProcessing) { + // Create basic configuration with the expiration specific parameters. + string config = "{ " + genIfaceConfig() + "," + + "\"expired-leases-processing\": " + "{" + " \"reclaim-timer-wait-time\": 20," + " \"flush-reclaimed-timer-wait-time\": 35," + " \"hold-reclaimed-time\": 1800," + " \"max-reclaim-leases\": 50," + " \"max-reclaim-time\": 100," + " \"unwarned-reclaim-cycles\": 10" + "}," + "\"subnet4\": [ ]" + "}"; + + ElementPtr json = Element::fromJSON(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json)); + + // Returned value should be 0 (success) + checkResult(status, 0); + + // The value of decline-probation-perion must be equal to the + // value specified. + CfgExpirationPtr cfg = CfgMgr::instance().getStagingCfg()->getCfgExpiration(); + ASSERT_TRUE(cfg); + + // Verify that parameters are correct. + EXPECT_EQ(20, cfg->getReclaimTimerWaitTime()); + EXPECT_EQ(35, cfg->getFlushReclaimedTimerWaitTime()); + EXPECT_EQ(1800, cfg->getHoldReclaimedTime()); + EXPECT_EQ(50, cfg->getMaxReclaimLeases()); + EXPECT_EQ(100, cfg->getMaxReclaimTime()); + EXPECT_EQ(10, cfg->getUnwarnedReclaimCycles()); +} + +// Check that invalid configuration for the expired leases processing is +// causing an error. +TEST_F(Dhcp4ParserTest, expiredLeasesProcessingError) { + // Create basic configuration with the expiration specific parameters. + // One of the parameters holds invalid value. + string config = "{ " + genIfaceConfig() + "," + + "\"expired-leases-processing\": " + "{" + " \"reclaim-timer-wait-time\": -5," + " \"flush-reclaimed-timer-wait-time\": 35," + " \"hold-reclaimed-time\": 1800," + " \"max-reclaim-leases\": 50," + " \"max-reclaim-time\": 100," + " \"unwarned-reclaim-cycles\": 10" + "}," + "\"subnet4\": [ ]" + "}"; + + ElementPtr json = Element::fromJSON(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json)); + + // Returned value should be 0 (error) + checkResult(status, 1); + + // Check that the error contains error position. + EXPECT_TRUE(errorContainsPosition(status, "")); +} + } diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec index e0fa45be45..f24d15f20a 100644 --- a/src/bin/dhcp6/dhcp6.spec +++ b/src/bin/dhcp6/dhcp6.spec @@ -38,6 +38,50 @@ ] }, + { "item_name": "expired-leases-processing", + "item_type": "map", + "item_optional": false, + "item_default": {}, + "map_item_spec": [ + { + "item_name": "reclaim-timer-wait-time", + "item_type": "integer", + "item_optional": false, + "item_default": 10 + }, + { + "item_name": "flush-reclaimed-timer-wait-time", + "item_type": "integer", + "item_optional": false, + "item_default": 25 + }, + { + "item_name": "hold-reclaimed-time", + "item_type": "integer", + "item_optional": false, + "item_default": 3600 + }, + { + "item_name": "max-reclaim-leases", + "item_type": "integer", + "item_optional": false, + "item_default": 100 + }, + { + "item_name": "max-reclaim-time", + "item_type": "integer", + "item_optional": false, + "item_default": 250 + }, + { + "item_name": "unwarned-reclaim-cycles", + "item_type": "integer", + "item_optional": false, + "item_default": 5 + } + ] + }, + { "item_name": "renew-timer", "item_type": "integer", "item_optional": false, diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index 89a90508bd..8f04b97346 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -697,6 +698,8 @@ namespace dhcp { parser = new RSOOListConfigParser(config_id); } else if (config_id.compare("control-socket") == 0) { parser = new ControlSocketParser(config_id); + } else if (config_id.compare("expired-leases-processing") == 0) { + parser = new ExpirationConfigParser(); } else { isc_throw(DhcpConfigError, "unsupported global configuration parameter: " diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index eb48f4c395..f2e945191a 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -4046,5 +4047,74 @@ TEST_F(Dhcp6ParserTest, declineTimerError) { EXPECT_TRUE(errorContainsPosition(status, "")); } +// Check that configuration for the expired leases processing may be +// specified. +TEST_F(Dhcp6ParserTest, expiredLeasesProcessing) { + // Create basic configuration with the expiration specific parameters. + string config = "{ " + genIfaceConfig() + "," + + "\"expired-leases-processing\": " + "{" + " \"reclaim-timer-wait-time\": 20," + " \"flush-reclaimed-timer-wait-time\": 35," + " \"hold-reclaimed-time\": 1800," + " \"max-reclaim-leases\": 50," + " \"max-reclaim-time\": 100," + " \"unwarned-reclaim-cycles\": 10" + "}," + "\"subnet6\": [ ]" + "}"; + + ElementPtr json = Element::fromJSON(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json)); + + // Returned value should be 0 (success) + checkResult(status, 0); + + // The value of decline-probation-perion must be equal to the + // value specified. + CfgExpirationPtr cfg = CfgMgr::instance().getStagingCfg()->getCfgExpiration(); + ASSERT_TRUE(cfg); + + // Verify that parameters are correct. + EXPECT_EQ(20, cfg->getReclaimTimerWaitTime()); + EXPECT_EQ(35, cfg->getFlushReclaimedTimerWaitTime()); + EXPECT_EQ(1800, cfg->getHoldReclaimedTime()); + EXPECT_EQ(50, cfg->getMaxReclaimLeases()); + EXPECT_EQ(100, cfg->getMaxReclaimTime()); + EXPECT_EQ(10, cfg->getUnwarnedReclaimCycles()); +} + +// Check that invalid configuration for the expired leases processing is +// causing an error. +TEST_F(Dhcp6ParserTest, expiredLeasesProcessingError) { + // Create basic configuration with the expiration specific parameters. + // One of the parameters holds invalid value. + string config = "{ " + genIfaceConfig() + "," + + "\"expired-leases-processing\": " + "{" + " \"reclaim-timer-wait-time\": -5," + " \"flush-reclaimed-timer-wait-time\": 35," + " \"hold-reclaimed-time\": 1800," + " \"max-reclaim-leases\": 50," + " \"max-reclaim-time\": 100," + " \"unwarned-reclaim-cycles\": 10" + "}," + "\"subnet6\": [ ]" + "}"; + + ElementPtr json = Element::fromJSON(config); + + ConstElementPtr status; + EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json)); + + // Returned value should be 0 (error) + checkResult(status, 1); + + // Check that the error contains error position. + EXPECT_TRUE(errorContainsPosition(status, "")); +} + }; diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index be7fd5c6bc..edb327fb1f 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -80,6 +80,7 @@ libkea_dhcpsrv_la_SOURCES += base_host_data_source.h libkea_dhcpsrv_la_SOURCES += callout_handle_store.h libkea_dhcpsrv_la_SOURCES += cfg_hosts.cc cfg_hosts.h libkea_dhcpsrv_la_SOURCES += cfg_iface.cc cfg_iface.h +libkea_dhcpsrv_la_SOURCES += cfg_expiration.cc cfg_expiration.h libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h libkea_dhcpsrv_la_SOURCES += cfg_rsoo.cc cfg_rsoo.h @@ -131,6 +132,8 @@ libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.cc libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.h libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.cc libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.h +libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.cc +libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.h libkea_dhcpsrv_la_SOURCES += parsers/host_reservation_parser.cc libkea_dhcpsrv_la_SOURCES += parsers/host_reservation_parser.h libkea_dhcpsrv_la_SOURCES += parsers/host_reservations_list_parser.h diff --git a/src/lib/dhcpsrv/cfg_expiration.cc b/src/lib/dhcpsrv/cfg_expiration.cc new file mode 100644 index 0000000000..d1b2d15706 --- /dev/null +++ b/src/lib/dhcpsrv/cfg_expiration.cc @@ -0,0 +1,108 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include + +namespace isc { +namespace dhcp { + +// Default values +const uint16_t CfgExpiration::DEFAULT_RECLAIM_TIMER_WAIT_TIME = 10; +const uint16_t CfgExpiration::DEFAULT_FLUSH_RECLAIMED_TIMER_WAIT_TIME = 25; +const uint32_t CfgExpiration::DEFAULT_HOLD_RECLAIMED_TIME = 3600; +const uint32_t CfgExpiration::DEFAULT_MAX_RECLAIM_LEASES = 100; +const uint16_t CfgExpiration::DEFAULT_MAX_RECLAIM_TIME = 250; +const uint16_t CfgExpiration::DEFAULT_UNWARNED_RECLAIM_CYCLES = 5; + +// Maximum values. +const uint16_t CfgExpiration::LIMIT_RECLAIM_TIMER_WAIT_TIME = + std::numeric_limits::max(); +const uint16_t CfgExpiration::LIMIT_FLUSH_RECLAIMED_TIMER_WAIT_TIME = + std::numeric_limits::max(); +const uint32_t CfgExpiration::LIMIT_HOLD_RECLAIMED_TIME = + std::numeric_limits::max(); +const uint32_t CfgExpiration::LIMIT_MAX_RECLAIM_LEASES = + std::numeric_limits::max(); +const uint16_t CfgExpiration::LIMIT_MAX_RECLAIM_TIME = 10000; +const uint16_t CfgExpiration::LIMIT_UNWARNED_RECLAIM_CYCLES = + std::numeric_limits::max(); + +CfgExpiration::CfgExpiration() + : reclaim_timer_wait_time_(DEFAULT_RECLAIM_TIMER_WAIT_TIME), + flush_reclaimed_timer_wait_time_(DEFAULT_FLUSH_RECLAIMED_TIMER_WAIT_TIME), + hold_reclaimed_time_(DEFAULT_HOLD_RECLAIMED_TIME), + max_reclaim_leases_(DEFAULT_MAX_RECLAIM_LEASES), + max_reclaim_time_(DEFAULT_MAX_RECLAIM_TIME), + unwarned_reclaim_cycles_(DEFAULT_UNWARNED_RECLAIM_CYCLES) { +} + +void +CfgExpiration::setReclaimTimerWaitTime(const int64_t reclaim_timer_wait_time) { + rangeCheck(reclaim_timer_wait_time, LIMIT_RECLAIM_TIMER_WAIT_TIME, + "reclaim-timer-wait-time"); + reclaim_timer_wait_time_ = reclaim_timer_wait_time; +} + +void +CfgExpiration::setFlushReclaimedTimerWaitTime(const int64_t flush_reclaimed_wait_time) { + rangeCheck(flush_reclaimed_wait_time, LIMIT_FLUSH_RECLAIMED_TIMER_WAIT_TIME, + "flush-reclaimed-timer-wait-time"); + flush_reclaimed_timer_wait_time_ = flush_reclaimed_wait_time; +} + +void +CfgExpiration::setHoldReclaimedTime(const int64_t hold_reclaimed_time) { + rangeCheck(hold_reclaimed_time, LIMIT_HOLD_RECLAIMED_TIME, "hold-reclaimed-time"); + hold_reclaimed_time_ = hold_reclaimed_time; +} + +void +CfgExpiration::setMaxReclaimLeases(const int64_t max_reclaim_leases) { + rangeCheck(max_reclaim_leases, LIMIT_MAX_RECLAIM_LEASES, "max-reclaim-leases"); + max_reclaim_leases_ = max_reclaim_leases; +} + +void +CfgExpiration::setMaxReclaimTime(const int64_t max_reclaim_time) { + rangeCheck(max_reclaim_time, LIMIT_MAX_RECLAIM_TIME, "max-reclaim-time"); + max_reclaim_time_ = max_reclaim_time; +} + +void +CfgExpiration::setUnwarnedReclaimCycles(const int64_t unwarned_reclaim_cycles) { + rangeCheck(unwarned_reclaim_cycles, LIMIT_UNWARNED_RECLAIM_CYCLES, + "unwarned-reclaim-cycles"); + unwarned_reclaim_cycles_ = unwarned_reclaim_cycles; +} + +void +CfgExpiration::rangeCheck(const int64_t value, const uint64_t max_value, + const std::string& config_parameter_name) const { + if (value < 0) { + isc_throw(OutOfRange, "value for configuration parameter '" + << config_parameter_name << "' must not be negtive"); + + } else if (value > max_value) { + isc_throw(OutOfRange, "out range value '" << value << "' for configuration" + " parameter '" << config_parameter_name << "', expected maximum" + " value of '" << max_value << "'"); + } +} + + + +} +} diff --git a/src/lib/dhcpsrv/cfg_expiration.h b/src/lib/dhcpsrv/cfg_expiration.h new file mode 100644 index 0000000000..b79558277d --- /dev/null +++ b/src/lib/dhcpsrv/cfg_expiration.h @@ -0,0 +1,227 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef CFG_EXPIRATION_H +#define CFG_EXPIRATION_H + +#include +#include +#include + +namespace isc { +namespace dhcp { + +/// @brief Holds configuration parameters pertaining to lease expiration +/// and lease affinity. +/// +/// This class holds the values of the following configuration parameters: +/// +/// - reclaim-timer-wait-time - is the time between two cycles of processing +/// expired leases, expressed in seconds, i.e. the time between the end of +/// one cycle and the beginning of the next cycle. If this value is 0, the +/// expired leases are not processed. +/// +/// - flush-reclaimed-timer-wait-time - is the time between two cycles of +/// recycling "expired-reclaimed" leases, expressed in seconds. If this +/// value is 0, the expired leases are removed by the leases reclamation +/// routine rather than recycling function. The recycling function is not +/// executed and the value of the "hold-reclaimed-time" is ignored. +/// +/// - hold-reclaimed-time -is the time for which "expired-reclaimed" leases +/// are held in the lease database in the "expired-reclaimed" state after +/// they expire. If this time is set to 0, the recycling function is not +/// executed and the value of the "recycle-timer-wait-time" is ignored. +/// This value is expressed in seconds. +/// +/// - max-reclaim-leases - is the maximum number of leases to be processed +/// in a single cycle. If this value is 0, all expired leases are +/// processed in a single cycle, unless the maximum processing time +/// (configured with the "max-time") parameter elapses first. +/// +/// - max-reclaim-time - the maximum time that a single processing cycle +/// may last, expressed in milliseconds. If this value is 0, there is no +/// limitation for the maximum processing time. This value is expressed +/// in milliseconds. +/// +/// - unwarned-reclaim-cycles - is the number of consecutive processing +/// cycles of expired leases, after which the system issues a warning if +/// there are still expired leases in the database. If this value is 0, +/// the warning is never issued. +/// +/// The @c CfgExpiration class provides a collection of accessors and +/// modifiers to manage the data. Each accessor checks if the given value +/// is in range allowed for this value. +class CfgExpiration { +public: + + /// @name Default values. + //@{ + /// + /// @brief Default value for reclaim-timer-wait-time. + static const uint16_t DEFAULT_RECLAIM_TIMER_WAIT_TIME; + + /// @brief Default value for flush-reclaimed-timer-wait-time. + static const uint16_t DEFAULT_FLUSH_RECLAIMED_TIMER_WAIT_TIME; + + /// @brief Default value for hold-reclaimed-time. + static const uint32_t DEFAULT_HOLD_RECLAIMED_TIME; + + /// @brief Default value for max-reclaim-leases. + static const uint32_t DEFAULT_MAX_RECLAIM_LEASES; + + /// @brief Default value for max-reclaim-time. + static const uint16_t DEFAULT_MAX_RECLAIM_TIME; + + /// @brief Default value for unwarned-reclaim-cycles. + static const uint16_t DEFAULT_UNWARNED_RECLAIM_CYCLES; + + //@} + + /// @name Upper limits for the parameters + //@{ + /// + /// @brief Maximum value for reclaim-timer-wait-time. + static const uint16_t LIMIT_RECLAIM_TIMER_WAIT_TIME; + + /// @brief Maximum value for flush-reclaimed-timer-wait-time. + static const uint16_t LIMIT_FLUSH_RECLAIMED_TIMER_WAIT_TIME; + + /// @brief Maximum value for hold-reclaimed-time. + static const uint32_t LIMIT_HOLD_RECLAIMED_TIME; + + /// @brief Maximum value for max-reclaim-leases. + static const uint32_t LIMIT_MAX_RECLAIM_LEASES; + + /// @brief Defalt value for max-reclaim-time. + static const uint16_t LIMIT_MAX_RECLAIM_TIME; + + /// @brief Maximum value for unwarned-reclaim-cycles. + static const uint16_t LIMIT_UNWARNED_RECLAIM_CYCLES; + + //@} + + /// @brief Constructor. + /// + /// Sets all parameters to their defaults. + CfgExpiration(); + + /// @brief Returns reclaim-timer-wait-time + uint16_t getReclaimTimerWaitTime() const { + return (reclaim_timer_wait_time_); + } + + /// @brief Sets reclaim-timer-wait-time + /// + /// @param reclaim_timer_wait_time New value. + void setReclaimTimerWaitTime(const int64_t reclaim_timer_wait_time); + + /// @brief Returns flush-reclaimed-timer-wait-time. + uint16_t getFlushReclaimedTimerWaitTime() const { + return (flush_reclaimed_timer_wait_time_); + } + + /// @brief Sets flush-reclaimed-timer-wait-time. + /// + /// @param flush_reclaimed_wait_time New value. + void setFlushReclaimedTimerWaitTime(const int64_t flush_reclaimed_wait_time); + + /// @brief Returns hold-reclaimed-time. + uint32_t getHoldReclaimedTime() const { + return (hold_reclaimed_time_); + } + + /// @brief Sets hold-reclaimed-time + /// + /// @param hold_reclaimed_time New value. + void setHoldReclaimedTime(const int64_t hold_reclaimed_time); + + /// @brief Returns max-reclaim-leases. + uint32_t getMaxReclaimLeases() const { + return (max_reclaim_leases_); + } + + /// @brief Sets max-reclaim-leases. + /// + /// @param max_reclaim_leases New value. + void setMaxReclaimLeases(const int64_t max_reclaim_leases); + + /// @brief Returns max-reclaim-time. + uint16_t getMaxReclaimTime() const { + return (max_reclaim_time_); + } + + /// @brief Sets max-reclaim-time. + /// + /// @param max_reclaim_time New value. + void setMaxReclaimTime(const int64_t max_reclaim_time); + + /// @brief Returns unwarned-reclaim-cycles. + uint16_t getUnwarnedReclaimCycles() const { + return (unwarned_reclaim_cycles_); + } + + /// @brief Sets unwarned-reclaim-cycles. + /// + /// @param unwarned_reclaim_cycles New value. + void setUnwarnedReclaimCycles(const int64_t unwarned_reclaim_cycles); + +private: + + /// @brief Checks if the value being set by one of the modifiers is + /// within an allowed range. + /// + /// @param value Value to be checked. + /// @param max_value Maximum allowed value. + /// @param config_parameter_name A name of the configuration parameter + /// (used for logging purposes if value is out of range). + /// + /// @throw isc::OutOfRange if the value is negative or greater than + /// the maximum value. + void rangeCheck(const int64_t value, const uint64_t max_value, + const std::string& config_parameter_name) const; + + /// @brief reclaim-timer-wait-time + uint16_t reclaim_timer_wait_time_; + + /// @brief flush-reclaimed-timer-wait-time + uint16_t flush_reclaimed_timer_wait_time_; + + /// @brief hold-reclaimed-time + uint32_t hold_reclaimed_time_; + + /// @brief max-reclaim-leases + uint32_t max_reclaim_leases_; + + /// @brief max-reclaim-time + uint16_t max_reclaim_time_; + + /// @brief unwarned-reclaim-cycles. + uint16_t unwarned_reclaim_cycles_; + +}; + +/// @name Pointers to the @c CfgExpiration objects. +//@{ +/// @brief Pointer to the Non-const object. +typedef boost::shared_ptr CfgExpirationPtr; + +/// @brief Pointer to the const object. +typedef boost::shared_ptr ConstCfgExpirationPtr; + +//@} + +} // end of isc::dhcp namespace +} // end of isc namespace + +#endif // CFG_EXPIRATION_H diff --git a/src/lib/dhcpsrv/parsers/expiration_config_parser.cc b/src/lib/dhcpsrv/parsers/expiration_config_parser.cc new file mode 100644 index 0000000000..ed41f58151 --- /dev/null +++ b/src/lib/dhcpsrv/parsers/expiration_config_parser.cc @@ -0,0 +1,80 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include +#include + +using namespace isc::data; + +namespace isc { +namespace dhcp { + +ExpirationConfigParser::ExpirationConfigParser() + : DhcpConfigParser() { +} + +void +ExpirationConfigParser::build(ConstElementPtr expiration_config) { + CfgExpirationPtr cfg = CfgMgr::instance().getStagingCfg()->getCfgExpiration(); + + BOOST_FOREACH(ConfigPair config_element, expiration_config->mapValue()) { + + // Get parameter name and value. + std::string param_name = config_element.first; + ConstElementPtr param_value = config_element.second; + + try { + // Set configuration parameters. + if (param_name == "reclaim-timer-wait-time") { + cfg->setReclaimTimerWaitTime(param_value->intValue()); + + } else if (param_name == "flush-reclaimed-timer-wait-time") { + cfg->setFlushReclaimedTimerWaitTime(param_value->intValue()); + + } else if (param_name == "hold-reclaimed-time") { + cfg->setHoldReclaimedTime(param_value->intValue()); + + } else if (param_name == "max-reclaim-leases") { + cfg->setMaxReclaimLeases(param_value->intValue()); + + } else if (param_name == "max-reclaim-time") { + cfg->setMaxReclaimTime(param_value->intValue()); + + } else if (param_name == "unwarned-reclaim-cycles") { + cfg->setUnwarnedReclaimCycles(param_value->intValue()); + + } else { + isc_throw(DhcpConfigError, "unsupported parameter '" + << param_name << "'"); + } + + } catch (const std::exception& ex) { + // Append position of the configuration parameter to the error + // message. + isc_throw(DhcpConfigError, ex.what() << " (" + << param_value->getPosition() << ")"); + } + } +} + +void +ExpirationConfigParser::commit() { + // Nothing to do. +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/lib/dhcpsrv/parsers/expiration_config_parser.h b/src/lib/dhcpsrv/parsers/expiration_config_parser.h new file mode 100644 index 0000000000..a4f19e37a8 --- /dev/null +++ b/src/lib/dhcpsrv/parsers/expiration_config_parser.h @@ -0,0 +1,69 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef EXPIRATION_CONFIG_PARSER_H +#define EXPIRATION_CONFIG_PARSER_H + +#include + +namespace isc { +namespace dhcp { + + +/// @brief Parser for the configuration parameters pertaining to the +/// processing of expired leases. +/// +/// This parser iterates over parameters stored in the map and tries to +/// set the appropriate values in the @c CfgExpiration object of the +/// Configuration Manager. +/// +/// Currently supported parameters are: +/// - reclaim-timer-wait-time, +/// - flush-reclaimed-timer-wait-time, +/// - hold-reclaimed-time, +/// - max-reclaim-leases, +/// - max-reclaim-time, +/// - unwarned-reclaim-cycles. +/// +/// These parameters are optional and the default values are used for +/// those that aren't specified. +/// +/// The parser checks if the values of the specified parameters are within +/// the allowed ranges and throws exception if they are. Each parameter +/// has a corresponding maximum value defined in the @c CfgExpiration class. +/// None of them may be negative. +class ExpirationConfigParser : public DhcpConfigParser { +public: + + /// @brief Constructor + ExpirationConfigParser(); + + /// @brief Parses parameters in the JSON map, pertaining to the processing + /// of the expired leases. + /// + /// @param value pointer to the content of parsed values + /// + /// @throw DhcpConfigError if unknown parameter specified or the + /// parameter contains invalid value.. + virtual void build(isc::data::ConstElementPtr value); + + /// @brief Does nothing. + virtual void commit(); + +}; + +} // end of namespace isc::dhcp +} // end of namespace isc + +#endif // EXPIRATION_CONFIG_PARSER_H diff --git a/src/lib/dhcpsrv/srv_config.cc b/src/lib/dhcpsrv/srv_config.cc index bdf4ea3763..b614ff5d2d 100644 --- a/src/lib/dhcpsrv/srv_config.cc +++ b/src/lib/dhcpsrv/srv_config.cc @@ -31,6 +31,7 @@ SrvConfig::SrvConfig() cfg_option_def_(new CfgOptionDef()), cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()), cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()), cfg_rsoo_(new CfgRSOO()), + cfg_expiration_(new CfgExpiration()), decline_timer_(0) { } @@ -39,6 +40,7 @@ SrvConfig::SrvConfig(const uint32_t sequence) cfg_option_def_(new CfgOptionDef()), cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()), cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()), cfg_rsoo_(new CfgRSOO()), + cfg_expiration_(new CfgExpiration()), decline_timer_(0) { } diff --git a/src/lib/dhcpsrv/srv_config.h b/src/lib/dhcpsrv/srv_config.h index b1b9dbe88e..da387c9a56 100644 --- a/src/lib/dhcpsrv/srv_config.h +++ b/src/lib/dhcpsrv/srv_config.h @@ -15,6 +15,7 @@ #ifndef DHCPSRV_CONFIG_H #define DHCPSRV_CONFIG_H +#include #include #include #include @@ -259,6 +260,18 @@ public: return (cfg_rsoo_); } + /// @brief Returns pointer to the object holding configuration pertaining + /// to processing expired leases. + CfgExpirationPtr getCfgExpiration() { + return (cfg_expiration_); + } + + /// @brief Returns pointer to the const object holding configuration + /// pertaining to processing expired leases. + ConstCfgExpirationPtr getCfgExpiration() const { + return (cfg_expiration_); + } + //@} /// @brief Returns non-const reference to an array that stores @@ -441,6 +454,10 @@ private: /// RFC 6422 for the definition of the RSOO-enabled option. CfgRSOOPtr cfg_rsoo_; + /// @brief Pointer to the configuration pertaining to processing of + /// expired leases. + CfgExpirationPtr cfg_expiration_; + /// @brief Pointer to the control-socket information isc::data::ConstElementPtr control_socket_; diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am index e8a1438559..2267667e61 100644 --- a/src/lib/dhcpsrv/tests/Makefile.am +++ b/src/lib/dhcpsrv/tests/Makefile.am @@ -65,6 +65,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 += cfg_expiration_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_hosts_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_iface_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_mac_source_unittest.cc @@ -80,6 +81,7 @@ libdhcpsrv_unittests_SOURCES += d2_client_unittest.cc libdhcpsrv_unittests_SOURCES += d2_udp_unittest.cc libdhcpsrv_unittests_SOURCES += daemon_unittest.cc libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc +libdhcpsrv_unittests_SOURCES += expiration_config_parser_unittest.cc libdhcpsrv_unittests_SOURCES += host_mgr_unittest.cc libdhcpsrv_unittests_SOURCES += host_unittest.cc libdhcpsrv_unittests_SOURCES += host_reservation_parser_unittest.cc diff --git a/src/lib/dhcpsrv/tests/cfg_expiration_unittest.cc b/src/lib/dhcpsrv/tests/cfg_expiration_unittest.cc new file mode 100644 index 0000000000..5bb65afa06 --- /dev/null +++ b/src/lib/dhcpsrv/tests/cfg_expiration_unittest.cc @@ -0,0 +1,161 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include +#include +#include + +using namespace isc; +using namespace isc::dhcp; + +namespace { + +/// @brief Type definition of the @c CfgExpiration modified function. +typedef boost::function ModifierFun; +/// @brief Type definition of the @c CfgExpiration accessor function +/// returning uint16_t value. +typedef boost::function AccessorFunUint16; +/// @brief Type definition of the @c CfgExpiration accessor function +/// returning uint32_t value. +typedef boost::function AccessorFunUint32; + +/// @brief Tests the accessor and modifier function for a particular +/// configuration parameter held in @c CfgExpiration. +/// +/// This is a simple test which tries to set the given parameter to +/// different values: +/// - value greater than maximum allowed for this parameter - expects +/// the exception to be thrown, +/// - value lower than 0 - expects the exception to be thrown, +/// - value equal to the maximum allowed, +/// - value equal to maximum allowed minus 1. +/// +/// @param limit Maximum allowed value for the parameter. +/// @param modifier Pointer to the modifier function to be tested. +/// @param accessor Pointer to the accessor function to be tested. +/// @tparam ReturnType Type of the value returned by the accessor, +/// i.e. uint16_t or uint32_t. +template +void +testAccessModify(const int64_t limit, const ModifierFun& modifier, + const boost::function& accessor) { + CfgExpiration cfg; + + // Setting the value to maximum allowed + 1 should result in + // an exception. + ASSERT_THROW(modifier(&cfg, limit + 1), OutOfRange); + + // Setting to the negative value should result in an exception. + ASSERT_THROW(modifier(&cfg, -1), OutOfRange); + + // Setting the value to the maximum allowed should pass. + ASSERT_NO_THROW(modifier(&cfg, limit)); + EXPECT_EQ(limit, accessor(&cfg)); + + // Setting the value to the maximum allowed - 1 should pass. + ASSERT_NO_THROW(modifier(&cfg, limit - 1)); + EXPECT_EQ(limit - 1, accessor(&cfg)); + + // Setting the value to 0 should pass. + ASSERT_NO_THROW(modifier(&cfg, 0)); + EXPECT_EQ(0, accessor(&cfg)); +} + +/// @brief Tests that modifier and the accessor returning uint16_t value +/// work as expected. +/// +/// @param limit Maximum allowed value for the parameter. +/// @param modifier Pointer to the modifier function to be tested. +/// @param accessor Pointer to the accessor function to be tested. +void +testAccessModifyUint16(const int64_t limit, const ModifierFun& modifier, + const AccessorFunUint16& accessor) { + testAccessModify(limit, modifier, accessor); +} + +/// @brief Tests that modifier and the accessor returning uint32_t value +/// work as expected. +/// +/// @param limit Maximum allowed value for the parameter. +/// @param modifier Pointer to the modifier function to be tested. +/// @param accessor Pointer to the accessor function to be tested. +void +testAccessModifyUint32(const int64_t limit, const ModifierFun& modifier, + const AccessorFunUint32& accessor) { + testAccessModify(limit, modifier, accessor); +} + +/// Test the default values of CfgExpiration object. +TEST(CfgExpirationTest, defaults) { + CfgExpiration cfg; + EXPECT_EQ(CfgExpiration::DEFAULT_RECLAIM_TIMER_WAIT_TIME, + cfg.getReclaimTimerWaitTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_FLUSH_RECLAIMED_TIMER_WAIT_TIME, + cfg.getFlushReclaimedTimerWaitTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_HOLD_RECLAIMED_TIME, + cfg.getHoldReclaimedTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_LEASES, + cfg.getMaxReclaimLeases()); + EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_TIME, + cfg.getMaxReclaimTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_UNWARNED_RECLAIM_CYCLES, + cfg.getUnwarnedReclaimCycles()); +} + +// Test the {get,set}ReclaimTimerWaitTime. +TEST(CfgExpirationTest, getReclaimTimerWaitTime) { + testAccessModify(CfgExpiration::LIMIT_RECLAIM_TIMER_WAIT_TIME, + &CfgExpiration::setReclaimTimerWaitTime, + &CfgExpiration::getReclaimTimerWaitTime); +} + +// Test the {get,set}FlushReclaimedTimerWaitTime. +TEST(CfgExpirationTest, getFlushReclaimedTimerWaitTime) { + testAccessModifyUint16(CfgExpiration::LIMIT_FLUSH_RECLAIMED_TIMER_WAIT_TIME, + &CfgExpiration::setFlushReclaimedTimerWaitTime, + &CfgExpiration::getFlushReclaimedTimerWaitTime); +} + +// Test the {get,set}HoldReclaimedTime. +TEST(CfgExpirationTest, getHoldReclaimedTime) { + testAccessModifyUint32(CfgExpiration::LIMIT_HOLD_RECLAIMED_TIME, + &CfgExpiration::setHoldReclaimedTime, + &CfgExpiration::getHoldReclaimedTime); +} + +// Test the {get,set}MaxReclaimLeases. +TEST(CfgExpirationTest, getMaxReclaimLeases) { + testAccessModifyUint32(CfgExpiration::LIMIT_MAX_RECLAIM_LEASES, + &CfgExpiration::setMaxReclaimLeases, + &CfgExpiration::getMaxReclaimLeases); +} + +// Test the {get,set}MaxReclaimTime. +TEST(CfgExpirationTest, getMaxReclaimTime) { + testAccessModifyUint16(CfgExpiration::LIMIT_MAX_RECLAIM_TIME, + &CfgExpiration::setMaxReclaimTime, + &CfgExpiration::getMaxReclaimTime); +} + +// Test the {get,set}UnwarnedReclaimCycles. +TEST(CfgExpirationTest, getUnwarnedReclaimCycles) { + testAccessModifyUint16(CfgExpiration::LIMIT_UNWARNED_RECLAIM_CYCLES, + &CfgExpiration::setUnwarnedReclaimCycles, + &CfgExpiration::getUnwarnedReclaimCycles); +} + +} // end of anonymous namespace diff --git a/src/lib/dhcpsrv/tests/expiration_config_parser_unittest.cc b/src/lib/dhcpsrv/tests/expiration_config_parser_unittest.cc new file mode 100644 index 0000000000..82f870aa36 --- /dev/null +++ b/src/lib/dhcpsrv/tests/expiration_config_parser_unittest.cc @@ -0,0 +1,268 @@ +// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace isc::data; +using namespace isc::dhcp; + +namespace { + +/// @brief Test fixture class for @c ExpirationConfigParser. +class ExpirationConfigParserTest : public ::testing::Test { +protected: + + /// @brief Setup for each test. + /// + /// Clears the configuration in the @c CfgMgr. + virtual void SetUp(); + + /// @brief Cleans up after each test. + /// + /// Clears the configuration in the @c CfgMgr. + virtual void TearDown(); + + /// @brief Include a specified parameter in the configuration. + /// + /// If the specified parameter already exists, its value is replaced. + /// + /// @param param_name Parameter name. + /// @param value Parameter value. + void addParam(const std::string& param_name, const int64_t value); + + /// @brief Creates configuration and parses it with the parser under test. + /// + /// This method creates the JSON configuration form the parameters + /// specified using the @c ExpirationConfigParserTest::addParam method. + /// It then uses the parser to parse this configuration. Any exceptions + /// emitted by the parser are propagated to the caller (they aren't + /// caught by this method). + /// + /// @return Pointer to the parsed configuration. + CfgExpirationPtr renderConfig() const; + + /// @brief Tests that the out of range parameter value is not accepted. + /// + /// This test checks that the negative value and the value which is + /// greater than the maximum for the given parameter is not accepted. + /// + /// @param param Parameter name. + /// @param max_value Maximum value allowed for the parameter. + void testOutOfRange(const std::string& param, const uint64_t max_value); + +private: + + /// @brief Holds configuration parameters specified for a test. + std::map config_params_; + +}; + +void +ExpirationConfigParserTest::SetUp() { + CfgMgr::instance().clear(); +} + +void +ExpirationConfigParserTest::TearDown() { + CfgMgr::instance().clear(); +} + +void +ExpirationConfigParserTest::addParam(const std::string& param_name, + const int64_t value) { + config_params_[param_name] = value; +} + +CfgExpirationPtr +ExpirationConfigParserTest::renderConfig() const { + std::ostringstream s; + // Create JSON configuration from the parameters in the map. + s << "{"; + for (std::map::const_iterator param = + config_params_.begin(); param != config_params_.end(); + ++param) { + // Include comma sign if we're at the subsequent parameter. + if (std::distance(config_params_.begin(), param) > 0) { + s << ","; + } + s << "\"" << param->first << "\": " << param->second; + } + s << "}"; + + ElementPtr config_element = Element::fromJSON(s.str()); + + // Parse the configuration. This may emit exceptions. + ExpirationConfigParser parser; + parser.build(config_element); + + // No exception so return configuration. + return (CfgMgr::instance().getStagingCfg()->getCfgExpiration()); +} + +void +ExpirationConfigParserTest::testOutOfRange(const std::string& param, + const uint64_t max_value) { + // Remove any existing parameters which would influence the + // behavior of the test. + config_params_.clear(); + + // Negative value is not allowed. + addParam(param, -3); + EXPECT_THROW(renderConfig(), DhcpConfigError) + << "test for negative value of '" << param << "' failed"; + + // Value greater than maximum is not allowed. + addParam(param, max_value + 1); + EXPECT_THROW(renderConfig(), DhcpConfigError) + << "test for out of range value of '" << param << "' failed"; + + // Value in range should be accepted. + addParam(param, max_value); + EXPECT_NO_THROW(renderConfig()) + << "test for in range value of '" << param << "' failed"; + + // Value of 0 should be accepted. + addParam(param, 0); + EXPECT_NO_THROW(renderConfig()) + << "test for zero value of '" << param << "' failed"; +} + + +// This test verifies that all parameters for the expiration may be configured. +TEST_F(ExpirationConfigParserTest, allParameters) { + // Create configuration which overrides default values of all parameters. + addParam("reclaim-timer-wait-time", 20); + addParam("flush-reclaimed-timer-wait-time", 35); + addParam("hold-reclaimed-time", 1800); + addParam("max-reclaim-leases", 50); + addParam("max-reclaim-time", 100); + addParam("unwarned-reclaim-cycles", 10); + + CfgExpirationPtr cfg; + ASSERT_NO_THROW(cfg = renderConfig()); + EXPECT_EQ(20, cfg->getReclaimTimerWaitTime()); + EXPECT_EQ(35, cfg->getFlushReclaimedTimerWaitTime()); + EXPECT_EQ(1800, cfg->getHoldReclaimedTime()); + EXPECT_EQ(50, cfg->getMaxReclaimLeases()); + EXPECT_EQ(100, cfg->getMaxReclaimTime()); + EXPECT_EQ(10, cfg->getUnwarnedReclaimCycles()); +} + +// This test verifies that default values are used if no parameter is +// specified. +TEST_F(ExpirationConfigParserTest, noParameters) { + CfgExpirationPtr cfg; + ASSERT_NO_THROW(cfg = renderConfig()); + EXPECT_EQ(CfgExpiration::DEFAULT_RECLAIM_TIMER_WAIT_TIME, + cfg->getReclaimTimerWaitTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_FLUSH_RECLAIMED_TIMER_WAIT_TIME, + cfg->getFlushReclaimedTimerWaitTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_HOLD_RECLAIMED_TIME, + cfg->getHoldReclaimedTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_LEASES, + cfg->getMaxReclaimLeases()); + EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_TIME, + cfg->getMaxReclaimTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_UNWARNED_RECLAIM_CYCLES, + cfg->getUnwarnedReclaimCycles()); +} + +// This test verifies that a subset of parameters may be specified and +// that default values are used for those that aren't specified. +TEST_F(ExpirationConfigParserTest, someParameters) { + addParam("reclaim-timer-wait-time", 15); + addParam("hold-reclaimed-time", 2000); + addParam("max-reclaim-time", 200); + + CfgExpirationPtr cfg; + ASSERT_NO_THROW(cfg = renderConfig()); + EXPECT_EQ(15, cfg->getReclaimTimerWaitTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_FLUSH_RECLAIMED_TIMER_WAIT_TIME, + cfg->getFlushReclaimedTimerWaitTime()); + EXPECT_EQ(2000, cfg->getHoldReclaimedTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_LEASES, + cfg->getMaxReclaimLeases()); + EXPECT_EQ(200, cfg->getMaxReclaimTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_UNWARNED_RECLAIM_CYCLES, + cfg->getUnwarnedReclaimCycles()); +} + +// This test verifies that another subset of parameters may be specified +// and that default values are used for those that aren't specified. +TEST_F(ExpirationConfigParserTest, otherParameters) { + addParam("flush-reclaimed-timer-wait-time", 50); + addParam("max-reclaim-leases", 60); + addParam("unwarned-reclaim-cycles", 20); + + CfgExpirationPtr cfg; + ASSERT_NO_THROW(cfg = renderConfig()); + + EXPECT_EQ(CfgExpiration::DEFAULT_RECLAIM_TIMER_WAIT_TIME, + cfg->getReclaimTimerWaitTime()); + EXPECT_EQ(50, cfg->getFlushReclaimedTimerWaitTime()); + EXPECT_EQ(CfgExpiration::DEFAULT_HOLD_RECLAIMED_TIME, + cfg->getHoldReclaimedTime()); + EXPECT_EQ(60, cfg->getMaxReclaimLeases()); + EXPECT_EQ(CfgExpiration::DEFAULT_MAX_RECLAIM_TIME, + cfg->getMaxReclaimTime()); + EXPECT_EQ(20, cfg->getUnwarnedReclaimCycles()); +} + +// This test verifies that the exception is thrown if unsupported +// parameter is specified. +TEST_F(ExpirationConfigParserTest, invalidParameter) { + addParam("reclaim-timer-wait-time", 20); + addParam("invalid-parameter", 20); + + EXPECT_THROW(renderConfig(), DhcpConfigError); +} + +// This test verifies that negative parameter values are not allowed. +TEST_F(ExpirationConfigParserTest, outOfRangeValues) { + testOutOfRange("reclaim-timer-wait-time", + CfgExpiration::LIMIT_RECLAIM_TIMER_WAIT_TIME); + testOutOfRange("flush-reclaimed-timer-wait-time", + CfgExpiration::LIMIT_FLUSH_RECLAIMED_TIMER_WAIT_TIME); + testOutOfRange("hold-reclaimed-time", + CfgExpiration::LIMIT_HOLD_RECLAIMED_TIME); + testOutOfRange("max-reclaim-leases", + CfgExpiration::LIMIT_MAX_RECLAIM_LEASES); + testOutOfRange("max-reclaim-time", + CfgExpiration::LIMIT_MAX_RECLAIM_TIME); + testOutOfRange("unwarned-reclaim-cycles", + CfgExpiration::LIMIT_UNWARNED_RECLAIM_CYCLES); +} + +// This test verifies that it is not allowed to specify a value as +// a text. +TEST_F(ExpirationConfigParserTest, notNumberValue) { + // The value should not be in quotes. + std::string config = "{ \"reclaim-timer-wait-time\": \"10\" }"; + ElementPtr config_element = Element::fromJSON(config); + + // Parse the configuration. It should throw exception. + ExpirationConfigParser parser; + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + +} // end of anonymous namespace