[svn] commit: r4030 - in /branches/trac447: ./ doc/guide/ src/bin/auth/ src/bin/auth/benchmarks/ src/bin/auth/tests/ src/bin/auth/tests/testdata/ src/bin/bind10/ src/bin/bind10/tests/ src/bin/bindctl/ src/bin/bindctl/tests/ src/bin/cfgmgr/tests/ src/bin/cmdctl/ src/bin/cmdctl/tests/ src/bin/loadzone/ src/bin/loadzone/tests/correct/ src/bin/loadzone/tests/error/ src/bin/msgq/ src/bin/msgq/tests/ src/bin/recurse/ src/bin/stats/ src/bin/stats/tests/ src/bin/stats/tests/isc/util/ src/bin/tests/ src/bin/usermgr/ src/bin/xfrin/ src/bin/xfrin/tests/ src/bin/xfrout/ src/bin/xfrout/tests/ src/bin/zonemgr/ src/bin/zonemgr/tests/ src/lib/asiolink/ src/lib/asiolink/internal/ src/lib/asiolink/tests/ src/lib/config/ src/lib/config/tests/ src/lib/config/tests/testdata/ src/lib/datasrc/ src/lib/datasrc/tests/ src/lib/dns/python/tests/ src/lib/python/isc/cc/tests/ src/lib/python/isc/config/ src/lib/python/isc/config/tests/ src/lib/python/isc/datasrc/tests/ src/lib/python/isc/log/tests/ src/lib/python/isc/net/tests/ src/lib/python/isc/notify/tests/ src/lib/python/isc/util/tests/ src/lib/python/isc/utils/

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Dec 28 10:31:10 UTC 2010


Author: vorner
Date: Tue Dec 28 10:31:10 2010
New Revision: 4030

Log:
Sync with trunk

Added:
    branches/trac447/src/bin/auth/config.cc
      - copied unchanged from r4028, trunk/src/bin/auth/config.cc
    branches/trac447/src/bin/auth/config.h
      - copied unchanged from r4028, trunk/src/bin/auth/config.h
    branches/trac447/src/bin/auth/statistics.cc
      - copied unchanged from r4028, trunk/src/bin/auth/statistics.cc
    branches/trac447/src/bin/auth/statistics.h
      - copied unchanged from r4028, trunk/src/bin/auth/statistics.h
    branches/trac447/src/bin/auth/tests/config_unittest.cc
      - copied unchanged from r4028, trunk/src/bin/auth/tests/config_unittest.cc
    branches/trac447/src/bin/auth/tests/statistics_unittest.cc
      - copied unchanged from r4028, trunk/src/bin/auth/tests/statistics_unittest.cc
    branches/trac447/src/bin/auth/tests/testdata/
      - copied from r4028, trunk/src/bin/auth/tests/testdata/
    branches/trac447/src/lib/config/tests/testdata/data22_9.data
      - copied unchanged from r4028, trunk/src/lib/config/tests/testdata/data22_9.data
    branches/trac447/src/lib/python/isc/utils/   (props changed)
      - copied from r4028, trunk/src/lib/python/isc/utils/
Modified:
    branches/trac447/   (props changed)
    branches/trac447/ChangeLog
    branches/trac447/Makefile.am
    branches/trac447/README
    branches/trac447/configure.ac
    branches/trac447/doc/guide/bind10-guide.xml
    branches/trac447/src/bin/auth/Makefile.am
    branches/trac447/src/bin/auth/auth.spec.pre.in
    branches/trac447/src/bin/auth/auth_srv.cc
    branches/trac447/src/bin/auth/auth_srv.h
    branches/trac447/src/bin/auth/benchmarks/Makefile.am
    branches/trac447/src/bin/auth/benchmarks/query_bench.cc
    branches/trac447/src/bin/auth/change_user.cc
    branches/trac447/src/bin/auth/common.h
    branches/trac447/src/bin/auth/main.cc
    branches/trac447/src/bin/auth/query.cc
    branches/trac447/src/bin/auth/query.h
    branches/trac447/src/bin/auth/tests/Makefile.am
    branches/trac447/src/bin/auth/tests/auth_srv_unittest.cc
    branches/trac447/src/bin/auth/tests/query_unittest.cc
    branches/trac447/src/bin/bind10/bind10.py.in   (props changed)
    branches/trac447/src/bin/bind10/run_bind10.sh.in
    branches/trac447/src/bin/bind10/tests/Makefile.am
    branches/trac447/src/bin/bindctl/run_bindctl.sh.in
    branches/trac447/src/bin/bindctl/tests/Makefile.am
    branches/trac447/src/bin/cfgmgr/tests/Makefile.am
    branches/trac447/src/bin/cmdctl/run_b10-cmdctl.sh.in
    branches/trac447/src/bin/cmdctl/tests/Makefile.am
    branches/trac447/src/bin/loadzone/run_loadzone.sh.in
    branches/trac447/src/bin/loadzone/tests/correct/Makefile.am
    branches/trac447/src/bin/loadzone/tests/error/Makefile.am
    branches/trac447/src/bin/msgq/run_msgq.sh.in
    branches/trac447/src/bin/msgq/tests/Makefile.am
    branches/trac447/src/bin/recurse/b10-recurse.8
    branches/trac447/src/bin/recurse/b10-recurse.xml
    branches/trac447/src/bin/stats/run_b10-stats.sh.in
    branches/trac447/src/bin/stats/run_b10-stats_stub.sh.in
    branches/trac447/src/bin/stats/tests/Makefile.am
    branches/trac447/src/bin/stats/tests/isc/util/   (props changed)
    branches/trac447/src/bin/tests/Makefile.am
    branches/trac447/src/bin/usermgr/run_b10-cmdctl-usermgr.sh.in
    branches/trac447/src/bin/xfrin/run_b10-xfrin.sh.in
    branches/trac447/src/bin/xfrin/tests/Makefile.am
    branches/trac447/src/bin/xfrout/run_b10-xfrout.sh.in
    branches/trac447/src/bin/xfrout/tests/Makefile.am
    branches/trac447/src/bin/zonemgr/run_b10-zonemgr.sh.in
    branches/trac447/src/bin/zonemgr/tests/Makefile.am
    branches/trac447/src/lib/asiolink/asiolink.cc
    branches/trac447/src/lib/asiolink/asiolink.h
    branches/trac447/src/lib/asiolink/internal/tcpdns.h
    branches/trac447/src/lib/asiolink/tests/asiolink_unittest.cc
    branches/trac447/src/lib/config/module_spec.cc
    branches/trac447/src/lib/config/tests/module_spec_unittests.cc
    branches/trac447/src/lib/config/tests/testdata/Makefile.am
    branches/trac447/src/lib/config/tests/testdata/data22_8.data
    branches/trac447/src/lib/datasrc/data_source.h
    branches/trac447/src/lib/datasrc/memory_datasrc.cc
    branches/trac447/src/lib/datasrc/memory_datasrc.h
    branches/trac447/src/lib/datasrc/tests/memory_datasrc_unittest.cc
    branches/trac447/src/lib/datasrc/tests/zonetable_unittest.cc
    branches/trac447/src/lib/datasrc/zonetable.cc
    branches/trac447/src/lib/datasrc/zonetable.h
    branches/trac447/src/lib/dns/python/tests/Makefile.am
    branches/trac447/src/lib/python/isc/cc/tests/Makefile.am
    branches/trac447/src/lib/python/isc/config/ccsession.py
    branches/trac447/src/lib/python/isc/config/config_data.py
    branches/trac447/src/lib/python/isc/config/module_spec.py
    branches/trac447/src/lib/python/isc/config/tests/Makefile.am
    branches/trac447/src/lib/python/isc/config/tests/ccsession_test.py
    branches/trac447/src/lib/python/isc/config/tests/config_data_test.py
    branches/trac447/src/lib/python/isc/config/tests/module_spec_test.py
    branches/trac447/src/lib/python/isc/datasrc/tests/Makefile.am
    branches/trac447/src/lib/python/isc/log/tests/Makefile.am
    branches/trac447/src/lib/python/isc/net/tests/Makefile.am
    branches/trac447/src/lib/python/isc/notify/tests/Makefile.am
    branches/trac447/src/lib/python/isc/util/tests/Makefile.am

