diff options
Diffstat (limited to 'src/lib/python/isc/memmgr/tests/builder_tests.py')
-rw-r--r-- | src/lib/python/isc/memmgr/tests/builder_tests.py | 115 |
1 files changed, 113 insertions, 2 deletions
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() |