diff options
author | Mukund Sivaraman <muks@isc.org> | 2013-07-12 08:09:20 +0200 |
---|---|---|
committer | Mukund Sivaraman <muks@isc.org> | 2013-07-12 08:37:29 +0200 |
commit | 37753c0dc215875538463720a5bdd68afdb4fc4e (patch) | |
tree | 0ef1a6ce7a34020f86999b66bc4bae92f502d7dd /src/lib/python | |
parent | [2856] Rename env variable (diff) | |
download | kea-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.py | 22 | ||||
-rw-r--r-- | src/lib/python/isc/memmgr/tests/Makefile.am | 2 | ||||
-rw-r--r-- | src/lib/python/isc/memmgr/tests/builder_tests.py | 115 | ||||
-rw-r--r-- | src/lib/python/isc/memmgr/tests/testdata/Makefile.am | 2 | ||||
-rw-r--r-- | src/lib/python/isc/memmgr/tests/testdata/example.com.zone | 8 |
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 |