Modified: branches/trac447/ChangeLog
==============================================================================
--- branches/trac447/ChangeLog (original)
+++ branches/trac447/ChangeLog Tue Dec 28 10:31:10 2010
@@ -1,3 +1,55 @@
+  140.  [func]		y-aharen
+	src/bin/auth: Added a feature to count queries and send counter
+	values to statistics periodically. To support it, added wrapping
+	class of asio::deadline_timer to use as interval timer.
+	The counters can be seen using the "Stats show" command from
+	bindctl.  The result would look like:
+	  ... "auth.queries.tcp": 1, "auth.queries.udp": 1 ...
+	Using the "Auth sendstats" command you can make b10-auth send the
+	counters to b10-stats immediately.
+	(Trac #347, svn r4026)
+
+  139.  [build]		jreed
+	Introduced configure option and make targets for generating
+	Python code coverage report. This adds new make targets:
+	report-python-coverage and clean-python-coverage. The C++
+	code coverage targets were renamed to clean-cpp-coverage
+	and report-cpp-coverage. (Trac #362, svn r4023)
+
+  138.	[func]*		jinmei
+	b10-auth: added a configuration interface to support in memory
+	data sources.  For example, the following command to bindctl
+	will configure a memory data source containing the "example.com"
+	zone with the zone file named "example.com.zone":
+	> config set Auth/datasources/ [{"type": "memory", "zones": \
+	 [{"origin": "example.com", "file": "example.com.zone"}]}]
+	By default, the memory data source is disabled; it must be
+	configured explicitly.  To disable it again, specify a null list
+	for Auth/datasources:
+	> config set Auth/datasources/ []
+	Notes: it's currently for class IN only.  The zone files are not
+	actually loaded into memory yet (which will soon be implemented).
+	This is an experimental feature and the syntax may change in
+	future versions.
+	(Trac #446, svn r3998)
+
+  137.	[bug]		jreed
+	Fix run_*.sh scripts that are used for development testing
+	so they use a msgq socket file in the build tree.
+	(Trac #226, svn r3989)
+
+  136.  [bug]       jelte
+  	bindctl (and the configuration manager in general) now no longer
+	accepts 'unknown' data; i.e. data for modules that it does not know
+	about, or configuration items that are not specified in the .spec
+	files.
+	(Trac #202, svn r3967)
+
+  135.  [func]      each
+	Add b10-recurse. This is an example recursive server that
+	currently does forwarding only and no caching.
+	(Trac #327, svn r3903)
+
   134.  [func]      vorner
 	b10-recurse supports timeouts and retries in forwarder mode.
 	(Trac #401, svn r3660)
@@ -8,7 +60,7 @@
 	(Trac #393, r3602)
 
   132.  [func]      vorner
-	The b10-recursive is configured through config manager.
+	The b10-recurse is configured through config manager.
 	It has "listen_on" and "forward_addresses" options.
 	(Trac #389, r3448)
 
@@ -39,7 +91,6 @@
 	for root zone was added.
 	(Trac #85, svn r3836)
 
->>>>>>> .merge-right.r3894
   127.  [bug]       stephen
 	During normal operation process termination and resurrection messages
 	are now output regardless of the state of the verbose flag.

Modified: branches/trac447/Makefile.am
==============================================================================
--- branches/trac447/Makefile.am (original)
+++ branches/trac447/Makefile.am Tue Dec 28 10:31:10 2010
@@ -8,20 +8,30 @@
 # When running distcheck target, do not install the configurations
 DISTCHECK_CONFIGURE_FLAGS = --disable-install-configurations
 
-clean-coverage:
+clean-cpp-coverage:
 	@if [ $(USE_LCOV) = yes ] ; then \
 		$(LCOV) --directory . --zerocounters; \
 		rm -rf coverage/; \
 	else \
-		echo "Code coverage not enabled at configuration time"; \
-		exit 1; \
+		echo "C++ code coverage not enabled at configuration time." ; \
+		echo "Use: ./configure --with-lcov" ; \
+	fi
+
+clean-python-coverage:
+	@if [ $(USE_PYCOVERAGE) = yes ] ; then \
+		rm -f $(abs_top_srcdir)/.coverage ; \
+		rm -rf $(abs_top_srcdir)/py-coverage-html ; \
+	else \
+		echo "Python code coverage not enabled at configuration time." ; \
+		echo "Use: ./configure --with-pycoverage" ; \
 	fi
 
 perform-coverage: check
 
-report-coverage:
-	$(LCOV) --capture --directory . --output-file all.info
-	$(LCOV) --remove all.info \
+report-cpp-coverage:
+	@if [ $(USE_LCOV) = yes ] ; then \
+		$(LCOV) --capture --directory . --output-file all.info ; \
+		$(LCOV) --remove all.info \
 			c++/4.4\*/\* \
 			c++/4.4\*/backward/\* \
 			c++/4.4\*/bits/\* \
@@ -36,10 +46,29 @@
 			\*_unittests.cc \
 			\*_unittest.cc \
 			\*_unittests.h \
-		--output report.info
-	$(GENHTML) --legend -o coverage report.info 
-
+			--output report.info ; \
+		$(GENHTML) --legend -o $(abs_top_builddir)/coverage-cpp-html report.info ; \
+		echo "Generated C++ Code Coverage report in HTML at $(abs_top_builddir)/coverage-cpp-html" ; \
+	else \
+		echo "C++ code coverage not enabled at configuration time." ; \
+		echo "Use: ./configure --with-lcov" ; \
+	fi
+
+report-python-coverage:
+	@if [ $(USE_PYCOVERAGE) = yes ] ; then \
+		$(PYCOVERAGE) html -d $(abs_top_builddir)/coverage-python-html --omit=src/bin/bind10/tests/,src/bin/bindctl/tests/,src/bin/cfgmgr/tests/,src/bin/cmdctl/tests/,src/bin/loadzone/tests/,src/bin/msgq/tests/,src/bin/stats/tests/,src/bin/tests/,src/bin/xfrin/tests/,src/bin/xfrout/tests/,src/bin/zonemgr/tests/,src/lib/dns/python/tests/,src/lib/dns/tests/,src/lib/python/isc/cc/tests/,src/lib/python/isc/config/tests/,src/lib/python/isc/datasrc/tests/,src/lib/python/isc/log/tests/,src/lib/python/isc/net/tests/,src/lib/python/isc/notify/tests/,src/lib/python/isc/util/tests/ ; \
+		echo "Generated Python Code Coverage report in HTML at $(abs_top_builddir)/coverage-python-html" ; \
+	else \
+		echo "Python code coverage not enabled at configuration time." ; \
+		echo "Use: ./configure --with-pycoverage" ; \
+	fi
+
+# for python and c++ test coverage
 coverage: clean-coverage perform-coverage report-coverage
+
+clean-coverage: clean-cpp-coverage clean-python-coverage
+
+report-coverage: report-cpp-coverage report-python-coverage
 
 #### include external sources in the distributed tarball:
 EXTRA_DIST = ext/asio/README

Modified: branches/trac447/README
==============================================================================
--- branches/trac447/README (original)
+++ branches/trac447/README Tue Dec 28 10:31:10 2010
@@ -15,11 +15,11 @@
 
 This release includes the bind10 master process, b10-msgq message
 bus, b10-auth authoritative DNS server (with SQLite3 backend),
-b10-cmdctl remote control daemon, b10-cfgmgr configuration manager,
-b10-xfrin AXFR inbound service, b10-xfrout outgoing AXFR service,
-b10-zonemgr secondary manager, b10-stats statistics collection and
-reporting daemon, and a new libdns++ library for C++ with a python
-wrapper.
+b10-recurse forwarding DNS server, b10-cmdctl remote control daemon,
+b10-cfgmgr configuration manager, b10-xfrin AXFR inbound service,
+b10-xfrout outgoing AXFR service, b10-zonemgr secondary manager,
+b10-stats statistics collection and reporting daemon, and a new
+libdns++ library for C++ with a python wrapper.
 
 Documentation is included and also available via the BIND 10
 website at http://bind10.isc.org/
@@ -93,26 +93,55 @@
 
 TEST COVERAGE
 
+Code coverage reports may be generated using make. These are
+based on running on the unit tests. The resulting reports are placed
+in coverage-cpp-html and coverage-python-html directories for C++
+and Python, respectively.
+
 The code coverage report for the C++ tests uses LCOV. It is available
-from http://ltp.sourceforge.net/. To generate your own HTML report,
+from http://ltp.sourceforge.net/. To generate the HTML report,
 first configure BIND 10 with:
  
   ./configure --with-lcov
 
+The code coverage report for the Python tests uses coverage.py (aka
+pycoverage). It is available from http://nedbatchelder.com/code/coverage/.
+To generate the HTML report, first configure BIND 10 with:
+
+  ./configure --with-pycoverage
+
 Doing code coverage tests:
 
   make coverage
-	Does the following:
+	Does the clean, perform, and report targets for C++ and Python.
 
   make clean-coverage
-	Zeroes the lcov code coverage counters and removes the coverage HTML.
+	Zeroes the code coverage counters and removes the HTML reports
+	for C++ and Python.
 
   make perform-coverage
-	Runs the C++ tests (using googletests framework).
+	Runs the C++ (using the googletests framework) and Python
+	tests.
 
   make report-coverage
-	Generates the coverage HTML, excluding some unrelated headers.
-	The HTML reports are placed in a directory called coverage/.
+	Generates the coverage reports in HTML for C++ and Python.
+
+  make clean-cpp-coverage
+	Zeroes the code coverage counters and removes the HTML report
+	for the C++ tests.
+
+  make clean-python-coverage
+	Zeroes the code coverage counters and removes the HTML report
+	for the Python tests.
+
+  make report-cpp-coverage
+	Generates the coverage report in HTML for C++, excluding
+	some unrelated headers.  The HTML reports are placed in a
+	directory called coverage-cpp-html/.
+
+  make report-python-coverage
+	Generates the coverage report in HTML for Python. The HTML
+	reports are placed in a directory called coverage-python-html/.
 
 DEVELOPERS
 

Modified: branches/trac447/configure.ac
==============================================================================
--- branches/trac447/configure.ac (original)
+++ branches/trac447/configure.ac Tue Dec 28 10:31:10 2010
@@ -287,6 +287,26 @@
         AC_DEFINE(HAVE_SA_LEN, 1, [Define to 1 if sockaddr has a sa_len member, and corresponding sin_len and sun_len])],
         AC_MSG_RESULT(no))
 
+AC_ARG_WITH(pycoverage,
+[  --with-pycoverage[=PROGRAM]         enable python code coverage using the specified coverage], pycoverage="$withval", pycoverage="no")
+if test "$pycoverage" = "no" ; then
+	# just run the tests normally with python
+	PYCOVERAGE_RUN="${PYTHON}"
+	USE_PYCOVERAGE="no"
+elif test "$pycoverage" = "yes" ; then
+	PYCOVERAGE="coverage"
+	PYCOVERAGE_RUN="${PYCOVERAGE} run --branch --append"
+	USE_PYCOVERAGE="yes"
+else
+	PYCOVERAGE="$pycoverage"
+	PYCOVERAGE_RUN="${PYCOVERAGE} run --branch --append"
+	USE_PYCOVERAGE="yes"
+fi
+AM_CONDITIONAL(ENABLE_PYTHON_COVERAGE, test x$USE_PYCOVERAGE != xno)
+AC_SUBST(PYCOVERAGE)
+AC_SUBST(PYCOVERAGE_RUN)
+AC_SUBST(USE_PYCOVERAGE)
+
 AC_ARG_WITH(lcov,
 [  --with-lcov[=PROGRAM]         enable gtest and coverage target using the specified lcov], lcov="$withval", lcov="no")
 
@@ -351,7 +371,7 @@
 	BOOST_INCLUDES="-I${boost_include_path}"
 	CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES"
 fi
-AC_CHECK_HEADERS([boost/shared_ptr.hpp boost/foreach.hpp boost/interprocess/sync/interprocess_upgradable_mutex.hpp],,
+AC_CHECK_HEADERS([boost/shared_ptr.hpp boost/foreach.hpp boost/interprocess/sync/interprocess_upgradable_mutex.hpp boost/date_time/posix_time/posix_time_types.hpp boost/bind.hpp boost/function.hpp],,
   AC_MSG_ERROR([Missing required header files.]))
 CPPFLAGS="$CPPFLAGS_SAVES"
 AC_SUBST(BOOST_INCLUDES)
@@ -729,7 +749,8 @@
 
 Developer:
   Google Tests:  $gtest_path
-  Code Coverage: $USE_LCOV
+  C++ Code Coverage: $USE_LCOV
+  Python Code Coverage: $USE_PYCOVERAGE
   Generate Manuals:  $enable_man
 
 END

Modified: branches/trac447/doc/guide/bind10-guide.xml
==============================================================================
--- branches/trac447/doc/guide/bind10-guide.xml (original)
+++ branches/trac447/doc/guide/bind10-guide.xml Tue Dec 28 10:31:10 2010
@@ -42,9 +42,8 @@
 
     <note>
       <para>
-        BIND 10, at this time, does not provide a recursive
-        DNS server. It does provide a EDNS0- and DNSSEC-capable
-        authoritative DNS server.
+        BIND 10 provides a EDNS0- and DNSSEC-capable
+        authoritative DNS server and a forwarding DNS server.
       </para>
     </note>
 

Modified: branches/trac447/src/bin/auth/Makefile.am
==============================================================================
--- branches/trac447/src/bin/auth/Makefile.am (original)
+++ branches/trac447/src/bin/auth/Makefile.am Tue Dec 28 10:31:10 2010
@@ -34,12 +34,14 @@
 spec_config.h: spec_config.h.pre
 	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@
 
-BUILT_SOURCES = spec_config.h 
+BUILT_SOURCES = spec_config.h
 pkglibexec_PROGRAMS = b10-auth
-b10_auth_SOURCES = auth_srv.cc auth_srv.h
-b10_auth_SOURCES += query.cc query.h
+b10_auth_SOURCES = query.cc query.h
+b10_auth_SOURCES += auth_srv.cc auth_srv.h
 b10_auth_SOURCES += change_user.cc change_user.h
+b10_auth_SOURCES += config.cc config.h
 b10_auth_SOURCES += common.h
+b10_auth_SOURCES += statistics.cc statistics.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

Modified: branches/trac447/src/bin/auth/auth.spec.pre.in
==============================================================================
--- branches/trac447/src/bin/auth/auth.spec.pre.in (original)
+++ branches/trac447/src/bin/auth/auth.spec.pre.in Tue Dec 28 10:31:10 2010
@@ -7,6 +7,51 @@
         "item_type": "string",
         "item_optional": true,
         "item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3"
+      },
+      { "item_name": "datasources",
+        "item_type": "list",
+        "item_optional": true,
+        "item_default": [],
+	"list_item_spec": {
+          "item_name": "list_element",
+          "item_type": "map",
+          "item_optional": false,
+          "item_default": {},
+	  "map_item_spec": [
+	    { "item_name": "type",
+	      "item_type": "string",
+	      "item_optional": false,
+	      "item_default": ""
+	    },
+	    { "item_name": "class",
+	      "item_type": "string",
+	      "item_optional": false,
+	      "item_default": "IN"
+	    },
+	    { "item_name": "zones",
+	      "item_type": "list",
+	      "item_optional": false,
+	      "item_default": [],
+	      "list_item_spec": {
+	        "item_name": "list_element",
+	        "item_type": "map",
+	        "item_optional": true,
+	        "map_item_spec": [
+		  { "item_name": "origin",
+		    "item_type": "string",
+		    "item_optional": false,
+		    "item_default": ""
+		  },
+		  { "item_name": "file",
+		    "item_type": "string",
+		    "item_optional": false,
+		    "item_default": ""
+		  }
+		]
+	      }
+	    }
+	  ]
+        }
       }
     ],
     "commands": [
@@ -14,6 +59,11 @@
         "command_name": "shutdown",
         "command_description": "Shut down authoritative DNS server",
         "command_args": []
+      },
+      {
+        "command_name": "sendstats",
+        "command_description": "Send data to a statistics module at once",
+        "command_args": []
       }
     ]
   }

Modified: branches/trac447/src/bin/auth/auth_srv.cc
==============================================================================
--- branches/trac447/src/bin/auth/auth_srv.cc (original)
+++ branches/trac447/src/bin/auth/auth_srv.cc Tue Dec 28 10:31:10 2010
@@ -45,13 +45,17 @@
 
 #include <datasrc/query.h>
 #include <datasrc/data_source.h>
+#include <datasrc/memory_datasrc.h>
 #include <datasrc/static_datasrc.h>
 #include <datasrc/sqlite3_datasrc.h>
 
 #include <xfr/xfrout_client.h>
 
 #include <auth/common.h>
+#include <auth/config.h>
 #include <auth/auth_srv.h>
+#include <auth/query.h>
+#include <auth/statistics.h>
 
 using namespace std;
 
@@ -59,6 +63,7 @@
 using namespace isc::cc;
 using namespace isc::datasrc;
 using namespace isc::dns;
+using namespace isc::auth;
 using namespace isc::dns::rdata;
 using namespace isc::data;
 using namespace isc::config;
@@ -90,8 +95,15 @@
     bool verbose_mode_;
     AbstractSession* xfrin_session_;
 
+    /// In-memory data source.  Currently class IN only for simplicity.
+    const RRClass memory_datasrc_class_;
+    AuthSrv::MemoryDataSrcPtr memory_datasrc_;
+
     /// Hot spot cache
     isc::datasrc::HotCache cache_;
+
+    /// Query counters for statistics
+    AuthCounters counters_;
 private:
     std::string db_file_;
 
@@ -103,12 +115,17 @@
 
     bool xfrout_connected_;
     AbstractXfroutClient& xfrout_client_;
+
+    /// Increment query counter
+    void incCounter(const int protocol);
 };
 
 AuthSrvImpl::AuthSrvImpl(const bool use_cache,
                          AbstractXfroutClient& xfrout_client) :
     config_session_(NULL), verbose_mode_(false),
     xfrin_session_(NULL),
+    memory_datasrc_class_(RRClass::IN()),
+    counters_(verbose_mode_),
     xfrout_connected_(false),
     xfrout_client_(xfrout_client)
 {
@@ -285,9 +302,47 @@
     impl_->config_session_ = config_session;
 }
 
+void
+AuthSrv::setStatisticsSession(AbstractSession* statistics_session) {
+    impl_->counters_.setStatisticsSession(statistics_session);
+}
+
 ModuleCCSession*
 AuthSrv::getConfigSession() const {
     return (impl_->config_session_);
+}
+
+AuthSrv::ConstMemoryDataSrcPtr
+AuthSrv::getMemoryDataSrc(const RRClass& rrclass) const {
+    // XXX: for simplicity, we only support the IN class right now.
+    if (rrclass != impl_->memory_datasrc_class_) {
+        isc_throw(InvalidParameter,
+                  "Memory data source is not supported for RR class "
+                  << rrclass);
+    }
+    return (impl_->memory_datasrc_);
+}
+
+void
+AuthSrv::setMemoryDataSrc(const isc::dns::RRClass& rrclass,
+                          MemoryDataSrcPtr memory_datasrc)
+{
+    // XXX: see above
+    if (rrclass != impl_->memory_datasrc_class_) {
+        isc_throw(InvalidParameter,
+                  "Memory data source is not supported for RR class "
+                  << rrclass);
+    }
+    if (impl_->verbose_mode_) {
+        if (!impl_->memory_datasrc_ && memory_datasrc) {
+            cerr << "[b10-auth] Memory data source is enabled for class "
+                 << rrclass << endl;
+        } else if (impl_->memory_datasrc_ && !memory_datasrc) {
+            cerr << "[b10-auth] Memory data source is disabled for class "
+                 << rrclass << endl;
+        }
+    }
+    impl_->memory_datasrc_ = memory_datasrc;
 }
 
 void
@@ -387,6 +442,9 @@
     message->setHeaderFlag(Message::HEADERFLAG_AA);
     message->setRcode(Rcode::NOERROR());
 
+    // Increment query counter.
+    incCounter(io_message.getSocket().getProtocol());
+
     if (remote_edns) {
         EDNSPtr local_edns = EDNSPtr(new EDNS());
         local_edns->setDNSSECAwareness(dnssec_ok);
@@ -395,8 +453,17 @@
     }
 
     try {
-        Query query(*message, cache_, dnssec_ok);
-        data_sources_.doQuery(query);
+        // If a memory data source is configured call the separate
+        // Query::process()
+        const ConstQuestionPtr question = *message->beginQuestion();
+        if (memory_datasrc_ && memory_datasrc_class_ == question->getClass()) {
+            const RRType& qtype = question->getType();
+            const Name& qname = question->getName();
+            auth::Query(*memory_datasrc_, qname, qtype, *message).process();
+        } else {
+            datasrc::Query query(*message, cache_, dnssec_ok);
+            data_sources_.doQuery(query);
+        }
     } catch (const Exception& ex) {
         if (verbose_mode_) {
             cerr << "[b10-auth] Internal error, returning SERVFAIL: " <<
@@ -405,7 +472,6 @@
         makeErrorMessage(message, buffer, Rcode::SERVFAIL(), verbose_mode_);
         return (true);
     }
-
 
     MessageRenderer renderer(*buffer);
     const bool udp_buffer =
@@ -426,6 +492,9 @@
 AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, MessagePtr message,
                               OutputBufferPtr buffer)
 {
+    // Increment query counter.
+    incCounter(io_message.getSocket().getProtocol());
+
     if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
         if (verbose_mode_) {
             cerr << "[b10-auth] AXFR query over UDP isn't allowed" << endl;
@@ -551,6 +620,19 @@
     return (true);
 }
 
+void
+AuthSrvImpl::incCounter(const int protocol) {
+    // Increment query counter.
+    if (protocol == IPPROTO_UDP) {
+        counters_.inc(AuthCounters::COUNTER_UDP_QUERY);
+    } else if (protocol == IPPROTO_TCP) {
+        counters_.inc(AuthCounters::COUNTER_TCP_QUERY);
+    } else {
+        // unknown protocol
+        isc_throw(Unexpected, "Unknown protocol: " << protocol);
+    }
+}
+
 ConstElementPtr
 AuthSrvImpl::setDbFile(ConstElementPtr config) {
     ConstElementPtr answer = isc::config::createAnswer();
@@ -609,6 +691,9 @@
     try {
         // the ModuleCCSession has already checked if we have
         // the correct ElementPtr type as specified in our .spec file
+        if (new_config) {
+            configureAuthServer(*this, new_config);
+        }
         return (impl_->setDbFile(new_config));
     } catch (const isc::Exception& error) {
         if (impl_->verbose_mode_) {
@@ -617,3 +702,12 @@
         return (isc::config::createAnswer(1, error.what()));
     }
 }
+
+bool AuthSrv::submitStatistics() const {
+    return (impl_->counters_.submitStatistics());
+}
+
+uint64_t
+AuthSrv::getCounter(const AuthCounters::CounterType type) const {
+    return (impl_->counters_.getCounter(type));
+}

Modified: branches/trac447/src/bin/auth/auth_srv.h
==============================================================================
--- branches/trac447/src/bin/auth/auth_srv.h (original)
+++ branches/trac447/src/bin/auth/auth_srv.h Tue Dec 28 10:31:10 2010
@@ -19,16 +19,25 @@
 
 #include <string>
 
+// For MemoryDataSrcPtr below.  This should be a temporary definition until
+// we reorganize the data source framework.
+#include <boost/shared_ptr.hpp>
+
 #include <cc/data.h>
 #include <config/ccsession.h>
 
 #include <asiolink/asiolink.h>
+#include <auth/statistics.h>
 
 namespace isc {
+namespace datasrc {
+class MemoryDataSrc;
+}
 namespace xfr {
 class AbstractXfroutClient;
 }
 }
+
 
 /// \brief The implementation class for the \c AuthSrv class using the pimpl
 /// idiom.
@@ -54,6 +63,7 @@
 ///
 /// The design of this class is still in flux.  It's quite likely to change
 /// in future versions.
+///
 class AuthSrv {
     ///
     /// \name Constructors, Assignment Operator and Destructor.
@@ -88,6 +98,8 @@
     /// \param message Pointer to the \c Message object
     /// \param buffer Pointer to an \c OutputBuffer for the resposne
     /// \param server Pointer to the \c DNSServer
+    ///
+    /// \throw isc::Unexpected Protocol type of \a message is unexpected
     void processMessage(const asiolink::IOMessage& io_message,
                         isc::dns::MessagePtr message,
                         isc::dns::OutputBufferPtr buffer,
@@ -123,9 +135,11 @@
     /// If there is a data source installed, it will be replaced with the
     /// new one.
     ///
-    /// In the current implementation, the SQLite data source is assumed.
-    /// The \c config parameter will simply be passed to the initialization
-    /// routine of the \c Sqlite3DataSrc class.
+    /// In the current implementation, the SQLite data source and MemoryDataSrc
+    /// are assumed.
+    /// We can enable memory data source and get the path of SQLite database by
+    /// the \c config parameter.  If we disabled memory data source, the SQLite
+    /// data source will be used.
     ///
     /// On success this method returns a data \c Element (in the form of a
     /// pointer like object) indicating the successful result,
@@ -224,6 +238,96 @@
     ///
     void setXfrinSession(isc::cc::AbstractSession* xfrin_session);
 
+    /// A shared pointer type for \c MemoryDataSrc.
+    ///
+    /// This is defined inside the \c AuthSrv class as it's supposed to be
+    /// a short term interface until we integrate the in-memory and other
+    /// data source frameworks.
+    typedef boost::shared_ptr<isc::datasrc::MemoryDataSrc> MemoryDataSrcPtr;
+
+    /// An immutable shared pointer type for \c MemoryDataSrc.
+    typedef boost::shared_ptr<const isc::datasrc::MemoryDataSrc>
+    ConstMemoryDataSrcPtr;
+
+    /// Returns the in-memory data source configured for the \c AuthSrv,
+    /// if any.
+    ///
+    /// The in-memory data source is configured per RR class.  However,
+    /// the data source may not be available for all RR classes.
+    /// If it is not available for the specified RR class, an exception of
+    /// class \c InvalidParameter will be thrown.
+    /// This method never throws an exception otherwise.
+    ///
+    /// Even for supported RR classes, the in-memory data source is not
+    /// configured by default.  In that case a NULL (shared) pointer will
+    /// be returned.
+    ///
+    /// \param rrclass The RR class of the requested in-memory data source.
+    /// \return A pointer to the in-memory data source, if configured;
+    /// otherwise NULL.
+    ConstMemoryDataSrcPtr
+    getMemoryDataSrc(const isc::dns::RRClass& rrclass) const;
+
+    /// Sets or replaces the in-memory data source of the specified RR class.
+    ///
+    /// As noted in \c getMemoryDataSrc(), some RR classes may not be
+    /// supported, in which case an exception of class \c InvalidParameter
+    /// will be thrown.
+    /// This method never throws an exception otherwise.
+    ///
+    /// If there is already an in memory data source configured, it will be
+    /// replaced with the newly specified one.
+    /// \c memory_datasrc can be NULL, in which case it will (re)disable the
+    /// in-memory data source.
+    ///
+    /// \param rrclass The RR class of the in-memory data source to be set.
+    /// \param memory_datasrc A (shared) pointer to \c MemoryDataSrc to be set.
+    void setMemoryDataSrc(const isc::dns::RRClass& rrclass,
+                          MemoryDataSrcPtr memory_datasrc);
+
+    /// \brief Set the communication session with Statistics.
+    ///
+    /// This function never throws an exception as far as
+    /// AuthCounters::setStatisticsSession() doesn't throw.
+    ///
+    /// Note: this interface is tentative.  We'll revisit the ASIO and
+    /// session frameworks, at which point the session will probably
+    /// be passed on construction of the server.
+    ///
+    /// \param statistics_session A Session object over which statistics
+    /// information is exchanged with statistics module.
+    /// The session must be established before setting in the server
+    /// object.
+    /// Ownership isn't transferred: the caller is responsible for keeping
+    /// this object to be valid while the server object is working and for
+    /// disconnecting the session and destroying the object when the server
+    /// is shutdown.
+    void setStatisticsSession(isc::cc::AbstractSession* statistics_session);
+
+    /// \brief Submit statistics counters to statistics module.
+    ///
+    /// This function can throw an exception from
+    /// AuthCounters::submitStatistics().
+    ///
+    /// \return true on success, false on failure (e.g. session timeout,
+    /// session error).
+    bool submitStatistics() const;
+
+    /// \brief Get the value of counter in the AuthCounters.
+    /// 
+    /// This function calls AuthCounters::getCounter() and
+    /// returns its return value.
+    ///
+    /// This function never throws an exception as far as
+    /// AuthCounters::getCounter() doesn't throw.
+    /// 
+    /// Note: Currently this function is for testing purpose only.
+    ///
+    /// \param type Type of a counter to get the value of
+    ///
+    /// \return the value of the counter.
+    uint64_t getCounter(const AuthCounters::CounterType type) const;
+
 private:
     AuthSrvImpl* impl_;
     asiolink::IOService* io_service_;

Modified: branches/trac447/src/bin/auth/benchmarks/Makefile.am
==============================================================================
--- branches/trac447/src/bin/auth/benchmarks/Makefile.am (original)
+++ branches/trac447/src/bin/auth/benchmarks/Makefile.am Tue Dec 28 10:31:10 2010
@@ -8,7 +8,10 @@
 
 noinst_PROGRAMS = query_bench
 query_bench_SOURCES = query_bench.cc
+query_bench_SOURCES += ../query.h  ../query.cc
 query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
+query_bench_SOURCES += ../config.h ../config.cc
+query_bench_SOURCES += ../statistics.h ../statistics.cc
 
 query_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
 query_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la

Modified: branches/trac447/src/bin/auth/benchmarks/query_bench.cc
==============================================================================
--- branches/trac447/src/bin/auth/benchmarks/query_bench.cc (original)
+++ branches/trac447/src/bin/auth/benchmarks/query_bench.cc Tue Dec 28 10:31:10 2010
@@ -33,11 +33,14 @@
 #include <xfr/xfrout_client.h>
 
 #include <auth/auth_srv.h>
+#include <auth/query.h>
+
 #include <asiolink/asiolink.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::data;
+using namespace isc::auth;
 using namespace isc::dns;
 using namespace isc::xfr;
 using namespace isc::bench;

Modified: branches/trac447/src/bin/auth/change_user.cc
==============================================================================
--- branches/trac447/src/bin/auth/change_user.cc (original)
+++ branches/trac447/src/bin/auth/change_user.cc Tue Dec 28 10:31:10 2010
@@ -26,6 +26,7 @@
 #include <auth/common.h>
 
 using namespace boost;
+using namespace std;
 
 void
 changeUser(const char* const username) {
@@ -42,14 +43,14 @@
         }
     }
     if (runas_pw == NULL) {
-        isc_throw(FatalError, "Unknown user name or UID:" << username);
+        throw FatalError("Unknown user name or UID:" + string(username));
     }
 
     if (setgid(runas_pw->pw_gid) < 0) {
-        isc_throw(FatalError, "setgid() failed: " << strerror(errno));
+        throw FatalError("setgid() failed: " + string(strerror(errno)));
     }
 
     if (setuid(runas_pw->pw_uid) < 0) {
-        isc_throw(FatalError, "setuid() failed: " << strerror(errno));
+        throw FatalError("setuid() failed: " + string(strerror(errno)));
     }
 }

Modified: branches/trac447/src/bin/auth/common.h
==============================================================================
--- branches/trac447/src/bin/auth/common.h (original)
+++ branches/trac447/src/bin/auth/common.h Tue Dec 28 10:31:10 2010
@@ -17,12 +17,18 @@
 #ifndef __COMMON_H
 #define __COMMON_H 1
 
-#include <exceptions/exceptions.h>
+#include <stdexcept>
+#include <string>
 
-class FatalError : public isc::Exception {
+/// An exception class that is thrown in an unrecoverable error condition.
+///
+/// This exception should not be caught except at the highest level of
+/// the application only for terminating the program gracefully, and so
+/// it cannot be a derived class of \c isc::Exception.
+class FatalError : public std::runtime_error {
 public:
-    FatalError(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
+    FatalError(const std::string& what) : std::runtime_error(what)
+    {}
 };
 
 #endif // __COMMON_H

Modified: branches/trac447/src/bin/auth/main.cc
==============================================================================
--- branches/trac447/src/bin/auth/main.cc (original)
+++ branches/trac447/src/bin/auth/main.cc Tue Dec 28 10:31:10 2010
@@ -25,7 +25,7 @@
 #include <cassert>
 #include <iostream>
 
-#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
 
 #include <exceptions/exceptions.h>
 
@@ -41,6 +41,7 @@
 
 #include <auth/spec_config.h>
 #include <auth/common.h>
+#include <auth/config.h>
 #include <auth/change_user.h>
 #include <auth/auth_srv.h>
 #include <asiolink/asiolink.h>
@@ -61,6 +62,10 @@
 static const string PROGRAM = "Auth";
 static const char* DNSPORT = "5300";
 
+// Note: this value must be greater than 0.
+// TODO: make it configurable via command channel.
+const uint32_t STATISTICS_SEND_INTERVAL_SEC = 60;
+
 /* need global var for config/command handlers.
  * todo: turn this around, and put handlers in the authserver
  * class itself? */
@@ -83,8 +88,14 @@
         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;
+        }
+        assert(auth_server != NULL);
+        auth_server->submitStatistics();
+    }
+
     return (answer);
 }
 
@@ -102,6 +113,12 @@
     cerr << "\t-v: verbose output" << endl;
     exit(1);
 }
+
+void
+statisticsTimerCallback(AuthSrv* auth_server) {
+    assert(auth_server != NULL);
+    auth_server->submitStatistics();
+}
 } // end of anonymous namespace
 
 int
@@ -167,7 +184,10 @@
     // XXX: we should eventually pass io_service here.
     Session* cc_session = NULL;
     Session* xfrin_session = NULL;
+    Session* statistics_session = NULL;
+    IntervalTimer* itimer = NULL;
     bool xfrin_session_established = false; // XXX (see Trac #287)
+    bool statistics_session_established = false; // XXX (see Trac #287)
     ModuleCCSession* config_session = NULL;
     string xfrout_socket_path;
     if (getenv("B10_FROM_BUILD") != NULL) {
@@ -229,14 +249,35 @@
         xfrin_session_established = true;
         cout << "[b10-auth] Xfrin session channel established." << endl;
 
+        statistics_session = new Session(io_service.get_io_service());
+        cout << "[b10-auth] Statistics session channel created." << endl;
+        statistics_session->establish(NULL);
+        statistics_session_established = true;
+        cout << "[b10-auth] Statistics session channel established." << endl;
+
         // XXX: with the current interface to asiolink we have to create
         // auth_server before io_service while Session needs io_service.
         // In a next step of refactoring we should make asiolink independent
         // from auth_server, and create io_service, auth_server, and
         // sessions in that order.
         auth_server->setXfrinSession(xfrin_session);
+        auth_server->setStatisticsSession(statistics_session);
+
+        // Configure the server.  configureAuthServer() is expected to install
+        // all initial configurations, but as a short term workaround we
+        // handle the traditional "database_file" setup by directly calling
+        // updateConfig().
         auth_server->setConfigSession(config_session);
+        configureAuthServer(*auth_server, config_session->getFullConfig());
         auth_server->updateConfig(ElementPtr());
+
+        // create interval timer instance
+        itimer = new IntervalTimer(io_service);
+        // set up interval timer
+        // register function to send statistics with interval
+        itimer->setupTimer(boost::bind(statisticsTimerCallback, auth_server),
+                           STATISTICS_SEND_INTERVAL_SEC);
+        cout << "[b10-auth] Interval timer to send statistics set." << endl;
 
         cout << "[b10-auth] Server started." << endl;
         io_service.run();
@@ -247,10 +288,16 @@
         ret = 1;
     }
 
+    if (statistics_session_established) {
+        statistics_session->disconnect();
+    }
+
     if (xfrin_session_established) {
         xfrin_session->disconnect();
     }
 
+    delete itimer;
+    delete statistics_session;
     delete xfrin_session;
     delete config_session;
     delete cc_session;

Modified: branches/trac447/src/bin/auth/query.cc
==============================================================================
--- branches/trac447/src/bin/auth/query.cc (original)
+++ branches/trac447/src/bin/auth/query.cc Tue Dec 28 10:31:10 2010
@@ -15,7 +15,7 @@
 #include <dns/message.h>
 #include <dns/rcode.h>
 
-#include <datasrc/zonetable.h>
+#include <datasrc/memory_datasrc.h>
 
 #include <auth/query.h>
 
@@ -24,19 +24,54 @@
 
 namespace isc {
 namespace auth {
+
 void
 Query::process() const {
-    const ZoneTable::FindResult result = zone_table_.findZone(qname_);
+    bool keep_doing = true;
+    response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
+    const MemoryDataSrc::FindResult result =
+        memory_datasrc_.findZone(qname_);
 
-    if (result.code != isc::datasrc::result::SUCCESS &&
-        result.code != isc::datasrc::result::PARTIALMATCH) {
-        response_.setRcode(Rcode::SERVFAIL());
+    // If we have no matching authoritative zone for the query name, return
+    // REFUSED.  In short, this is to be compatible with BIND 9, but the
+    // background discussion is not that simple.  See the relevant topic
+    // at the BIND 10 developers's ML:
+    // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
+    if (result.code != result::SUCCESS &&
+        result.code != result::PARTIALMATCH) {
+        response_.setRcode(Rcode::REFUSED());
         return;
     }
 
-    // Right now we have no code to search the zone, so we simply return
-    // NXDOMAIN for tests.
-    response_.setRcode(Rcode::NXDOMAIN());
+    // Found a zone which is the nearest ancestor to QNAME, set the AA bit
+    response_.setHeaderFlag(Message::HEADERFLAG_AA);
+    while (keep_doing) {
+        keep_doing = false;
+        Zone::FindResult db_result = result.zone->find(qname_, qtype_);
+        switch (db_result.code) {
+            case Zone::SUCCESS:
+                response_.setRcode(Rcode::NOERROR());
+                response_.addRRset(Message::SECTION_ANSWER,
+                            boost::const_pointer_cast<RRset>(db_result.rrset));
+                // TODO : fill in authority and addtional sections.
+                break;
+            case Zone::DELEGATION:
+                // TODO : add NS to authority section, fill in additional section.
+                break;
+            case Zone::NXDOMAIN:
+                response_.setRcode(Rcode::NXDOMAIN());
+                // TODO : add SOA to authority section
+                break;
+            case Zone::NXRRSET:
+                response_.setRcode(Rcode::NOERROR());
+                // TODO : add SOA to authority section
+                break;
+            case Zone::CNAME:
+            case Zone::DNAME:
+                // TODO : replace qname, continue lookup
+                break;
+        }
+    }
 }
 }
 }

Modified: branches/trac447/src/bin/auth/query.h
==============================================================================
--- branches/trac447/src/bin/auth/query.h (original)
+++ branches/trac447/src/bin/auth/query.h Tue Dec 28 10:31:10 2010
@@ -22,7 +22,7 @@
 }
 
 namespace datasrc {
-class ZoneTable;
+class MemoryDataSrc;
 }
 
 namespace auth {
@@ -32,11 +32,11 @@
 ///
 /// Many of the design details for this class are still in flux.
 /// We'll revisit and update them as we add more functionality, for example:
-/// - zone_table parameter of the constructor.  This will eventually be
-///   replaced with a generic DataSrc object, or perhaps a notion of "view".
+/// - memory_datasrc parameter of the constructor.  It is a data source that
+///   uses in memory dedicated backend.
 /// - as a related point, we may have to pass the RR class of the query.
-///   in the initial implementation the RR class is an attribute of zone
-///   table and omitted.  It's not clear if this assumption holds with
+///   in the initial implementation the RR class is an attribute of memory
+///   datasource and omitted.  It's not clear if this assumption holds with
 ///   generic data sources.  On the other hand, it will help keep
 ///   implementation simpler, and we might rather want to modify the design
 ///   of the data source on this point.
@@ -47,8 +47,8 @@
 ///   separate attribute setter.
 /// - likewise, we'll eventually need to do per zone access control, for which
 ///   we need querier's information such as its IP address.
-/// - zone_table (or DataSrc eventually) and response may better be parameters
-///   to process() instead of the constructor.
+/// - memory_datasrc and response may better be parameters to process() instead
+///   of the constructor.
 ///
 /// <b>Note:</b> The class name is intentionally the same as the one used in
 /// the datasrc library.  This is because the plan is to eventually merge
@@ -65,15 +65,15 @@
     ///
     /// This constructor never throws an exception.
     ///
-    /// \param zone_table The zone table wherein the answer to the query is
+    /// \param memory_datasrc The memory datasource wherein the answer to the query is
     /// to be found.
     /// \param qname The query name
     /// \param qtype The RR type of the query
     /// \param response The response message to store the answer to the query.
-    Query(const isc::datasrc::ZoneTable& zone_table,
+    Query(const isc::datasrc::MemoryDataSrc& memory_datasrc,
           const isc::dns::Name& qname, const isc::dns::RRType& qtype,
           isc::dns::Message& response) :
-        zone_table_(zone_table), qname_(qname), qtype_(qtype),
+        memory_datasrc_(memory_datasrc), qname_(qname), qtype_(qtype),
         response_(response)
     {}
 
@@ -87,7 +87,7 @@
     /// successful search would result in adding a corresponding RRset to
     /// the answer section of the response.
     ///
-    /// If no matching zone is found in the zone table, the RCODE of
+    /// If no matching zone is found in the memory datasource, the RCODE of
     /// SERVFAIL will be set in the response.
     /// <b>Note:</b> this is different from the error code that BIND 9 returns
     /// by default when it's configured as an authoritative-only server (and
@@ -105,7 +105,7 @@
     void process() const;
 
 private:
-    const isc::datasrc::ZoneTable& zone_table_;
+    const isc::datasrc::MemoryDataSrc& memory_datasrc_;
     const isc::dns::Name& qname_;
     const isc::dns::RRType& qtype_;
     isc::dns::Message& response_;

Modified: branches/trac447/src/bin/auth/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/auth/tests/Makefile.am (original)
+++ branches/trac447/src/bin/auth/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -21,9 +21,13 @@
 run_unittests_SOURCES += ../auth_srv.h ../auth_srv.cc
 run_unittests_SOURCES += ../query.h ../query.cc
 run_unittests_SOURCES += ../change_user.h ../change_user.cc
+run_unittests_SOURCES += ../config.h ../config.cc
+run_unittests_SOURCES += ../statistics.h ../statistics.cc
 run_unittests_SOURCES += auth_srv_unittest.cc
+run_unittests_SOURCES += config_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += change_user_unittest.cc
+run_unittests_SOURCES += statistics_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

Modified: branches/trac447/src/bin/auth/tests/auth_srv_unittest.cc
==============================================================================
--- branches/trac447/src/bin/auth/tests/auth_srv_unittest.cc (original)
+++ branches/trac447/src/bin/auth/tests/auth_srv_unittest.cc Tue Dec 28 10:31:10 2010
@@ -15,10 +15,11 @@
 // $Id$
 
 #include <config.h>
+#include <datasrc/memory_datasrc.h>
 #include <auth/auth_srv.h>
 #include <testutils/srv_unittest.h>
-
-using namespace std;
+#include <auth/statistics.h>
+
 using namespace isc::cc;
 using namespace isc::dns;
 using namespace isc::data;
@@ -36,11 +37,14 @@
 
 class AuthSrvTest : public SrvTestBase {
 protected:
-    AuthSrvTest() : server(true, xfrout) {
+    AuthSrvTest() : server(true, xfrout), rrclass(RRClass::IN()) {
         server.setXfrinSession(&notify_session);
+        server.setStatisticsSession(&statistics_session);
     }
+    MockSession statistics_session;
     MockXfroutClient xfrout;
     AuthSrv server;
+    const RRClass rrclass;
 };
 
 // Unsupported requests.  Should result in NOTIMP.
@@ -325,11 +329,11 @@
 }
 
 void
-updateConfig(AuthSrv* server, const char* const dbfile,
+updateConfig(AuthSrv* server, const char* const config_data,
              const bool expect_success)
 {
     ConstElementPtr config_answer =
-        server->updateConfig(Element::fromJSON(dbfile));
+        server->updateConfig(Element::fromJSON(config_data));
     EXPECT_EQ(Element::map, config_answer->getType());
     EXPECT_TRUE(config_answer->contains("result"));
 
@@ -381,6 +385,44 @@
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
+TEST_F(AuthSrvTest, updateWithMemoryDataSrc) {
+    // Test configuring memory data source.  Detailed test cases are covered
+    // in the configuration tests.  We only check the AuthSrv interface here.
+
+    // By default memory data source isn't enabled
+    EXPECT_EQ(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
+    updateConfig(&server,
+                 "{\"datasources\": [{\"type\": \"memory\"}]}", true);
+    // after successful configuration, we should have one (with empty zoneset).
+    ASSERT_NE(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
+    EXPECT_EQ(0, server.getMemoryDataSrc(rrclass)->getZoneCount());
+
+    // The memory data source is empty, should return REFUSED rcode.
+    createDataFromFile("examplequery_fromWire.wire");
+    server.processMessage(*io_message, parse_message, response_obuffer,
+                          &dnsserv);
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::REFUSED(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+}
+
+TEST_F(AuthSrvTest, chQueryWithMemoryDataSrc) {
+    // Configure memory data source for class IN
+    updateConfig(&server, "{\"datasources\": "
+                 "[{\"class\": \"IN\", \"type\": \"memory\"}]}", true);
+
+    // This shouldn't affect the result of class CH query
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("version.bind"),
+                                       RRClass::CH(), RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    server.processMessage(*io_message, parse_message, response_obuffer,
+                          &dnsserv);
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
+}
+
 TEST_F(AuthSrvTest, cacheSlots) {
     // simple check for the get/set operations
     server.setCacheSlots(10);    // 10 = arbitrary choice
@@ -390,4 +432,90 @@
     server.setCacheSlots(0);
     EXPECT_EQ(00, server.getCacheSlots());
 }
-}
+
+// Submit UDP normal query and check query counter
+TEST_F(AuthSrvTest, queryCounterUDPNormal) {
+    // The counter should be initialized to 0.
+    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_UDP_QUERY));
+    // Create UDP message and process.
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("example.com"),
+                                       RRClass::IN(), RRType::NS());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    server.processMessage(*io_message, parse_message, response_obuffer,
+                          &dnsserv);
+    // After processing UDP query, the counter should be 1.
+    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_UDP_QUERY));
+}
+
+// Submit TCP normal query and check query counter
+TEST_F(AuthSrvTest, queryCounterTCPNormal) {
+    // The counter should be initialized to 0.
+    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+    // Create TCP message and process.
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("example.com"),
+                                       RRClass::IN(), RRType::NS());
+    createRequestPacket(request_message, IPPROTO_TCP);
+    server.processMessage(*io_message, parse_message, response_obuffer,
+                          &dnsserv);
+    // After processing TCP query, the counter should be 1.
+    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+}
+
+// Submit TCP AXFR query and check query counter
+TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
+    // The counter should be initialized to 0.
+    EXPECT_EQ(0, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
+                         Name("example.com"), RRClass::IN(), RRType::AXFR());
+    createRequestPacket(request_message, IPPROTO_TCP);
+    // On success, the AXFR query has been passed to a separate process,
+    // so we shouldn't have to respond.
+    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
+    // After processing TCP AXFR query, the counter should be 1.
+    EXPECT_EQ(1, server.getCounter(AuthCounters::COUNTER_TCP_QUERY));
+}
+
+// class for queryCounterUnexpected test
+// getProtocol() returns IPPROTO_IP
+class DummyUnknownSocket : public IOSocket {
+public:
+    DummyUnknownSocket() {}
+    virtual int getNative() const { return (0); }
+    virtual int getProtocol() const { return (IPPROTO_IP); }
+};
+
+// function for queryCounterUnexpected test
+// returns a reference to a static object of DummyUnknownSocket
+IOSocket&
+getDummyUnknownSocket() {
+    static DummyUnknownSocket socket;
+    return (socket);
+}
+
+// Submit unexpected type of query and check it throws isc::Unexpected
+TEST_F(AuthSrvTest, queryCounterUnexpected) {
+    // This code isn't exception safe, but we'd rather keep the code
+    // simpler and more readable as this is only for tests and if it throws
+    // the program would immediately terminate anyway.
+
+    // Create UDP query packet.
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("example.com"),
+                                       RRClass::IN(), RRType::NS());
+    createRequestPacket(request_message, IPPROTO_UDP);
+
+    // Modify the message.
+    delete io_message;
+    endpoint = IOEndpoint::create(IPPROTO_UDP,
+                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
+    io_message = new IOMessage(request_renderer.getData(),
+                               request_renderer.getLength(),
+                               getDummyUnknownSocket(), *endpoint);
+
+    EXPECT_THROW(server.processMessage(*io_message, parse_message,
+                                       response_obuffer, &dnsserv),
+                 isc::Unexpected);
+}
+}

Modified: branches/trac447/src/bin/auth/tests/query_unittest.cc
==============================================================================
--- branches/trac447/src/bin/auth/tests/query_unittest.cc (original)
+++ branches/trac447/src/bin/auth/tests/query_unittest.cc Tue Dec 28 10:31:10 2010
@@ -15,9 +15,9 @@
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/rcode.h>
+#include <dns/rrttl.h>
 #include <dns/rrtype.h>
 
-#include <datasrc/zonetable.h>
 #include <datasrc/memory_datasrc.h>
 
 #include <auth/query.h>
@@ -28,17 +28,69 @@
 using namespace isc::datasrc;
 using namespace isc::auth;
 
+RRsetPtr a_rrset = RRsetPtr(new RRset(Name("www.example.com"),
+                                      RRClass::IN(), RRType::A(),
+                                      RRTTL(3600)));
 namespace {
+// This is a mock Zone class for testing.
+// It is a derived class of Zone, and simply hardcode the results of find()
+// return SUCCESS for "www.example.com",
+// return NXDOMAIN for "nxdomain.example.com",
+// return NXRRSET for "nxrrset.example.com",
+// return CNAME for "cname.example.com",
+// else return DNAME
+class MockZone : public Zone {
+public:
+    MockZone() : origin_(Name("example.com"))
+    {}
+    virtual const isc::dns::Name& getOrigin() const;
+    virtual const isc::dns::RRClass& getClass() const;
+
+    FindResult find(const isc::dns::Name& name,
+            const isc::dns::RRType& type) const;
+
+private:
+    Name origin_;
+};
+
+const Name&
+MockZone::getOrigin() const {
+    return (origin_);
+}
+
+const RRClass&
+MockZone::getClass() const {
+    return (RRClass::IN());
+}
+
+Zone::FindResult
+MockZone::find(const Name& name, const RRType&) const {
+    // hardcode the find results
+    if (name == Name("www.example.com")) {
+        return FindResult(SUCCESS, a_rrset);
+    } else if (name == Name("delegation.example.com")) {
+        return FindResult(DELEGATION, RRsetPtr());
+    } else if (name == Name("nxdomain.example.com")) {
+        return FindResult(NXDOMAIN, RRsetPtr());
+    } else if (name == Name("nxrrset.example.com")) {
+        return FindResult(NXRRSET, RRsetPtr());
+    } else if (name == Name("cname.example.com")) {
+        return FindResult(CNAME, RRsetPtr());
+    } else {
+        return FindResult(DNAME, RRsetPtr());
+    }
+}
+
 class QueryTest : public ::testing::Test {
 protected:
     QueryTest() :
         qname(Name("www.example.com")), qclass(RRClass::IN()),
         qtype(RRType::A()), response(Message::RENDER),
-        query(zone_table, qname, qtype, response)
+        query(memory_datasrc, qname, qtype, response)
     {
         response.setRcode(Rcode::NOERROR());
     }
-    ZoneTable zone_table;
+    MemoryDataSrc memory_datasrc;
     const Name qname;
     const RRClass qclass;
     const RRType qtype;
@@ -47,25 +99,41 @@
 };
 
 TEST_F(QueryTest, noZone) {
-    // There's no zone in the zone table.  So the response should have
-    // SERVFAIL.
+    // There's no zone in the memory datasource.  So the response should have
+    // REFUSED.
     query.process();
-    EXPECT_EQ(Rcode::SERVFAIL(), response.getRcode());
+    EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 
 TEST_F(QueryTest, matchZone) {
-    // add a matching zone.  since the zone is empty right now, the response
-    // should have NXDOMAIN.
-    zone_table.addZone(ZonePtr(new MemoryZone(qclass, Name("example.com"))));
+    // match qname, normal query
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
     query.process();
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
+                                  Name("www.example.com"), RRClass::IN(),
+                                  RRType::A()));
+
+    // NXDOMAIN
+    const Name nxdomain_name(Name("nxdomain.example.com"));
+    Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);
+    nxdomain_query.process();
     EXPECT_EQ(Rcode::NXDOMAIN(), response.getRcode());
+
+    // NXRRSET
+    const Name nxrrset_name(Name("nxrrset.example.com"));
+    Query nxrrset_query(memory_datasrc, nxrrset_name, qtype, response);
+    nxrrset_query.process();
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
 }
 
 TEST_F(QueryTest, noMatchZone) {
-    // there's a zone in the table but it doesn't match the qname.  should
-    // result in SERVFAIL.
-    zone_table.addZone(ZonePtr(new MemoryZone(qclass, Name("example.org"))));
-    query.process();
-    EXPECT_EQ(Rcode::SERVFAIL(), response.getRcode());
+    // there's a zone in the memory datasource but it doesn't match the qname.
+    // should result in REFUSED.
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    const Name nomatch_name(Name("example.org"));
+    Query nomatch_query(memory_datasrc, nomatch_name, qtype, response);
+    nomatch_query.process();
+    EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 }

