summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/Makefile.am2
-rw-r--r--src/lib/statistics/Makefile.am24
-rw-r--r--src/lib/statistics/counter.cc65
-rw-r--r--src/lib/statistics/counter.h54
-rw-r--r--src/lib/statistics/counter_dict.cc246
-rw-r--r--src/lib/statistics/counter_dict.h151
-rw-r--r--src/lib/statistics/tests/Makefile.am47
-rw-r--r--src/lib/statistics/tests/counter_dict_unittest.cc198
-rw-r--r--src/lib/statistics/tests/counter_unittest.cc73
-rw-r--r--src/lib/statistics/tests/run_unittests.cc25
10 files changed, 884 insertions, 1 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 5adf150027..c5d6b8d8c1 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,3 +1,3 @@
SUBDIRS = exceptions util log cryptolink dns cc config acl python xfr \
bench asiolink asiodns nsas cache resolve testutils datasrc \
- server_common
+ server_common statistics
diff --git a/src/lib/statistics/Makefile.am b/src/lib/statistics/Makefile.am
new file mode 100644
index 0000000000..6c7b91047d
--- /dev/null
+++ b/src/lib/statistics/Makefile.am
@@ -0,0 +1,24 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/statistics -I$(top_builddir)/src/lib/statistics
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+if USE_CLANGPP
+# clang++ complains about unused function parameters in some boost header
+# files.
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
+
+lib_LTLIBRARIES = libstatistics.la
+libstatistics_la_SOURCES = counter.h counter.cc
+libstatistics_la_SOURCES += counter_dict.h counter_dict.cc
+
+CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/statistics/counter.cc b/src/lib/statistics/counter.cc
new file mode 100644
index 0000000000..5436c6de03
--- /dev/null
+++ b/src/lib/statistics/counter.cc
@@ -0,0 +1,65 @@
+#include <vector>
+#include <cassert>
+#include <boost/unordered_map.hpp>
+
+#include <statistics/counter.h>
+
+namespace {
+const unsigned int InitialValue = 0;
+} // namespace
+
+namespace isc {
+namespace statistics {
+
+class CounterImpl {
+ private:
+ CounterImpl(const CounterImpl& source);
+ CounterImpl& operator=(const CounterImpl& source);
+ private:
+ std::vector<Counter::Value> counters_;
+ public:
+ CounterImpl(const size_t nelements);
+ ~CounterImpl();
+ void inc(const Counter::Type&);
+ const Counter::Value& get(const Counter::Type&) const;
+};
+
+CounterImpl::CounterImpl(const size_t items) :
+ counters_(items, InitialValue)
+{
+ assert(items != 0);
+}
+
+CounterImpl::~CounterImpl() {}
+
+void
+CounterImpl::inc(const Counter::Type& type) {
+ assert(type < counters_.size());
+ ++counters_.at(type);
+ return;
+}
+
+const Counter::Value&
+CounterImpl::get(const Counter::Type& type) const {
+ assert(type < counters_.size());
+ return (counters_.at(type));
+}
+
+Counter::Counter(const size_t items) : impl_(new CounterImpl(items))
+{}
+
+Counter::~Counter() {}
+
+void
+Counter::inc(const Type& type) {
+ impl_->inc(type);
+ return;
+}
+
+const Counter::Value&
+Counter::get(const Type& type) const {
+ return (impl_->get(type));
+}
+
+} // namespace statistics
+} // namespace isc
diff --git a/src/lib/statistics/counter.h b/src/lib/statistics/counter.h
new file mode 100644
index 0000000000..073f760fb6
--- /dev/null
+++ b/src/lib/statistics/counter.h
@@ -0,0 +1,54 @@
+#ifndef __COUNTER_H
+#define __COUNTER_H 1
+
+#include <boost/scoped_ptr.hpp>
+
+namespace isc {
+namespace statistics {
+
+// forward declaration for pImpl idiom
+class CounterImpl;
+
+class Counter {
+ private:
+ Counter(const Counter& source);
+ Counter& operator=(const Counter& source);
+ boost::scoped_ptr<CounterImpl> impl_;
+ public:
+ typedef unsigned int Type;
+ typedef unsigned int Value;
+
+ /// The constructor.
+ ///
+ /// This constructor is mostly exception free. But it may still throw
+ /// a standard exception if memory allocation fails inside the method.
+ ///
+ /// Note: \a items must be greater than 0. Otherwise this constructor
+ /// causes an assertion failure.
+ ///
+ /// \param items A number of counter items to hold (greater than 0)
+ Counter(const size_t items);
+
+ /// The destructor.
+ ///
+ /// This method never throws an exception.
+ ~Counter();
+
+ /// \brief Increment a counter item specified with \a type.
+ ///
+ /// Note: \a type must be valid counter type. Otherwise this method
+ /// causes an assertion failure.
+ ///
+ /// \param type %Counter item to increment
+ void inc(const Type& type);
+
+ /// \brief Get the value of a counter item specified with \a type.
+ ///
+ /// \param type %Counter item to get the value of
+ const Value& get(const Type& type) const;
+};
+
+} // namespace statistics
+} // namespace isc
+
+#endif
diff --git a/src/lib/statistics/counter_dict.cc b/src/lib/statistics/counter_dict.cc
new file mode 100644
index 0000000000..d18c6a5ef1
--- /dev/null
+++ b/src/lib/statistics/counter_dict.cc
@@ -0,0 +1,246 @@
+#include <cassert>
+#include <stdexcept>
+#include <iterator>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/unordered_map.hpp>
+
+#include <statistics/counter_dict.h>
+
+namespace {
+typedef boost::shared_ptr<isc::statistics::Counter> CounterPtr;
+typedef boost::unordered_map<std::string, CounterPtr> DictionaryMap;
+}
+
+namespace isc {
+namespace statistics {
+
+// Implementation detail class for CounterDictionary::ConstIterator
+class CounterDictionaryConstIteratorImpl;
+
+class CounterDictionaryImpl : boost::noncopyable {
+ private:
+ DictionaryMap dictionary_;
+ std::vector<std::string> elements_;
+ const size_t items_;
+ // Default constructor is forbidden; number of counter items must be
+ // specified at the construction of this class.
+ CounterDictionaryImpl();
+ public:
+ CounterDictionaryImpl(const size_t items);
+ ~CounterDictionaryImpl();
+ void addElement(const std::string& element);
+ void deleteElement(const std::string& elemet);
+ Counter& getElement(const std::string& element);
+ public:
+ CounterDictionaryConstIteratorImpl begin() const;
+ CounterDictionaryConstIteratorImpl end() const;
+};
+
+// Constructor with number of items
+CounterDictionaryImpl::CounterDictionaryImpl(const size_t items) :
+ items_(items)
+{
+ // The number of the items must not be 0.
+ assert(items != 0);
+}
+
+// Destructor
+CounterDictionaryImpl::~CounterDictionaryImpl() {}
+
+void
+CounterDictionaryImpl::addElement(const std::string& element) {
+ // throw if the element already exists
+ if (dictionary_.count(element) != 0) {
+ isc_throw(isc::InvalidParameter,
+ "Element " << element << " already exists");
+ }
+ // Create a new Counter and add to the map
+ dictionary_.insert(
+ DictionaryMap::value_type(element, CounterPtr(new Counter(items_))));
+}
+
+void
+CounterDictionaryImpl::deleteElement(const std::string& element) {
+ size_t result = dictionary_.erase(element);
+ if (result != 1) {
+ // If an element with specified name does not exist, throw
+ // isc::OutOfRange.
+ isc_throw(isc::OutOfRange, "Element " << element << " does not exist");
+ }
+}
+
+Counter&
+CounterDictionaryImpl::getElement(const std::string& element) {
+ try {
+ return (*(dictionary_.at(element)));
+ } catch (const std::out_of_range &e) {
+ // If an element with specified name does not exist, throw
+ // isc::OutOfRange.
+ isc_throw(isc::OutOfRange, "Element " << element << " does not exist");
+ }
+}
+
+// Constructor
+// Initialize impl_
+CounterDictionary::CounterDictionary(const size_t items) :
+ impl_(new CounterDictionaryImpl(items))
+{}
+
+// Destructor
+// impl_ will be freed automatically with scoped_ptr
+CounterDictionary::~CounterDictionary() {}
+
+void
+CounterDictionary::addElement(const std::string& element) {
+ impl_->addElement(element);
+}
+
+void
+CounterDictionary::deleteElement(const std::string& element) {
+ impl_->deleteElement(element);
+}
+
+Counter&
+CounterDictionary::getElement(const std::string& element) const {
+ return (impl_->getElement(element));
+}
+
+Counter&
+CounterDictionary::operator[](const std::string& element) const {
+ return (impl_->getElement(element));
+}
+
+// Implementation detail class for CounterDictionary::ConstIterator
+class CounterDictionaryConstIteratorImpl {
+ public:
+ CounterDictionaryConstIteratorImpl();
+ ~CounterDictionaryConstIteratorImpl();
+ CounterDictionaryConstIteratorImpl(
+ const CounterDictionaryConstIteratorImpl &other);
+ CounterDictionaryConstIteratorImpl &operator=(
+ const CounterDictionaryConstIteratorImpl &source);
+ CounterDictionaryConstIteratorImpl(
+ DictionaryMap::const_iterator iterator);
+ public:
+ void increment();
+ CounterDictionary::ValueType dereference() const;
+ bool equal(const CounterDictionaryConstIteratorImpl& other) const;
+ private:
+ DictionaryMap::const_iterator iterator_;
+};
+
+CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl() {}
+
+CounterDictionaryConstIteratorImpl::~CounterDictionaryConstIteratorImpl() {}
+
+// Copy constructor: deep copy of iterator_
+CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl(
+ const CounterDictionaryConstIteratorImpl &other) :
+ iterator_(other.iterator_)
+{}
+
+// Assignment operator: deep copy of iterator_
+CounterDictionaryConstIteratorImpl &
+CounterDictionaryConstIteratorImpl::operator=(
+ const CounterDictionaryConstIteratorImpl &source)
+{
+ iterator_ = source.iterator_;
+ return (*this);
+}
+
+// Constructor from implementation detail DictionaryMap::const_iterator
+CounterDictionaryConstIteratorImpl::CounterDictionaryConstIteratorImpl(
+ DictionaryMap::const_iterator iterator) :
+ iterator_(iterator)
+{}
+
+CounterDictionaryConstIteratorImpl
+CounterDictionaryImpl::begin() const {
+ return (CounterDictionaryConstIteratorImpl(dictionary_.begin()));
+}
+
+CounterDictionaryConstIteratorImpl
+CounterDictionaryImpl::end() const {
+ return (CounterDictionaryConstIteratorImpl(dictionary_.end()));
+}
+
+void
+CounterDictionaryConstIteratorImpl::increment() {
+ ++iterator_;
+ return;
+}
+
+CounterDictionary::ValueType
+CounterDictionaryConstIteratorImpl::dereference() const {
+ return (CounterDictionary::ValueType(iterator_->first,
+ *(iterator_->second)));
+}
+
+bool
+CounterDictionaryConstIteratorImpl::equal(
+ const CounterDictionaryConstIteratorImpl& other) const
+{
+ return (iterator_ == other.iterator_);
+}
+
+CounterDictionary::ConstIterator
+CounterDictionary::begin() const {
+ return (CounterDictionary::ConstIterator(
+ CounterDictionaryConstIteratorImpl(impl_->begin())));
+}
+
+CounterDictionary::ConstIterator
+CounterDictionary::end() const {
+ return (CounterDictionary::ConstIterator(
+ CounterDictionaryConstIteratorImpl(impl_->end())));
+}
+
+CounterDictionary::ConstIterator::ConstIterator() :
+ impl_(new CounterDictionaryConstIteratorImpl())
+{}
+
+CounterDictionary::ConstIterator::~ConstIterator() {}
+
+// Copy constructor: deep copy of impl_
+CounterDictionary::ConstIterator::ConstIterator(
+ const CounterDictionary::ConstIterator& source) :
+ impl_(new CounterDictionaryConstIteratorImpl(*(source.impl_)))
+{}
+
+// Assignment operator: deep copy of impl_
+CounterDictionary::ConstIterator &
+CounterDictionary::ConstIterator::operator=(
+ const CounterDictionary::ConstIterator &source)
+{
+ *impl_ = *source.impl_;
+ return (*this);
+}
+
+// The constructor from implementation detail
+CounterDictionary::ConstIterator::ConstIterator(
+ const CounterDictionaryConstIteratorImpl& source) :
+ impl_(new CounterDictionaryConstIteratorImpl(source))
+{}
+
+const CounterDictionary::ValueType
+CounterDictionary::ConstIterator::dereference() const
+{
+ return (impl_->dereference());
+}
+
+bool
+CounterDictionary::ConstIterator::equal(
+ CounterDictionary::ConstIterator const& other) const
+{
+ return (impl_->equal(*(other.impl_)));
+}
+
+void
+CounterDictionary::ConstIterator::increment() {
+ impl_->increment();
+ return;
+}
+
+} // namespace statistics
+} // namespace isc
diff --git a/src/lib/statistics/counter_dict.h b/src/lib/statistics/counter_dict.h
new file mode 100644
index 0000000000..359671a187
--- /dev/null
+++ b/src/lib/statistics/counter_dict.h
@@ -0,0 +1,151 @@
+#ifndef __COUNTER_DICT_H
+#define __COUNTER_DICT_H 1
+
+#include <string>
+#include <vector>
+#include <utility>
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <exceptions/exceptions.h>
+#include <statistics/counter.h>
+
+namespace isc {
+namespace statistics {
+
+class CounterDictionaryImpl;
+class CounterDictionaryConstIteratorImpl;
+
+class CounterDictionary : boost::noncopyable {
+ private:
+ boost::scoped_ptr<CounterDictionaryImpl> impl_;
+ // Default constructor is forbidden; number of counter items must be
+ // specified at the construction of this class.
+ CounterDictionary();
+ public:
+ /// The constructor.
+ /// This constructor is mostly exception free. But it may still throw
+ /// a standard exception if memory allocation fails inside the method.
+ ///
+ /// Note: \a items must be greater than 0; otherwise thist constructor
+ /// causes assertion failure.
+ ///
+ /// \param items A number of counter items to hold (greater than 0)
+ CounterDictionary(const size_t items);
+
+ /// The destructor.
+ ///
+ /// This method never throws an exception.
+ ~CounterDictionary();
+
+ /// \brief Add an element
+ ///
+ /// \throw isc::InvalidParameter \a element alerady exists.
+ ///
+ /// \param element A name of the element to append
+ void addElement(const std::string& element);
+
+ /// \brief Delete
+ ///
+ /// \throw isc::OutOfRange \a element does not exist.
+ ///
+ /// \param element A name of the element to delete
+ void deleteElement(const std::string& element);
+
+ /// \brief Lookup
+ ///
+ /// \throw isc::OutOfRange \a element does not exist.
+ ///
+ /// \param element A name of the element to get the counters
+ Counter& getElement(const std::string &element) const;
+
+ /// Same as getElement()
+ Counter& operator[](const std::string &element) const;
+
+ /// Typedef for the pair which represents an element of
+ /// CounterDictionary. This type is used for the iterator.
+ typedef std::pair<const std::string&, const Counter&> ValueType;
+
+ /// \brief \c ConstIterator is a constant iterator that provides an
+ /// interface for accessing elements stored in CounterDictionary.
+ ///
+ /// This class is derived from boost::iterator_facade and uses pImpl
+ /// idiom not to expose implementation detail of
+ /// CounterDictionary::iterator.
+ ///
+ /// It is intended to walk through the elements when sending the
+ /// counters to statistics module.
+ class ConstIterator :
+ public boost::iterator_facade<ConstIterator,
+ const ValueType,
+ boost::forward_traversal_tag>
+ {
+ private:
+ boost::scoped_ptr<CounterDictionaryConstIteratorImpl> impl_;
+ public:
+ /// The constrcutor.
+ ///
+ /// This constructor is mostly exception free. But it may still
+ /// throw a standard exception if memory allocation fails
+ /// inside the method.
+ ConstIterator();
+ /// The destrcutor.
+ ///
+ /// This method never throws an exception.
+ ~ConstIterator();
+ /// The assignment operator.
+ ///
+ /// This method is mostly exception free. But it may still
+ /// throw a standard exception if memory allocation fails
+ /// inside the method.
+ ConstIterator& operator=(const ConstIterator &source);
+ /// The copy constructor.
+ ///
+ /// This constructor is mostly exception free. But it may still
+ /// throw a standard exception if memory allocation fails
+ /// inside the method.
+ ConstIterator(const ConstIterator& source);
+ /// The constructor from implementation detail.
+ ///
+ /// This method is used to create an instance of ConstIterator
+ /// by CounterDict::begin() and CounterDict::end().
+ ///
+ /// This constructor is mostly exception free. But it may still
+ /// throw a standard exception if memory allocation fails
+ /// inside the method.
+ ConstIterator(
+ const CounterDictionaryConstIteratorImpl& source);
+ private:
+ /// \brief An internal method to increment this iterator.
+ void increment();
+ /// \brief An internal method to check equality.
+ bool equal(const ConstIterator& other) const;
+ /// \brief An internal method to dereference this iterator.
+ const value_type dereference() const;
+ private:
+ friend class boost::iterator_core_access;
+ };
+
+ typedef ConstIterator const_iterator;
+
+ /// \brief Return an iterator corresponding to the beginning of the
+ /// elements stored in CounterDictionary.
+ ///
+ /// This method is mostly exception free. But it may still throw a
+ /// standard exception if memory allocation fails inside the method.
+ const_iterator begin() const;
+
+ /// \brief Return an iterator corresponding to the end of the elements
+ /// stored in CounterDictionary.
+ ///
+ /// This method is mostly exception free. But it may still throw a
+ /// standard exception if memory allocation fails inside the method.
+ const_iterator end() const;
+
+};
+
+} // namespace statistics
+} // namespace isc
+
+#endif
diff --git a/src/lib/statistics/tests/Makefile.am b/src/lib/statistics/tests/Makefile.am
new file mode 100644
index 0000000000..d66acdf857
--- /dev/null
+++ b/src/lib/statistics/tests/Makefile.am
@@ -0,0 +1,47 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += counter_unittest.cc
+run_unittests_SOURCES += counter_dict_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+run_unittests_CXXFLAGS += -Wno-unused-parameter
+endif
+if USE_CLANGPP
+# Same for clang++, but we need to turn off -Werror completely.
+run_unittests_CXXFLAGS += -Wno-error
+endif
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/statistics/tests/counter_dict_unittest.cc b/src/lib/statistics/tests/counter_dict_unittest.cc
new file mode 100644
index 0000000000..52a8a0bf6b
--- /dev/null
+++ b/src/lib/statistics/tests/counter_dict_unittest.cc
@@ -0,0 +1,198 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <set>
+
+#include <boost/foreach.hpp>
+
+#include <statistics/counter_dict.h>
+
+enum CounterItems {
+ ITEM1 = 0,
+ ITEM2 = 1,
+ ITEM3 = 2,
+ NUMBER_OF_ITEMS = 3
+};
+
+using namespace isc::statistics;
+
+// This fixture is for testing CounterDictionary.
+class CounterDictionaryTest : public ::testing::Test {
+protected:
+ CounterDictionaryTest() {}
+ ~CounterDictionaryTest() {}
+};
+
+TEST_F(CounterDictionaryTest, createCounterDictionary) {
+ // Create counters
+ CounterDictionary counters(NUMBER_OF_ITEMS);
+ // Add an element for this test
+ counters.addElement("test");
+ // Check if the all counters are initialized with 0
+ EXPECT_EQ(counters["test"].get(ITEM1), 0);
+ EXPECT_EQ(counters["test"].get(ITEM2), 0);
+ EXPECT_EQ(counters["test"].get(ITEM3), 0);
+}
+
+TEST_F(CounterDictionaryTest, getElement) {
+ // Create counters
+ CounterDictionary counters(NUMBER_OF_ITEMS);
+ // Add an element for this test
+ counters.addElement("test");
+ // Another member function to get counters for the element
+ EXPECT_EQ(counters.getElement("test").get(ITEM1), 0);
+ EXPECT_EQ(counters.getElement("test").get(ITEM2), 0);
+ EXPECT_EQ(counters.getElement("test").get(ITEM3), 0);
+}
+
+TEST_F(CounterDictionaryTest, incrementCounterItem) {
+ // Create counters
+ CounterDictionary counters(NUMBER_OF_ITEMS);
+ // Add elements for this test
+ counters.addElement("test");
+ counters.addElement("sub.test");
+ // Increment counters
+ counters["test"].inc(ITEM1);
+ counters["test"].inc(ITEM2);
+ counters["test"].inc(ITEM2);
+ counters["test"].inc(ITEM3);
+ counters["test"].inc(ITEM3);
+ counters["test"].inc(ITEM3);
+ // Check if the counters have expected values
+ EXPECT_EQ(counters["test"].get(ITEM1), 1);
+ EXPECT_EQ(counters["test"].get(ITEM2), 2);
+ EXPECT_EQ(counters["test"].get(ITEM3), 3);
+ EXPECT_EQ(counters["sub.test"].get(ITEM1), 0);
+ EXPECT_EQ(counters["sub.test"].get(ITEM2), 0);
+ EXPECT_EQ(counters["sub.test"].get(ITEM3), 0);
+}
+
+TEST_F(CounterDictionaryTest, deleteElement) {
+ // Create counters
+ CounterDictionary counters(NUMBER_OF_ITEMS);
+ // Add an element for this test
+ counters.addElement("test");
+ // Ensure the element is accessible
+ EXPECT_EQ(counters["test"].get(ITEM1), 0);
+ EXPECT_EQ(counters["test"].get(ITEM2), 0);
+ EXPECT_EQ(counters["test"].get(ITEM3), 0);
+ // Delete the element
+ counters.deleteElement("test");
+ // Accessing to the deleted element will cause an isc::OutOfRange exception
+ EXPECT_THROW(counters["test"].get(ITEM1), isc::OutOfRange);
+ // Deleting an element which does not exist will cause an isc::OutOfRange
+ // exception
+ EXPECT_THROW(counters.deleteElement("test"), isc::OutOfRange);
+}
+
+TEST_F(CounterDictionaryTest, invalidCounterSize) {
+ // Creating counter with 0 elements will cause assertion failure
+ EXPECT_DEATH(CounterDictionary counters(0), "Assertion.+failed");
+}
+
+TEST_F(CounterDictionaryTest, invalidCounterItem) {
+ // Create counters
+ CounterDictionary counters(NUMBER_OF_ITEMS);
+ // Add an element for this test
+ counters.addElement("test");
+ // Incrementing out-of-bound counter will cause assertion failure
+ EXPECT_DEATH(counters["test"].inc(NUMBER_OF_ITEMS), "Assertion.+failed");
+}
+
+TEST_F(CounterDictionaryTest, uniqueCheck) {
+ // Create counters
+ CounterDictionary counters(NUMBER_OF_ITEMS);
+ // Add an element for this test
+ counters.addElement("test");
+ // Adding an element which already exists will cause an isc::OutOfRange
+ // exception
+ EXPECT_THROW(counters.addElement("test"), isc::InvalidParameter);
+}
+
+TEST_F(CounterDictionaryTest, iteratorTest) {
+ // Create counters
+ CounterDictionary counters(NUMBER_OF_ITEMS);
+ // Add elements for this test
+ counters.addElement("test");
+ counters.addElement("sub.test");
+ // Increment counters
+ counters["test"].inc(ITEM1);
+ counters["sub.test"].inc(ITEM2);
+ counters["sub.test"].inc(ITEM2);
+
+ // boolean values to check all of the elements can be accessed through
+ // the iterator
+ bool element_test_visited = false;
+ bool element_sub_test_visited = false;
+ // Walk through the elements with iterator
+ // Check if the elements "test" and "sub.test" appears only once
+ // and the counters have expected value
+ BOOST_FOREACH(CounterDictionary::ValueType i,
+ static_cast<const CounterDictionary &>(counters))
+ {
+ if (i.first == "test" && element_test_visited == false) {
+ element_test_visited = true;
+ // Check if the counters have expected value
+ EXPECT_EQ(i.second.get(ITEM1), 1);
+ EXPECT_EQ(i.second.get(ITEM2), 0);
+ } else if (i.first == "sub.test" &&
+ element_sub_test_visited == false) {
+ element_sub_test_visited = true;
+ // Check if the counters have expected value
+ EXPECT_EQ(i.second.get(ITEM1), 0);
+ EXPECT_EQ(i.second.get(ITEM2), 2);
+ } else {
+ // Test fails when reaches here: the element is not expected or
+ // the element appeared twice
+ FAIL() << "Unexpected iterator value";
+ }
+ }
+ // Check if the "test" and "sub.test" could be accessed
+ EXPECT_TRUE(element_test_visited);
+ EXPECT_TRUE(element_sub_test_visited);
+}
+
+TEST_F(CounterDictionaryTest, iteratorCopyTest) {
+ // Create counters
+ CounterDictionary counters(NUMBER_OF_ITEMS);
+ // Add elements for this test
+ counters.addElement("test");
+ counters.addElement("sub.test");
+ // Increment counters
+ counters["test"].inc(ITEM1);
+ counters["sub.test"].inc(ITEM2);
+ counters["sub.test"].inc(ITEM2);
+
+ CounterDictionary::ConstIterator i1 = counters.begin();
+ CounterDictionary::ConstIterator i2(i1);
+ CounterDictionary::ConstIterator i3;
+ i3 = i1;
+
+ EXPECT_TRUE(i1 == i2);
+ EXPECT_TRUE(i1 == i3);
+ EXPECT_TRUE(i2 == i3);
+
+ ++i2;
+ EXPECT_TRUE(i1 != i2);
+ EXPECT_TRUE(i1 == i3);
+ EXPECT_TRUE(i2 != i3);
+
+ ++i3;
+ EXPECT_TRUE(i1 != i2);
+ EXPECT_TRUE(i1 != i3);
+ EXPECT_TRUE(i2 == i3);
+}
diff --git a/src/lib/statistics/tests/counter_unittest.cc b/src/lib/statistics/tests/counter_unittest.cc
new file mode 100644
index 0000000000..b43487be97
--- /dev/null
+++ b/src/lib/statistics/tests/counter_unittest.cc
@@ -0,0 +1,73 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <statistics/counter.h>
+
+namespace {
+enum CounterItems {
+ ITEM1 = 0,
+ ITEM2 = 1,
+ ITEM3 = 2,
+ NUMBER_OF_ITEMS = 3
+};
+}
+
+using namespace isc::statistics;
+
+// This fixture is for testing Counter.
+class CounterTest : public ::testing::Test {
+protected:
+ CounterTest() {}
+ ~CounterTest() {}
+};
+
+TEST_F(CounterTest, createCounter) {
+ // Create counter
+ Counter counter(NUMBER_OF_ITEMS);
+ // Check if the all counters are initialized with 0
+ EXPECT_EQ(counter.get(ITEM1), 0);
+ EXPECT_EQ(counter.get(ITEM2), 0);
+ EXPECT_EQ(counter.get(ITEM3), 0);
+}
+
+TEST_F(CounterTest, incrementCounterItem) {
+ // Create counter
+ Counter counter(NUMBER_OF_ITEMS);
+ // Increment counters
+ counter.inc(ITEM1);
+ counter.inc(ITEM2);
+ counter.inc(ITEM2);
+ counter.inc(ITEM3);
+ counter.inc(ITEM3);
+ counter.inc(ITEM3);
+ // Check if the counters have expected values
+ EXPECT_EQ(counter.get(ITEM1), 1);
+ EXPECT_EQ(counter.get(ITEM2), 2);
+ EXPECT_EQ(counter.get(ITEM3), 3);
+}
+
+TEST_F(CounterTest, invalidCounterSize) {
+ // Creating counter with 0 elements will cause assertion failure
+ EXPECT_DEATH(Counter counter(0), "Assertion.+failed");
+}
+
+TEST_F(CounterTest, invalidCounterItem) {
+ // Create counter
+ Counter counter(NUMBER_OF_ITEMS);
+ // Incrementing out-of-bound counter will cause assertion failure
+ EXPECT_DEATH(counter.inc(NUMBER_OF_ITEMS), "Assertion.+failed");
+}
diff --git a/src/lib/statistics/tests/run_unittests.cc b/src/lib/statistics/tests/run_unittests.cc
new file mode 100644
index 0000000000..b07ce7e8b2
--- /dev/null
+++ b/src/lib/statistics/tests/run_unittests.cc
@@ -0,0 +1,25 @@
+// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+#include <util/unittests/run_all.h>
+#include <log/logger_manager.h>
+
+int
+main(int argc, char* argv[])
+{
+ ::testing::InitGoogleTest(&argc, argv); // Initialize Google test
+ isc::log::LoggerManager::init("unittest"); // Set a root logger name
+ return (isc::util::unittests::run_all());
+}