Browse Source

[3793] Unit-tests for StatsMgr implemented.

Tomek Mrugalski 10 years ago
parent
commit
83b9b8a8e1
2 changed files with 291 additions and 23 deletions
  1. 52 20
      src/lib/stats/stats_mgr.h
  2. 239 3
      src/lib/stats/tests/stats_mgr_unittest.cc

+ 52 - 20
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<std::string, ObservationPtr> 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<std::string, StatContextPtr> contexts_;
 };
 
 };

+ 239 - 3
src/lib/stats/tests/stats_mgr_unittest.cc

@@ -16,28 +16,264 @@
 
 #include <stats/stats_mgr.h>
 #include <exceptions/exceptions.h>
-
+#include <boost/date_time/posix_time/posix_time_types.hpp>
 #include <boost/shared_ptr.hpp>
+#include <cc/data.h>
 #include <gtest/gtest.h>
 
 #include <iostream>
 #include <sstream>
 
 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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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"));
 }
 
 };