From 83b9b8a8e1bfc88400255e3cfc75f642ca5bea29 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Fri, 8 May 2015 13:02:15 +0200 Subject: [PATCH] [3793] Unit-tests for StatsMgr implemented. --- src/lib/stats/stats_mgr.h | 72 +++++-- src/lib/stats/tests/stats_mgr_unittest.cc | 242 +++++++++++++++++++++- 2 files changed, 291 insertions(+), 23 deletions(-) diff --git a/src/lib/stats/stats_mgr.h b/src/lib/stats/stats_mgr.h index b0155a415f..7319bbbcd4 100644 --- a/src/lib/stats/stats_mgr.h +++ b/src/lib/stats/stats_mgr.h @@ -32,17 +32,14 @@ class StatsMgr : public boost::noncopyable { static StatsMgr& instance(); // methods used data producers - void addValue(const std::string& name, uint64_t value = 1); - void addValue(const std::string& name, double value = 1.0f); + void addValue(const std::string& name, uint64_t value); + void addValue(const std::string& name, double value); void addValue(const std::string& name, StatsDuration time); + void addValue(const std::string& name, const std::string& value); void setValue(const std::string& name, uint64_t value = 1); void setValue(const std::string& name, double value = 1.0f); void setValue(const std::string& name, StatsDuration time); - - // resets statistic - // this is a convenience function and is equivalent to - // setValue(0) or setValue(0.0f) - void reset(const std::string& name); + void setValue(const std::string& name, const std::string& value); /// @brief determines whether a given statistic is kept as a single value /// or as a number of values @@ -50,14 +47,17 @@ class StatsMgr : public boost::noncopyable { /// Specifies that statistic name should be stored not as a single value, /// but rather as a set of values. duration determines the timespan. /// Samples older than duration will be discarded. This is time-constrained - /// approach. For sample count constrained approach, see setStorage() below. + /// approach. For sample count constrained approach, see @ref + /// setMaxSampleCount() below. + /// + /// @todo: Not implemented. /// /// Example: to set a statistic to keep observations for the last 5 minutes, - /// call setStorage("incoming-packets", time_duration(0,5,0,0)); + /// call setMaxSampleAge("incoming-packets", time_duration(0,5,0,0)); /// to revert statistic to a single value, call: - /// setStorage("incoming-packets" time_duration(0,0,0,0)) - void setStorage(const std::string& name, - boost::posix_time::time_duration duration); + /// setMaxSampleAge("incoming-packets" time_duration(0,0,0,0)) + void setMaxSampleAge(const std::string& name, + boost::posix_time::time_duration duration); /// @brief determines how many samples of a given statistic should be kept. /// @@ -65,16 +65,50 @@ class StatsMgr : public boost::noncopyable { /// rather as a set of values. In this form, at most max_samples will be kept. /// When adding max_samples+1 sample, the oldest sample will be discarded. /// + /// @todo: Not implemented. + /// /// Example: /// To set a statistic to keep the last 100 observations, call: - /// setStorage("incoming-packets", 100); - void setStorage(const std::string& name, uint32_t max_samples); + /// setMaxSampleCount("incoming-packets", 100); + void setMaxSampleCount(const std::string& name, uint32_t max_samples); + + /// @brief Resets specified statistic. + /// + /// This is a convenience function and is equivalent to setValue(name, + /// neutral_value), where neutral_value is 0, 0.0 or "". + /// @param name name of the statistic to be reset. + /// @return true if successful, false if there's no such statistic + bool reset(const std::string& name); + + /// @brief Removes specified statistic. + /// @param name name of the statistic to be removed. + /// @return true if successful, false if there's no such statistic + bool remove(const std::string& name); - // methods used by data consumers - const ObservationPtr& getValue(const std::string& name); + /// @brief Resets all collected statistics back to zero. + void resetAll(); - // returns all statistics - const std::map getValues(); + /// @brief Removes all collected statistics. + void removeAll(); + + /// @brief Returns number of available statistics. + /// @return number of recorded statistics. + size_t count(); + + /// @brief Returns a single statistic as a JSON structure + /// @return JSON structures representing a single statistic + isc::data::ConstElementPtr get(const std::string& name); + + /// @brief Returns all statistics as a JSON structure + /// @return JSON structures representing all statistics + isc::data::ConstElementPtr getAll(); + + /// @brief Returns an observation + /// + /// Used in testing only. Production code should use @ref get() method. + /// @param name name of the statistic + /// @return Pointer to the Observation object + ObservationPtr getObservation(const std::string& name); private: /// @brief returns a context for specified name @@ -82,8 +116,6 @@ class StatsMgr : public boost::noncopyable { // This is a global context. All stats will initially be stored here. StatContextPtr global_; - - std::map contexts_; }; }; diff --git a/src/lib/stats/tests/stats_mgr_unittest.cc b/src/lib/stats/tests/stats_mgr_unittest.cc index 68ec157303..8174a417d5 100644 --- a/src/lib/stats/tests/stats_mgr_unittest.cc +++ b/src/lib/stats/tests/stats_mgr_unittest.cc @@ -16,28 +16,264 @@ #include #include - +#include #include +#include #include #include #include using namespace isc; +using namespace isc::data; using namespace isc::stats; +using namespace boost::posix_time; namespace { class StatsMgrTest : public ::testing::Test { public: StatsMgrTest() { + StatsMgr::instance(); + } + + ~StatsMgrTest() { + StatsMgr::instance().removeAll(); } }; -// Basic tests for V4 functionality +// Basic test for statistics manager interface. TEST_F(StatsMgrTest, basic) { - // EXPECT_NO_THROW(StatsMgr::instance()); + // Getting an instance + EXPECT_NO_THROW(StatsMgr::instance()); + + // Check that there are no statistics recorded by default. + EXPECT_EQ(0, StatsMgr::instance().count()); +} + +// Test checks whether it's possible to record and later report +// an integer statistic. +TEST_F(StatsMgrTest, integerStat) { + EXPECT_NO_THROW(StatsMgr::instance().setValue("alpha", + static_cast(1234))); + + ObservationPtr alpha; + EXPECT_NO_THROW(alpha = StatsMgr::instance().getObservation("alpha")); + EXPECT_TRUE(alpha); + + std::string exp = "\"alpha\": [ [ 1234, \"" + + Observation::ptimeToText(alpha->getInteger().second) + "\" ] ]"; + + EXPECT_EQ(exp, StatsMgr::instance().get("alpha")->str()); +} + +// Test checks whether it's possible to record and later report +// a floating point statistic. +TEST_F(StatsMgrTest, floatStat) { + EXPECT_NO_THROW(StatsMgr::instance().setValue("beta", 12.34)); + + ObservationPtr beta; + EXPECT_NO_THROW(beta = StatsMgr::instance().getObservation("beta")); + EXPECT_TRUE(beta); + + std::string exp = "\"beta\": [ [ 12.34, \"" + + Observation::ptimeToText(beta->getFloat().second) + "\" ] ]"; + + EXPECT_EQ(exp, StatsMgr::instance().get("beta")->str()); +} + +// Test checks whether it's possible to record and later report +// a duration statistic. +TEST_F(StatsMgrTest, durationStat) { + EXPECT_NO_THROW(StatsMgr::instance().setValue("gamma", + microsec::time_duration(1,2,3,4))); + + ObservationPtr gamma; + EXPECT_NO_THROW(gamma = StatsMgr::instance().getObservation("beta")); + EXPECT_TRUE(gamma); + + std::string exp = "\"gamma\": [ [ \"01:02:03.000004\", \"" + + Observation::ptimeToText(gamma->getDuration().second) + "\" ] ]"; + + EXPECT_EQ(exp, StatsMgr::instance().get("gamma")->str()); +} + +// Test checks whether it's possible to record and later report +// a string statistic. +TEST_F(StatsMgrTest, stringStat) { + EXPECT_NO_THROW(StatsMgr::instance().setValue("delta", + "Lorem ipsum")); + + ObservationPtr delta; + EXPECT_NO_THROW(delta = StatsMgr::instance().getObservation("delta")); + EXPECT_TRUE(delta); + + std::string exp = "\"delta\": [ [ \"Lorem impsum\", \"" + + Observation::ptimeToText(delta->getString().second) + "\" ] ]"; + + EXPECT_EQ(exp, StatsMgr::instance().get("delta")->str()); +} + +// Setting limits is currently not implemented, so those methods should +// throw. +TEST_F(StatsMgrTest, setLimits) { + EXPECT_THROW(StatsMgr::instance().setMaxSampleAge("foo", + time_duration(1,0,0,0)), + NotImplemented); + + EXPECT_THROW(StatsMgr::instance().setMaxSampleCount("foo", 100), + NotImplemented); +} + +// This test checks whether a single (get("foo")) and all (getAll()) +// statistics are reported properly. +TEST_F(StatsMgrTest, getGetAll) { + + // 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"); + + // Now add some values to them + StatsMgr::instance().addValue("alpha", static_cast(5678)); + StatsMgr::instance().addValue("beta", 56.78); + StatsMgr::instance().addValue("gamma", time_duration(5,6,7,8)); + StatsMgr::instance().addValue("delta", " ipsum"); + + // There should be 4 statistics reported + EXPECT_EQ(4, StatsMgr::instance().count()); + + // Now check whether they can be reported back + 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 = "\"alpha\": [ [ 1234, \"" + + Observation::ptimeToText(StatsMgr::instance().getObservation("alpha") + ->getInteger().second) + "\" ] ]"; + std::string exp_str_beta = "\"beta\": [ [ 12.34, \"" + + Observation::ptimeToText(StatsMgr::instance().getObservation("beta") + ->getFloat().second) + "\" ] ]"; + std::string exp_str_gamma = "\"gamma\": [ [ \"01:02:03.000004\", \"" + + Observation::ptimeToText(StatsMgr::instance().getObservation("gamma") + ->getDuration().second) + "\" ] ]"; + std::string exp_str_delta = "\"delta\": [ [ \"Lorem impsum\", \"" + + Observation::ptimeToText(StatsMgr::instance().getObservation("delta") + ->getString().second) + "\" ] ]"; + + // Check that individual stats are reported properly + EXPECT_EQ(exp_str_alpha, rep_alpha->str()); + EXPECT_EQ(exp_str_beta, rep_beta->str()); + EXPECT_EQ(exp_str_gamma, rep_gamma->str()); + EXPECT_EQ(exp_str_delta, rep_delta->str()); + + // Check that non-existent metric is not reported. + EXPECT_FALSE(StatsMgr::instance().get("epsilon")); + + // Check that all of them can be reported at once + ConstElementPtr rep_all = StatsMgr::instance().getAll(); + ASSERT_TRUE(rep_all); + + // This may not be the best verification. There's no guarantee that the + // statistics will be reported in this specific order. + std::string exp_all = exp_str_alpha + ", " + exp_str_beta + ", " + + exp_str_gamma + ", " + exp_str_delta; + EXPECT_EQ(exp_all, rep_all->str()); +} + +// This test checks whether existing statistics can be reset. +TEST_F(StatsMgrTest, reset) { + + // 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"); + + // This should reset alpha to 0 + EXPECT_NO_THROW(StatsMgr::instance().reset("alpha")); + EXPECT_EQ(0, StatsMgr::instance().getObservation("alpha")->getInteger().first); + + // The other stats should remain untouched + EXPECT_EQ(12.34, + StatsMgr::instance().getObservation("beta")->getFloat().first); + EXPECT_EQ(time_duration(1,2,3,4), + StatsMgr::instance().getObservation("gamma")->getDuration().first); + EXPECT_EQ("Lorem ipsum", + StatsMgr::instance().getObservation("delta")->getString().first); + + // Now let's wipe them, too. + EXPECT_NO_THROW(StatsMgr::instance().reset("beta")); + EXPECT_NO_THROW(StatsMgr::instance().reset("gamma")); + EXPECT_NO_THROW(StatsMgr::instance().reset("delta")); + EXPECT_EQ(0.0, + 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); + + // Resetting statistics should not remove them + EXPECT_EQ(4, StatsMgr::instance().count()); +} + +// This test checks whether existing statistics can be reset. +TEST_F(StatsMgrTest, resetAll) { + + // 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"); + + // This should reset alpha to 0 + EXPECT_NO_THROW(StatsMgr::instance().resetAll()); + EXPECT_EQ(0, StatsMgr::instance().getObservation("alpha")->getInteger().first); + EXPECT_EQ(0.0, + 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); + + // Resetting all statistics should not remove them + EXPECT_EQ(4, StatsMgr::instance().count()); +} + +// This test checks whether statistics can be removed. +TEST_F(StatsMgrTest, removeAll) { + + // 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"); + + // This should reset alpha to 0 + EXPECT_NO_THROW(StatsMgr::instance().removeAll()); + + // Resetting all statistics should not remove them + EXPECT_EQ(0, StatsMgr::instance().count()); + + // There should be no such statistics anymore + EXPECT_FALSE(StatsMgr::instance().get("alpha")); + EXPECT_FALSE(StatsMgr::instance().get("beta")); + EXPECT_FALSE(StatsMgr::instance().get("gamma")); + EXPECT_FALSE(StatsMgr::instance().get("delta")); + + // There should be no such statistics anymore + EXPECT_FALSE(StatsMgr::instance().getObservation("alpha")); + EXPECT_FALSE(StatsMgr::instance().getObservation("beta")); + EXPECT_FALSE(StatsMgr::instance().getObservation("gamma")); + EXPECT_FALSE(StatsMgr::instance().getObservation("delta")); } }; -- 2.47.3