BIND 10 trac930, updated. c470ef720afcc366232cecc55dbb6257df7a07f6 [trac930] add changes because query counter names described in the specfile are changed.

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Jul 22 11:04:14 UTC 2011


The branch, trac930 has been updated
  discards  372471fb8b522e639b6a4bcf8a93eb0d06dfbe6a (commit)
  discards  b2aec5f9113d8fff197c8779e09cf0e8e3ed5a53 (commit)
  discards  3fe1e47ee5d0896e62fbfdb73be724e7fe48ee16 (commit)
  discards  60f8ec5a6641c0553d2c8933101551bd6142b3a3 (commit)
  discards  47988290be92cd09e32d2ee3f51179f9133e2bfc (commit)
  discards  edf3a943c94921c528a4132b2c65b609701a5668 (commit)
  discards  6f67259c2de2a336fa5e038756da57be1a70e427 (commit)
  discards  b8f9e3f9bbcd6626064093f474940ad06e884d0f (commit)
  discards  133f0001fafea84190e73e766fca8b6d87c8c09c (commit)
  discards  514963d8458ef888d9bc07e138e0051d3f697bac (commit)
  discards  1087e06463720a1491aafcce6ee7f8694e83ebc5 (commit)
  discards  e75e95121605158605452a9ba6917d1e29b925af (commit)
  discards  0b81f6faa78ba4ad7c010af476a5af6a3fd1db54 (commit)
  discards  4201a627a42c9b7e9cbf9c8ac17792d07686e9b7 (commit)
  discards  13252373f8307c13642990ce7acd3ac5a3395f5e (commit)
  discards  86671ed6103a70fb0d7df2bd5fff4dc7e3b05dd1 (commit)
  discards  5475b3a80199fed9a007e6d5d89ef18013a15b67 (commit)
  discards  a13e9592cec4afb50759e2900551a62867b8c9a6 (commit)
  discards  acc6f06a09cce9a11ebf1ea8441aa78ba5a8c6b9 (commit)
  discards  4822c0d4fb880fe881b505fb78578f2076c9ba95 (commit)
  discards  d0ec422478e20dedd71c836cc76d9afc0e2fd8e9 (commit)
  discards  c2f743fb187ae98111aaa5b4789ba1641d32f986 (commit)
       via  c470ef720afcc366232cecc55dbb6257df7a07f6 (commit)
       via  88bc916092c93976a539256c6f49a1b9f751403c (commit)
       via  b00b835feaba28c2490acf966f6f766092b01663 (commit)
       via  07e432ff00cbbe6814896083cc6193b3f5f50077 (commit)
       via  8e3feb3306471399c42abe6e19116fb11fb0082b (commit)
       via  1170bbea14723782657aa2ff77e82f0ef6517cfe (commit)
       via  26be98d9f4677c12e1573d8babd0670c43c86503 (commit)
       via  20aacc60cc9e9ee47d1510cb069561abea44438c (commit)
       via  5565e1218b7694b1ceedd3ac86abdff3a303f868 (commit)
       via  f1e3fbb5513e3d767a3c6c575193e9c3adb75f69 (commit)
       via  8fa853a2021d3f03fb6cba9f33e2bb00f69a87fd (commit)
       via  e60721208d5be0b0d62f02c24495c6d0d952343c (commit)
       via  b76a84efc6138689cb65b0c43936886e39dc6ee5 (commit)
       via  3188ad7a466386e8ef0852575e85048367fce8c0 (commit)
       via  0621b921d8dbe8a3862d21b97f008064fd96f8e1 (commit)
       via  a9958ac963f7187c5c63003d853cc54507819bd2 (commit)
       via  8370f4300fad9e9ae4126521fe0c6c28e601de0a (commit)
       via  5ed6fabaa368f360ab2c65a9fce0e66fdb4d3a01 (commit)
       via  63835fd548d761461f5d723ff469204cd6de4029 (commit)
       via  f61e9e236c089122b90914924b3f1ab0a17a052f (commit)
       via  ae1dc0aa6e33f0249fca9ae98e8179d3d1dac7ad (commit)
       via  e32fbc918060f9407f1b76e9e0dd20eac46bc39a (commit)
       via  9ab3a2e5c02edc14f22562dc7a4d7e9087bca735 (commit)
       via  456de3a5647fa836547b6238169aebbec933f852 (commit)
       via  343ee47dcdf0d1d48eba525189db5c0cc789d4f3 (commit)
       via  2d74f6935838788ac864de5f647734dd4aff085c (commit)
       via  9162b03e7e66c7f3763e854ef6d7c56dd576aae6 (commit)
       via  406019a4e371e1de2412bd206e299601eba545d9 (commit)
       via  1d22cafef31ee83ab4ed646e67f9cd57ab1d30ce (commit)
       via  2fc3572cc76548463f8342cd2f0d9b92b14bb732 (commit)
       via  39901e5b831ba424c8aa17d06ecba87d53fdce4c (commit)
       via  42042bbaeaa7bc1523bb23e3e6cb9f3a84a1638a (commit)
       via  26100f264a9c48aa80748256db1e94c6091ba729 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (372471fb8b522e639b6a4bcf8a93eb0d06dfbe6a)
            \
             N -- N -- N (c470ef720afcc366232cecc55dbb6257df7a07f6)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit c470ef720afcc366232cecc55dbb6257df7a07f6
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:50:41 2011 +0900

    [trac930] add changes because query counter names described in the specfile are changed.

commit 88bc916092c93976a539256c6f49a1b9f751403c
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:45:19 2011 +0900

    [trac930] add the logging when the validation of statistics data fails

commit b00b835feaba28c2490acf966f6f766092b01663
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:43:26 2011 +0900

    [trac930] Add unittests to test sumitStatistics with the validation of statistics data and add mock ModuleSpec class

commit 07e432ff00cbbe6814896083cc6193b3f5f50077
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:41:34 2011 +0900

    [trac930] Add prototypes of validator_typea and registerStatisticsValidator
     - validator_type -- a type of statistics validation function
     - registerStatisticsValidator -- the function to register the validation function

commit 8e3feb3306471399c42abe6e19116fb11fb0082b
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:37:22 2011 +0900

    [trac930]
    - Add implementation to validate statistics data
      -- When validation is success, it sends data to statistics module. But when it fails, it doesn't send and logs the message.
    
    - Add the function to register the validation function into the class

commit 1170bbea14723782657aa2ff77e82f0ef6517cfe
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:32:22 2011 +0900

    [trac930] add the helper functions which are used around the registration of the function to validate the statistics data.

