diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 21:11:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 21:11:59 +0000 |
commit | 3cd01b932e1c85394272ae64fae67ebeda92fb00 (patch) | |
tree | c5a3115d710afc1879ddea5349362a2bc651733c /test-dnsdistbackend_cc.cc | |
parent | Initial commit. (diff) | |
download | dnsdist-3cd01b932e1c85394272ae64fae67ebeda92fb00.tar.xz dnsdist-3cd01b932e1c85394272ae64fae67ebeda92fb00.zip |
Adding upstream version 1.8.3.upstream/1.8.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | test-dnsdistbackend_cc.cc | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/test-dnsdistbackend_cc.cc b/test-dnsdistbackend_cc.cc new file mode 100644 index 0000000..983f912 --- /dev/null +++ b/test-dnsdistbackend_cc.cc @@ -0,0 +1,291 @@ + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#include <boost/test/unit_test.hpp> + +#include "dnsdist.hh" + +BOOST_AUTO_TEST_SUITE(dnsdistbackend_cc) + +BOOST_AUTO_TEST_CASE(test_Basic) +{ + DownstreamState::Config config; + DownstreamState ds(std::move(config), nullptr, false); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + + ds.setUp(); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Up); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "UP"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); + + ds.setDown(); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Down); + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "DOWN"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); + + ds.setAuto(); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + + ds.submitHealthCheckResult(true, true); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); +} + +BOOST_AUTO_TEST_CASE(test_MaxCheckFailures) +{ + const size_t maxCheckFailures = 5; + DownstreamState::Config config; + config.maxCheckFailures = maxCheckFailures; + /* prevents a re-connection */ + config.remote = ComboAddress("0.0.0.0"); + + DownstreamState ds(std::move(config), nullptr, false); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + ds.setUpStatus(true); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + + for (size_t idx = 0; idx < maxCheckFailures - 1; idx++) { + ds.submitHealthCheckResult(false, false); + } + + /* four failed checks is not enough */ + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + + /* but five is */ + ds.submitHealthCheckResult(false, false); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + + /* only one successful check is needed to go back up */ + ds.submitHealthCheckResult(false, true); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); +} + +BOOST_AUTO_TEST_CASE(test_Rise) +{ + const size_t minRise = 5; + DownstreamState::Config config; + config.minRiseSuccesses = minRise; + /* prevents a re-connection */ + config.remote = ComboAddress("0.0.0.0"); + + DownstreamState ds(std::move(config), nullptr, false); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + + for (size_t idx = 0; idx < minRise - 1; idx++) { + ds.submitHealthCheckResult(false, true); + } + + /* four successful checks is not enough */ + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + + /* but five is */ + ds.submitHealthCheckResult(false, true); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + + /* only one failed check is needed to go back down */ + ds.submitHealthCheckResult(false, false); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Auto); + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); +} + +BOOST_AUTO_TEST_CASE(test_Lazy) +{ + DownstreamState::Config config; + config.minRiseSuccesses = 5; + config.maxCheckFailures = 3; + config.d_lazyHealthCheckMinSampleCount = 11; + config.d_lazyHealthCheckThreshold = 20; + config.d_lazyHealthCheckUseExponentialBackOff = false; + config.availability = DownstreamState::Availability::Lazy; + /* prevents a re-connection */ + config.remote = ComboAddress("0.0.0.0"); + + DownstreamState ds(std::move(config), nullptr, false); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Lazy); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); + + /* submit a few results, first successful ones */ + for (size_t idx = 0; idx < 5; idx++) { + ds.reportResponse(RCode::NoError); + } + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); + /* then failed ones */ + for (size_t idx = 0; idx < 5; idx++) { + ds.reportTimeoutOrError(); + } + + /* the threshold should be reached (50% > 20%) but we do not have enough sample yet + (10 < config.d_lazyHealthCheckMinSampleCount) */ + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); + + /* reporting one valid answer put us above the minimum number of samples, + and we are still above the threshold */ + ds.reportResponse(RCode::NoError); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + + /* we should be in Potential Failure mode now, and thus always returning true */ + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + + /* even if we fill the whole circular buffer with valid answers */ + for (size_t idx = 0; idx < config.d_lazyHealthCheckSampleSize; idx++) { + ds.reportResponse(RCode::NoError); + } + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + + /* if we submit at least one valid health-check, we go back to Healthy */ + ds.submitHealthCheckResult(false, true); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); + + /* now let's reach the threshold again, this time just barely */ + for (size_t idx = 0; idx < config.d_lazyHealthCheckThreshold; idx++) { + ds.reportTimeoutOrError(); + } + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + + /* we need maxCheckFailures failed health-checks to go down */ + BOOST_REQUIRE(config.maxCheckFailures >= 1); + for (size_t idx = 0; idx < static_cast<size_t>(config.maxCheckFailures - 1); idx++) { + ds.submitHealthCheckResult(false, false); + } + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + time_t failedCheckTime = time(nullptr); + ds.submitHealthCheckResult(false, false); + + /* now we are in Failed state */ + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + BOOST_CHECK(ds.getNextLazyHealthCheck() == (failedCheckTime + config.d_lazyHealthCheckFailedInterval)); + + /* let fill the buffer with successes, it does not matter */ + for (size_t idx = 0; idx < config.d_lazyHealthCheckSampleSize; idx++) { + ds.reportResponse(RCode::NoError); + } + + /* we need minRiseSuccesses successful health-checks to go up */ + BOOST_REQUIRE(config.minRiseSuccesses >= 1); + for (size_t idx = 0; idx < static_cast<size_t>(config.minRiseSuccesses - 1); idx++) { + ds.submitHealthCheckResult(false, true); + } + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + + ds.submitHealthCheckResult(false, true); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); +} + +BOOST_AUTO_TEST_CASE(test_LazyExponentialBackOff) +{ + DownstreamState::Config config; + config.minRiseSuccesses = 5; + config.maxCheckFailures = 3; + config.d_lazyHealthCheckMinSampleCount = 11; + config.d_lazyHealthCheckThreshold = 20; + config.d_lazyHealthCheckUseExponentialBackOff = true; + config.d_lazyHealthCheckMaxBackOff = 600; + config.d_lazyHealthCheckFailedInterval = 15; + config.availability = DownstreamState::Availability::Lazy; + /* prevents a re-connection */ + config.remote = ComboAddress("0.0.0.0"); + + DownstreamState ds(std::move(config), nullptr, false); + BOOST_CHECK(ds.d_config.availability == DownstreamState::Availability::Lazy); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); + + /* submit a few failed results */ + for (size_t idx = 0; idx < config.d_lazyHealthCheckMinSampleCount; idx++) { + ds.reportTimeoutOrError(); + } + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + + /* we should be in Potential Failure mode now, and thus always returning true */ + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + + /* we need maxCheckFailures failed health-checks to go down */ + BOOST_REQUIRE(config.maxCheckFailures >= 1); + for (size_t idx = 0; idx < static_cast<size_t>(config.maxCheckFailures - 1); idx++) { + ds.submitHealthCheckResult(false, false); + } + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), true); + time_t currentTime = time(nullptr); + ds.submitHealthCheckResult(false, false); + + /* now we are in Failed state */ + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(currentTime), false); + /* and the wait time between two checks will double every time a failure occurs */ + BOOST_CHECK_EQUAL(ds.getNextLazyHealthCheck(), (currentTime + (config.d_lazyHealthCheckFailedInterval * std::pow(2U, ds.currentCheckFailures)))); + BOOST_CHECK_EQUAL(ds.currentCheckFailures, 0U); + + /* so after 5 failures */ + const size_t nbFailures = 5; + for (size_t idx = 0; idx < nbFailures; idx++) { + currentTime = ds.getNextLazyHealthCheck(); + BOOST_CHECK(ds.healthCheckRequired(currentTime)); + ds.submitHealthCheckResult(false, false); + } + BOOST_CHECK_EQUAL(ds.currentCheckFailures, nbFailures); + BOOST_CHECK_EQUAL(ds.getNextLazyHealthCheck(), (currentTime + (config.d_lazyHealthCheckFailedInterval * std::pow(2U, ds.currentCheckFailures)))); + + /* we need minRiseSuccesses successful health-checks to go up */ + BOOST_REQUIRE(config.minRiseSuccesses >= 1); + for (size_t idx = 0; idx < static_cast<size_t>(config.minRiseSuccesses - 1); idx++) { + ds.submitHealthCheckResult(false, true); + } + BOOST_CHECK_EQUAL(ds.isUp(), false); + BOOST_CHECK_EQUAL(ds.getStatus(), "down"); + + ds.submitHealthCheckResult(false, true); + BOOST_CHECK_EQUAL(ds.isUp(), true); + BOOST_CHECK_EQUAL(ds.getStatus(), "up"); + BOOST_CHECK_EQUAL(ds.healthCheckRequired(), false); +} + +BOOST_AUTO_TEST_SUITE_END() |