Modified: branches/trac447/src/bin/bind10/run_bind10.sh.in
==============================================================================
--- branches/trac447/src/bin/bind10/run_bind10.sh.in (original)
+++ branches/trac447/src/bin/bind10/run_bind10.sh.in Tue Dec 28 10:31:10 2010
@@ -46,5 +46,5 @@
 export BIND10_MSGQ_SOCKET_FILE
 
 cd ${BIND10_PATH}
-exec ${PYTHON_EXEC} -O bind10 $*
+exec ${PYTHON_EXEC} -O bind10 "$@"
 

Modified: branches/trac447/src/bin/bind10/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/bind10/tests/Makefile.am (original)
+++ branches/trac447/src/bin/bind10/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,12 +1,17 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
+#PYTESTS = args_test.py bind10_test.py
 PYTESTS = bind10_test.py
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/bin/bindctl/run_bindctl.sh.in
==============================================================================
--- branches/trac447/src/bin/bindctl/run_bindctl.sh.in (original)
+++ branches/trac447/src/bin/bindctl/run_bindctl.sh.in Tue Dec 28 10:31:10 2010
@@ -26,5 +26,8 @@
 B10_FROM_SOURCE=@abs_top_srcdir@
 export B10_FROM_SOURCE
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 cd ${BINDCTL_PATH}
-exec ${PYTHON_EXEC} -O bindctl $*
+exec ${PYTHON_EXEC} -O bindctl "$@"