commit 26be98d9f4677c12e1573d8babd0670c43c86503
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:28:40 2011 +0900

    [trac930] add new messages into the message file of Auth and Boss
    when validation of statistics data to send to statistics module is failed.

commit 20aacc60cc9e9ee47d1510cb069561abea44438c
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 20 10:00:29 2011 +0900

    [trac930] add statistics validation for bob

commit 5565e1218b7694b1ceedd3ac86abdff3a303f868
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 13 20:25:54 2011 +0900

    [trac930]
     - increase seconds in sleep time which is before HTTP client connects to the server
     - delete 'test_log_message' because of the deletion of original function

commit f1e3fbb5513e3d767a3c6c575193e9c3adb75f69
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 21:22:34 2011 +0900

    [trac930] remove unneeded empty TODO comments

commit 8fa853a2021d3f03fb6cba9f33e2bb00f69a87fd
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 21:09:41 2011 +0900

    [trac930] add new entry for #928-#930

commit e60721208d5be0b0d62f02c24495c6d0d952343c
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 20:08:22 2011 +0900

    [trac930] refurbish the unittests for new stats module, new stats httpd module
    and new mockups and utilities in test_utils.py

commit b76a84efc6138689cb65b0c43936886e39dc6ee5
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 19:56:24 2011 +0900

    [trac930] modify Stats
     - remove unneeded subject and listener classes
    
     - add StatsError for handling errors in Stats
    
     - add some new methods (update_modules, update_statistics_data and
       get_statistics_data)
    
     - modify implementations of existent commands(show and set) according changes
       stats.spec
    
     - remove reset and remove command because stats module couldn't manage other
       modules' statistics data schema
    
     - add implementation of strict validation of each statistics data
       (If the validation is failed, it puts out the error.)
    
     - stats module shows its PID when status command invoked
    
     - add new command showschema invokable via bindctl
    
     - set command requires arguments of owner module name and statistics item name
    
     - show and showschema commands accepts arguments of owner module name and
       statistics item name
    
     - exits at exit code 1 if got runtime errors
    
     - has boot time in _BASETIME

commit 3188ad7a466386e8ef0852575e85048367fce8c0
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 19:40:15 2011 +0900

    [trac930]
     - remove "stats-schema.spec" setting and getting statistics data schema via
       this spec file
    
     - add "version" item in DEFAULT_CONFIG
    
     - get the address family by socket.getaddrinfo function with specified
       server_address in advance, and create HttpServer object once, in stead of
       creating double HttpServer objects for IPv6 and IPv4 in the prior code
       (It is aimed for avoiding to fail to close the once opened sockets.)
    
     - open HTTP port in start method
    
     - avoid calling config_handler recursively in the except statement
    
     - create XML, XSD, XSL documents after getting statistics data and schema from
       remote stats module via CC session
    
     - definitely close once opened template file object

commit 0621b921d8dbe8a3862d21b97f008064fd96f8e1
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:33:59 2011 +0900

    [trac930] update spec file of stats module
    - update description of status command, shutdown command and show command
    - change argument of show command (Owner module name of statistics data can be
    specified)
    - change argument of set command (Owner module name of statistics data is
    always required)
    - add showschema command which shows statistics data schema of each module
    specified)
    - disabled reset command and remove command

commit a9958ac963f7187c5c63003d853cc54507819bd2
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:21:49 2011 +0900

    [trac930] update argument name and argument format of set command in auth module and boss module
    and also update related unittests of their modules

commit 8370f4300fad9e9ae4126521fe0c6c28e601de0a
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:18:38 2011 +0900

    [trac930] remove description about removing statistics data by stats module
    update example format in bindctl when show command of stats module is invoked

commit 5ed6fabaa368f360ab2c65a9fce0e66fdb4d3a01
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:13:17 2011 +0900

    [trac930] add a column "Owner" in the table tag

commit 63835fd548d761461f5d723ff469204cd6de4029
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:12:09 2011 +0900

    [trac930] remove descriptions about "stats-schema.spec" and add description about new
    features because stats module can be requested to show statistics data schema.

commit f61e9e236c089122b90914924b3f1ab0a17a052f
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:00:30 2011 +0900

    [trac930] add utilities and mock-up modules for unittests of
    statistics modules and change some environ variables (PYTHONPATH,
    CONFIG_TESTDATA_PATH) in Makefile
    
    test_utilies.py internally calls msgq, cfgmgr and some mock modules
    with threads for as real situation as possible.

commit ae1dc0aa6e33f0249fca9ae98e8179d3d1dac7ad
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 15:57:41 2011 +0900

    [trac930] remove unneeded mockups, fake modules and dummy data

commit e32fbc918060f9407f1b76e9e0dd20eac46bc39a
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 15:55:55 2011 +0900

    [trac930] remove unneeded specfile "stats-schema.spec"

-----------------------------------------------------------------------

Summary of changes:
 src/bin/auth/auth_messages.mes                     |    3 +
 src/bin/auth/auth_srv.cc                           |   24 ++++
 src/bin/auth/statistics.cc                         |   25 ++++
 src/bin/auth/statistics.h                          |   20 +++
 src/bin/auth/tests/statistics_unittest.cc          |   66 +++++++++-
 src/bin/bind10/bind10.py.in                        |   22 ++-
 src/bin/bind10/bind10_messages.mes                 |    3 +
 src/bin/bind10/tests/bind10_test.py.in             |   18 +++
 src/bin/cfgmgr/plugins/logging.spec                |    3 +-
 src/bin/cfgmgr/plugins/tsig_keys.spec              |    3 +-
 src/bin/cmdctl/cmdctl.spec.pre.in                  |    3 +-
 src/bin/dhcp6/dhcp6.spec                           |    3 +-
 src/bin/resolver/resolver.spec.pre.in              |    3 +-
 src/bin/stats/stats-httpd.spec                     |    3 +-
 src/bin/stats/stats-schema.spec                    |   87 ++++++++++++
 src/bin/stats/tests/testdata/stats_test.spec       |   19 +++
 src/bin/xfrin/xfrin.spec                           |    3 +-
 src/bin/xfrout/xfrout.spec.pre.in                  |    3 +-
 src/bin/zonemgr/zonemgr.spec.pre.in                |    3 +-
 src/lib/config/module_spec.cc                      |   84 +++++++++++-
 src/lib/config/module_spec.h                       |   23 +++-
 src/lib/config/tests/module_spec_unittests.cc      |  145 +++++++++++++++++++-
 .../python/isc/config/tests/module_spec_test.py    |    3 +
 tests/system/bindctl/tests.sh                      |   16 ++-
 24 files changed, 550 insertions(+), 35 deletions(-)
 create mode 100644 src/bin/stats/stats-schema.spec
 create mode 100644 src/bin/stats/tests/testdata/stats_test.spec

