From 9fe0906d81138d6ffede0e800fe0421a619b3ec3 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Mon, 7 Oct 2019 01:51:06 +0200 Subject: [PATCH] [904-add-ability-to-force-a-cb-update-remotely] Added server-update command --- doc/sphinx/api-files.txt | 1 + doc/sphinx/api/server-update.json | 30 ++++++++++ doc/sphinx/arm/config-backend.rst | 2 - doc/sphinx/arm/ctrl-channel.rst | 17 ++++++ doc/sphinx/arm/dhcp4-srv.rst | 4 ++ src/bin/dhcp4/ctrl_dhcp4_srv.cc | 41 +++++++++++++- src/bin/dhcp4/ctrl_dhcp4_srv.h | 13 +++++ .../dhcp4/tests/ctrl_dhcp4_srv_unittest.cc | 15 +++++ .../dhcp4/tests/kea_controller_unittest.cc | 56 ++++++++++++++++++- src/bin/dhcp6/ctrl_dhcp6_srv.cc | 35 ++++++++++++ src/bin/dhcp6/ctrl_dhcp6_srv.h | 13 +++++ .../dhcp6/tests/ctrl_dhcp6_srv_unittest.cc | 15 +++++ .../dhcp6/tests/kea_controller_unittest.cc | 56 ++++++++++++++++++- 13 files changed, 289 insertions(+), 9 deletions(-) create mode 100644 doc/sphinx/api/server-update.json diff --git a/doc/sphinx/api-files.txt b/doc/sphinx/api-files.txt index 248bea7403..51346dd3e7 100644 --- a/doc/sphinx/api-files.txt +++ b/doc/sphinx/api-files.txt @@ -129,6 +129,7 @@ api/reservation-get-all.json api/reservation-get-by-hostname.json api/reservation-get-page.json api/server-tag-get.json +api/server-update.json api/shutdown.json api/statistic-get-all.json api/statistic-get.json diff --git a/doc/sphinx/api/server-update.json b/doc/sphinx/api/server-update.json new file mode 100644 index 0000000000..a0eeb42b5f --- /dev/null +++ b/doc/sphinx/api/server-update.json @@ -0,0 +1,30 @@ +{ + "avail": "1.7.1", + "brief": [ + "This command forces an immediate update of the server using Config Backends.", + "This command does not take any parameters." + ], + "cmd-syntax": [ + "{", + " \"command\": \"server-update\"", + "}" + ], + "description": "See ", + "name": "server-update", + "resp-comment": [ + "When no Config Backends are configured this command returns empty (3); ", + "If an error occurs error (1) is returned with the error details; ", + "otherwise success (0) is returned." + ], + "resp-syntax": [ + "{", + " \"result\": 0,", + " \"text\": \"Server update successful.\"", + "}" + ], + + "support": [ + "kea-dhcp4", + "kea-dhcp6" + ] +} diff --git a/doc/sphinx/arm/config-backend.rst b/doc/sphinx/arm/config-backend.rst index f88c107487..71e5bd7acb 100644 --- a/doc/sphinx/arm/config-backend.rst +++ b/doc/sphinx/arm/config-backend.rst @@ -159,8 +159,6 @@ the list of supported configuration parameters, can be found in .. _cb-sharing: -.. _command-server-tag-get: - Configuration Sharing and Server Tags ------------------------------------- diff --git a/doc/sphinx/arm/ctrl-channel.rst b/doc/sphinx/arm/ctrl-channel.rst index 3650964beb..3b839f51f5 100644 --- a/doc/sphinx/arm/ctrl-channel.rst +++ b/doc/sphinx/arm/ctrl-channel.rst @@ -538,6 +538,23 @@ The ``dhcp-enable`` command globally enables the DHCP service. "command": "dhcp-enable" } +.. _command-server-tag-get: + +The server-tag-get Command: +--------------------------- + +The ``server-tag-get`` command returns the configured server tag of +the DHCPv4 or DHCPv6 server (:ref:`cb-sharing` explains the server tag concept) + +.. _command-server-update: + +The server-update Command: +-------------------------- + +The ``server-update`` command triggers the polling of Config Backends +(which should be configured for this command to do something) +explained in :ref:`dhcp4-cb-json`. + .. _command-version-get: The version-get Command diff --git a/doc/sphinx/arm/dhcp4-srv.rst b/doc/sphinx/arm/dhcp4-srv.rst index 3e6d8647df..cb7613271b 100644 --- a/doc/sphinx/arm/dhcp4-srv.rst +++ b/doc/sphinx/arm/dhcp4-srv.rst @@ -5891,6 +5891,10 @@ server's performance, because the server needs to make at least one query to the database to discover the pending configuration updates. The default value of the ``config-fetch-wait-time`` is 30 seconds. +To trigger an immediate polling the ``server-update`` command is +available for both DHCPv4 and DHCPv6 servers since the 1.7.1 Kea +release. + Finally, in the configuration example above, two hooks libraries are loaded. The first, ``libdhcp_mysql_cb.so``, is the implementation of the Configuration Backend for MySQL. It must be always present when the diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc index 4c8d33ab80..5c24fe64d8 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc @@ -544,6 +544,34 @@ ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&, return (createAnswer(CONTROL_RESULT_SUCCESS, response)); } +ConstElementPtr +ControlledDhcpv4Srv::commandServerUpdateHandler(const std::string&, + ConstElementPtr) { + auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo(); + if (!ctl_info) { + return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend.")); + } + + // Reschedule the periodic CB fetch. + if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) { + TimerMgr::instance()->cancel("Dhcp4CBFetchTimer"); + TimerMgr::instance()->setup("Dhcp4CBFetchTimer"); + } + + // Code from cbFetchUpdates. + try { + auto srv_cfg = CfgMgr::instance().getStagingCfg(); + auto mode = CBControlDHCPv4::FetchMode::FETCH_UPDATE; + server_->getCBControl()->databaseConfigFetch(srv_cfg, mode); + } catch (const std::exception& ex) { + LOG_ERROR(dhcp4_logger, DHCP4_CB_FETCH_UPDATES_FAIL) + .arg(ex.what()); + return (createAnswer(CONTROL_RESULT_ERROR, + "Server update failed: " + string(ex.what()))); + } + return (createAnswer(CONTROL_RESULT_SUCCESS, "Server update successful.")); +} + ConstElementPtr ControlledDhcpv4Srv::processCommand(const string& command, ConstElementPtr args) { @@ -601,6 +629,9 @@ ControlledDhcpv4Srv::processCommand(const string& command, } else if (command == "server-tag-get") { return (srv->commandServerTagGetHandler(command, args)); + } else if (command == "server-update") { + return (srv->commandServerUpdateHandler(command, args)); + } ConstElementPtr answer = isc::config::createAnswer(1, "Unrecognized command:" + command); @@ -838,6 +869,9 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_P CommandMgr::instance().registerCommand("server-tag-get", boost::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, _1, _2)); + CommandMgr::instance().registerCommand("server-update", + boost::bind(&ControlledDhcpv4Srv::commandServerUpdateHandler, this, _1, _2)); + CommandMgr::instance().registerCommand("shutdown", boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2)); @@ -898,14 +932,15 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() { CommandMgr::instance().deregisterCommand("build-report"); CommandMgr::instance().deregisterCommand("config-get"); CommandMgr::instance().deregisterCommand("config-reload"); + CommandMgr::instance().deregisterCommand("config-set"); CommandMgr::instance().deregisterCommand("config-test"); CommandMgr::instance().deregisterCommand("config-write"); - CommandMgr::instance().deregisterCommand("leases-reclaim"); - CommandMgr::instance().deregisterCommand("libreload"); - CommandMgr::instance().deregisterCommand("config-set"); CommandMgr::instance().deregisterCommand("dhcp-disable"); CommandMgr::instance().deregisterCommand("dhcp-enable"); + CommandMgr::instance().deregisterCommand("leases-reclaim"); + CommandMgr::instance().deregisterCommand("libreload"); CommandMgr::instance().deregisterCommand("server-tag-get"); + CommandMgr::instance().deregisterCommand("server-update"); CommandMgr::instance().deregisterCommand("shutdown"); CommandMgr::instance().deregisterCommand("statistic-get"); CommandMgr::instance().deregisterCommand("statistic-get-all"); diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h index ae8095c2a7..39a2feed05 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.h +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h @@ -304,6 +304,19 @@ private: commandServerTagGetHandler(const std::string& command, isc::data::ConstElementPtr args); + /// @brief handler for server-update command + /// + /// This method handles the server-update command, which updates + /// the server configuration from the Config Backends immediately. + /// + /// @param command (parameter ignored) + /// @param args (ignored) + /// + /// @return status of the command/ + isc::data::ConstElementPtr + commandServerUpdateHandler(const std::string& command, + isc::data::ConstElementPtr args); + /// @brief Reclaims expired IPv4 leases and reschedules timer. /// /// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases4. diff --git a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc index 7aa0f28a3f..1452017f94 100644 --- a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc @@ -485,6 +485,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, commandsRegistration) { EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos); EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos); EXPECT_TRUE(command_list.find("\"server-tag-get\"") != string::npos); + EXPECT_TRUE(command_list.find("\"server-update\"") != string::npos); EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos); EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos); EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos); @@ -1025,6 +1026,19 @@ TEST_F(CtrlChannelDhcpv4SrvTest, serverTagGet) { expected = "{ \"arguments\": { \"server-tag\": \"foobar\" }, \"result\": 0 }"; } +// This test verifies that the DHCP server handles server-update command +TEST_F(CtrlChannelDhcpv4SrvTest, serverUpdate) { + createUnixChannelServer(); + + std::string response; + std::string expected; + + // Send the server-update command. Note there is no configured backed. + sendUnixCommand("{ \"command\": \"server-update\" }", response); + expected = "{ \"result\": 3, \"text\": \"No config backend.\" }"; + EXPECT_EQ(expected, response); +} + // This test verifies that the DHCP server immediately reclaims expired // leases on leases-reclaim command TEST_F(CtrlChannelDhcpv4SrvTest, controlLeasesReclaim) { @@ -1145,6 +1159,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, listCommands) { checkListCommands(rsp, "libreload"); checkListCommands(rsp, "version-get"); checkListCommands(rsp, "server-tag-get"); + checkListCommands(rsp, "server-update"); checkListCommands(rsp, "shutdown"); checkListCommands(rsp, "statistic-get"); checkListCommands(rsp, "statistic-get-all"); diff --git a/src/bin/dhcp4/tests/kea_controller_unittest.cc b/src/bin/dhcp4/tests/kea_controller_unittest.cc index 724af35212..bbd0eaf23a 100644 --- a/src/bin/dhcp4/tests/kea_controller_unittest.cc +++ b/src/bin/dhcp4/tests/kea_controller_unittest.cc @@ -217,7 +217,8 @@ public: /// @brief This test verifies that the timer used to fetch the configuration /// updates from the database works as expected. void testConfigBackendTimer(const int config_wait_fetch_time, - const bool throw_during_fetch = false) { + const bool throw_during_fetch = false, + const bool call_command = false) { std::ostringstream config; config << "{ \"Dhcp4\": {" @@ -261,7 +262,40 @@ public: EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls()); - if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) { + if (call_command) { + // The case where there is no backend is tested in the + // controlled server tests so we have only to verify + // that the command calls the database config fetch. + + // Count the startup. + EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 1); + + ConstElementPtr result = + ControlledDhcpv4Srv::processCommand("server-update", + ConstElementPtr()); + EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 2); + std::string expected; + + if (throw_during_fetch) { + expected = "{ \"result\": 1, \"text\": "; + expected += "\"Server update failed: "; + expected += "testing if exceptions are corectly handled\" }"; + } else { + expected = "{ \"result\": 0, \"text\": "; + expected += "\"Server update successful.\" }"; + } + EXPECT_EQ(expected, result->str()); + + // No good way to check the rescheduling... + ASSERT_NO_THROW(runTimersWithTimeout(srv->getIOService(), 15)); + + if (config_wait_fetch_time > 0) { + EXPECT_GE(cb_control->getDatabaseConfigFetchCalls(), 12); + } else { + EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 2); + } + + } else if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) { // If we're configured to run the timer, we expect that it was // invoked at least 3 times. This is sufficient to verify that // the timer was scheduled and that the timer continued to run @@ -857,6 +891,24 @@ TEST_F(JSONFileBackendTest, configBackendTimerWithThrow) { testConfigBackendTimer(1, true); } +// This test verifies that the server will be updated by the server-update +// command. +TEST_F(JSONFileBackendTest, configBackendCommand) { + testConfigBackendTimer(0, false, true); +} + +// This test verifies that the server will be updated by the server-update +// command even when updates fail. +TEST_F(JSONFileBackendTest, configBackendCommandWithThrow) { + testConfigBackendTimer(0, true, true); +} + +// This test verifies that the server will be updated by the server-update +// command and the timer rescheduled. +TEST_F(JSONFileBackendTest, configBackendCommandWithTimer) { + testConfigBackendTimer(1, false, true); +} + // Starting tests which require MySQL backend availability. Those tests // will not be executed if Kea has been compiled without the // --with-mysql. diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index 755619e158..c84e71ba6d 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -544,6 +544,34 @@ ControlledDhcpv6Srv::commandServerTagGetHandler(const std::string&, return (createAnswer(CONTROL_RESULT_SUCCESS, response)); } +ConstElementPtr +ControlledDhcpv6Srv::commandServerUpdateHandler(const std::string&, + ConstElementPtr) { + auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo(); + if (!ctl_info) { + return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend.")); + } + + // Reschedule the periodic CB fetch. + if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) { + TimerMgr::instance()->cancel("Dhcp6CBFetchTimer"); + TimerMgr::instance()->setup("Dhcp6CBFetchTimer"); + } + + // Code from cbFetchUpdates. + try { + auto srv_cfg = CfgMgr::instance().getStagingCfg(); + auto mode = CBControlDHCPv6::FetchMode::FETCH_UPDATE; + server_->getCBControl()->databaseConfigFetch(srv_cfg, mode); + } catch (const std::exception& ex) { + LOG_ERROR(dhcp6_logger, DHCP6_CB_FETCH_UPDATES_FAIL) + .arg(ex.what()); + return (createAnswer(CONTROL_RESULT_ERROR, + "Server update failed: " + string(ex.what()))); + } + return (createAnswer(CONTROL_RESULT_SUCCESS, "Server update successful.")); +} + isc::data::ConstElementPtr ControlledDhcpv6Srv::processCommand(const std::string& command, isc::data::ConstElementPtr args) { @@ -601,6 +629,9 @@ ControlledDhcpv6Srv::processCommand(const std::string& command, } else if (command == "server-tag-get") { return (srv->commandServerTagGetHandler(command, args)); + } else if (command == "server-update") { + return (srv->commandServerUpdateHandler(command, args)); + } return (isc::config::createAnswer(1, "Unrecognized command:" @@ -851,6 +882,9 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port, CommandMgr::instance().registerCommand("server-tag-get", boost::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, _1, _2)); + CommandMgr::instance().registerCommand("server-update", + boost::bind(&ControlledDhcpv6Srv::commandServerUpdateHandler, this, _1, _2)); + CommandMgr::instance().registerCommand("libreload", boost::bind(&ControlledDhcpv6Srv::commandLibReloadHandler, this, _1, _2)); @@ -925,6 +959,7 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() { CommandMgr::instance().deregisterCommand("leases-reclaim"); CommandMgr::instance().deregisterCommand("libreload"); CommandMgr::instance().deregisterCommand("server-tag-get"); + CommandMgr::instance().deregisterCommand("server-update"); CommandMgr::instance().deregisterCommand("shutdown"); CommandMgr::instance().deregisterCommand("statistic-get"); CommandMgr::instance().deregisterCommand("statistic-get-all"); diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.h b/src/bin/dhcp6/ctrl_dhcp6_srv.h index 83a2d29ab4..0be001c30e 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.h +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.h @@ -303,6 +303,19 @@ private: commandServerTagGetHandler(const std::string& command, isc::data::ConstElementPtr args); + /// @brief handler for server-update command + /// + /// This method handles the server-update command, which updates + /// the server configuration from the Config Backends immediately. + /// + /// @param command (parameter ignored) + /// @param args (ignored) + /// + /// @return status of the command/ + isc::data::ConstElementPtr + commandServerUpdateHandler(const std::string& command, + isc::data::ConstElementPtr args); + /// @brief Reclaims expired IPv6 leases and reschedules timer. /// /// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases6. diff --git a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc index 41de6ff27c..06fcbba27a 100644 --- a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc @@ -504,6 +504,7 @@ TEST_F(CtrlDhcpv6SrvTest, commandsRegistration) { EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos); EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos); EXPECT_TRUE(command_list.find("\"server-tag-get\"") != string::npos); + EXPECT_TRUE(command_list.find("\"server-update\"") != string::npos); EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos); EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos); EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos); @@ -937,6 +938,19 @@ TEST_F(CtrlChannelDhcpv6SrvTest, serverTagGet) { expected = "{ \"arguments\": { \"server-tag\": \"foobar\" }, \"result\": 0 }"; } +// This test verifies that the DHCP server handles server-update command +TEST_F(CtrlChannelDhcpv6SrvTest, serverUpdate) { + createUnixChannelServer(); + + std::string response; + std::string expected; + + // Send the server-update command. Note there is no configured backed. + sendUnixCommand("{ \"command\": \"server-update\" }", response); + expected = "{ \"result\": 3, \"text\": \"No config backend.\" }"; + EXPECT_EQ(expected, response); +} + // This test verifies that the DHCP server immediately reclaims expired // leases on leases-reclaim command TEST_F(CtrlChannelDhcpv6SrvTest, controlLeasesReclaim) { @@ -1176,6 +1190,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, listCommands) { checkListCommands(rsp, "libreload"); checkListCommands(rsp, "version-get"); checkListCommands(rsp, "server-tag-get"); + checkListCommands(rsp, "server-update"); checkListCommands(rsp, "shutdown"); checkListCommands(rsp, "statistic-get"); checkListCommands(rsp, "statistic-get-all"); diff --git a/src/bin/dhcp6/tests/kea_controller_unittest.cc b/src/bin/dhcp6/tests/kea_controller_unittest.cc index b9d6749460..6eebbe68ab 100644 --- a/src/bin/dhcp6/tests/kea_controller_unittest.cc +++ b/src/bin/dhcp6/tests/kea_controller_unittest.cc @@ -203,7 +203,8 @@ public: /// @brief This test verifies that the timer used to fetch the configuration /// updates from the database works as expected. void testConfigBackendTimer(const int config_wait_fetch_time, - const bool throw_during_fetch = false) { + const bool throw_during_fetch = false, + const bool call_command = false) { std::ostringstream config; config << "{ \"Dhcp6\": {" @@ -247,7 +248,40 @@ public: EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls()); - if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) { + if (call_command) { + // The case where there is no backend is tested in the + // controlled server tests so we have only to verify + // that the command calls the database config fetch. + + // Count the startup. + EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 1); + + ConstElementPtr result = + ControlledDhcpv6Srv::processCommand("server-update", + ConstElementPtr()); + EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 2); + std::string expected; + + if (throw_during_fetch) { + expected = "{ \"result\": 1, \"text\": "; + expected += "\"Server update failed: "; + expected += "testing if exceptions are corectly handled\" }"; + } else { + expected = "{ \"result\": 0, \"text\": "; + expected += "\"Server update successful.\" }"; + } + EXPECT_EQ(expected, result->str()); + + // No good way to check the rescheduling... + ASSERT_NO_THROW(runTimersWithTimeout(srv->getIOService(), 15)); + + if (config_wait_fetch_time > 0) { + EXPECT_GE(cb_control->getDatabaseConfigFetchCalls(), 12); + } else { + EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 2); + } + + } else if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) { // If we're configured to run the timer, we expect that it was // invoked at least 3 times. This is sufficient to verify that // the timer was scheduled and that the timer continued to run @@ -844,6 +878,24 @@ TEST_F(JSONFileBackendTest, configBackendTimerWithThrow) { testConfigBackendTimer(1, true); } +// This test verifies that the server will be updated by the server-update +// command. +TEST_F(JSONFileBackendTest, configBackendCommand) { + testConfigBackendTimer(0, false, true); +} + +// This test verifies that the server will be updated by the server-update +// command even when updates fail. +TEST_F(JSONFileBackendTest, configBackendCommandWithThrow) { + testConfigBackendTimer(0, true, true); +} + +// This test verifies that the server will be updated by the server-update +// command and the timer rescheduled. +TEST_F(JSONFileBackendTest, configBackendCommandWithTimer) { + testConfigBackendTimer(1, false, true); +} + // Starting tests which require MySQL backend availability. Those tests // will not be executed if Kea has been compiled without the // --with-mysql. -- GitLab