diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/Makefile.am | 2 | ||||
-rw-r--r-- | src/lib/statistics/Makefile.am | 24 | ||||
-rw-r--r-- | src/lib/statistics/counter.cc | 65 | ||||
-rw-r--r-- | src/lib/statistics/counter.h | 54 | ||||
-rw-r--r-- | src/lib/statistics/counter_dict.cc | 246 | ||||
-rw-r--r-- | src/lib/statistics/counter_dict.h | 151 | ||||
-rw-r--r-- | src/lib/statistics/tests/Makefile.am | 47 | ||||
-rw-r--r-- | src/lib/statistics/tests/counter_dict_unittest.cc | 198 | ||||
-rw-r--r-- | src/lib/statistics/tests/counter_unittest.cc | 73 | ||||
-rw-r--r-- | src/lib/statistics/tests/run_unittests.cc | 25 |
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()); +} |