-----------------------------------------------------------------------
diff --git a/src/bin/auth/auth_messages.mes b/src/bin/auth/auth_messages.mes
index 2bb402c..ec9fa8a 100644
--- a/src/bin/auth/auth_messages.mes
+++ b/src/bin/auth/auth_messages.mes
@@ -257,4 +257,7 @@ request. The zone manager component has been informed of the request,
 but has returned an error response (which is included in the message). The
 NOTIFY request will not be honored.
 
+% AUTH_INVALID_STATISTICS_DATA invalid specification of statistics data specified
+An error was encountered when the authoritiative server specified
+statistics data which is invalid for the auth specification file.
 
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index f29fd05..acc9d4f 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -125,6 +125,10 @@ public:
 
     /// The TSIG keyring
     const shared_ptr<TSIGKeyRing>* keyring_;
+
+    /// Bind the ModuleSpec object in config_session_ with
+    /// isc:config::ModuleSpec::validateStatistics.
+    void registerStatisticsValidator();
 private:
     std::string db_file_;
 
@@ -139,6 +143,9 @@ private:
 
     /// Increment query counter
     void incCounter(const int protocol);
+
+    // validateStatistics
+    bool validateStatistics(isc::data::ConstElementPtr data) const;
 };
 
 AuthSrvImpl::AuthSrvImpl(const bool use_cache,
@@ -317,6 +324,7 @@ AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
 void
 AuthSrv::setConfigSession(ModuleCCSession* config_session) {
     impl_->config_session_ = config_session;
+    impl_->registerStatisticsValidator();
 }
 
 void
@@ -670,6 +678,22 @@ AuthSrvImpl::incCounter(const int protocol) {
     }
 }
 
+void
+AuthSrvImpl::registerStatisticsValidator() {
+    counters_.registerStatisticsValidator(
+        boost::bind(&AuthSrvImpl::validateStatistics, this, _1));
+}
+
+bool
+AuthSrvImpl::validateStatistics(isc::data::ConstElementPtr data) const {
+    if (config_session_ == NULL) {
+        return (false);
+    }
+    return (
+        config_session_->getModuleSpec().validateStatistics(
+            data, true));
+}
+
 ConstElementPtr
 AuthSrvImpl::setDbFile(ConstElementPtr config) {
     ConstElementPtr answer = isc::config::createAnswer();
diff --git a/src/bin/auth/statistics.cc b/src/bin/auth/statistics.cc
index 444fb8b..e62719f 100644
--- a/src/bin/auth/statistics.cc
+++ b/src/bin/auth/statistics.cc
@@ -37,11 +37,14 @@ public:
     void inc(const AuthCounters::CounterType type);
     bool submitStatistics() const;
     void setStatisticsSession(isc::cc::AbstractSession* statistics_session);
+    void registerStatisticsValidator
+    (AuthCounters::validator_type validator);
     // Currently for testing purpose only
     uint64_t getCounter(const AuthCounters::CounterType type) const;
 private:
     std::vector<uint64_t> counters_;
     isc::cc::AbstractSession* statistics_session_;
+    AuthCounters::validator_type validator_;
 };
 
 AuthCountersImpl::AuthCountersImpl() :
@@ -78,6 +81,14 @@ AuthCountersImpl::submitStatistics() const {
                       << "]}";
     isc::data::ConstElementPtr statistics_element =
         isc::data::Element::fromJSON(statistics_string);
+    // validate the statistics data before send
+    if (validator_) {
+        if (!validator_(
+                statistics_element->get("command")->get(1)->get("data"))) {
+            LOG_ERROR(auth_logger, AUTH_INVALID_STATISTICS_DATA);
+            return (false);
+        }
+    }
     try {
         // group_{send,recv}msg() can throw an exception when encountering
         // an error, and group_recvmsg() will throw an exception on timeout.
@@ -106,6 +117,13 @@ AuthCountersImpl::setStatisticsSession
     statistics_session_ = statistics_session;
 }
 
+void
+AuthCountersImpl::registerStatisticsValidator
+    (AuthCounters::validator_type validator)
+{
+    validator_ = validator;
+}
+
 // Currently for testing purpose only
 uint64_t
 AuthCountersImpl::getCounter(const AuthCounters::CounterType type) const {
@@ -140,3 +158,10 @@ uint64_t
 AuthCounters::getCounter(const AuthCounters::CounterType type) const {
     return (impl_->getCounter(type));
 }
+
+void
+AuthCounters::registerStatisticsValidator
+    (AuthCounters::validator_type validator) const
+{
+    return (impl_->registerStatisticsValidator(validator));
+}
diff --git a/src/bin/auth/statistics.h b/src/bin/auth/statistics.h
index 5bf6436..c930414 100644
--- a/src/bin/auth/statistics.h
+++ b/src/bin/auth/statistics.h
@@ -131,6 +131,26 @@ public:
     /// \return the value of the counter specified by \a type.
     ///
     uint64_t getCounter(const AuthCounters::CounterType type) const;
+
+    /// \brief A type of validation function for the specification in
+    /// isc::config::ModuleSpec.
+    ///
+    /// This type might be useful for not only statistics
+    /// specificatoin but also for config_data specification and for
+    /// commnad.
+    ///
+    typedef boost::function<bool(const isc::data::ConstElementPtr&)>
+    validator_type;
+
+    /// \brief Register a function type of the statistics validation
+    /// function for AuthCounters.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param validator A function type of the validation of
+    /// statistics specification.
+    ///
+    void registerStatisticsValidator(AuthCounters::validator_type validator) const;
 };
 
 #endif // __STATISTICS_H
diff --git a/src/bin/auth/tests/statistics_unittest.cc b/src/bin/auth/tests/statistics_unittest.cc
index cd2755b..98e573b 100644
--- a/src/bin/auth/tests/statistics_unittest.cc
+++ b/src/bin/auth/tests/statistics_unittest.cc
@@ -16,6 +16,8 @@
 
 #include <gtest/gtest.h>
 
+#include <boost/bind.hpp>
+
 #include <cc/data.h>
 #include <cc/session.h>
 
@@ -76,6 +78,13 @@ protected:
     }
     MockSession statistics_session_;
     AuthCounters counters;
+    // no need to be inherited from the original class here.
+    class MockModuleSpec {
+    public:
+        bool validateStatistics(ConstElementPtr, const bool valid) const
+            { return (valid); }
+    };
+    MockModuleSpec module_spec_;
 };
 
 void