Modified: branches/trac447/src/bin/bindctl/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/bindctl/tests/Makefile.am (original)
+++ branches/trac447/src/bin/bindctl/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,12 +1,16 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = bindctl_test.py
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/bin/cfgmgr/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/cfgmgr/tests/Makefile.am (original)
+++ branches/trac447/src/bin/cfgmgr/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,13 +1,17 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = b10-cfgmgr_test.py
 
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr \
-	$(PYCOVERAGE) $(abs_builddir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/bin/cmdctl/run_b10-cmdctl.sh.in
==============================================================================
--- branches/trac447/src/bin/cmdctl/run_b10-cmdctl.sh.in (original)
+++ branches/trac447/src/bin/cmdctl/run_b10-cmdctl.sh.in Tue Dec 28 10:31:10 2010
@@ -22,6 +22,8 @@
 PYTHONPATH=@abs_top_srcdir@/src/lib/python
 export PYTHONPATH
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 cd ${CMD_CTRLD_PATH}
-${PYTHON_EXEC} b10-cmdctl
-
+exec ${PYTHON_EXEC} b10-cmdctl "$@"

Modified: branches/trac447/src/bin/cmdctl/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/cmdctl/tests/Makefile.am (original)
+++ branches/trac447/src/bin/cmdctl/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,14 +1,18 @@
+PYCOVERAGE_RUN=@PYCOVERAGE_RUN@
 PYTESTS = cmdctl_test.py
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cmdctl \
 	CMDCTL_SPEC_PATH=$(abs_top_builddir)/src/bin/cmdctl \
 	CMDCTL_SRC_PATH=$(abs_top_srcdir)/src/bin/cmdctl \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/bin/loadzone/run_loadzone.sh.in
==============================================================================
--- branches/trac447/src/bin/loadzone/run_loadzone.sh.in (original)
+++ branches/trac447/src/bin/loadzone/run_loadzone.sh.in Tue Dec 28 10:31:10 2010
@@ -21,5 +21,8 @@
 PYTHONPATH=@abs_top_builddir@/src/lib/python
 export PYTHONPATH
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 LOADZONE_PATH=@abs_top_builddir@/src/bin/loadzone
-exec ${LOADZONE_PATH}/b10-loadzone $*
+exec ${LOADZONE_PATH}/b10-loadzone "$@"

Modified: branches/trac447/src/bin/loadzone/tests/correct/Makefile.am
==============================================================================
--- branches/trac447/src/bin/loadzone/tests/correct/Makefile.am (original)
+++ branches/trac447/src/bin/loadzone/tests/correct/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,4 +1,3 @@
-PYTESTS = correct_test.sh
 EXTRA_DIST = get_zonedatas.py
 EXTRA_DIST += include.db
 EXTRA_DIST += inclsub.db
@@ -14,12 +13,8 @@
 EXTRA_DIST += ttlext.db
 EXTRA_DIST += example.db
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
+# TODO: maybe use TESTS?
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
-	for pytest in $(PYTESTS) ; do \
-	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
-	$(SHELL) $(abs_builddir)/$$pytest || exit ; \
-	done
+	echo Running test: correct_test.sh 
+	$(SHELL) $(abs_builddir)/correct_test.sh

Modified: branches/trac447/src/bin/loadzone/tests/error/Makefile.am
==============================================================================
--- branches/trac447/src/bin/loadzone/tests/error/Makefile.am (original)
+++ branches/trac447/src/bin/loadzone/tests/error/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,5 +1,3 @@
-PYTESTS = error_test.sh
-
 EXTRA_DIST = error.known
 EXTRA_DIST += formerr1.db 
 EXTRA_DIST += formerr2.db
@@ -14,12 +12,8 @@
 EXTRA_DIST += originerr1.db
 EXTRA_DIST += originerr2.db
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
+# TODO: use TESTS ?
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
-	for pytest in $(PYTESTS) ; do \
-	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
-	$(SHELL) $(abs_builddir)/$$pytest || exit ; \
-	done
+	echo Running test: error_test.sh
+	$(SHELL) $(abs_builddir)/error_test.sh

Modified: branches/trac447/src/bin/msgq/run_msgq.sh.in
==============================================================================
--- branches/trac447/src/bin/msgq/run_msgq.sh.in (original)
+++ branches/trac447/src/bin/msgq/run_msgq.sh.in Tue Dec 28 10:31:10 2010
@@ -23,5 +23,8 @@
 PYTHONPATH=@abs_top_srcdir@/src/lib/python
 export PYTHONPATH
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 cd ${MYPATH_PATH}
-exec ${PYTHON_EXEC} -O b10-msgq $*
+exec ${PYTHON_EXEC} -O b10-msgq "$@"

Modified: branches/trac447/src/bin/msgq/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/msgq/tests/Makefile.am (original)
+++ branches/trac447/src/bin/msgq/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,14 +1,18 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@          
 PYTESTS = msgq_test.py
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/msgq:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	BIND10_TEST_SOCKET_FILE=$(builddir)/test_msgq_socket.sock \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done
 

Modified: branches/trac447/src/bin/recurse/b10-recurse.8
==============================================================================
--- branches/trac447/src/bin/recurse/b10-recurse.8 (original)
+++ branches/trac447/src/bin/recurse/b10-recurse.8 Tue Dec 28 10:31:10 2010
@@ -2,12 +2,12 @@
 .\"     Title: b10-recurse
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: September 16, 2010
+.\"      Date: December 27, 2010
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-RECURSE" "8" "September 16, 2010" "BIND10" "BIND10"
+.TH "B10\-RECURSE" "8" "December 27, 2010" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -22,7 +22,7 @@
 b10-recurse \- Recursive DNS server
 .SH "SYNOPSIS"
 .HP \w'\fBb10\-recurse\fR\ 'u
-\fBb10\-recurse\fR [\fB\-4\fR] [\fB\-6\fR] [\fB\-a\ \fR\fB\fIaddress\fR\fR] [\fB\-n\fR] [\fB\-p\ \fR\fB\fInumber\fR\fR] [\fB\-u\ \fR\fB\fIusername\fR\fR] [\fB\-v\fR]
+\fBb10\-recurse\fR [\fB\-u\ \fR\fB\fIusername\fR\fR] [\fB\-v\fR]
 .SH "DESCRIPTION"
 .PP
 The
@@ -60,55 +60,6 @@
 .PP
 The arguments are as follows:
 .PP
-\fB\-4\fR
-.RS 4
-Enables IPv4 only mode\&. This switch may not be used with
-\fB\-6\fR
-nor
-\fB\-a\fR\&. By default, it listens on both IPv4 and IPv6 (if capable)\&.
-.RE
-.PP
-\fB\-6\fR
-.RS 4
-Enables IPv6 only mode\&. This switch may not be used with
-\fB\-4\fR
-nor
-\fB\-a\fR\&. By default, it listens on both IPv4 and IPv6 (if capable)\&.
-.RE
-.PP
-\fB\-a \fR\fB\fIaddress\fR\fR
-.RS 4
-The IPv4 or IPv6 address to listen on\&. This switch may not be used with
-\fB\-4\fR
-nor
-\fB\-6\fR\&. The default is to listen on all addresses\&. (This is a short term workaround\&. This argument may change\&.)
-.RE
-.PP
-\fB\-n\fR
-.RS 4
-Do not cache answers in memory\&. The default is to use the cache for faster responses\&. The cache keeps the most recent 30,000 answers (positive and negative) in memory for 30 seconds (instead of querying the data source, such as SQLite3 database, each time)\&.
-.RE
-.PP
-\fB\-p \fR\fB\fInumber\fR\fR
-.RS 4
-The port number it listens on\&. The default is 5300\&.
-.if n \{\
-.sp
-.\}
-.RS 4
-.it 1 an-trap
-.nr an-no-space-flag 1
-.nr an-break-flag 1
-.br
-.ps +1
-\fBNote\fR
-.ps -1
-.br
-The Y1 prototype runs on all interfaces and on this nonstandard port\&.
-.sp .5v
-.RE
-.RE
-.PP
 \fB\-u \fR\fB\fIusername\fR\fR
 .RS 4
 The user name of the
@@ -130,7 +81,6 @@
 
 \fBb10-cfgmgr\fR(8),
 \fBb10-cmdctl\fR(8),
-\fBb10-loadzone\fR(8),
 \fBb10-msgq\fR(8),
 \fBbind10\fR(8),
 BIND 10 Guide\&.

Modified: branches/trac447/src/bin/recurse/b10-recurse.xml
==============================================================================
--- branches/trac447/src/bin/recurse/b10-recurse.xml (original)
+++ branches/trac447/src/bin/recurse/b10-recurse.xml Tue Dec 28 10:31:10 2010
@@ -21,7 +21,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>September 16, 2010</date>
+    <date>December 27, 2010</date>
   </refentryinfo>
 
   <refmeta>
@@ -45,11 +45,6 @@
   <refsynopsisdiv>
     <cmdsynopsis>
       <command>b10-recurse</command>
-      <arg><option>-4</option></arg>
-      <arg><option>-6</option></arg>
-      <arg><option>-a <replaceable>address</replaceable></option></arg>
-      <arg><option>-n</option></arg>
-      <arg><option>-p <replaceable>number</replaceable></option></arg>
       <arg><option>-u <replaceable>username</replaceable></option></arg>
       <arg><option>-v</option></arg>
     </cmdsynopsis>
@@ -89,59 +84,6 @@
     <para>The arguments are as follows:</para>
 
     <variablelist>
-      <varlistentry>
-        <term><option>-4</option></term>
-        <listitem><para>
-          Enables IPv4 only mode.
-          This switch may not be used with <option>-6</option> nor
-          <option>-a</option>.
-          By default, it listens on both IPv4 and IPv6 (if capable).
-        </para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-6</option></term>
-        <listitem><para>
-          Enables IPv6 only mode.
-          This switch may not be used with <option>-4</option> nor
-          <option>-a</option>.
-          By default, it listens on both IPv4 and IPv6 (if capable).
-        </para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-a <replaceable>address</replaceable></option></term>
-
-        <listitem>
-          <para>The IPv4 or IPv6 address to listen on.
-            This switch may not be used with <option>-4</option> nor
-            <option>-6</option>.
-            The default is to listen on all addresses.
-            (This is a short term workaround. This argument may change.)   
-          </para>                      
-         </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-n</option></term>
-        <listitem><para>
-          Do not cache answers in memory.
-          The default is to use the cache for faster responses.
-	  The cache keeps the most recent 30,000 answers (positive
-	  and negative) in memory for 30 seconds (instead of querying
-	  the data source, such as SQLite3 database, each time).
-        </para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-p <replaceable>number</replaceable></option></term>
-        <listitem><para>
-          The port number it listens on.
-          The default is 5300.</para>
-	  <note><simpara>The Y1 prototype runs on all interfaces
-	  and on this nonstandard port.</simpara></note>
-        </listitem>
-      </varlistentry>
 
       <varlistentry>
         <term><option>-u <replaceable>username</replaceable></option></term>
@@ -187,9 +129,6 @@
         <refentrytitle>b10-cmdctl</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
-        <refentrytitle>b10-loadzone</refentrytitle><manvolnum>8</manvolnum>
-      </citerefentry>,
-      <citerefentry>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>

Modified: branches/trac447/src/bin/stats/run_b10-stats.sh.in
==============================================================================
--- branches/trac447/src/bin/stats/run_b10-stats.sh.in (original)
+++ branches/trac447/src/bin/stats/run_b10-stats.sh.in Tue Dec 28 10:31:10 2010
@@ -21,10 +21,13 @@
 PYTHONPATH=@abs_top_builddir@/src/lib/python
 export PYTHONPATH
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 B10_FROM_BUILD=@abs_top_builddir@
 export B10_FROM_BUILD
 
 STATS_PATH=@abs_top_builddir@/src/bin/stats
 
 cd ${STATS_PATH}
-exec ${PYTHON_EXEC} -O b10-stats $*
+exec ${PYTHON_EXEC} -O b10-stats "$@"

Modified: branches/trac447/src/bin/stats/run_b10-stats_stub.sh.in
==============================================================================
--- branches/trac447/src/bin/stats/run_b10-stats_stub.sh.in (original)
+++ branches/trac447/src/bin/stats/run_b10-stats_stub.sh.in Tue Dec 28 10:31:10 2010
@@ -24,7 +24,10 @@
 B10_FROM_BUILD=@abs_top_srcdir@
 export B10_FROM_BUILD
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 STATS_PATH=@abs_top_builddir@/src/bin/stats
 
 cd ${STATS_PATH}
-exec ${PYTHON_EXEC} -O b10-stats_stub $*
+exec ${PYTHON_EXEC} -O b10-stats_stub "$@"

Modified: branches/trac447/src/bin/stats/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/stats/tests/Makefile.am (original)
+++ branches/trac447/src/bin/stats/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,15 +1,19 @@
 SUBDIRS = isc testdata
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = b10-stats_test.py b10-stats_stub_test.py
 EXTRA_DIST = $(PYTESTS) fake_time.py
 CLEANFILES = fake_time.pyc
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/stats:$(abs_top_builddir)/src/bin/stats/tests \
 	B10_FROM_BUILD=$(abs_top_builddir) \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/bin/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/tests/Makefile.am (original)
+++ branches/trac447/src/bin/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,13 +1,17 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = process_rename_test.py
 # .py will be generated by configure, so we don't have to include it
 # in EXTRA_DIST.
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
-	$(PYCOVERAGE) $(abs_builddir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/bin/usermgr/run_b10-cmdctl-usermgr.sh.in
==============================================================================
--- branches/trac447/src/bin/usermgr/run_b10-cmdctl-usermgr.sh.in (original)
+++ branches/trac447/src/bin/usermgr/run_b10-cmdctl-usermgr.sh.in Tue Dec 28 10:31:10 2010
@@ -20,6 +20,8 @@
 
 MYPATH_PATH=@abs_top_builddir@/src/bin/usermgr
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 cd ${MYPATH_PATH}
-${PYTHON_EXEC} b10-cmdctl-usermgr
-
+exec ${PYTHON_EXEC} b10-cmdctl-usermgr "$@"

Modified: branches/trac447/src/bin/xfrin/run_b10-xfrin.sh.in
==============================================================================
--- branches/trac447/src/bin/xfrin/run_b10-xfrin.sh.in (original)
+++ branches/trac447/src/bin/xfrin/run_b10-xfrin.sh.in Tue Dec 28 10:31:10 2010
@@ -22,6 +22,8 @@
 PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/.libs
 export PYTHONPATH
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 cd ${MYPATH_PATH}
-${PYTHON_EXEC} b10-xfrin
-
+exec ${PYTHON_EXEC} b10-xfrin "$@"

Modified: branches/trac447/src/bin/xfrin/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/xfrin/tests/Makefile.am (original)
+++ branches/trac447/src/bin/xfrin/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,3 +1,4 @@
+PYCOVERAGE_RUN=@PYCOVERAGE_RUN@
 PYTESTS = xfrin_test.py
 EXTRA_DIST = $(PYTESTS)
 
@@ -8,13 +9,16 @@
 LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
 endif
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	$(LIBRARY_PATH_PLACEHOLDER) \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/bin/xfrout/run_b10-xfrout.sh.in
==============================================================================
--- branches/trac447/src/bin/xfrout/run_b10-xfrout.sh.in (original)
+++ branches/trac447/src/bin/xfrout/run_b10-xfrout.sh.in Tue Dec 28 10:31:10 2010
@@ -22,6 +22,8 @@
 PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/dns/python/.libs
 export PYTHONPATH
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 cd ${MYPATH_PATH}
-${PYTHON_EXEC} b10-xfrout
-
+exec ${PYTHON_EXEC} b10-xfrout "$@"

Modified: branches/trac447/src/bin/xfrout/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/xfrout/tests/Makefile.am (original)
+++ branches/trac447/src/bin/xfrout/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,3 +1,4 @@
+PYCOVERAGE_RUN=@PYCOVERAGE_RUN@
 PYTESTS = xfrout_test.py
 EXTRA_DIST = $(PYTESTS)
 
@@ -8,13 +9,16 @@
 LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
 endif
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
 	$(LIBRARY_PATH_PLACEHOLDER) \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/bin/zonemgr/run_b10-zonemgr.sh.in
==============================================================================
--- branches/trac447/src/bin/zonemgr/run_b10-zonemgr.sh.in (original)
+++ branches/trac447/src/bin/zonemgr/run_b10-zonemgr.sh.in Tue Dec 28 10:31:10 2010
@@ -22,6 +22,8 @@
 PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/.libs
 export PYTHONPATH
 
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
+
 cd ${MYPATH_PATH}
-${PYTHON_EXEC} b10-zonemgr
-
+exec ${PYTHON_EXEC} b10-zonemgr "$@"

Modified: branches/trac447/src/bin/zonemgr/tests/Makefile.am
==============================================================================
--- branches/trac447/src/bin/zonemgr/tests/Makefile.am (original)
+++ branches/trac447/src/bin/zonemgr/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,14 +1,17 @@
+PYCOVERAGE_RUN=@PYCOVERAGE_RUN@
 PYTESTS = zonemgr_test.py
 EXTRA_DIST = $(PYTESTS)
-
 CLEANFILES = initdb.file
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/zonemgr:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/lib/asiolink/asiolink.cc
==============================================================================
--- branches/trac447/src/lib/asiolink/asiolink.cc (original)
+++ branches/trac447/src/lib/asiolink/asiolink.cc Tue Dec 28 10:31:10 2010
@@ -26,6 +26,7 @@
 #include <asio.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/bind.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
 
 #include <boost/shared_ptr.hpp>
 
@@ -374,4 +375,90 @@
          timeout_, retries_);
 }
 
