Browse Source

add query counters in b10-auth, interval timer class in asio_link and unittests (ticket #347)

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac347@3686 e5f2f494-b856-4b98-b285-d166d9295462
Yoshitaka Aharen 14 years ago
parent
commit
da0bb5777f

+ 7 - 0
ChangeLog

@@ -1,3 +1,10 @@
+  TBD.  [func]		y-aharen
+	src/bin/auth: Added a feature to count query and send counter
+	values to b10-stats periodically. To support it, added wrapping
+	class of asio::deadline_timer to use as interval timer.
+	Added a command 'sendstats' to send counter values at once.
+	(Trac #347, svn rxxxx)
+
   122.  [func]		stephen
 	src/bin/bind10: Added configuration options to Boss to determine
 	whether to start the authoritative server, recursive server (or

+ 1 - 0
src/bin/auth/Makefile.am

@@ -58,6 +58,7 @@ pkglibexec_PROGRAMS = b10-auth
 b10_auth_SOURCES = auth_srv.cc auth_srv.h
 b10_auth_SOURCES += change_user.cc change_user.h
 b10_auth_SOURCES += common.h
+b10_auth_SOURCES += stats.cc stats.h
 b10_auth_SOURCES += main.cc
 b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/libdatasrc.la
 b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la

+ 74 - 0
src/bin/auth/asio_link.cc

@@ -666,4 +666,78 @@ IOService::setCallBack(const IOCallBack callback) {
         impl_->tcp6_server_->setCallBack(&impl_->callback_);
     }
 }
+
+class IntervalTimerImpl {
+private:
+    // prohibit copy to avoid the function be called twice
+    IntervalTimerImpl(const IntervalTimerImpl& source);
+    IntervalTimerImpl& operator=(const IntervalTimerImpl& source);
+public:
+    IntervalTimerImpl(asio::io_service& io_service);
+    ~IntervalTimerImpl();
+    bool setupTimer(const IntervalTimer::Callback& cbfunc,
+                    const uint32_t interval);
+    void callback(const asio::error_code& error);
+private:
+    void updateTimer();
+    IntervalTimer::Callback cbfunc_;
+    // interval in seconds
+    uint32_t interval_;
+    asio::deadline_timer timer_;
+};
+
+IntervalTimerImpl::IntervalTimerImpl(asio::io_service& io_service) :
+    timer_(io_service)
+{}
+
+IntervalTimerImpl::~IntervalTimerImpl() {
+    timer_.cancel();
+}
+
+bool
+IntervalTimerImpl::setupTimer(const IntervalTimer::Callback& cbfunc,
+                              const uint32_t interval)
+{
+    // interval value must be positive
+    assert(interval > 0);
+    cbfunc_ = cbfunc;
+    interval_ = interval;
+    // start timer
+    updateTimer();
+    return (true);
+}
+
+void
+IntervalTimerImpl::updateTimer() {
+    // update expire time (current time + interval_)
+    timer_.expires_from_now(boost::posix_time::seconds(interval_));
+    // restart timer
+    timer_.async_wait(boost::bind(&IntervalTimerImpl::callback, this, _1));
+}
+
+void
+IntervalTimerImpl::callback(const asio::error_code& cancelled) {
+    assert(!cbfunc_.empty());
+    // skip function call in case the timer was cancelled
+    if (!cancelled) {
+        cbfunc_();
+        // restart timer
+        updateTimer();
+    }
+}
+
+IntervalTimer::IntervalTimer(asio::io_service& io_service) {
+    impl_ = new IntervalTimerImpl(io_service);
+}
+
+IntervalTimer::~IntervalTimer() {
+    delete impl_;
+}
+
+bool
+IntervalTimer::setupTimer(const Callback& cbfunc,
+                                const uint32_t interval)
+{
+    return (impl_->setupTimer(cbfunc, interval));
+}
 }

+ 41 - 0
src/bin/auth/asio_link.h

@@ -89,6 +89,7 @@ class AuthSrv;
 
 namespace asio_link {
 class IOServiceImpl;
+struct IntervalTimerImpl;
 
 /// \brief An exception that is thrown if an error occurs within the IO
 /// module.  This is mainly intended to be a wrapper exception class for
@@ -444,6 +445,46 @@ public:
 private:
     IOServiceImpl* impl_;
 };
+
+/// \brief The \c IntervalTimer class is a wrapper for the ASIO \c deadline_timer
+/// class.
+///
+/// This class is implemented to use boost::deadline_timer as interval timer.
+/// Copy of this class is prohibited not to call the callback function twice.
+class IntervalTimer {
+public:
+    /// \name The type of timer callback function
+    typedef boost::function<void(void)> Callback;
+
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are
+    /// intentionally defined as private, making this class non-copyable.
+    //@{
+private:
+    IntervalTimer(const IntervalTimer& source);
+    IntervalTimer& operator=(const IntervalTimer& source);
+public:
+    /// \brief The constructor with asio::io_service.
+    ///
+    /// \param io_service A reference to an instance of asio::io_service
+    IntervalTimer(asio::io_service& io_service);
+    /// \brief The destructor.
+    ~IntervalTimer();
+    //@}
+
+    /// \brief Register timer callback function
+    ///
+    /// \param cbfunc A reference to a function to call back
+    /// when the timer is expired
+    /// \param interval Interval in seconds
+    ///
+    /// \return \c true on success
+    bool setupTimer(const Callback& cbfunc, const uint32_t interval);
+private:
+    IntervalTimerImpl* impl_;
+};
 }      // asio_link
 #endif // __ASIO_LINK_H
 