@@ -181,7 +190,7 @@ TEST_F(AuthCountersTest, submitStatisticsWithException) {
     statistics_session_.setThrowSessionTimeout(false);
 }
 
-TEST_F(AuthCountersTest, submitStatistics) {
+TEST_F(AuthCountersTest, submitStatisticsWithoutValidator) {
     // Submit statistics data.
     // Validate if it submits correct data.
 
@@ -211,4 +220,59 @@ TEST_F(AuthCountersTest, submitStatistics) {
     EXPECT_EQ(1, statistics_data->get("queries.tcp")->intValue());
 }
 
+TEST_F(AuthCountersTest, submitStatisticsWithValidator) {
+
+    //a validator for the unittest
+    AuthCounters::validator_type validator;
+    ConstElementPtr el;
+
+    // Submit statistics data with correct statistics validator.
+    validator = boost::bind(
+        &AuthCountersTest::MockModuleSpec::validateStatistics,
+        &module_spec_, _1, true);
+
+    EXPECT_TRUE(validator(el));
+
+    // register validator to AuthCounters
+    counters.registerStatisticsValidator(validator);
+
+    // Counters should be initialized to 0.
+    EXPECT_EQ(0, counters.getCounter(AuthCounters::COUNTER_UDP_QUERY));
+    EXPECT_EQ(0, counters.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+
+    // UDP query counter is set to 2.
+    counters.inc(AuthCounters::COUNTER_UDP_QUERY);
+    counters.inc(AuthCounters::COUNTER_UDP_QUERY);
+    // TCP query counter is set to 1.
+    counters.inc(AuthCounters::COUNTER_TCP_QUERY);
+
+    // checks the value returned by submitStatistics
+    EXPECT_TRUE(counters.submitStatistics());
+
+    // Destination is "Stats".
+    EXPECT_EQ("Stats", statistics_session_.msg_destination);
+    // Command is "set".
+    EXPECT_EQ("set", statistics_session_.sent_msg->get("command")
+                         ->get(0)->stringValue());
+    EXPECT_EQ("Auth", statistics_session_.sent_msg->get("command")
+                         ->get(1)->get("owner")->stringValue());
+    ConstElementPtr statistics_data = statistics_session_.sent_msg
+                                          ->get("command")->get(1)
+                                          ->get("data");
+    // UDP query counter is 2 and TCP query counter is 1.
+    EXPECT_EQ(2, statistics_data->get("queries.udp")->intValue());
+    EXPECT_EQ(1, statistics_data->get("queries.tcp")->intValue());
+
+    // Submit statistics data with incorrect statistics validator.
+    validator = boost::bind(
+        &AuthCountersTest::MockModuleSpec::validateStatistics,
+        &module_spec_, _1, false);
+
+    EXPECT_FALSE(validator(el));
+
+    counters.registerStatisticsValidator(validator);
+
+    // checks the value returned by submitStatistics
+    EXPECT_FALSE(counters.submitStatistics());
+}
 }
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index 4814a8a..f28bae5 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -316,14 +316,22 @@ class BoB:
                 answer = isc.config.ccsession.create_answer(0)
             elif command == "sendstats":
                 # send statistics data to the stats daemon immediately
-                cmd = isc.config.ccsession.create_command(
+                statistics_data = {
+                    'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
+                    }
+                valid = self.ccs.get_module_spec().validate_statistics(
+                    True, statistics_data)
+                if valid:
+                    cmd = isc.config.ccsession.create_command(
                     'set', { "owner": "Boss",
-                             "data": {
-                            'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
-                            }})
-                seq = self.cc_session.group_sendmsg(cmd, 'Stats')
-                self.cc_session.group_recvmsg(True, seq)
-                answer = isc.config.ccsession.create_answer(0)
+                             "data": statistics_data })
+                    seq = self.cc_session.group_sendmsg(cmd, 'Stats')
+                    self.cc_session.group_recvmsg(True, seq)
+                    answer = isc.config.ccsession.create_answer(0)
+                else:
+                    logger.fatal(BIND10_INVALID_STATISTICS_DATA);
+                    answer = isc.config.ccsession.create_answer(
+                        1, "specified statistics data is invalid")
             elif command == "ping":
                 answer = isc.config.ccsession.create_answer(0, "pong")
             elif command == "show_processes":
diff --git a/src/bin/bind10/bind10_messages.mes b/src/bin/bind10/bind10_messages.mes
index 3f5f637..516e137 100644
--- a/src/bin/bind10/bind10_messages.mes
+++ b/src/bin/bind10/bind10_messages.mes
@@ -155,3 +155,6 @@ the message channel.
 An unknown child process has exited. The PID is printed, but no further
 action will be taken by the boss process.
 
+% BIND10_INVALID_STATISTICS_DATA invalid specification of statistics data specified
+An error was encountered when the boss module specified
+statistics data which is invalid for the boss specification file.
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
index 7833afb..cd1326e 100644
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -137,9 +137,27 @@ class TestBoB(unittest.TestCase):
             def group_sendmsg(self, msg, group):
                 (self.msg, self.group) = (msg, group)
             def group_recvmsg(self, nonblock, seq): pass
+        class DummyModuleCCSession():
+            module_spec = isc.config.module_spec.ModuleSpec({
+                    "module_name": "Boss",
+                    "statistics": [
+                        {
+                            "item_name": "boot_time",
+                            "item_type": "string",
+                            "item_optional": False,
+                            "item_default": "1970-01-01T00:00:00Z",
+                            "item_title": "Boot time",
+                            "item_description": "A date time when bind10 process starts initially",
+                            "item_format": "date-time"
+                            }
+                        ]
+                    })
+            def get_module_spec(self):
+                return self.module_spec
         bob = BoB()
         bob.verbose = True
         bob.cc_session = DummySession()
+        bob.ccs = DummyModuleCCSession()
         # a bad command
         self.assertEqual(bob.command_handler(-1, None),
                          isc.config.ccsession.create_answer(1, "bad command"))
diff --git a/src/bin/cfgmgr/plugins/logging.spec b/src/bin/cfgmgr/plugins/logging.spec
index 37dab21..e377b0e 100644
--- a/src/bin/cfgmgr/plugins/logging.spec
+++ b/src/bin/cfgmgr/plugins/logging.spec
@@ -76,7 +76,6 @@
                 }
             }
         ],
-        "commands": [],
-        "statistics": []
+        "commands": []
     }
 }
