From: Tomek Mrugalski Date: Mon, 8 Jun 2015 19:35:22 +0000 (+0200) Subject: [3880] Implemented handlers for statistic-* commands. X-Git-Tag: trac3830_base~5^2~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a3856901aa1694ddb112c22fc73cbba0895d9c32;p=thirdparty%2Fkea.git [3880] Implemented handlers for statistic-* commands. --- diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 5c20c3d32d..67b5065b70 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -1,3 +1,3 @@ # The following build order must be maintained. -SUBDIRS = exceptions util log hooks cryptolink dns cc stats dhcp config \ +SUBDIRS = exceptions util log hooks cryptolink dns cc dhcp config stats \ asiolink asiodns testutils dhcp_ddns dhcpsrv diff --git a/src/lib/stats/Makefile.am b/src/lib/stats/Makefile.am index 4ff2abbf44..0556c18348 100644 --- a/src/lib/stats/Makefile.am +++ b/src/lib/stats/Makefile.am @@ -11,6 +11,7 @@ libkea_stats_la_SOURCES += stats_mgr.h stats_mgr.cc libkea_stats_la_CPPFLAGS = $(AM_CPPFLAGS) libkea_stats_la_LIBADD = $(top_builddir)/src/lib/cc/libkea-cc.la +libkea_stats_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la libkea_stats_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la libkea_stats_includedir = $(includedir)/$(PACKAGE_NAME)/stats diff --git a/src/lib/stats/stats_mgr.cc b/src/lib/stats/stats_mgr.cc index 2a592b63f1..8a11ab216e 100644 --- a/src/lib/stats/stats_mgr.cc +++ b/src/lib/stats/stats_mgr.cc @@ -14,8 +14,12 @@ #include #include +#include +#include using namespace std; +using namespace isc::data; +using namespace isc::config; namespace isc { namespace stats { @@ -142,6 +146,95 @@ size_t StatsMgr::count() const { return (global_->stats_.size()); } +isc::data::ConstElementPtr +StatsMgr::statisticGetHandler(const std::string& /*name*/, + const isc::data::ConstElementPtr& params) { + if (!params) { + return (createAnswer(CONTROL_RESULT_ERROR, + "Missing mandatory 'name' parameter.")); + } + ConstElementPtr stat_name = params->get("name"); + if (!stat_name) { + return (createAnswer(CONTROL_RESULT_ERROR, + "Missing mandatory 'name' parameter.")); + } + if (stat_name->getType() != Element::string) { + return (createAnswer(CONTROL_RESULT_ERROR, + "'name' parameter expected to be a string.")); + } + return (createAnswer(CONTROL_RESULT_SUCCESS, get(stat_name->stringValue()))); +} + +isc::data::ConstElementPtr +StatsMgr::statisticResetHandler(const std::string& /*name*/, + const isc::data::ConstElementPtr& params) { + if (!params) { + return (createAnswer(CONTROL_RESULT_ERROR, + "Missing mandatory 'name' parameter.")); + } + ConstElementPtr stat_name = params->get("name"); + if (!stat_name) { + return (createAnswer(CONTROL_RESULT_ERROR, + "Missing mandatory 'name' parameter.")); + } + if (stat_name->getType() != Element::string) { + return (createAnswer(CONTROL_RESULT_ERROR, + "'name' parameter expected to be a string.")); + } + + if (reset(stat_name->stringValue())) { + return (createAnswer(CONTROL_RESULT_SUCCESS, + "Statistic '" + stat_name->stringValue() + "' reset.")); + } else { + return (createAnswer(CONTROL_RESULT_ERROR, + "No '" + stat_name->stringValue() + "' statistic found")); + } +} + +isc::data::ConstElementPtr +StatsMgr::statisticRemoveHandler(const std::string& /*name*/, + const isc::data::ConstElementPtr& params) { + if (!params) { + return (createAnswer(CONTROL_RESULT_ERROR, + "Missing mandatory 'name' parameter.")); + } + ConstElementPtr stat_name = params->get("name"); + if (!stat_name) { + return (createAnswer(CONTROL_RESULT_ERROR, + "Missing mandatory 'name' parameter.")); + } + if (del(stat_name->stringValue())) { + return (createAnswer(CONTROL_RESULT_SUCCESS, + "Statistic '" + stat_name->stringValue() + "' removed.")); + } else { + return (createAnswer(CONTROL_RESULT_ERROR, + "No '" + stat_name->stringValue() + "' statistic found")); + } + +} + +isc::data::ConstElementPtr +StatsMgr::statisticRemoveAllHandler(const std::string& /*name*/, + const isc::data::ConstElementPtr& /*params*/) { + removeAll(); + return (createAnswer(CONTROL_RESULT_SUCCESS, + "All statistics removed.")); +} + +isc::data::ConstElementPtr +StatsMgr::statisticGetAllHandler(const std::string& /*name*/, + const isc::data::ConstElementPtr& /*params*/) { + ConstElementPtr all_stats = getAll(); + return (createAnswer(CONTROL_RESULT_SUCCESS, all_stats)); +} + +isc::data::ConstElementPtr +StatsMgr::statisticResetAllHandler(const std::string& /*name*/, + const isc::data::ConstElementPtr& /*params*/) { + resetAll(); + return (createAnswer(CONTROL_RESULT_SUCCESS, + "All statistics reset to neutral values.")); +} }; diff --git a/src/lib/stats/stats_mgr.h b/src/lib/stats/stats_mgr.h index dbbea8bcbb..ae73cb0904 100644 --- a/src/lib/stats/stats_mgr.h +++ b/src/lib/stats/stats_mgr.h @@ -197,6 +197,104 @@ class StatsMgr : public boost::noncopyable { /// @return Pointer to the Observation object ObservationPtr getObservation(const std::string& name) const; + /// @defgroup command_methods Methods are used to handle commands. + /// + /// @brief The following methods are used to handle commands: + /// + /// @{ + + /// @brief Handles statistic-get command + /// + /// This method handles statistic-get command, which returns value + /// of a given statistic). It expects one parameter stored in params map: + /// name: name-of-the-statistic + /// + /// Example params structure: + /// { + /// "name": "packets-received" + /// } + /// + /// @param name name of the command (ignored, should be "statistic-get") + /// @param params structure containing a map that contains "name" + /// @param return answer containing details of specified statistic + isc::data::ConstElementPtr + statisticGetHandler(const std::string& name, + const isc::data::ConstElementPtr& params); + + /// @param Handles statistic-reset command + /// + /// This method handles statistic-reset command, which resets value + /// of a given statistic. It expects one parameter stored in params map: + /// name: name-of-the-statistic + /// + /// Example params structure: + /// { + /// "name": "packets-received" + /// } + /// + /// @param name name of the command (ignored, should be "statistic-reset") + /// @param params structure containing a map that contains "name" + /// @param return answer containing confirmation + isc::data::ConstElementPtr + statisticResetHandler(const std::string& name, + const isc::data::ConstElementPtr& params); + + /// @param Handles statistic-remove command + /// + /// This method handles statistic-reset command, which removes a given + /// statistic completely. It expects one parameter stored in params map: + /// name: name-of-the-statistic + /// + /// Example params structure: + /// { + /// "name": "packets-received" + /// } + /// + /// @param name name of the command (ignored, should be "statistic-remove") + /// @param params structure containing a map that contains "name" element + /// @param return answer containing confirmation + isc::data::ConstElementPtr + statisticRemoveHandler(const std::string& name, + const isc::data::ConstElementPtr& params); + + /// @brief Handles statistic-get-all command + /// + /// This method handles statistic-get-all command, which returns values + /// of all statistics. Params parameter is ignored. + /// + /// @param name name of the command (ignored, should be "statistic-get-all") + /// @param params ignored + /// @param return answer containing values of all statistic + isc::data::ConstElementPtr + statisticGetAllHandler(const std::string& name, + const isc::data::ConstElementPtr& params); + + /// @brief Handles statistic-reset-all command + /// + /// This method handles statistic-reset-all command, which sets values of + /// all statistics back to zero. Params parameter is ignored. + /// + /// @param name name of the command (ignored, should be "statistic-reset-all") + /// @param params ignored + /// @param return answer confirming success of this operation + isc::data::ConstElementPtr + statisticResetAllHandler(const std::string& name, + const isc::data::ConstElementPtr& params); + + /// @brief Handles statistic-remove-all command + /// + /// This method handles statistic-remove-all command, which removes all + /// statistics. Params parameter is ignored. + /// + /// @param name name of the command (ignored, should be "statistic-remove-all") + /// @param params ignored + /// @param return answer confirming success of this operation + isc::data::ConstElementPtr + statisticRemoveAllHandler(const std::string& name, + const isc::data::ConstElementPtr& params); + + /// @} + private: /// @brief Sets a given statistic to specified value (internal version). diff --git a/src/lib/stats/tests/Makefile.am b/src/lib/stats/tests/Makefile.am index e42f4c1716..0b41a1555c 100644 --- a/src/lib/stats/tests/Makefile.am +++ b/src/lib/stats/tests/Makefile.am @@ -24,6 +24,7 @@ libstats_unittests_CXXFLAGS = $(AM_CXXFLAGS) libstats_unittests_LDADD = $(top_builddir)/src/lib/stats/libkea-stats.la libstats_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la +libstats_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la libstats_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la libstats_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la libstats_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la diff --git a/src/lib/stats/tests/stats_mgr_unittest.cc b/src/lib/stats/tests/stats_mgr_unittest.cc index 6ff79b106d..f7226f6509 100644 --- a/src/lib/stats/tests/stats_mgr_unittest.cc +++ b/src/lib/stats/tests/stats_mgr_unittest.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ using namespace isc; using namespace isc::data; using namespace isc::stats; +using namespace isc::config; using namespace boost::posix_time; namespace { @@ -42,6 +44,7 @@ public: /// Makes sure that the Statistics Manager is instantiated. StatsMgrTest() { StatsMgr::instance(); + StatsMgr::instance().removeAll(); } /// @brief Destructor @@ -397,4 +400,274 @@ TEST_F(StatsMgrTest, DISABLED_performanceMultipleSet) { << " times took: " << isc::util::durationToText(dur) << std::endl; } +// Test checks if statistic-get handler is able to return specified statistic. +TEST_F(StatsMgrTest, commandStatisticGet) { + StatsMgr::instance().setValue("alpha", static_cast(1234)); + + ElementPtr params = Element::createMap(); + params->set("name", Element::create("alpha")); + + ConstElementPtr rsp = StatsMgr::instance().statisticGetHandler("statistic-get", + params); + + ObservationPtr alpha; + EXPECT_NO_THROW(alpha = StatsMgr::instance().getObservation("alpha")); + ASSERT_TRUE(alpha); + + std::string exp = "{ \"alpha\": [ [ 1234, \"" + + isc::util::ptimeToText(alpha->getInteger().second) + "\" ] ] }"; + + EXPECT_EQ("{ \"arguments\": " + exp + ", \"result\": 0 }", rsp->str()); +} + +// Test checks if statistic-get is able to handle: +// - a request without parameters +// - a request with missing statistic name +// - a request for non-existing statistic. +TEST_F(StatsMgrTest, commandStatisticGetNegative) { + + // Case 1: a request without parameters + ConstElementPtr rsp = StatsMgr::instance().statisticGetHandler("statistic-get", + ElementPtr()); + int status_code; + ASSERT_NO_THROW(parseAnswer(status_code, rsp)); + EXPECT_EQ(status_code, CONTROL_RESULT_ERROR); + + // Case 2: a request with missing statistic name + ElementPtr params = Element::createMap(); + rsp = StatsMgr::instance().statisticGetHandler("statistic-get", params); + ASSERT_NO_THROW(parseAnswer(status_code, rsp)); + EXPECT_EQ(status_code, CONTROL_RESULT_ERROR); + + // Case 3: a request for non-existing statistic + params->set("name", Element::create("alpha")); + rsp = StatsMgr::instance().statisticGetHandler("statistic-get", params); + EXPECT_EQ("{ \"arguments\": { }, \"result\": 0 }", rsp->str()); +} + +// This test checks whether statistc-get-all command returns all statistics +// correctly. +TEST_F(StatsMgrTest, commandGetAll) { + + // Set a couple of statistics + StatsMgr::instance().setValue("alpha", static_cast(1234)); + StatsMgr::instance().setValue("beta", 12.34); + StatsMgr::instance().setValue("gamma", time_duration(1,2,3,4)); + StatsMgr::instance().setValue("delta", "Lorem ipsum"); + + // Now get them. They're used to generate expected output + ConstElementPtr rep_alpha = StatsMgr::instance().get("alpha"); + ConstElementPtr rep_beta = StatsMgr::instance().get("beta"); + ConstElementPtr rep_gamma = StatsMgr::instance().get("gamma"); + ConstElementPtr rep_delta = StatsMgr::instance().get("delta"); + + ASSERT_TRUE(rep_alpha); + ASSERT_TRUE(rep_beta); + ASSERT_TRUE(rep_gamma); + ASSERT_TRUE(rep_delta); + + std::string exp_str_alpha = "[ [ 1234, \"" + + isc::util::ptimeToText(StatsMgr::instance().getObservation("alpha") + ->getInteger().second) + "\" ] ]"; + std::string exp_str_beta = "[ [ 12.34, \"" + + isc::util::ptimeToText(StatsMgr::instance().getObservation("beta") + ->getFloat().second) + "\" ] ]"; + std::string exp_str_gamma = "[ [ \"01:02:03.000004\", \"" + + isc::util::ptimeToText(StatsMgr::instance().getObservation("gamma") + ->getDuration().second) + "\" ] ]"; + std::string exp_str_delta = "[ [ \"Lorem ipsum\", \"" + + isc::util::ptimeToText(StatsMgr::instance().getObservation("delta") + ->getString().second) + "\" ] ]"; + + // Check that all of them can be reported at once + ConstElementPtr rsp = StatsMgr::instance().statisticGetAllHandler( + "statistic-get-all", ElementPtr()); + ASSERT_TRUE(rsp); + int status_code; + ConstElementPtr rep_all = parseAnswer(status_code, rsp); + ASSERT_EQ(0, status_code); + ASSERT_TRUE(rep_all); + + // Verifying this is a bit more involved, as we don't know whether the + // order would be preserved or not. + EXPECT_EQ(4, rep_all->size()); + ASSERT_TRUE(rep_all->get("alpha")); + ASSERT_TRUE(rep_all->get("beta")); + ASSERT_TRUE(rep_all->get("delta")); + ASSERT_TRUE(rep_all->get("gamma")); + EXPECT_FALSE(rep_all->get("epsilon")); + + EXPECT_EQ(exp_str_alpha, rep_all->get("alpha")->str()); + EXPECT_EQ(exp_str_beta, rep_all->get("beta")->str()); + EXPECT_EQ(exp_str_gamma, rep_all->get("gamma")->str()); + EXPECT_EQ(exp_str_delta, rep_all->get("delta")->str()); +} + +// Test checks if statistic-reset handler is able to reset specified statistic. +TEST_F(StatsMgrTest, commandStatisticReset) { + StatsMgr::instance().setValue("alpha", static_cast(1234)); + + ElementPtr params = Element::createMap(); + params->set("name", Element::create("alpha")); + + ConstElementPtr rsp = + StatsMgr::instance().statisticResetHandler("statistic-reset", params); + int status_code; + ASSERT_NO_THROW(parseAnswer(status_code, rsp)); + EXPECT_EQ(CONTROL_RESULT_SUCCESS, status_code); + + ObservationPtr alpha; + EXPECT_NO_THROW(alpha = StatsMgr::instance().getObservation("alpha")); + ASSERT_TRUE(alpha); + + // Check that it was indeed reset + EXPECT_EQ(0, alpha->getInteger().first); +} + +// Test checks if statistic-reset is able to handle: +// - a request without parameters +// - a request with missing statistic name +// - a request for non-existing statistic. +TEST_F(StatsMgrTest, commandStatisticResetNegative) { + + // Case 1: a request without parameters + ConstElementPtr rsp = + StatsMgr::instance().statisticResetHandler("statistic-reset", ElementPtr()); + int status_code; + ASSERT_NO_THROW(parseAnswer(status_code, rsp)); + EXPECT_EQ(status_code, CONTROL_RESULT_ERROR); + + // Case 2: a request with missing statistic name + ElementPtr params = Element::createMap(); + rsp = StatsMgr::instance().statisticResetHandler("statistic-reset", params); + ASSERT_NO_THROW(parseAnswer(status_code, rsp)); + EXPECT_EQ(status_code, CONTROL_RESULT_ERROR); + + // Case 3: a request for non-existing statistic + params->set("name", Element::create("alpha")); + rsp = StatsMgr::instance().statisticResetHandler("statistic-reset", params); + EXPECT_EQ("{ \"result\": 1, \"text\": \"No 'alpha' statistic found\" }", + rsp->str()); +} + +// This test checks whether statistic-reset-all command really resets all +// statistics correctly. +TEST_F(StatsMgrTest, commandResetAll) { + + // Set a couple of statistics + StatsMgr::instance().setValue("alpha", static_cast(1234)); + StatsMgr::instance().setValue("beta", 12.34); + StatsMgr::instance().setValue("gamma", time_duration(1,2,3,4)); + StatsMgr::instance().setValue("delta", "Lorem ipsum"); + + // Now get them. They're used to generate expected output + ConstElementPtr rep_alpha = StatsMgr::instance().get("alpha"); + ConstElementPtr rep_beta = StatsMgr::instance().get("beta"); + ConstElementPtr rep_gamma = StatsMgr::instance().get("gamma"); + ConstElementPtr rep_delta = StatsMgr::instance().get("delta"); + + ASSERT_TRUE(rep_alpha); + ASSERT_TRUE(rep_beta); + ASSERT_TRUE(rep_gamma); + ASSERT_TRUE(rep_delta); + + std::string exp_str_alpha = "[ [ 1234, \"" + + isc::util::ptimeToText(StatsMgr::instance().getObservation("alpha") + ->getInteger().second) + "\" ] ]"; + std::string exp_str_beta = "[ [ 12.34, \"" + + isc::util::ptimeToText(StatsMgr::instance().getObservation("beta") + ->getFloat().second) + "\" ] ]"; + std::string exp_str_gamma = "[ [ \"01:02:03.000004\", \"" + + isc::util::ptimeToText(StatsMgr::instance().getObservation("gamma") + ->getDuration().second) + "\" ] ]"; + std::string exp_str_delta = "[ [ \"Lorem ipsum\", \"" + + isc::util::ptimeToText(StatsMgr::instance().getObservation("delta") + ->getString().second) + "\" ] ]"; + + // Check that all of them can be reset at once + ConstElementPtr rsp = StatsMgr::instance().statisticResetAllHandler( + "statistic-reset-all", ElementPtr()); + ASSERT_TRUE(rsp); + int status_code; + ConstElementPtr rep_all = parseAnswer(status_code, rsp); + ASSERT_EQ(0, status_code); + ASSERT_TRUE(rep_all); + + // Check that they're indeed reset + EXPECT_EQ(0, StatsMgr::instance().getObservation("alpha")->getInteger().first); + EXPECT_EQ(0.0f, + StatsMgr::instance().getObservation("beta")->getFloat().first); + EXPECT_EQ(time_duration(0,0,0,0), + StatsMgr::instance().getObservation("gamma")->getDuration().first); + EXPECT_EQ("", + StatsMgr::instance().getObservation("delta")->getString().first); +} + +// Test checks if statistic-remove handler is able to remove a statistic. +TEST_F(StatsMgrTest, commandStatisticRemove) { + StatsMgr::instance().setValue("alpha", static_cast(1234)); + + ElementPtr params = Element::createMap(); + params->set("name", Element::create("alpha")); + + ConstElementPtr rsp = + StatsMgr::instance().statisticRemoveHandler("statistic-remove", params); + int status_code; + ASSERT_NO_THROW(parseAnswer(status_code, rsp)); + EXPECT_EQ(CONTROL_RESULT_SUCCESS, status_code); + + // It should be gone. + EXPECT_FALSE(StatsMgr::instance().getObservation("alpha")); +} + +// Test checks if statistic-remove is able to handle: +// - a request without parameters +// - a request with missing statistic name +// - a request for non-existing statistic. +TEST_F(StatsMgrTest, commandStatisticRemoveNegative) { + + // Case 1: a request without parameters + ConstElementPtr rsp = + StatsMgr::instance().statisticRemoveHandler("statistic-remove", ElementPtr()); + int status_code; + ASSERT_NO_THROW(parseAnswer(status_code, rsp)); + EXPECT_EQ(status_code, CONTROL_RESULT_ERROR); + + // Case 2: a request with missing statistic name + ElementPtr params = Element::createMap(); + rsp = StatsMgr::instance().statisticRemoveHandler("statistic-remove", params); + ASSERT_NO_THROW(parseAnswer(status_code, rsp)); + EXPECT_EQ(status_code, CONTROL_RESULT_ERROR); + + // Case 3: a request for non-existing statistic + params->set("name", Element::create("alpha")); + rsp = StatsMgr::instance().statisticRemoveHandler("statistic-remove", params); + EXPECT_EQ("{ \"result\": 1, \"text\": \"No 'alpha' statistic found\" }", + rsp->str()); +} + +// This test checks whether statistic-remove-all command really resets all +// statistics correctly. +TEST_F(StatsMgrTest, commandRemoveAll) { + + // Set a couple of statistics + StatsMgr::instance().setValue("alpha", static_cast(1234)); + StatsMgr::instance().setValue("beta", 12.34); + StatsMgr::instance().setValue("gamma", time_duration(1,2,3,4)); + StatsMgr::instance().setValue("delta", "Lorem ipsum"); + + // Check that all of them can be reset at once + ConstElementPtr rsp = StatsMgr::instance().statisticRemoveAllHandler( + "statistic-remove-all", ElementPtr()); + ASSERT_TRUE(rsp); + int status_code; + ConstElementPtr rep_all = parseAnswer(status_code, rsp); + ASSERT_EQ(0, status_code); + + EXPECT_FALSE(StatsMgr::instance().getObservation("alpha")); + EXPECT_FALSE(StatsMgr::instance().getObservation("beta")); + EXPECT_FALSE(StatsMgr::instance().getObservation("gamma")); + EXPECT_FALSE(StatsMgr::instance().getObservation("delta")); +} + };