-}
+class IntervalTimerImpl {
+private:
+    // prohibit copy
+    IntervalTimerImpl(const IntervalTimerImpl& source);
+    IntervalTimerImpl& operator=(const IntervalTimerImpl& source);
+public:
+    IntervalTimerImpl(IOService& io_service);
+    ~IntervalTimerImpl();
+    void setupTimer(const IntervalTimer::Callback& cbfunc,
+                    const uint32_t interval);
+    void callback(const asio::error_code& error);
+private:
+    // a function to update timer_ when it expires
+    void updateTimer();
+    // a function to call back when timer_ expires
+    IntervalTimer::Callback cbfunc_;
+    // interval in seconds
+    uint32_t interval_;
+    // asio timer
+    asio::deadline_timer timer_;
+};
+
+IntervalTimerImpl::IntervalTimerImpl(IOService& io_service) :
+    timer_(io_service.get_io_service())
+{}
+
+IntervalTimerImpl::~IntervalTimerImpl()
+{}
+
+void
+IntervalTimerImpl::setupTimer(const IntervalTimer::Callback& cbfunc,
+                              const uint32_t interval)
+{
+    // Interval should not be 0.
+    if (interval == 0) {
+        isc_throw(isc::BadValue, "Interval should not be 0");
+    }
+    // Call back function should not be empty.
+    if (cbfunc.empty()) {
+        isc_throw(isc::InvalidParameter, "Callback function is empty");
+    }
+    cbfunc_ = cbfunc;
+    interval_ = interval;
+    // Set initial expire time.
+    // At this point the timer is not running yet and will not expire.
+    // After calling IOService::run(), the timer will expire.
+    updateTimer();
+    return;
+}
+
+void
+IntervalTimerImpl::updateTimer() {
+    try {
+        // Update expire time to (current time + interval_).
+        timer_.expires_from_now(boost::posix_time::seconds(interval_));
+    } catch (const asio::system_error& e) {
+        isc_throw(isc::Unexpected, "Failed to update timer");
+    }
+    // Reset timer.
+    timer_.async_wait(boost::bind(&IntervalTimerImpl::callback, this, _1));
+}
+
+void
+IntervalTimerImpl::callback(const asio::error_code& cancelled) {
+    // Do not call cbfunc_ in case the timer was cancelled.
+    // The timer will be canelled in the destructor of asio::deadline_timer.
+    if (!cancelled) {
+        cbfunc_();
+        // Set next expire time.
+        updateTimer();
+    }
+}
+
+IntervalTimer::IntervalTimer(IOService& io_service) {
+    impl_ = new IntervalTimerImpl(io_service);
+}
+
+IntervalTimer::~IntervalTimer() {
+    delete impl_;
+}
+
+void
+IntervalTimer::setupTimer(const Callback& cbfunc, const uint32_t interval) {
+    return (impl_->setupTimer(cbfunc, interval));
+}
+
+}