diff --git a/src/bin/cfgmgr/plugins/tsig_keys.spec b/src/bin/cfgmgr/plugins/tsig_keys.spec
index f404af0..e558dd2 100644
--- a/src/bin/cfgmgr/plugins/tsig_keys.spec
+++ b/src/bin/cfgmgr/plugins/tsig_keys.spec
@@ -16,7 +16,6 @@
                 }
             }
         ],
-        "commands": [],
-        "statistics": []
+        "commands": []
     }
 }
diff --git a/src/bin/cmdctl/cmdctl.spec.pre.in b/src/bin/cmdctl/cmdctl.spec.pre.in
index 8651a70..537b678 100644
--- a/src/bin/cmdctl/cmdctl.spec.pre.in
+++ b/src/bin/cmdctl/cmdctl.spec.pre.in
@@ -33,8 +33,7 @@
         "command_description": "shutdown cmdctl",
         "command_args": []
       }
-    ],
-    "statistics": []
+    ]
   }
 }
 
diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec
index 9afc798..0e7e852 100644
--- a/src/bin/dhcp6/dhcp6.spec
+++ b/src/bin/dhcp6/dhcp6.spec
@@ -9,7 +9,6 @@
         "item_default": "eth0"
       }
     ],
-    "commands": [],
-    "statistics": []
+    "commands": []
   }
 }
diff --git a/src/bin/resolver/resolver.spec.pre.in b/src/bin/resolver/resolver.spec.pre.in
index f0ce600..076ef85 100644
--- a/src/bin/resolver/resolver.spec.pre.in
+++ b/src/bin/resolver/resolver.spec.pre.in
@@ -156,8 +156,7 @@
         "command_description": "Shut down recursive DNS server",
         "command_args": []
       }
-    ],
-    "statistics": []
+    ]
   }
 }
 
diff --git a/src/bin/stats/stats-httpd.spec b/src/bin/stats/stats-httpd.spec
index 05b5ee9..6307135 100644
--- a/src/bin/stats/stats-httpd.spec
+++ b/src/bin/stats/stats-httpd.spec
@@ -49,7 +49,6 @@
         "command_description": "Shut down the stats httpd",
         "command_args": []
       }
-    ],
-    "statistics": []
+    ]
   }
 }
diff --git a/src/bin/stats/stats-schema.spec b/src/bin/stats/stats-schema.spec
new file mode 100644
index 0000000..37e9c1a
--- /dev/null
+++ b/src/bin/stats/stats-schema.spec
@@ -0,0 +1,87 @@
+{
+  "module_spec": {
+    "module_name": "Stats",
+    "module_description": "Statistics data schema",
+    "config_data": [
+      {
+        "item_name": "report_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "Report time",
+        "item_description": "A date time when stats module reports",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "bind10.boot_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "bind10.BootTime",
+        "item_description": "A date time when bind10 process starts initially",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.boot_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.BootTime",
+        "item_description": "A date time when the stats module starts initially or when the stats module restarts",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.start_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.StartTime",
+        "item_description": "A date time when the stats module starts collecting data or resetting values last time",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.last_update_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.LastUpdateTime",
+        "item_description": "The latest date time when the stats module receives from other modules like auth server or boss process and so on",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.timestamp",
+        "item_type": "real",
+        "item_optional": false,
+        "item_default": 0.0,
+        "item_title": "stats.Timestamp",
+        "item_description": "A current time stamp since epoch time (1970-01-01T00:00:00Z)",
+        "item_format": "second"
+      },
+      {
+        "item_name": "stats.lname",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "",
+        "item_title": "stats.LocalName",
+        "item_description": "A localname of stats module given via CC protocol"
+      },
+      {
+        "item_name": "auth.queries.tcp",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 0,
+        "item_title": "auth.queries.tcp",
+        "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
+      },
+      {
+        "item_name": "auth.queries.udp",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 0,
+        "item_title": "auth.queries.udp",
+        "item_description": "A number of total query counts which all auth servers receive over UDP since they started initially"
+      }
+    ],
+    "commands": []
+  }
+}
diff --git a/src/bin/stats/tests/testdata/stats_test.spec b/src/bin/stats/tests/testdata/stats_test.spec
new file mode 100644
index 0000000..8136756
--- /dev/null
+++ b/src/bin/stats/tests/testdata/stats_test.spec
@@ -0,0 +1,19 @@
+{
+  "module_spec": {
+    "module_name": "Stats",
+    "module_description": "Stats daemon",
+    "config_data": [],
+    "commands": [
+      {
+        "command_name": "status",
+        "command_description": "identify whether stats module is alive or not",
+        "command_args": []
+      },
+      {
+        "command_name": "the_dummy",
+        "command_description": "this is for testing",
+        "command_args": []
+      }
+    ]
+  }
+}
diff --git a/src/bin/xfrin/xfrin.spec b/src/bin/xfrin/xfrin.spec
index 4380dec..a3e62ce 100644
--- a/src/bin/xfrin/xfrin.spec
+++ b/src/bin/xfrin/xfrin.spec
@@ -83,7 +83,6 @@
         "command_description": "Shut down xfrin module",
         "command_args": []
       }
-    ],
-    "statistics": []
+    ]
   }
 }
diff --git a/src/bin/xfrout/xfrout.spec.pre.in b/src/bin/xfrout/xfrout.spec.pre.in
index d1f3a9b..2efa3d7 100644
--- a/src/bin/xfrout/xfrout.spec.pre.in
+++ b/src/bin/xfrout/xfrout.spec.pre.in
@@ -57,8 +57,7 @@
           "command_description": "Shut down Xfrout",
           "command_args": []
         }
-      ],
-      "statistics": []
+      ]
   }
 }
 
diff --git a/src/bin/zonemgr/zonemgr.spec.pre.in b/src/bin/zonemgr/zonemgr.spec.pre.in
index 99610df..36f02df 100644
--- a/src/bin/zonemgr/zonemgr.spec.pre.in
+++ b/src/bin/zonemgr/zonemgr.spec.pre.in
@@ -65,8 +65,7 @@
           "command_description": "Shut down Zonemgr",
           "command_args": []
         }
-      ],
-      "statistics": []
+      ]
   }
 }
      
diff --git a/src/lib/config/module_spec.cc b/src/lib/config/module_spec.cc
index 1621fe3..b5644a8 100644
--- a/src/lib/config/module_spec.cc
+++ b/src/lib/config/module_spec.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium.
+// Copyright (C) 2010, 2011  Internet Systems Consortium.
 //
 // Permission to use, copy, modify, and distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -84,6 +84,54 @@ check_config_item_list(ConstElementPtr spec) {
     }
 }
 
