summaryrefslogtreecommitdiffstats
path: root/src/lib/python/isc/memmgr/tests/builder_tests.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/python/isc/memmgr/tests/builder_tests.py')
-rw-r--r--src/lib/python/isc/memmgr/tests/builder_tests.py115
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()