Modified: branches/trac447/src/lib/asiolink/asiolink.h
==============================================================================
--- branches/trac447/src/lib/asiolink/asiolink.h (original)
+++ branches/trac447/src/lib/asiolink/asiolink.h Tue Dec 28 10:31:10 2010
@@ -23,6 +23,7 @@
 #include <unistd.h>             // for some network system calls
 #include <asio/ip/address.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
 
 #include <functional>
 #include <string>
@@ -98,6 +99,7 @@
 namespace asiolink {
 class DNSServiceImpl;
 struct 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
@@ -300,13 +302,13 @@
     ///
     /// \param done If true, this signals the system there is an answer
     ///             to return.
-    virtual inline void resume(const bool done) { self_->resume(done); }
+    virtual void resume(const bool done) { self_->resume(done); }
 
     /// \brief Indicate whether the server is able to send an answer
     /// to a query.
     /// 
     /// This is presently used only for testing purposes.
-    virtual inline bool hasAnswer() { return (self_->hasAnswer()); }
+    virtual bool hasAnswer() { return (self_->hasAnswer()); }
 
     /// \brief Returns the current value of the 'coroutine' object
     ///
@@ -316,7 +318,7 @@
     /// about its current state.
     ///
     /// \return The value of the 'coroutine' object
-    virtual inline int value() { return (self_->value()); }
+    virtual int value() { return (self_->value()); }
 
     /// \brief Returns a pointer to a clone of this DNSServer object.
     ///
@@ -326,7 +328,7 @@
     /// that the underlying object is also correctly copied.
     ///
     /// \return A deep copy of this DNSServer object
-    virtual inline DNSServer* clone() { return (self_->clone()); }
+    virtual DNSServer* clone() { return (self_->clone()); }
     //@}
 
 protected:
@@ -349,7 +351,7 @@
     class AsyncLookup {
     public:
         AsyncLookup(T& caller) : caller_(caller) {}
-        inline void operator()() { caller_.asyncLookup(); }
+        void operator()() { caller_.asyncLookup(); }
     private:
         T caller_;
     };
@@ -361,7 +363,7 @@
     /// the details of the query and a pointer back to the current
     /// server object.  It is called asynchronously via the AsyncLookup
     /// handler class.
-    virtual inline void asyncLookup() { self_->asyncLookup(); }
+    virtual void asyncLookup() { self_->asyncLookup(); }
 
 private:
     DNSServer* self_;
@@ -567,6 +569,98 @@
     unsigned retries_;
 };
 
+/// \brief The \c IntervalTimer class is a wrapper for the ASIO
+/// \c asio::deadline_timer class.
+///
+/// This class is implemented to use \c asio::deadline_timer as
+/// interval timer.
+///
+/// \c setupTimer() sets a timer to expire on (now + interval) and
+/// a call back function.
+///
+/// \c IntervalTimerImpl::callback() is called by the timer when
+/// it expires.
+///
+/// The function calls the call back function set by \c setupTimer()
+/// and updates the timer to expire in (now + interval) seconds.
+/// The type of call back function is \c void(void).
+/// 
+/// The call back function will not be called if the instance of this
+/// class is destructed before the timer is expired.
+///
+/// Note: Destruction of an instance of this class while call back
+/// is pending causes throwing an exception from \c IOService.
+///
+/// Sample code:
+/// \code
+///  void function_to_call_back() {
+///      // this function will be called periodically
+///  }
+///  int interval_in_seconds = 1;
+///  IOService io_service;
+///
+///  IntervalTimer intervalTimer(io_service);
+///  intervalTimer.setupTimer(function_to_call_back, interval_in_seconds);
+///  io_service.run();
+/// \endcode
+///
+class IntervalTimer {
+public:
+    /// \name The type of timer callback function
+    typedef boost::function<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 \c IOService.
+    ///
+    /// This constructor may throw a standard exception if
+    /// memory allocation fails inside the method.
+    /// This constructor may also throw \c asio::system_error.
+    ///
+    /// \param io_service A reference to an instance of IOService
+    ///
+    IntervalTimer(IOService& io_service);
+
+    /// \brief The destructor.
+    ///
+    /// This destructor never throws an exception.
+    ///
+    /// On the destruction of this class the timer will be canceled
+    /// inside \c asio::deadline_timer.
+    ///
+    ~IntervalTimer();
+    //@}
+
+    /// \brief Register timer callback function and interval.
+    ///
+    /// This function sets callback function and interval in seconds.
+    /// Timer will actually start after calling \c IOService::run().
+    ///
+    /// \param cbfunc A reference to a function \c void(void) to call back
+    /// when the timer is expired (should not be an empty functor)
+    /// \param interval Interval in seconds (greater than 0)
+    ///
+    /// Note: IntervalTimer will not pass \c asio::error_code to
+    /// call back function. In case the timer is cancelled, the function
+    /// will not be called.
+    ///
+    /// \throw isc::InvalidParameter cbfunc is empty
+    /// \throw isc::BadValue interval is 0
+    /// \throw isc::Unexpected ASIO library error
+    ///
+    void setupTimer(const Callback& cbfunc, const uint32_t interval);
+private:
+    IntervalTimerImpl* impl_;
+};
+
 }      // asiolink
 #endif // __ASIOLINK_H
 

Modified: branches/trac447/src/lib/asiolink/internal/tcpdns.h
==============================================================================
--- branches/trac447/src/lib/asiolink/internal/tcpdns.h (original)
+++ branches/trac447/src/lib/asiolink/internal/tcpdns.h Tue Dec 28 10:31:10 2010
@@ -79,25 +79,25 @@
     ~TCPEndpoint() { delete asio_endpoint_placeholder_; }
     //@}
 
-    inline IOAddress getAddress() const {
+    IOAddress getAddress() const {
         return (asio_endpoint_.address());
     }
 
-    inline uint16_t getPort() const {
+    uint16_t getPort() const {
         return (asio_endpoint_.port());
     }
 
-    inline short getProtocol() const {
+    short getProtocol() const {
         return (asio_endpoint_.protocol().protocol());
     }
 
-    inline short getFamily() const {
+    short getFamily() const {
         return (asio_endpoint_.protocol().family());
     }
 
     // This is not part of the exosed IOEndpoint API but allows
     // direct access to the ASIO implementation of the endpoint
-    inline const asio::ip::tcp::endpoint& getASIOEndpoint() const {
+    const asio::ip::tcp::endpoint& getASIOEndpoint() const {
         return (asio_endpoint_);
     }
 
@@ -123,8 +123,8 @@
     /// \param socket The ASIO representation of the TCP socket.
     TCPSocket(asio::ip::tcp::socket& socket) : socket_(socket) {}
 
-    inline int getNative() const { return (socket_.native()); }
-    inline int getProtocol() const { return (IPPROTO_TCP); }
+    int getNative() const { return (socket_.native()); }
+    int getProtocol() const { return (IPPROTO_TCP); }
 
 private:
     asio::ip::tcp::socket& socket_;

Modified: branches/trac447/src/lib/asiolink/tests/asiolink_unittest.cc
==============================================================================
--- branches/trac447/src/lib/asiolink/tests/asiolink_unittest.cc (original)
+++ branches/trac447/src/lib/asiolink/tests/asiolink_unittest.cc Tue Dec 28 10:31:10 2010
@@ -21,6 +21,7 @@
 
 #include <boost/lexical_cast.hpp>
 #include <boost/bind.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
 
 #include <gtest/gtest.h>
 
@@ -54,6 +55,9 @@
 // two octets encode the length of the rest of the data.  This is crucial
 // for the tests below.
 const uint8_t test_data[] = {0, 4, 1, 2, 3, 4};
+// TODO: Consider this margin
+const boost::posix_time::time_duration TIMER_MARGIN_MSEC =
+    boost::posix_time::milliseconds(50);
 
 TEST(IOAddressTest, fromText) {
     IOAddress io_address_v4("192.0.2.1");
@@ -710,4 +714,247 @@
     EXPECT_EQ(3, num);
 }
 
-}
+// This fixture is for testing IntervalTimer. Some callback functors are 
+// registered as callback function of the timer to test if they are called
+// or not.
+class IntervalTimerTest : public ::testing::Test {
+protected:
+    IntervalTimerTest() : io_service_() {};
+    ~IntervalTimerTest() {}
+    class TimerCallBack : public std::unary_function<void, void> {
+    public:
+        TimerCallBack(IntervalTimerTest* test_obj) : test_obj_(test_obj) {}
+        void operator()() const {
+            test_obj_->timer_called_ = true;
+            test_obj_->io_service_.stop();
+            return;
+        }
+    private:
+        IntervalTimerTest* test_obj_;
+    };
+    class TimerCallBackCounter : public std::unary_function<void, void> {
+    public:
+        TimerCallBackCounter(IntervalTimerTest* test_obj) : test_obj_(test_obj) {
+            counter_ = 0;
+        }
+        void operator()() {
+            ++counter_;
+            return;
+        }
+        int counter_;
+    private:
+        IntervalTimerTest* test_obj_;
+    };
+    class TimerCallBackCancelDeleter : public std::unary_function<void, void> {
+    public:
+        TimerCallBackCancelDeleter(IntervalTimerTest* test_obj,
+                                   IntervalTimer* timer,
+                                   TimerCallBackCounter& counter)
+            : test_obj_(test_obj), timer_(timer), counter_(counter), count_(0)
+        {}
+        void operator()() {
+            ++count_;
+            if (count_ == 1) {
+                // First time of call back.
+                // Store the value of counter_.counter_.
+                prev_counter_ = counter_.counter_;
+                delete timer_;
+            } else if (count_ == 2) {
+                // Second time of call back.
+                // Stop io_service to stop all timers.
+                test_obj_->io_service_.stop();
+                // Compare the value of counter_.counter_ with stored one.
+                // If TimerCallBackCounter was not called (expected behavior),
+                // they are same.
+                if (counter_.counter_ == prev_counter_) {
+                    test_obj_->timer_cancel_success_ = true;
+                }
+            }
+            return;
+        }
+    private:
+        IntervalTimerTest* test_obj_;
+        IntervalTimer* timer_;
+        TimerCallBackCounter& counter_;
+        int count_;
+        int prev_counter_;
+    };
+    class TimerCallBackOverwriter : public std::unary_function<void, void> {
+    public:
+        TimerCallBackOverwriter(IntervalTimerTest* test_obj,
+                                IntervalTimer& timer)
+            : test_obj_(test_obj), timer_(timer), count_(0)
+        {}
+        void operator()() {
+            ++count_;
+            if (count_ == 1) {
+                // First time of call back.
+                // Call setupTimer() to update callback function
+                // to TimerCallBack.
+                test_obj_->timer_called_ = false;
+                timer_.setupTimer(TimerCallBack(test_obj_), 1);
+            } else if (count_ == 2) {
+                // Second time of call back.
+                // If it reaches here, re-setupTimer() is failed (unexpected).
+                // We should stop here.
+                test_obj_->io_service_.stop();
+            }
+            return;
+        }
+    private:
+        IntervalTimerTest* test_obj_;
+        IntervalTimer& timer_;
+        int count_;
+    };
+protected:
+    IOService io_service_;
+    bool timer_called_;
+    bool timer_cancel_success_;
+};
+
+TEST_F(IntervalTimerTest, invalidArgumentToIntervalTimer) {
+    // Create asio_link::IntervalTimer and setup.
+    IntervalTimer itimer(io_service_);
+    // expect throw if call back function is empty
+    EXPECT_THROW(itimer.setupTimer(IntervalTimer::Callback(), 1),
+                     isc::InvalidParameter);
+    // expect throw if interval is 0
+    EXPECT_THROW(itimer.setupTimer(TimerCallBack(this), 0), isc::BadValue);
+}
+
+TEST_F(IntervalTimerTest, startIntervalTimer) {
+    // Create asio_link::IntervalTimer and setup.
+    // Then run IOService and test if the callback function is called.
+    IntervalTimer itimer(io_service_);
+    timer_called_ = false;
+    // store start time
+    boost::posix_time::ptime start;
+    start = boost::posix_time::microsec_clock::universal_time();
+    // setup timer
+    itimer.setupTimer(TimerCallBack(this), 1);
+    io_service_.run();
+    // reaches here after timer expired
+    // delta: difference between elapsed time and 1 second
+    boost::posix_time::time_duration delta =
+        (boost::posix_time::microsec_clock::universal_time() - start)
+         - boost::posix_time::seconds(1);
+    if (delta.is_negative()) {
+        delta.invert_sign();
+    }
+    // expect TimerCallBack is called; timer_called_ is true
+    EXPECT_TRUE(timer_called_);
+    // expect interval is 1 second +/- TIMER_MARGIN_MSEC.
+    EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
+}
+
+TEST_F(IntervalTimerTest, destructIntervalTimer) {
+    // Note: This test currently takes 6 seconds. The timer should have
+    // finer granularity and timer periods in this test should be shorter
+    // in the future.
+    // This code isn't exception safe, but we'd rather keep the code
+    // simpler and more readable as this is only for tests and if it throws
+    // the program would immediately terminate anyway.
+
+    // The call back function will not be called after the timer is
+    // destructed.
+    //
+    // There are two timers:
+    //  itimer_counter (A)
+    //   (Calls TimerCallBackCounter)
+    //     - increments internal counter in callback function
+    //  itimer_canceller (B)
+    //   (Calls TimerCallBackCancelDeleter)
+    //     - first time of callback, it stores the counter value of
+    //       callback_canceller and destructs itimer_counter
+    //     - second time of callback, it compares the counter value of
+    //       callback_canceller with stored value
+    //       if they are same the timer was not called; expected result
+    //       if they are different the timer was called after destructed
+    //
+    //     0  1  2  3  4  5  6 (s)
+    // (A) i-----+--x
+    //              ^
+    //              |destruct itimer_counter
+    // (B) i--------+--------s
+    //                       ^stop io_service
+    //                        and test itimer_counter have been stopped
+    //
+
+    // itimer_counter will be deleted in TimerCallBackCancelDeleter
+    IntervalTimer* itimer_counter = new IntervalTimer(io_service_);
+    IntervalTimer itimer_canceller(io_service_);
+    timer_cancel_success_ = false;
+    TimerCallBackCounter callback_canceller(this);
+    itimer_counter->setupTimer(callback_canceller, 2);
+    itimer_canceller.setupTimer(
+        TimerCallBackCancelDeleter(this, itimer_counter,
+                                   callback_canceller),
+        3);
+    io_service_.run();
+    EXPECT_TRUE(timer_cancel_success_);
+}
+
+TEST_F(IntervalTimerTest, overwriteIntervalTimer) {
+    // Note: This test currently takes 4 seconds. The timer should have
+    // finer granularity and timer periods in this test should be shorter
+    // in the future.
+
+    // Calling setupTimer() multiple times updates call back function
+    // and interval.
+    //
+    // There are two timers:
+    //  itimer (A)
+    //   (Calls TimerCallBackCounter / TimerCallBack)
+    //     - increments internal counter in callback function
+    //       (TimerCallBackCounter)
+    //       interval: 2 seconds
+    //     - io_service_.stop() (TimerCallBack)
+    //       interval: 1 second
+    //  itimer_overwriter (B)
+    //   (Calls TimerCallBackOverwriter)
+    //     - first time of callback, it calls setupTimer() to change
+    //       call back function and interval of itimer to
+    //       TimerCallBack / 1 second
+    //       after 3 + 1 seconds from the beginning of this test,
+    //       TimerCallBack() will be called and io_service_ stops.
+    //     - second time of callback, it means the test fails.
+    //
+    //     0  1  2  3  4  5  6 (s)
+    // (A) i-----+--C--s
+    //              ^  ^stop io_service
+    //              |change call back function
+    // (B) i--------+--------S
+    //                       ^(stop io_service on fail)
+    //
+
+    IntervalTimer itimer(io_service_);
+    IntervalTimer itimer_overwriter(io_service_);
+    // store start time
+    boost::posix_time::ptime start;
+    start = boost::posix_time::microsec_clock::universal_time();
+    itimer.setupTimer(TimerCallBackCounter(this), 2);
+    itimer_overwriter.setupTimer(TimerCallBackOverwriter(this, itimer), 3);
+    io_service_.run();
+    // reaches here after timer expired
+    // if interval is updated, it takes
+    //   3 seconds for TimerCallBackOverwriter
+    //   + 1 second for TimerCallBack (stop)
+    //   = 4 seconds.
+    // otherwise (test fails), it takes
+    //   3 seconds for TimerCallBackOverwriter
+    //   + 3 seconds for TimerCallBackOverwriter (stop)
+    //   = 6 seconds.
+    // delta: difference between elapsed time and 3 + 1 seconds
+    boost::posix_time::time_duration delta =
+        (boost::posix_time::microsec_clock::universal_time() - start)
+         - boost::posix_time::seconds(3 + 1);
+    if (delta.is_negative()) {
+        delta.invert_sign();
+    }
+    // expect callback function is updated: TimerCallBack is called
+    EXPECT_TRUE(timer_called_);
+    // expect interval is updated
+    EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
+}
+
+}

Modified: branches/trac447/src/lib/config/module_spec.cc
==============================================================================
--- branches/trac447/src/lib/config/module_spec.cc (original)
+++ branches/trac447/src/lib/config/module_spec.cc Tue Dec 28 10:31:10 2010
@@ -330,14 +330,33 @@
 ModuleSpec::validate_spec_list(ConstElementPtr spec, ConstElementPtr data,
                                const bool full, ElementPtr errors) const
 {
+    bool validated = true;
     std::string cur_item_name;
     BOOST_FOREACH(ConstElementPtr cur_spec_el, spec->listValue()) {
         if (!validate_spec(cur_spec_el, data, full, errors)) {
-            return (false);
-        }
-    }
-    return (true);
-}
-
-}
-}
+            validated = false;
+        }
+    }
+
+    typedef std::pair<std::string, ConstElementPtr> maptype;
+    
+    BOOST_FOREACH(maptype m, data->mapValue()) {
+        bool found = false;
+        BOOST_FOREACH(ConstElementPtr cur_spec_el, spec->listValue()) {
+            if (cur_spec_el->get("item_name")->stringValue().compare(m.first) == 0) {
+                found = true;
+            }
+        }
+        if (!found) {
+            validated = false;
+            if (errors) {
+                errors->add(Element::create("Unknown item " + m.first));
+            }
+        }
+    }
+
+    return (validated);
+}
+
+}
+}