+// checks whether the given element is a valid statistics specification
+// returns false if the specification is bad
+bool
+check_format(ConstElementPtr value, ConstElementPtr format_name) {
+    typedef std::map<std::string, std::string> format_types;
+    format_types time_formats;
+    // TODO: should be added other format types if necessary
+    time_formats.insert(
+        format_types::value_type("date-time", "%Y-%m-%dT%H:%M:%SZ") );
+    time_formats.insert(
+        format_types::value_type("date", "%Y-%m-%d") );
+    time_formats.insert(
+        format_types::value_type("time", "%H:%M:%S") );
+    BOOST_FOREACH (const format_types::value_type& f, time_formats) {
+        if (format_name->stringValue() == f.first) {
+            struct tm tm;
+            return (strptime(value->stringValue().c_str(),
+                             f.second.c_str(), &tm) != NULL);
+        }
+    }
+    return (false);
+}
+
+void check_statistics_item_list(ConstElementPtr spec);
+
+void
+check_statistics_item_list(ConstElementPtr spec) {
+    if (spec->getType() != Element::list) {
+        throw ModuleSpecError("statistics is not a list of elements");
+    }
+    BOOST_FOREACH(ConstElementPtr item, spec->listValue()) {
+        check_config_item(item);
+        // additional checks for statistics
+        check_leaf_item(item, "item_title", Element::string, true);
+        check_leaf_item(item, "item_description", Element::string, true);
+        check_leaf_item(item, "item_format", Element::string, false);
+        // checks name of item_format and validation of item_default
+        if (item->contains("item_format")
+            && item->contains("item_default")) {
+            if(!check_format(item->get("item_default"),
+                             item->get("item_format"))) {
+                throw ModuleSpecError(
+                    "item_default not valid type of item_format");
+            }
+        }
+    }
+}
+
 void
 check_command(ConstElementPtr spec) {
     check_leaf_item(spec, "command_name", Element::string, true);
@@ -113,6 +161,9 @@ check_data_specification(ConstElementPtr spec) {
     if (spec->contains("commands")) {
         check_command_list(spec->get("commands"));
     }
+    if (spec->contains("statistics")) {
+        check_statistics_item_list(spec->get("statistics"));
+    }
 }
 
 // checks whether the given element is a valid module specification
@@ -162,6 +213,15 @@ ModuleSpec::getConfigSpec() const {
     }
 }
 
+ConstElementPtr
+ModuleSpec::getStatisticsSpec() const {
+    if (module_specification->contains("statistics")) {
+        return (module_specification->get("statistics"));
+    } else {
+        return (ElementPtr());
+    }
+}
+
 const std::string
 ModuleSpec::getModuleName() const {
     return (module_specification->get("module_name")->stringValue());
@@ -183,6 +243,12 @@ ModuleSpec::validateConfig(ConstElementPtr data, const bool full) const {
 }
 
 bool
+ModuleSpec::validateStatistics(ConstElementPtr data, const bool full) const {
+    ConstElementPtr spec = module_specification->find("statistics");
+    return (validateSpecList(spec, data, full, ElementPtr()));
+}
+
+bool
 ModuleSpec::validateCommand(const std::string& command,
                              ConstElementPtr args,
                              ElementPtr errors) const
@@ -220,6 +286,14 @@ ModuleSpec::validateConfig(ConstElementPtr data, const bool full,
     return (validateSpecList(spec, data, full, errors));
 }
 
+bool
+ModuleSpec::validateStatistics(ConstElementPtr data, const bool full,
+                               ElementPtr errors) const
+{
+    ConstElementPtr spec = module_specification->find("statistics");
+    return (validateSpecList(spec, data, full, errors));
+}
+
 ModuleSpec
 moduleSpecFromFile(const std::string& file_name, const bool check)
                    throw(JSONError, ModuleSpecError)
@@ -327,6 +401,14 @@ ModuleSpec::validateItem(ConstElementPtr spec, ConstElementPtr data,
             return (false);
         }
     }
+    if (spec->contains("item_format")) {
+        if (!check_format(data, spec->get("item_format"))) {
+            if (errors) {
+                errors->add(Element::create("Format mismatch"));
+            }
+            return (false);
+        }
+    }
     return (true);
 }
 
diff --git a/src/lib/config/module_spec.h b/src/lib/config/module_spec.h
index ab6e273..ce3762f 100644
--- a/src/lib/config/module_spec.h
+++ b/src/lib/config/module_spec.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2010  Internet Systems Consortium.
+// Copyright (C) 2010, 2011  Internet Systems Consortium.
 //
 // Permission to use, copy, modify, and distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -71,6 +71,12 @@ namespace isc { namespace config {
         ///                    part of the specification
         isc::data::ConstElementPtr getConfigSpec() const;
 
