summaryrefslogtreecommitdiffstats
path: root/src/lib/python
diff options
context:
space:
mode:
authorMukund Sivaraman <muks@isc.org>2013-07-12 08:09:20 +0200
committerMukund Sivaraman <muks@isc.org>2013-07-12 08:37:29 +0200
commit37753c0dc215875538463720a5bdd68afdb4fc4e (patch)
tree0ef1a6ce7a34020f86999b66bc4bae92f502d7dd /src/lib/python
parent[2856] Rename env variable (diff)
downloadkea-37753c0dc215875538463720a5bdd68afdb4fc4e.tar.xz
kea-37753c0dc215875538463720a5bdd68afdb4fc4e.zip
[2856] Add test for "load" command to builder
Diffstat (limited to 'src/lib/python')
-rw-r--r--src/lib/python/isc/memmgr/builder.py22
-rw-r--r--src/lib/python/isc/memmgr/tests/Makefile.am2
-rw-r--r--src/lib/python/isc/memmgr/tests/builder_tests.py115
-rw-r--r--src/lib/python/isc/memmgr/tests/testdata/Makefile.am2
-rw-r--r--src/lib/python/isc/memmgr/tests/testdata/example.com.zone8
5 files changed, 139 insertions, 10 deletions
diff --git a/src/lib/python/isc/memmgr/builder.py b/src/lib/python/isc/memmgr/builder.py
index 07dd4a8714..5aa23dc6d0 100644
--- a/src/lib/python/isc/memmgr/builder.py
+++ b/src/lib/python/isc/memmgr/builder.py
@@ -13,6 +13,7 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+import json
from isc.datasrc import ConfigurableClientList
from isc.memmgr.datasrc_info import SegmentInfo
@@ -90,9 +91,10 @@ class MemorySegmentBuilder:
clist = dsrc_info.clients_map[rrclass]
sgmt_info = dsrc_info.segment_info_map[(rrclass, dsrc_name)]
+ params = json.dumps(sgmt_info.get_reset_param(SegmentInfo.WRITER))
clist.reset_memory_segment(dsrc_name,
- ConfigurableClientList.READ_ONLY,
- sgmt_info.get_reset_param(SegmentInfo.WRITER))
+ ConfigurableClientList.READ_WRITE,
+ params)
if zone_name is not None:
zones = [(None, zone_name)]
@@ -100,9 +102,13 @@ class MemorySegmentBuilder:
zones = clist.get_zone_table_accessor(dsrc_name, True)
for _, zone_name in zones:
- cache_load_error = (zone_name is None) # install empty zone initially
- writer = clist.get_cached_zone_writer(zone_name, catch_load_error,
- dsrc_name)
+ catch_load_error = (zone_name is None) # install empty zone initially
+ result, writer = clist.get_cached_zone_writer(zone_name, catch_load_error,
+ dsrc_name)
+ if result != ConfigurableClientList.CACHE_STATUS_ZONE_SUCCESS:
+ # FIXME: log the error
+ continue
+
try:
error = writer.load()
if error is not None:
@@ -119,7 +125,7 @@ class MemorySegmentBuilder:
# public API to just clear the segment)
clist.reset_memory_segment(dsrc_name,
ConfigurableClientList.READ_ONLY,
- sgmt_info.get_reset_param(SegmentInfo.WRITER))
+ params)
self._response_queue.append(('load-completed', dsrc_info, rrclass,
dsrc_name))
@@ -154,8 +160,8 @@ class MemorySegmentBuilder:
# See the comments for __handle_load() for
# details of the tuple passed to the "load"
# command.
- self.__handle_load(command_tuple[1], command_tuple[2],
- command_tuple[3], command_tuple[4])
+ _, zone_name, dsrc_info, rrclass, dsrc_name = command_tuple
+ self.__handle_load(zone_name, dsrc_info, rrclass, dsrc_name)
elif command == 'shutdown':
self.__handle_shutdown()
# When the shutdown command is received, we do
diff --git a/src/lib/python/isc/memmgr/tests/Makefile.am b/src/lib/python/isc/memmgr/tests/Makefile.am
index 8e41ae5f02..b171cb1367 100644
--- a/src/lib/python/isc/memmgr/tests/Makefile.am
+++ b/src/lib/python/isc/memmgr/tests/Makefile.am
@@ -1,3 +1,4 @@
+SUBDIRS = testdata
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
PYTESTS = builder_tests.py datasrc_info_tests.py
EXTRA_DIST = $(PYTESTS)
@@ -26,6 +27,7 @@ endif
for pytest in $(PYTESTS) ; do \
echo Running test: $$pytest ; \
$(LIBRARY_PATH_PLACEHOLDER) \
+ TESTDATA_PATH=$(abs_srcdir)/testdata \
TESTDATA_WRITE_PATH=$(builddir) \
B10_FROM_BUILD=$(abs_top_builddir) \
HAVE_SHARED_MEMORY=$(HAVE_SHARED_MEMORY) \
diff --git a/src/lib/python/isc/memmgr/tests/builder_tests.py b/src/lib/python/isc/memmgr/tests/builder_tests.py
index 94cb8e1e3d..249b5d0565 100644
--- a/src/lib/python/isc/memmgr/tests/builder_tests.py
+++ b/src/lib/python/isc/memmgr/tests/builder_tests.py
@@ -14,12 +14,28 @@
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import unittest
+import os
import socket
import select
import threading
import isc.log
+from isc.dns import *
+import isc.datasrc
from isc.memmgr.builder import *
+from isc.server_common.datasrc_clients_mgr import DataSrcClientsMgr
+from isc.memmgr.datasrc_info import *
+
+TESTDATA_PATH = os.environ['TESTDATA_PATH'] + os.sep
+
+# Defined for easier tests with DataSrcClientsMgr.reconfigure(), which
+# only needs get_value() method
+class MockConfigData:
+ def __init__(self, data):
+ self.__data = data
+
+ def get_value(self, identifier):
+ return self.__data[identifier], False
class TestMemorySegmentBuilder(unittest.TestCase):
def _create_builder_thread(self):
@@ -29,7 +45,8 @@ class TestMemorySegmentBuilder(unittest.TestCase):
self._builder_command_queue = []
self._builder_response_queue = []
- self._builder_cv = threading.Condition()
+ self._builder_lock = threading.Lock()
+ self._builder_cv = threading.Condition(lock=self._builder_lock)
self._builder = MemorySegmentBuilder(self._builder_sock,
self._builder_cv,
@@ -95,7 +112,7 @@ class TestMemorySegmentBuilder(unittest.TestCase):
self._builder_thread.start()
- # Now that the builder thread is running, send it the shutdown
+ # Now that the builder thread is running, send it the "shutdown"
# command. The thread should exit its main loop and be joinable.
with self._builder_cv:
self._builder_command_queue.append(('shutdown',))
@@ -115,6 +132,100 @@ class TestMemorySegmentBuilder(unittest.TestCase):
self.assertEqual(len(self._builder_command_queue), 0)
self.assertEqual(len(self._builder_response_queue), 0)
+ @unittest.skipIf(os.environ['HAVE_SHARED_MEMORY'] != 'yes',
+ 'shared memory is not available')
+ def test_load(self):
+ """
+ Test "load" command.
+ """
+
+ mapped_file_dir = os.environ['TESTDATA_WRITE_PATH']
+ mgr_config = {'mapped_file_dir': mapped_file_dir}
+
+ cfg_data = MockConfigData(
+ {"classes":
+ {"IN": [{"type": "MasterFiles",
+ "params": { "example.com": TESTDATA_PATH + "example.com.zone" },
+ "cache-enable": True,
+ "cache-type": "mapped"}]
+ }
+ })
+ cmgr = DataSrcClientsMgr(use_cache=True)
+ cmgr.reconfigure({}, cfg_data)
+
+ genid, clients_map = cmgr.get_clients_map()
+ datasrc_info = DataSrcInfo(genid, clients_map, mgr_config)
+
+ self.assertEqual(1, datasrc_info.gen_id)
+ self.assertEqual(clients_map, datasrc_info.clients_map)
+ self.assertEqual(1, len(datasrc_info.segment_info_map))
+ sgmt_info = datasrc_info.segment_info_map[(RRClass.IN, 'MasterFiles')]
+ self.assertIsNone(sgmt_info.get_reset_param(SegmentInfo.READER))
+ self.assertIsNotNone(sgmt_info.get_reset_param(SegmentInfo.WRITER))
+
+ self._builder_thread.start()
+
+ # Now that the builder thread is running, send it the "load"
+ # command. We should be notified when the load operation is
+ # complete.
+ with self._builder_cv:
+ self._builder_command_queue.append(('load',
+ isc.dns.Name("example.com"),
+ datasrc_info, RRClass.IN,
+ 'MasterFiles'))
+ self._builder_cv.notify_all()
+
+ # Wait 60 seconds to receive a notification on the socket from
+ # the builder.
+ (reads, _, _) = select.select([self._master_sock], [], [], 60)
+ self.assertTrue(self._master_sock in reads)
+
+ # Reading 1 byte should not block us here, especially as the
+ # socket is ready to read. It's a hack, but this is just a
+ # testcase.
+ got = self._master_sock.recv(1)
+ self.assertEqual(got, b'x')
+
+ with self._builder_lock:
+ # The command queue must be cleared, and the response queue
+ # must contain a response that a bad command was sent. The
+ # thread is no longer running, so we can use the queues
+ # without a lock.
+ self.assertEqual(len(self._builder_command_queue), 0)
+ self.assertEqual(len(self._builder_response_queue), 1)
+
+ response = self._builder_response_queue[0]
+ self.assertTrue(isinstance(response, tuple))
+ self.assertTupleEqual(response, ('load-completed', datasrc_info,
+ RRClass.IN, 'MasterFiles'))
+ del self._builder_response_queue[:]
+
+ # Now try looking for some loaded data
+ clist = datasrc_info.clients_map[RRClass.IN]
+ dsrc, finder, exact = clist.find(isc.dns.Name("example.com"))
+ self.assertIsNotNone(dsrc)
+ self.assertTrue(isinstance(dsrc, isc.datasrc.DataSourceClient))
+ self.assertIsNotNone(finder)
+ self.assertTrue(isinstance(finder, isc.datasrc.ZoneFinder))
+ self.assertTrue(exact)
+
+ # Send the builder thread the "shutdown" command. The thread
+ # should exit its main loop and be joinable.
+ with self._builder_cv:
+ self._builder_command_queue.append(('shutdown',))
+ self._builder_cv.notify_all()
+
+ # Wait 5 seconds at most for the main loop of the builder to
+ # exit.
+ self._builder_thread.join(5)
+ self.assertFalse(self._builder_thread.isAlive())
+
+ # The command queue must be cleared, and the response queue must
+ # be untouched (we don't use it in this test). The thread is no
+ # longer running, so we can use the queues without a lock.
+ self.assertEqual(len(self._builder_command_queue), 0)
+ self.assertEqual(len(self._builder_response_queue), 0)
+
if __name__ == "__main__":
isc.log.init("bind10-test")
isc.log.resetUnitTestRootLogger()
diff --git a/src/lib/python/isc/memmgr/tests/testdata/Makefile.am b/src/lib/python/isc/memmgr/tests/testdata/Makefile.am
new file mode 100644
index 0000000000..22e7ce3962
--- /dev/null
+++ b/src/lib/python/isc/memmgr/tests/testdata/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = \
+ example.com.zone
diff --git a/src/lib/python/isc/memmgr/tests/testdata/example.com.zone b/src/lib/python/isc/memmgr/tests/testdata/example.com.zone
new file mode 100644
index 0000000000..24e22e152f
--- /dev/null
+++ b/src/lib/python/isc/memmgr/tests/testdata/example.com.zone
@@ -0,0 +1,8 @@
+example.com. 1000 IN SOA a.dns.example.com. mail.example.com. 1 1 1 1 1
+example.com. 1000 IN NS a.dns.example.com.
+example.com. 1000 IN NS b.dns.example.com.
+example.com. 1000 IN NS c.dns.example.com.
+a.dns.example.com. 1000 IN A 1.1.1.1
+b.dns.example.com. 1000 IN A 3.3.3.3
+b.dns.example.com. 1000 IN AAAA 4:4::4:4
+b.dns.example.com. 1000 IN AAAA 5:5::5:5