Modified: branches/trac447/src/lib/config/tests/module_spec_unittests.cc
==============================================================================
--- branches/trac447/src/lib/config/tests/module_spec_unittests.cc (original)
+++ branches/trac447/src/lib/config/tests/module_spec_unittests.cc Tue Dec 28 10:31:10 2010
@@ -166,8 +166,13 @@
     EXPECT_TRUE(data_test(dd, "data22_6.data"));
     EXPECT_TRUE(data_test(dd, "data22_7.data"));
     EXPECT_FALSE(data_test(dd, "data22_8.data"));
+    EXPECT_FALSE(data_test(dd, "data22_9.data"));
 
     ElementPtr errors = Element::createList();
     EXPECT_FALSE(data_test_with_errors(dd, "data22_8.data", errors));
     EXPECT_EQ("[ \"Type mismatch\" ]", errors->str());
+
+    errors = Element::createList();
+    EXPECT_FALSE(data_test_with_errors(dd, "data22_9.data", errors));
+    EXPECT_EQ("[ \"Unknown item value_does_not_exist\" ]", errors->str());
 }

Modified: branches/trac447/src/lib/config/tests/testdata/Makefile.am
==============================================================================
--- branches/trac447/src/lib/config/tests/testdata/Makefile.am (original)
+++ branches/trac447/src/lib/config/tests/testdata/Makefile.am Tue Dec 28 10:31:10 2010
@@ -20,6 +20,7 @@
 EXTRA_DIST += data22_6.data
 EXTRA_DIST += data22_7.data
 EXTRA_DIST += data22_8.data
+EXTRA_DIST += data22_9.data
 EXTRA_DIST += spec1.spec
 EXTRA_DIST += spec2.spec
 EXTRA_DIST += spec3.spec

Modified: branches/trac447/src/lib/config/tests/testdata/data22_8.data
==============================================================================
--- branches/trac447/src/lib/config/tests/testdata/data22_8.data (original)
+++ branches/trac447/src/lib/config/tests/testdata/data22_8.data Tue Dec 28 10:31:10 2010
@@ -5,5 +5,6 @@
     "value4": "foo",
     "value5": [ 1, 2, 3 ],
     "value6": { "v61": "bar", "v62": true },
-    "value8": [ { "a": "d" }, { "a": 1 } ]
+    "value8": [ { "a": "d" }, { "a": 1 } ],
+    "value9": { "v91": "hi", "v92": { "v92a": "Hi", "v92b": 3 } }
 }

Modified: branches/trac447/src/lib/datasrc/data_source.h
==============================================================================
--- branches/trac447/src/lib/datasrc/data_source.h (original)
+++ branches/trac447/src/lib/datasrc/data_source.h Tue Dec 28 10:31:10 2010
@@ -248,7 +248,7 @@
     void addDataSrc(ConstDataSrcPtr data_src);
     void removeDataSrc(ConstDataSrcPtr data_src);
     size_t dataSrcCount() { return (data_sources.size()); }
-    
+
     void findClosestEnclosure(DataSrcMatch& match) const;
 
     // Actual queries for data should not be sent to a MetaDataSrc object,

Modified: branches/trac447/src/lib/datasrc/memory_datasrc.cc
==============================================================================
--- branches/trac447/src/lib/datasrc/memory_datasrc.cc (original)
+++ branches/trac447/src/lib/datasrc/memory_datasrc.cc Tue Dec 28 10:31:10 2010
@@ -181,7 +181,10 @@
 /// For now, \c MemoryDataSrc only contains a \c ZoneTable object, which
 /// consists of (pointers to) \c MemoryZone objects, we may add more
 /// member variables later for new features.
-struct MemoryDataSrc::MemoryDataSrcImpl {
+class MemoryDataSrc::MemoryDataSrcImpl {
+public:
+    MemoryDataSrcImpl() : zone_count(0) {}
+    unsigned int zone_count;
     ZoneTable zone_table;
 };
 
@@ -190,6 +193,11 @@
 
 MemoryDataSrc::~MemoryDataSrc() {
     delete impl_;
+}
+
+unsigned int
+MemoryDataSrc::getZoneCount() const {
+    return (impl_->zone_count);
 }
 
 result::Result
@@ -198,7 +206,12 @@
         isc_throw(InvalidParameter,
                   "Null pointer is passed to MemoryDataSrc::addZone()");
     }
-    return (impl_->zone_table.addZone(zone));
+
+    const result::Result result = impl_->zone_table.addZone(zone);
+    if (result == result::SUCCESS) {
+        ++impl_->zone_count;
+    }
+    return (result);
 }
 
 MemoryDataSrc::FindResult

Modified: branches/trac447/src/lib/datasrc/memory_datasrc.h
==============================================================================
--- branches/trac447/src/lib/datasrc/memory_datasrc.h (original)
+++ branches/trac447/src/lib/datasrc/memory_datasrc.h Tue Dec 28 10:31:10 2010
@@ -185,6 +185,13 @@
     ~MemoryDataSrc();
     //@}
 
+    /// Return the number of zones stored in the data source.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \return The number of zones stored in the data source.
+    unsigned int getZoneCount() const;
+
     /// Add a \c Zone to the \c MemoryDataSrc.
     ///
     /// \c Zone must not be associated with a NULL pointer; otherwise
@@ -221,7 +228,7 @@
     FindResult findZone(const isc::dns::Name& name) const;
 
 private:
-    struct MemoryDataSrcImpl;
+    class MemoryDataSrcImpl;
     MemoryDataSrcImpl* impl_;
 };
 }

Modified: branches/trac447/src/lib/datasrc/tests/memory_datasrc_unittest.cc
==============================================================================
--- branches/trac447/src/lib/datasrc/tests/memory_datasrc_unittest.cc (original)
+++ branches/trac447/src/lib/datasrc/tests/memory_datasrc_unittest.cc Tue Dec 28 10:31:10 2010
@@ -29,8 +29,9 @@
 
 class MemoryDataSrcTest : public ::testing::Test {
 protected:
-    MemoryDataSrcTest()
+    MemoryDataSrcTest() : rrclass(RRClass::IN())
     {}
+    RRClass rrclass;
     MemoryDataSrc memory_datasrc;
 };
 
@@ -111,6 +112,23 @@
               memory_datasrc.findZone(Name("z.i.g.h")).code);
     EXPECT_EQ(Name("i.g.h"),
               memory_datasrc.findZone(Name("z.i.g.h")).zone->getOrigin());
+}
+
+TEST_F(MemoryDataSrcTest, getZoneCount) {
+    EXPECT_EQ(0, memory_datasrc.getZoneCount());
+    memory_datasrc.addZone(
+                  ZonePtr(new MemoryZone(rrclass, Name("example.com"))));
+    EXPECT_EQ(1, memory_datasrc.getZoneCount());
+
+    // duplicate add.  counter shouldn't change
+    memory_datasrc.addZone(
+                  ZonePtr(new MemoryZone(rrclass, Name("example.com"))));
+    EXPECT_EQ(1, memory_datasrc.getZoneCount());
+
+    // add one more
+    memory_datasrc.addZone(
+                  ZonePtr(new MemoryZone(rrclass, Name("example.org"))));
+    EXPECT_EQ(2, memory_datasrc.getZoneCount());
 }
 
 /// \brief Test fixture for the MemoryZone class
@@ -189,7 +207,6 @@
     ASSERT_EQ(class_, zone_.getClass());
     ASSERT_EQ(origin_, zone_.getOrigin());
 }
-
 /**
  * \brief Test adding.
  *

Modified: branches/trac447/src/lib/datasrc/tests/zonetable_unittest.cc
==============================================================================
--- branches/trac447/src/lib/datasrc/tests/zonetable_unittest.cc (original)
+++ branches/trac447/src/lib/datasrc/tests/zonetable_unittest.cc Tue Dec 28 10:31:10 2010
@@ -75,7 +75,7 @@
     EXPECT_THROW(zone_table.addZone(ZonePtr()), isc::InvalidParameter);
 }
 
-TEST_F(ZoneTableTest, removeZone) {
+TEST_F(ZoneTableTest, DISABLED_removeZone) {
     EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone1));
     EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone2));
     EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone3));

Modified: branches/trac447/src/lib/datasrc/zonetable.cc
==============================================================================
--- branches/trac447/src/lib/datasrc/zonetable.cc (original)
+++ branches/trac447/src/lib/datasrc/zonetable.cc Tue Dec 28 10:31:10 2010
@@ -12,14 +12,12 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// Note: map and utility (for 'pair') are for temporary workaround.
-// we'll soon replace them with built-in intelligent backend structure. 
-#include <map>
-#include <utility>
+#include <cassert>
 
 #include <dns/name.h>
 
 #include <datasrc/zonetable.h>
+#include <datasrc/rbtree.h>
 
 using namespace std;
 using namespace isc::dns;
@@ -27,13 +25,79 @@
 namespace isc {
 namespace datasrc {
 
-// This is a temporary, inefficient implementation using std::map and handmade
-// iteration to realize longest match.
+/// \short Private data and implementation of ZoneTable
+struct ZoneTable::ZoneTableImpl {
+    // Type aliases to make it shorter
+    typedef RBTree<Zone> ZoneTree;
+    typedef RBNode<Zone> ZoneNode;
+    // The actual storage
+    ZoneTree zones_;
 
-struct ZoneTable::ZoneTableImpl {
-    typedef map<Name, ZonePtr> ZoneMap;
-    typedef pair<Name, ZonePtr> NameAndZone;
-    ZoneMap zones;
+    /*
+     * The implementation methods are here and just wrap-called in the
+     * ZoneTable. We have variables locally (without impl_->), have
+     * type aliases, etc. And they will get inlined anyway.
+     */
+
+    // Implementation of ZoneTable::addZone
+    result::Result addZone(ZonePtr zone) {
+        // Sanity check
+        if (!zone) {
+            isc_throw(InvalidParameter,
+                      "Null pointer is passed to ZoneTable::addZone()");
+        }
+
+        // Get the node where we put the zone
+        ZoneNode* node(NULL);
+        switch (zones_.insert(zone->getOrigin(), &node)) {
+            // This is OK
+            case ZoneTree::SUCCEED:
+            case ZoneTree::ALREADYEXIST:
+                break;
+            // Can Not Happen
+            default:
+                assert(0);
+        }
+        // Can Not Happen
+        assert(node);
+
+        // Is it empty? We either just created it or it might be nonterminal
+        if (node->isEmpty()) {
+            node->setData(zone);
+            return (result::SUCCESS);
+        } else { // There's something there already
+            return (result::EXIST);
+        }
+    }
+
+    // Implementation of ZoneTable::findZone
+    ZoneTable::FindResult findZone(const Name& name) const {
+        ZoneNode *node(NULL);
+        result::Result my_result;
+
+        // Translate the return codes
+        switch (zones_.find(name, &node)) {
+            case ZoneTree::EXACTMATCH:
+                my_result = result::SUCCESS;
+                break;
+            case ZoneTree::PARTIALMATCH:
+                my_result = result::PARTIALMATCH;
+                break;
+            // We have no data there, so translate the pointer to NULL as well
+            case ZoneTree::NOTFOUND:
+                return (FindResult(result::NOTFOUND, ConstZonePtr()));
+            // Can Not Happen
+            default:
+                assert(0);
+                // Because of warning
+                return (FindResult(result::NOTFOUND, ConstZonePtr()));
+        }
+
+        // Can Not Happen (remember, NOTFOUND is handled)
+        assert(node);
+
+        return (FindResult(my_result, node->getData()));
+    }
 };
 
 ZoneTable::ZoneTable() : impl_(new ZoneTableImpl)
@@ -45,40 +109,21 @@
 
 result::Result
 ZoneTable::addZone(ZonePtr zone) {
-    if (!zone) {
-        isc_throw(InvalidParameter,
-                  "Null pointer is passed to ZoneTable::addZone()");
-    }
-
-    if (impl_->zones.insert(
-            ZoneTableImpl::NameAndZone(zone->getOrigin(), zone)).second
-        == true) {
-        return (result::SUCCESS);
-    } else {
-        return (result::EXIST);
-    }
+    return (impl_->addZone(zone));
 }
 
 result::Result
-ZoneTable::removeZone(const Name& origin) {
-    return (impl_->zones.erase(origin) == 1 ? result::SUCCESS :
-                                              result::NOTFOUND);
+ZoneTable::removeZone(const Name&) {
+    // TODO Implement
+    assert(0);
+    // This should not ever be returned, the assert should kill us by now
+    return (result::SUCCESS);
 }
 
 ZoneTable::FindResult
 ZoneTable::findZone(const Name& name) const {
-    // Inefficient internal loop to find a longest match.
-    // This will be replaced with a single call to more intelligent backend.
-    for (int i = 0; i < name.getLabelCount(); ++i) {
-        Name matchname(name.split(i));
-        ZoneTableImpl::ZoneMap::const_iterator found =
-            impl_->zones.find(matchname);
-        if (found != impl_->zones.end()) {
-            return (FindResult(i == 0 ? result::SUCCESS :
-                               result::PARTIALMATCH, (*found).second));
-        }
-    }
-    return (FindResult(result::NOTFOUND, ConstZonePtr()));
+    return (impl_->findZone(name));
 }
+
 } // end of namespace datasrc
 } // end of namespace isc

