summaryrefslogtreecommitdiffstats
path: root/test-dnsdistbackend_cc.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:11:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:11:59 +0000
commit3cd01b932e1c85394272ae64fae67ebeda92fb00 (patch)
treec5a3115d710afc1879ddea5349362a2bc651733c /test-dnsdistbackend_cc.cc
parentInitial commit. (diff)
downloaddnsdist-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.cc291
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()