+        /// Returns the statistics part of the specification as an
+        /// ElementPtr
+        /// \return ElementPtr Shared pointer to the statistics
+        ///                    part of the specification
+        isc::data::ConstElementPtr getStatisticsSpec() const;
+
         /// Returns the full module specification as an ElementPtr
         /// \return ElementPtr Shared pointer to the specification
         isc::data::ConstElementPtr getFullSpec() const {
@@ -95,6 +101,17 @@ namespace isc { namespace config {
         bool validateConfig(isc::data::ConstElementPtr data,
                              const bool full = false) const;
 
+        // returns true if the given element conforms to this data
+        // statistics specification
+        /// Validates the given statistics data for this specification.
+        /// \param data The base \c Element of the data to check
+        /// \param full If true, all non-optional statistics parameters
+        /// must be specified.
+        /// \return true if the data conforms to the specification,
+        /// false otherwise.
+        bool validateStatistics(isc::data::ConstElementPtr data,
+                             const bool full = false) const;
+
         /// Validates the arguments for the given command
         ///
         /// This checks the command and argument against the
@@ -142,6 +159,10 @@ namespace isc { namespace config {
         bool validateConfig(isc::data::ConstElementPtr data, const bool full,
                              isc::data::ElementPtr errors) const;
 
+        /// errors must be of type ListElement
+        bool validateStatistics(isc::data::ConstElementPtr data, const bool full,
+                                isc::data::ElementPtr errors) const;
+
     private:
         bool validateItem(isc::data::ConstElementPtr spec,
                           isc::data::ConstElementPtr data,
diff --git a/src/lib/config/tests/module_spec_unittests.cc b/src/lib/config/tests/module_spec_unittests.cc
index 1b43350..a33ba1e 100644
--- a/src/lib/config/tests/module_spec_unittests.cc
+++ b/src/lib/config/tests/module_spec_unittests.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2009, 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
@@ -18,6 +18,8 @@
 
 #include <fstream>
 
+#include <boost/foreach.hpp>
+
 #include <config/tests/data_def_unittests_config.h>
 
 using namespace isc::data;
@@ -57,6 +59,7 @@ TEST(ModuleSpec, ReadingSpecfiles) {
 
     dd = moduleSpecFromFile(specfile("spec2.spec"));
     EXPECT_EQ("[ { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }, { \"command_args\": [  ], \"command_description\": \"Shut down BIND 10\", \"command_name\": \"shutdown\" } ]", dd.getCommandsSpec()->str());
+    EXPECT_EQ("[ { \"item_default\": \"1970-01-01T00:00:00Z\", \"item_description\": \"A dummy date time\", \"item_format\": \"date-time\", \"item_name\": \"dummy_time\", \"item_optional\": false, \"item_title\": \"Dummy Time\", \"item_type\": \"string\" } ]", dd.getStatisticsSpec()->str());
     EXPECT_EQ("Spec2", dd.getModuleName());
     EXPECT_EQ("", dd.getModuleDescription());
 
@@ -64,6 +67,11 @@ TEST(ModuleSpec, ReadingSpecfiles) {
     EXPECT_EQ("Spec25", dd.getModuleName());
     EXPECT_EQ("Just an empty module", dd.getModuleDescription());
     EXPECT_THROW(moduleSpecFromFile(specfile("spec26.spec")), ModuleSpecError);
+    EXPECT_THROW(moduleSpecFromFile(specfile("spec33.spec")), ModuleSpecError);
+    EXPECT_THROW(moduleSpecFromFile(specfile("spec34.spec")), ModuleSpecError);
+    EXPECT_THROW(moduleSpecFromFile(specfile("spec35.spec")), ModuleSpecError);
+    EXPECT_THROW(moduleSpecFromFile(specfile("spec36.spec")), ModuleSpecError);
+    EXPECT_THROW(moduleSpecFromFile(specfile("spec37.spec")), ModuleSpecError);
 
     std::ifstream file;
     file.open(specfile("spec1.spec").c_str());
@@ -71,6 +79,7 @@ TEST(ModuleSpec, ReadingSpecfiles) {
     EXPECT_EQ(dd.getFullSpec()->get("module_name")
                               ->stringValue(), "Spec1");
     EXPECT_TRUE(isNull(dd.getCommandsSpec()));
+    EXPECT_TRUE(isNull(dd.getStatisticsSpec()));
 
     std::ifstream file2;
     file2.open(specfile("spec8.spec").c_str());
@@ -114,6 +123,12 @@ TEST(ModuleSpec, SpecfileConfigData) {
                    "commands is not a list of elements");
 }
 
+TEST(ModuleSpec, SpecfileStatistics) {
+    moduleSpecError("spec35.spec", "item_default not valid type of item_format");
+    moduleSpecError("spec36.spec", "statistics is not a list of elements");
+    moduleSpecError("spec37.spec", "item_default not valid type of item_format");
+}
+
 TEST(ModuleSpec, SpecfileCommands) {
     moduleSpecError("spec17.spec",
                    "command_name missing in { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\" }");
@@ -137,6 +152,17 @@ dataTest(const ModuleSpec& dd, const std::string& data_file_name) {
 }
 
 bool
+statisticsTest(const ModuleSpec& dd, const std::string& data_file_name) {
+    std::ifstream data_file;
+
+    data_file.open(specfile(data_file_name).c_str());
+    ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
+    data_file.close();
+
+    return (dd.validateStatistics(data));
+}
+
+bool
 dataTestWithErrors(const ModuleSpec& dd, const std::string& data_file_name,
                       ElementPtr errors)
 {
@@ -149,6 +175,19 @@ dataTestWithErrors(const ModuleSpec& dd, const std::string& data_file_name,
     return (dd.validateConfig(data, true, errors));
 }
 
+bool
+statisticsTestWithErrors(const ModuleSpec& dd, const std::string& data_file_name,
+                      ElementPtr errors)
+{
+    std::ifstream data_file;
+
+    data_file.open(specfile(data_file_name).c_str());
+    ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
+    data_file.close();
+
+    return (dd.validateStatistics(data, true, errors));
+}
+
 TEST(ModuleSpec, DataValidation) {
     ModuleSpec dd = moduleSpecFromFile(specfile("spec22.spec"));
 
@@ -175,6 +214,17 @@ TEST(ModuleSpec, DataValidation) {
     EXPECT_EQ("[ \"Unknown item value_does_not_exist\" ]", errors->str());
 }
 
+TEST(ModuleSpec, StatisticsValidation) {
+    ModuleSpec dd = moduleSpecFromFile(specfile("spec32.spec"));
+
+    EXPECT_TRUE(statisticsTest(dd, "data32_1.data"));
+    EXPECT_FALSE(statisticsTest(dd, "data32_2.data"));
+
+    ElementPtr errors = Element::createList();
+    EXPECT_FALSE(statisticsTestWithErrors(dd, "data32_2.data", errors));
+    EXPECT_EQ("[ \"Format mismatch\", \"Format mismatch\", \"Format mismatch\" ]", errors->str());
+}
+
 TEST(ModuleSpec, CommandValidation) {
     ModuleSpec dd = moduleSpecFromFile(specfile("spec2.spec"));
     ConstElementPtr arg = Element::fromJSON("{}");
@@ -211,3 +261,96 @@ TEST(ModuleSpec, CommandValidation) {
     EXPECT_EQ(errors->get(0)->stringValue(), "Type mismatch");
 
 }
+
+TEST(ModuleSpec, CheckFormat) {
+
+    const std::string json_begin = "{ \"module_spec\": { \"module_name\": \"Foo\", \"statistics\": [ { \"item_name\": \"dummy_time\", \"item_type\": \"string\", \"item_optional\": true, \"item_title\": \"Dummy Time\", \"item_description\": \"A dummy date time\"";
+    const std::string json_end = " } ] } }";
+    std::string item_default;
+    std::string item_format;
+    std::vector<std::string> specs;
+    ConstElementPtr el;
+
+    specs.clear();
+    item_default = "\"item_default\": \"2011-05-27T19:42:57Z\",";
+    item_format  = "\"item_format\": \"date-time\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"2011-05-27\",";
+    item_format  = "\"item_format\": \"date\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"19:42:57Z\",";
+    item_format  = "\"item_format\": \"time\"";
+    specs.push_back("," + item_default + item_format);
+
+    item_format  = "\"item_format\": \"date-time\"";
+    specs.push_back("," + item_format);
+    item_default = "";
+    item_format  = "\"item_format\": \"date\"";
+    specs.push_back("," + item_format);
+    item_default = "";
+    item_format  = "\"item_format\": \"time\"";
+    specs.push_back("," + item_format);
+
+    item_default = "\"item_default\": \"a\"";
+    specs.push_back("," + item_default);
+    item_default = "\"item_default\": \"b\"";
+    specs.push_back("," + item_default);
+    item_default = "\"item_default\": \"c\"";
+    specs.push_back("," + item_default);
+
+    item_format  = "\"item_format\": \"dummy\"";
+    specs.push_back("," + item_format);
+
+    specs.push_back("");
+
+    BOOST_FOREACH(std::string s, specs) {
+        el = Element::fromJSON(json_begin + s + json_end)->get("module_spec");
+        EXPECT_NO_THROW(ModuleSpec(el, true));
+    }
+
+    specs.clear();
+    item_default = "\"item_default\": \"2011-05-27T19:42:57Z\",";
+    item_format  = "\"item_format\": \"dummy\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"2011-05-27\",";
+    item_format  = "\"item_format\": \"dummy\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"19:42:57Z\",";
+    item_format  = "\"item_format\": \"dummy\"";
+    specs.push_back("," + item_default + item_format);
+
+    item_default = "\"item_default\": \"2011-13-99T99:99:99Z\",";
+    item_format  = "\"item_format\": \"date-time\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"2011-13-99\",";
+    item_format  = "\"item_format\": \"date\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"99:99:99Z\",";
+    item_format  = "\"item_format\": \"time\"";
+    specs.push_back("," + item_default + item_format);
+
+    item_default = "\"item_default\": \"1\",";
+    item_format  = "\"item_format\": \"date-time\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"1\",";
+    item_format  = "\"item_format\": \"date\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"1\",";
+    item_format  = "\"item_format\": \"time\"";
+    specs.push_back("," + item_default + item_format);
+
+    item_default = "\"item_default\": \"\",";
+    item_format  = "\"item_format\": \"date-time\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"\",";
+    item_format  = "\"item_format\": \"date\"";
+    specs.push_back("," + item_default + item_format);
+    item_default = "\"item_default\": \"\",";
+    item_format  = "\"item_format\": \"time\"";
+    specs.push_back("," + item_default + item_format);
+
+    BOOST_FOREACH(std::string s, specs) {
+        el = Element::fromJSON(json_begin + s + json_end)->get("module_spec");
+        EXPECT_THROW(ModuleSpec(el, true), ModuleSpecError);
+    }
+}
diff --git a/src/lib/python/isc/config/tests/module_spec_test.py b/src/lib/python/isc/config/tests/module_spec_test.py
index 953a049..6ff9868 100644
--- a/src/lib/python/isc/config/tests/module_spec_test.py
+++ b/src/lib/python/isc/config/tests/module_spec_test.py
@@ -343,6 +343,9 @@ class TestModuleSpec(unittest.TestCase):
         self.assertFalse(isc.config.module_spec._check_format('2011-05-27T19:42:57Z', 'dummy'))
         self.assertFalse(isc.config.module_spec._check_format('2011-05-27', 'dummy'))
         self.assertFalse(isc.config.module_spec._check_format('19:42:57', 'dummy'))
+        self.assertFalse(isc.config.module_spec._check_format('2011-13-99T99:99:99Z', 'date-time'))
+        self.assertFalse(isc.config.module_spec._check_format('2011-13-99', 'date'))
+        self.assertFalse(isc.config.module_spec._check_format('99:99:99', 'time'))
         self.assertFalse(isc.config.module_spec._check_format('', 'date-time'))
         self.assertFalse(isc.config.module_spec._check_format(None, 'date-time'))
         self.assertFalse(isc.config.module_spec._check_format(None, None))
diff --git a/tests/system/bindctl/tests.sh b/tests/system/bindctl/tests.sh
index 6923c41..49ef0f1 100755
--- a/tests/system/bindctl/tests.sh
+++ b/tests/system/bindctl/tests.sh
@@ -24,6 +24,10 @@ SYSTEMTESTTOP=..
 status=0
 n=0
 
+# TODO: consider consistency with statistics definition in auth.spec
+auth_queries_tcp="\<queries\.tcp\>"
+auth_queries_udp="\<queries\.udp\>"
+
 echo "I:Checking b10-auth is working by default ($n)"
 $DIG +norec @10.53.0.1 -p 53210 ns.example.com. A >dig.out.$n || status=1
 # perform a simple check on the output (digcomp would be too much for this)
@@ -40,8 +44,8 @@ echo 'Stats show
 	--csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
 # the server should have received 1 UDP and 1 TCP queries (TCP query was
 # sent from the server startup script)
-grep "\"auth.queries.tcp\": 1," bindctl.out.$n > /dev/null || status=1
-grep "\"auth.queries.udp\": 1," bindctl.out.$n > /dev/null || status=1
+grep $auth_queries_tcp".*\<1\>" bindctl.out.$n > /dev/null || status=1
+grep $auth_queries_udp".*\<1\>" bindctl.out.$n > /dev/null || status=1
 if [ $status != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 
@@ -73,8 +77,8 @@ echo 'Stats show
 ' | $RUN_BINDCTL \
 	--csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
 # The statistics counters should have been reset while stop/start.
-grep "\"auth.queries.tcp\": 0," bindctl.out.$n > /dev/null || status=1
-grep "\"auth.queries.udp\": 1," bindctl.out.$n > /dev/null || status=1
+grep $auth_queries_tcp".*\<0\>" bindctl.out.$n > /dev/null || status=1
+grep $auth_queries_udp".*\<1\>" bindctl.out.$n > /dev/null || status=1
 if [ $status != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 
@@ -97,8 +101,8 @@ echo 'Stats show
 ' | $RUN_BINDCTL \
 	--csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
 # The statistics counters shouldn't be reset due to hot-swapping datasource.
-grep "\"auth.queries.tcp\": 0," bindctl.out.$n > /dev/null || status=1
-grep "\"auth.queries.udp\": 2," bindctl.out.$n > /dev/null || status=1
+grep $auth_queries_tcp".*\<0\>" bindctl.out.$n > /dev/null || status=1
+grep $auth_queries_udp".*\<2\>" bindctl.out.$n > /dev/null || status=1
 if [ $status != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 




More information about the bind10-changes mailing list