Modified: branches/trac447/src/lib/datasrc/zonetable.h
==============================================================================
--- branches/trac447/src/lib/datasrc/zonetable.h (original)
+++ branches/trac447/src/lib/datasrc/zonetable.h Tue Dec 28 10:31:10 2010
@@ -71,8 +71,18 @@
     //@}
 
     /// Add a \c Zone to the \c ZoneTable.
-    /// See the description of <code>MemoryDataSrc::addZone()</code> for more
-    /// details.
+    ///
+    /// \c Zone must not be associated with a NULL pointer; otherwise
+    /// an exception of class \c InvalidParameter will be thrown.
+    /// If internal resource allocation fails, a corresponding standard
+    /// exception will be thrown.
+    /// This method never throws an exception otherwise.
+    ///
+    /// \param zone A \c Zone object to be added.
+    /// \return \c result::SUCCESS If the zone is successfully
+    /// added to the zone table.
+    /// \return \c result::EXIST The zone table already contains
+    /// zone of the same origin.
     result::Result addZone(ZonePtr zone);
 
     /// Remove a \c Zone of the given origin name from the \c ZoneTable.
@@ -87,8 +97,23 @@
     result::Result removeZone(const isc::dns::Name& origin);
 
     /// Find a \c Zone that best matches the given name in the \c ZoneTable.
-    /// See the description of <code>MemoryDataSrc::findZone()</code> for more
-    /// details.
+    ///
+    /// It searches the internal storage for a \c Zone that gives the
+    /// longest match against \c name, and returns the result in the
+    /// form of a \c FindResult object as follows:
+    /// - \c code: The result code of the operation.
+    ///   - \c result::SUCCESS: A zone that gives an exact match
+    ///    is found
+    ///   - \c result::PARTIALMATCH: A zone whose origin is a
+    ///    super domain of \c name is found (but there is no exact match)
+    ///   - \c result::NOTFOUND: For all other cases.
+    /// - \c zone: A <Boost> shared pointer to the found \c Zone object if one
+    ///  is found; otherwise \c NULL.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param name A domain name for which the search is performed.
+    /// \return A \c FindResult object enclosing the search result (see above).
     FindResult findZone(const isc::dns::Name& name) const;
 
 private:

Modified: branches/trac447/src/lib/dns/python/tests/Makefile.am
==============================================================================
--- branches/trac447/src/lib/dns/python/tests/Makefile.am (original)
+++ branches/trac447/src/lib/dns/python/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,3 +1,4 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = edns_python_test.py
 PYTESTS += message_python_test.py
 PYTESTS += messagerenderer_python_test.py
@@ -22,14 +23,17 @@
 LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
 endif
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/dns/.libs:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
 	TESTDATA_PATH=$(abs_top_srcdir)/src/lib/dns/tests/testdata:$(abs_top_builddir)/src/lib/dns/tests/testdata \
 	$(LIBRARY_PATH_PLACEHOLDER) \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/lib/python/isc/cc/tests/Makefile.am
==============================================================================
--- branches/trac447/src/lib/python/isc/cc/tests/Makefile.am (original)
+++ branches/trac447/src/lib/python/isc/cc/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,16 +1,21 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@          
+
 PYTESTS = message_test.py data_test.py session_test.py
 # NOTE: test_session.py is to be run manually, so not automated.
 EXTRA_DIST = $(PYTESTS)
 EXTRA_DIST += sendcmd.py
 EXTRA_DIST += test_session.py
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	BIND10_TEST_SOCKET_FILE=$(builddir)/test_socket.sock \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/lib/python/isc/config/ccsession.py
==============================================================================
--- branches/trac447/src/lib/python/isc/config/ccsession.py (original)
+++ branches/trac447/src/lib/python/isc/config/ccsession.py Tue Dec 28 10:31:10 2010
@@ -224,7 +224,7 @@
                     if not self._config_handler:
                         answer = create_answer(2, self._module_name + " has no config handler")
                     elif not self.get_module_spec().validate_config(False, new_config, errors):
-                        answer = create_answer(1, " ".join(errors))
+                        answer = create_answer(1, ", ".join(errors))
                     else:
                         isc.cc.data.remove_identical(new_config, self.get_local_config())
                         answer = self._config_handler(new_config)
@@ -422,7 +422,16 @@
         """Commit all local changes, send them through b10-cmdctl to
            the configuration manager"""
         if self.get_local_changes():
-            self._conn.send_POST('/ConfigManager/set_config', [ self.get_local_changes() ])
-            # todo: check result
-            self.request_current_config()
-            self.clear_local_changes()
+            response = self._conn.send_POST('/ConfigManager/set_config',
+                                            [ self.get_local_changes() ])
+            answer = isc.cc.data.parse_value_str(response.read().decode())
+            # answer is either an empty dict (on success), or one
+            # containing errors
+            if answer == {}:
+                self.request_current_config()
+                self.clear_local_changes()
+            elif "error" in answer:
+                print("Error: " + answer["error"])
+                print("Configuration not committed")
+            else:
+                raise ModuleCCSessionError("Unknown format of answer in commit(): " + str(answer))

Modified: branches/trac447/src/lib/python/isc/config/config_data.py
==============================================================================
--- branches/trac447/src/lib/python/isc/config/config_data.py (original)
+++ branches/trac447/src/lib/python/isc/config/config_data.py Tue Dec 28 10:31:10 2010
@@ -464,12 +464,15 @@
            there is a specification for the given identifier, the type
            is checked."""
         spec_part = self.find_spec_part(identifier)
-        if spec_part is not None and value is not None:
-            id, list_indices = isc.cc.data.split_identifier_list_indices(identifier)
-            if list_indices is not None \
-               and spec_part['item_type'] == 'list':
-                spec_part = spec_part['list_item_spec']
-            check_type(spec_part, value)
+        if spec_part is not None:
+            if value is not None:
+                id, list_indices = isc.cc.data.split_identifier_list_indices(identifier)
+                if list_indices is not None \
+                   and spec_part['item_type'] == 'list':
+                    spec_part = spec_part['list_item_spec']
+                check_type(spec_part, value)
+        else:
+            raise isc.cc.data.DataNotFoundError(identifier)
 
         # Since we do not support list diffs (yet?), we need to
         # copy the currently set list of items to _local_changes

Modified: branches/trac447/src/lib/python/isc/config/module_spec.py
==============================================================================
--- branches/trac447/src/lib/python/isc/config/module_spec.py (original)
+++ branches/trac447/src/lib/python/isc/config/module_spec.py Tue Dec 28 10:31:10 2010
@@ -328,7 +328,24 @@
         return True
 
 def _validate_spec_list(module_spec, full, data, errors):
+    # we do not return immediately, there may be more errors
+    # so we keep a boolean to keep track if we found errors
+    validated = True
+
+    # check if the known items are correct
     for spec_item in module_spec:
         if not _validate_spec(spec_item, full, data, errors):
-            return False
-    return True
+            validated = False
+
+    # check if there are items in our data that are not in the
+    # specification
+    for item_name in data:
+        found = False
+        for spec_item in module_spec:
+            if spec_item["item_name"] == item_name:
+                found = True
+        if not found:
+            if errors != None:
+                errors.append("unknown item " + item_name)
+            validated = False
+    return validated

Modified: branches/trac447/src/lib/python/isc/config/tests/Makefile.am
==============================================================================
--- branches/trac447/src/lib/python/isc/config/tests/Makefile.am (original)
+++ branches/trac447/src/lib/python/isc/config/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,16 +1,20 @@
+PYCOVERAGE_RUN=@PYCOVERAGE_RUN@
 PYTESTS = ccsession_test.py cfgmgr_test.py config_data_test.py
 PYTESTS += module_spec_test.py
 EXTRA_DIST = $(PYTESTS)
 EXTRA_DIST += unittest_fakesession.py
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	CONFIG_TESTDATA_PATH=$(abs_top_srcdir)/src/lib/config/tests/testdata \
 	CONFIG_WR_TESTDATA_PATH=$(abs_top_builddir)/src/lib/config/tests/testdata \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/lib/python/isc/config/tests/ccsession_test.py
==============================================================================
--- branches/trac447/src/lib/python/isc/config/tests/ccsession_test.py (original)
+++ branches/trac447/src/lib/python/isc/config/tests/ccsession_test.py Tue Dec 28 10:31:10 2010
@@ -290,7 +290,7 @@
         mccs = self.create_session("spec2.spec", None, None, fake_session)
         mccs.set_config_handler(self.my_config_handler_ok)
         self.assertEqual(len(fake_session.message_queue), 0)
-        cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, { 'Spec2': { 'item1': 2 }})
+        cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, { 'item1': 2 })
         fake_session.group_sendmsg(cmd, 'Spec2')
         self.assertEqual(len(fake_session.message_queue), 1)
         mccs.check_command()
@@ -303,12 +303,12 @@
         mccs = self.create_session("spec2.spec", None, None, fake_session)
         mccs.set_config_handler(self.my_config_handler_err)
         self.assertEqual(len(fake_session.message_queue), 0)
-        cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, { 'Spec2': { 'item1': 'aaa' }})
+        cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, { 'item1': 'aaa' })
         fake_session.group_sendmsg(cmd, 'Spec2')
         self.assertEqual(len(fake_session.message_queue), 1)
         mccs.check_command()
         self.assertEqual(len(fake_session.message_queue), 1)
-        self.assertEqual({'result': [1, 'just an error']},
+        self.assertEqual({'result': [1, 'aaa should be an integer']},
                          fake_session.get_message('Spec2', None))
         
     def test_check_command5(self):
@@ -316,12 +316,12 @@
         mccs = self.create_session("spec2.spec", None, None, fake_session)
         mccs.set_config_handler(self.my_config_handler_exc)
         self.assertEqual(len(fake_session.message_queue), 0)
-        cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, { 'Spec2': { 'item1': 'aaa' }})
+        cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, { 'item1': 'aaa' })
         fake_session.group_sendmsg(cmd, 'Spec2')
         self.assertEqual(len(fake_session.message_queue), 1)
         mccs.check_command()
         self.assertEqual(len(fake_session.message_queue), 1)
-        self.assertEqual({'result': [1, 'just an exception']},
+        self.assertEqual({'result': [1, 'aaa should be an integer']},
                          fake_session.get_message('Spec2', None))
         
     def test_check_command6(self):
@@ -416,7 +416,7 @@
         mccs = self.create_session("spec2.spec", None, None, fake_session)
         mccs.set_config_handler(self.my_config_handler_ok)
         self.assertEqual(len(fake_session.message_queue), 0)
-        cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, { 'Spec2': { 'item1': 2 }})
+        cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, { 'item1': 2 })
         self.assertEqual(len(fake_session.message_queue), 0)
         env = { 'group':'Spec2', 'from':None }
         mccs.check_command_without_recvmsg(cmd, env)
@@ -559,6 +559,14 @@
         mccs.check_command()
         self.assertEqual(len(fake_session.message_queue), 0)
         
+
+class fakeData:
+    def decode(self):
+        return "{}";
+
+class fakeAnswer:
+    def read(self):
+        return fakeData();
 
 class fakeUIConn():
     def __init__(self):
@@ -581,7 +589,7 @@
         if name in self.post_answers:
             return self.post_answers[name]
         else:
-            return None
+            return fakeAnswer()
     
 
 class TestUIModuleCCSession(unittest.TestCase):

Modified: branches/trac447/src/lib/python/isc/config/tests/config_data_test.py
==============================================================================
--- branches/trac447/src/lib/python/isc/config/tests/config_data_test.py (original)
+++ branches/trac447/src/lib/python/isc/config/tests/config_data_test.py Tue Dec 28 10:31:10 2010
@@ -335,6 +335,8 @@
         pass
 
     def test_get_local_value(self):
+        module_spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
+        self.mcd.set_specification(module_spec)
         value = self.mcd.get_local_value("Spec2/item1")
         self.assertEqual(None, value)
         self.mcd.set_value("Spec2/item1", 2)
@@ -464,12 +466,11 @@
         module_spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
         self.mcd.set_specification(module_spec)
         self.mcd.set_value("Spec2/item1", 2)
-        self.assertRaises(isc.cc.data.DataTypeError, self.mcd.set_value, "Spec2/item1", "asdf")
-
-        self.mcd.set_value("Spec2/no_such_item", 4)
-        value, status = self.mcd.get_value("Spec2/no_such_item")
-        self.assertEqual(value, 4)
-        self.assertEqual(MultiConfigData.LOCAL, status)
+        self.assertRaises(isc.cc.data.DataTypeError,
+                          self.mcd.set_value, "Spec2/item1", "asdf")
+
+        self.assertRaises(isc.cc.data.DataNotFoundError,
+                          self.mcd.set_value, "Spec2/no_such_item", 4)
 
         self.mcd.set_value("Spec2/item5[0]", "c")
         value, status = self.mcd.get_value("Spec2/item5[0]")

Modified: branches/trac447/src/lib/python/isc/config/tests/module_spec_test.py
==============================================================================
--- branches/trac447/src/lib/python/isc/config/tests/module_spec_test.py (original)
+++ branches/trac447/src/lib/python/isc/config/tests/module_spec_test.py Tue Dec 28 10:31:10 2010
@@ -312,6 +312,18 @@
         self.assertEqual(False, isc.config.module_spec._validate_spec(spec, True, {}, None))
         self.assertEqual(False, isc.config.module_spec._validate_spec(spec, True, {}, errors))
         self.assertEqual(['non-optional item an_item missing'], errors)
+
+    def test_validate_unknown_items(self):
+        spec = [{ 'item_name': "an_item",
+                 'item_type': "string",
+                 'item_optional': True,
+                 'item_default': "asdf"
+               }]
+
+        errors = []
+        self.assertEqual(False, isc.config.module_spec._validate_spec_list(spec, True, { 'does_not_exist': 1 }, None))
+        self.assertEqual(False, isc.config.module_spec._validate_spec_list(spec, True, { 'does_not_exist': 1 }, errors))
+        self.assertEqual(['unknown item does_not_exist'], errors)
         
 
 

Modified: branches/trac447/src/lib/python/isc/datasrc/tests/Makefile.am
==============================================================================
--- branches/trac447/src/lib/python/isc/datasrc/tests/Makefile.am (original)
+++ branches/trac447/src/lib/python/isc/datasrc/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,12 +1,16 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = master_test.py
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/python/isc/log \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/lib/python/isc/log/tests/Makefile.am
==============================================================================
--- branches/trac447/src/lib/python/isc/log/tests/Makefile.am (original)
+++ branches/trac447/src/lib/python/isc/log/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,12 +1,16 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = log_test.py
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/python/isc/log \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/lib/python/isc/net/tests/Makefile.am
==============================================================================
--- branches/trac447/src/lib/python/isc/net/tests/Makefile.am (original)
+++ branches/trac447/src/lib/python/isc/net/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,12 +1,16 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = addr_test.py parse_test.py
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/lib/python/isc/notify/tests/Makefile.am
==============================================================================
--- branches/trac447/src/lib/python/isc/notify/tests/Makefile.am (original)
+++ branches/trac447/src/lib/python/isc/notify/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,3 +1,4 @@
+PYCOVERAGE_RUN=@PYCOVERAGE_RUN@
 PYTESTS = notify_out_test.py
 EXTRA_DIST = $(PYTESTS)
 
@@ -8,13 +9,16 @@
 LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
 endif
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
 	$(LIBRARY_PATH_PLACEHOLDER) \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac447/src/lib/python/isc/util/tests/Makefile.am
==============================================================================
--- branches/trac447/src/lib/python/isc/util/tests/Makefile.am (original)
+++ branches/trac447/src/lib/python/isc/util/tests/Makefile.am Tue Dec 28 10:31:10 2010
@@ -1,12 +1,16 @@
+PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = process_test.py socketserver_mixin_test.py
 EXTRA_DIST = $(PYTESTS)
 
-# later will have configure option to choose this, like: coverage run --branch
-PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 check-local:
+if ENABLE_PYTHON_COVERAGE
+	touch $(abs_top_srcdir)/.coverage 
+	rm -f .coverage
+	${LN_S} $(abs_top_srcdir)/.coverage .coverage
+endif
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done




More information about the bind10-changes mailing list