+ 5 - 0
src/bin/auth/auth.spec.pre.in

@@ -14,6 +14,11 @@
         "command_name": "shutdown",
         "command_description": "Shut down authoritative DNS server",
         "command_args": []
+      },
+      {
+        "command_name": "sendstats",
+        "command_description": "Send statistics data to b10-stats at once",
+        "command_args": []
       }
     ]
   }

+ 29 - 1
src/bin/auth/auth_srv.cc

@@ -128,10 +128,13 @@ AuthSrvImpl::~AuthSrvImpl() {
 
 AuthSrv::AuthSrv(const bool use_cache, AbstractXfroutClient& xfrout_client) :
     impl_(new AuthSrvImpl(use_cache, xfrout_client))
-{}
+{
+    counter = new statistics::Counter(impl_->verbose_mode_);
+}
 
 AuthSrv::~AuthSrv() {
     delete impl_;
+    delete counter;
 }
 
 namespace {
@@ -214,6 +217,11 @@ AuthSrv::setConfigSession(ModuleCCSession* config_session) {
     impl_->config_session_ = config_session;
 }
 
+void
+AuthSrv::setStatsSession(AbstractSession* stats_session) {
+    counter->setStatsSession(stats_session);
+}
+
 ModuleCCSession*
 AuthSrv::getConfigSession() const {
     return (impl_->config_session_);
@@ -266,6 +274,19 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         cerr << "[b10-auth] received a message:\n" << message.toText() << endl;
     }
 
+    // increment Query Counter
+    if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
+        counter->inc(statistics::Counter::COUNTER_UDP);
+    } else if (io_message.getSocket().getProtocol() == IPPROTO_TCP) {
+        counter->inc(statistics::Counter::COUNTER_TCP);
+    } else {
+        // unknown protocol
+        if (impl_->verbose_mode_) {
+            cerr << "[b10-auth] Unknown protocol: " <<
+                     io_message.getSocket().getProtocol() << endl;
+        }
+    }
+
     // Perform further protocol-level validation.
 
     if (message.getOpcode() == Opcode::NOTIFY()) {
@@ -543,3 +564,10 @@ AuthSrv::updateConfig(ConstElementPtr new_config) {
         return (isc::config::createAnswer(1, error.what()));
     }
 }
+
+asio_link::IntervalTimer::Callback
+AuthSrv::getStatsCallback() {
+    // just invoke statistics::Counter::getStatsCallback()
+    // and return its return value
+    return (counter->getCallback());
+}

+ 26 - 0
src/bin/auth/auth_srv.h

@@ -22,6 +22,12 @@
 #include <cc/data.h>
 #include <config/ccsession.h>
 
+/// for the typedef of asio_link::IntervalTimer::Callback
+#include <auth/asio_link.h>
+
+// for class statistics::Counter
+#include <auth/stats.h>
+
 namespace isc {
 namespace dns {
 class InputBuffer;
@@ -199,8 +205,28 @@ public:
     /// is shutdown.
     ///
     void setXfrinSession(isc::cc::AbstractSession* xfrin_session);
+
+    /// \brief Set the communication session with Statistics.
+    ///
+    void setStatsSession(isc::cc::AbstractSession* stats_session);
+
+    /// \brief Return the function that sends statistics information
+    /// to Statistics module.
+    /// 
+    /// This function returns the return value of
+    /// statistics::Counter::getCallback().
+    ///
+    /// \return \c boost::function which contains the procedure
+    /// to send statistics.
+    asio_link::IntervalTimer::Callback getStatsCallback();
 private:
     AuthSrvImpl* impl_;
+
+    // TODO: consider where to put the counter.
+    // Currently, count-up is in AuthSrv::processMessage.
+    // In the future, count-up will be in AuthSrvImpl::process*Query
+    // and this declaration will be moved into AuthSrvImpl.
+    statistics::Counter *counter;
 };
 
 #endif // __AUTH_SRV_H

+ 1 - 0
src/bin/auth/benchmarks/Makefile.am

@@ -9,6 +9,7 @@ CLEANFILES = *.gcno *.gcda
 noinst_PROGRAMS = query_bench
 query_bench_SOURCES = query_bench.cc
 query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
+query_bench_SOURCES += ../stats.h ../stats.cc
 
 query_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
 query_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la

+ 35 - 0
src/bin/auth/main.cc

@@ -59,6 +59,10 @@ bool verbose_mode = false;
 const string PROGRAM = "Auth";
 const char* DNSPORT = "5300";
 
+// Note: this value must be greater than 0.
+// TODO: make it configurable via command channel.
+const uint32_t STATS_SEND_INTERVAL_SEC = 60;
+
 /* need global var for config/command handlers.
  * todo: turn this around, and put handlers in the authserver
  * class itself? */
@@ -81,6 +85,13 @@ my_command_handler(const string& command, ConstElementPtr args) {
         answer = createAnswer(0, args);
     } else if (command == "shutdown") {
         io_service->stop();
+    } else if (command == "sendstats") {
+        if (verbose_mode) {
+            cerr << "[b10-auth] command 'sendstats' received" << endl;
+        }
+        if (auth_server != NULL) {
+            auth_server->getStatsCallback()();
+        }
     }
     
     return (answer);
@@ -154,7 +165,10 @@ main(int argc, char* argv[]) {
     // XXX: we should eventually pass io_service here.
     Session* cc_session = NULL;
     Session* xfrin_session = NULL;
+    Session* stats_session = NULL;
+    asio_link::IntervalTimer* itimer = NULL;
     bool xfrin_session_established = false; // XXX (see Trac #287)
+    bool stats_session_established = false; // XXX (see Trac #287)
     ModuleCCSession* config_session = NULL;
     string xfrout_socket_path;
     if (getenv("B10_FROM_BUILD") != NULL) {
@@ -209,15 +223,30 @@ main(int argc, char* argv[]) {
         xfrin_session_established = true;
         cout << "[b10-auth] Xfrin session channel established." << endl;
 
+        stats_session = new Session(io_service->get_io_service());
+        cout << "[b10-auth] Stats session channel created." << endl;
+        stats_session->establish(NULL);
+        stats_session_established = true;
+        cout << "[b10-auth] Stats session channel established." << endl;
+
         // XXX: with the current interface to asio_link we have to create
         // auth_server before io_service while Session needs io_service.
         // In a next step of refactoring we should make asio_link independent
         // from auth_server, and create io_service, auth_server, and
         // sessions in that order.
         auth_server->setXfrinSession(xfrin_session);
+        auth_server->setStatsSession(stats_session);
         auth_server->setConfigSession(config_session);
         auth_server->updateConfig(ElementPtr());
 
+        // create interval timer instance
+        itimer = new asio_link::IntervalTimer(io_service->get_io_service());
+        // set up interval timer
+        // register function to send statistics with interval
+        itimer->setupTimer(auth_server->getStatsCallback(),
+                           STATS_SEND_INTERVAL_SEC);
+        cout << "[b10-auth] Interval timer set to send stats." << endl;
+
         cout << "[b10-auth] Server started." << endl;
         io_service->run();
     } catch (const std::exception& ex) {
@@ -225,10 +254,16 @@ main(int argc, char* argv[]) {
         ret = 1;
     }
 
+    if (stats_session_established) {
+        stats_session->disconnect();
+    }
+
     if (xfrin_session_established) {
         xfrin_session->disconnect();
     }
 
+    delete itimer;
+    delete stats_session;
     delete xfrin_session;
     delete config_session;
     delete cc_session;

+ 148 - 0
src/bin/auth/stats.cc

@@ -0,0 +1,148 @@
+// Copyright (C) 2010  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.
+
+// $Id$
+
+#include <boost/bind.hpp>
+
+#include <auth/stats.h>
+
+#include <cc/data.h>
+
+#include <sstream>
+#include <iostream>
+
+namespace statistics {
+
+class CounterImpl {
+private:
+    // prohibit copy
+    CounterImpl(const CounterImpl& source);
+    CounterImpl& operator=(const CounterImpl& source);
+public:
+    CounterImpl(const bool& verbose_mode);
+    ~CounterImpl();
+    void inc(const Counter::CounterType type);
+    asio_link::IntervalTimer::Callback getCallback();
+    void sendStats();
+    void setStatsSession(isc::cc::AbstractSession* stats_session);
+private:
+    std::vector<uint64_t>* counters_;
+    isc::cc::AbstractSession* stats_session_;
+    const bool& verbose_mode_;
+};
+
+CounterImpl::CounterImpl(const bool& verbose_mode) :
+    // initialize counter
+    // size: Counter::COUNTER_TYPES, initial value: 0
+    stats_session_(NULL),
+    verbose_mode_(verbose_mode)
+{
+    counters_ = new std::vector<uint64_t>(Counter::COUNTER_TYPES, 0);
+}
+
+CounterImpl::~CounterImpl() {
+    delete counters_;
+}
+
+void
+CounterImpl::inc(const Counter::CounterType type)
+{
+    ++counters_->at(type);
+}
+
+asio_link::IntervalTimer::Callback
+CounterImpl::getCallback()
+{
+    return (boost::bind(&CounterImpl::sendStats, this));
+}
+
+void
+CounterImpl::sendStats()
+{
+    if (stats_session_ == NULL) {
+        if (verbose_mode_) {
+            std::cerr << "[b10-auth] "
+                      << "session interface for statistics"
+                      << " is not available" << std::endl;
+        }
+        return;
+    }
+    std::stringstream strstats;
+    strstats << "{\"command\": [\"set\","
+             <<   "{ \"stats_data\": "
+             <<     "{ \"auth.queries.udp\": "
+             <<     counters_->at(Counter::COUNTER_UDP)
+             <<     ", \"auth.queries.tcp\": "
+             <<     counters_->at(Counter::COUNTER_TCP)
+             <<   " }"
+             <<   "}"
+             << "]}";
+    isc::data::ConstElementPtr set_stats =
+        isc::data::Element::fromJSON(strstats);
+    try {
+        // group_recvmsg() will time out in MSGQ_DEFAULT_TIMEOUT.
+        // On timeout or error, an exception will be thrown
+        const int seq =
+            stats_session_->group_sendmsg(set_stats, "Stats");
+        isc::data::ConstElementPtr env, answer;
+        if (verbose_mode_) {
+            std::cerr << "[b10-auth] "
+                      << "send statistics data to b10-stats"
+                      << std::endl;
+        }
+        // TODO: parse and check response from b10-stats
+        // currently it just returns empty message
+        stats_session_->group_recvmsg(env, answer, false, seq);
+    } catch (const isc::Exception& ex) {
+        // catch the exception and do nothing.
+        if (verbose_mode_) {
+            std::cerr << "[b10-auth] "
+                      << "failed to send statistics data to b10-stats: "
+                      << ex.what() << std::endl;
+        }
+    }
+    return;
+}
+
+void
+CounterImpl::setStatsSession(isc::cc::AbstractSession* stats_session) {
+    stats_session_ = stats_session;
+}
+
+Counter::Counter(const bool& verbose_mode) :
+    impl_(new CounterImpl(verbose_mode))
+{}
+
+Counter::~Counter() {
+    delete impl_;
+}
+
+asio_link::IntervalTimer::Callback
+Counter::getCallback()
+{
+    return (impl_->getCallback());
+}
+
+void
+Counter::inc(const Counter::CounterType type) {
+    impl_->inc(type);
+}
+
+void
+Counter::setStatsSession(isc::cc::AbstractSession* stats_session) {
+    impl_->setStatsSession(stats_session);
+}
+
+} // statistics

+ 86 - 0
src/bin/auth/stats.h

@@ -0,0 +1,86 @@
+// Copyright (C) 2010  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.
+
+// $Id$
+
+#ifndef __STATS_H
+#define __STATS_H 1
+
+#include <boost/function.hpp>
+
+#include <cc/session.h>
+
+/// for asio_link::IntervalTimer::Callback
+#include <auth/asio_link.h>
+
+namespace statistics {
+
+class CounterImpl;
+
+/// \brief A query counter.
+///
+/// \c Counter is a query counter class. It holds query counter
+/// and provide an interface to increment the counter.
+/// This class also provides a function to send information to
+/// statistics (b10-stats).
+///
+/// This class uses pimpl idiom and hides detailed implementation.
+/// This class is constructed on startup of the server, so
+/// construction overhead of this approach should be acceptable.
+class Counter {
+private:
+    CounterImpl* impl_;
+public:
+    // Enum for the type of counter
+    // COUNTER_UDP: counter for UDP queries
+    // COUNTER_TCP: counter for TCP queries
+    enum CounterType {
+        COUNTER_UDP = 0,
+        COUNTER_TCP = 1,
+        COUNTER_TYPES = 2
+    };
+    /// The constructor.
+    ///
+    /// verbose_mode references verbose_mode_ of AuthSrvImpl
+    Counter(const bool& verbose_mode);
+    /// The destructor.
+    ~Counter();
+
+    /// \brief Increment the counter specified by the parameter
+    ///
+    /// \param type Type of a counter to increment
+    /// usage: counter->inc(CounterType::COUNTER_DUP);
+    /// 
+    void inc(const CounterType type);
+
+    /// \brief Get the function to send statistics information
+    /// to Statistics module
+    ///
+    /// The returned function is inteneded to be called
+    /// perioically.
+    ///
+    /// \return \c asio_link::IntervalTimer::Callback points
+    /// to a function to send statistics
+    asio_link::IntervalTimer::Callback getCallback();
+
+    /// \brief Set the session to communicate with Statistics
+    /// module
+    ///
+    /// \param stats_session A pointer to the session
+    void setStatsSession(isc::cc::AbstractSession* stats_session);
+};
+
+} // statistics
+
+#endif // __STATS_H

+ 1 - 0
src/bin/auth/tests/Makefile.am

@@ -22,6 +22,7 @@ run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
 run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
 run_unittests_SOURCES += ../auth_srv.h ../auth_srv.cc
 run_unittests_SOURCES += ../change_user.h ../change_user.cc
+run_unittests_SOURCES += ../stats.h ../stats.cc
 run_unittests_SOURCES += auth_srv_unittest.cc
 run_unittests_SOURCES += change_user_unittest.cc
 run_unittests_SOURCES += asio_link_unittest.cc

+ 32 - 0
src/bin/auth/tests/asio_link_unittest.cc

@@ -252,6 +252,15 @@ protected:
                             callback_data_.size(),
                             expected_data, expected_datasize);
     }
+    void doTimerTest(asio_link::IntervalTimer* itimer) {
+        // interval timer test
+        // set test_obj_->timerCallBack() as callback function
+        // and check that the function was called
+        timer_called_ = false;
+        EXPECT_TRUE(itimer->setupTimer(TimerCallBack(this), 1));
+        io_service_->run();
+        EXPECT_TRUE(timer_called_);
+    }
 private:
     class ASIOCallBack : public std::unary_function<IOMessage, void> {
     public:
@@ -273,12 +282,27 @@ private:
             io_message.getDataSize());
         io_service_->stop();
     }
+private:
+    class TimerCallBack : public std::unary_function<void, void> {
+    public:
+        TimerCallBack(ASIOLinkTest* test_obj) : test_obj_(test_obj) {}
+        void operator()(void) const {
+            test_obj_->timerCallBack();
+        }
+    private:
+        ASIOLinkTest* test_obj_;
+    };
+    void timerCallBack() {
+        timer_called_ = true;
+        io_service_->stop();
+    }
 protected:
     IOService* io_service_;
     int callback_protocol_;
     int callback_native_;
     string callback_address_;
     vector<uint8_t> callback_data_;
+    bool timer_called_;
     int sock_;
 private:
     struct addrinfo* res_;
@@ -354,4 +378,12 @@ TEST_F(ASIOLinkTest, v4TCPOnly) {
     EXPECT_THROW(sendTCP(AF_INET6), IOError);
 }
 
+TEST_F(ASIOLinkTest, startIntervalTimer) {
+    // Create asio_link::IntervalTimer and setup.
+    // Then run IOService and test if the callback function is called.
+    setIOService(false, false);
+    asio_link::IntervalTimer *itimer = new asio_link::IntervalTimer(io_service_->get_io_service());
+    doTimerTest(itimer);
+    delete itimer;
+}
 }

+ 59 - 1
src/bin/auth/tests/auth_srv_unittest.cc

@@ -44,6 +44,7 @@ using namespace isc::dns;
 using namespace isc::data;
 using namespace isc::xfr;
 using namespace asio_link;
+using namespace statistics;
 
 namespace {
 const char* const CONFIG_TESTDB =
@@ -120,15 +121,18 @@ protected:
                     qclass(RRClass::IN()), qtype(RRType::A()),
                     io_message(NULL), endpoint(NULL), request_obuffer(0),
                     request_renderer(request_obuffer),
-                    response_obuffer(0), response_renderer(response_obuffer)
+                    response_obuffer(0), response_renderer(response_obuffer),
+                    counter(counter_verbose)
     {
         server.setXfrinSession(&notify_session);
+        server.setStatsSession(&stats_session);
     }
     ~AuthSrvTest() {
         delete io_message;
         delete endpoint;
     }
     MockSession notify_session;
+    MockSession stats_session;
     MockXfroutClient xfrout;
     AuthSrv server;
     Message request_message;
@@ -145,6 +149,12 @@ protected:
     OutputBuffer response_obuffer;
     MessageRenderer response_renderer;
     vector<uint8_t> data;
+    // for Counter unittest
+    // TODO: consider where to put Counter
+    // AuthSrvTest is now includes a test for Counter
+    // In future make a test class CounterTest
+    bool counter_verbose;
+    Counter counter;
 
     void createDataFromFile(const char* const datafile, int protocol);
     void createRequestMessage(const Opcode& opcode, const Name& request_name,
@@ -767,4 +777,52 @@ TEST_F(AuthSrvTest, cacheSlots) {
     server.setCacheSlots(0);
     EXPECT_EQ(00, server.getCacheSlots());
 }
+
+TEST_F(AuthSrvTest, statsCallback) {
+    // getStatsCallback() test
+    // expect returning a valid function
+    asio_link::IntervalTimer::Callback cbFunc;
+    cbFunc = server.getStatsCallback();
+    EXPECT_FALSE(cbFunc.empty());
+}
+
+TEST_F(AuthSrvTest, sendStatsWithoutSession) {
+    // to cover the code path in case the stats session is not set
+    // expect to put an error message
+    server.setStatsSession(NULL);
+    bool verbose = server.getVerbose();
+    server.setVerbose(true);
+    server.getStatsCallback()();
+    server.setVerbose(verbose);
+}
+
+//
+// statistics::Counter unittest
+
+TEST_F(AuthSrvTest, counter_incUDP) {
+    counter.inc(Counter::COUNTER_UDP);
+}
+
+TEST_F(AuthSrvTest, counter_incTCP) {
+    counter.inc(Counter::COUNTER_TCP);
+}
+
+TEST_F(AuthSrvTest, counter_incUnknown) {
+    EXPECT_THROW(counter.inc(Counter::COUNTER_TYPES), std::out_of_range);
+}
+
+TEST_F(AuthSrvTest, counter_getCallback) {
+    // getCallback() test
+    // expect returning a valid function
+    asio_link::IntervalTimer::Callback cbFunc;
+    cbFunc = counter.getCallback();
+    EXPECT_FALSE(cbFunc.empty());
+}
+
+TEST_F(AuthSrvTest, counter_sendStatsWithSession) {
+    // Test the function to send statistics information to b10-stats
+    // expect to run without throwing any exception
+    counter.setStatsSession(&stats_session);
+    counter.getCallback()();
+}
 }

+ 1 - 1
src/bin/bind10/bind10.py.in

@@ -544,10 +544,10 @@ class BoB:
         self.cc_session.group_sendmsg(cmd, "ConfigManager", "ConfigManager")
         self.cc_session.group_sendmsg(cmd, "Auth", "Auth")
         self.cc_session.group_sendmsg(cmd, "Recurse", "Recurse")
+        self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
         self.cc_session.group_sendmsg(cmd, "Xfrout", "Xfrout")
         self.cc_session.group_sendmsg(cmd, "Xfrin", "Xfrin")
         self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")
-        self.cc_session.group_sendmsg(cmd, "Boss", "Stats")
 
     def stop_process(self, process):
         """Stop the given process, friendly-like."""