Commit f9fbac74 authored by Michal Vaner's avatar Michal Vaner
Browse files

Merged trac 349

git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@3153 e5f2f494-b856-4b98-b285-d166d9295462
parents 9b06feab eb2962f7
#!@PYTHON@
# Copyright (C) 2010 Internet Systems Consortium.
# Copyright (C) 2010 CZ NIC
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
......@@ -323,8 +324,8 @@ class CommandControl():
def _handle_msg_from_msgq(self):
'''Process all the received commands with module session. '''
while self._serving:
self._module_cc.check_command()
self._module_cc.check_command(False)
def _parse_command_result(self, rcode, reply):
'''Ignore the error reason when command rcode isn't 0, '''
if rcode != 0:
......
#!@PYTHON@
# Copyright (C) 2010 Internet Systems Consortium.
# Copyright (C) 2010 CZ NIC
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
......@@ -396,7 +397,7 @@ class Xfrin:
'''This is a straightforward wrapper for cc.check_command,
but provided as a separate method for the convenience
of unit tests.'''
self._module_cc.check_command()
self._module_cc.check_command(False)
def config_handler(self, new_config):
self._max_transfers_in = new_config.get("transfers_in") or self._max_transfers_in
......
#!@PYTHON@
# Copyright (C) 2010 Internet Systems Consortium.
# Copyright (C) 2010 CZ NIC
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
......@@ -494,7 +495,7 @@ class XfroutServer:
def run(self):
'''Get and process all commands sent from cfgmgr or other modules. '''
while not self._shutdown_event.is_set():
self._cc.check_command()
self._cc.check_command(False)
xfrout_server = None
......
#!@PYTHON@
# Copyright (C) 2010 Internet Systems Consortium.
# Copyright (C) 2010 CZ NIC
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
......@@ -481,7 +482,7 @@ class Zonemgr:
def run(self):
while not self._shutdown_event.is_set():
self._module_cc.check_command()
self._module_cc.check_command(False)
zonemgrd = None
......
# Copyright (C) 2009 Internet Systems Consortium.
# Copyright (C) 2010 CZ NIC
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
......@@ -169,20 +170,30 @@ class ModuleCCSession(ConfigData):
time-critical, it is strongly recommended to only use
check_command(), and not look at the socket at all."""
return self._session._socket
def close(self):
"""Close the session to the command channel"""
self._session.close()
def check_command(self):
def check_command(self, nonblock=True):
"""Check whether there is a command or configuration update
on the channel. Call the corresponding callback function if
there is. This function does a non-blocking read on the
cc session, and returns nothing. It will respond to any
command by either an error or the answer message returned
by the callback, unless the latter is None."""
msg, env = self._session.group_recvmsg(True)
there is. This function does a read on the cc session, and
returns nothing. It will respond to any command by either
an error or the answer message returned by the callback,
unless the latter is None.
If nonblock is True, it just checks if there's a command
and does nothing if there isn't. If nonblock is False, it
waits until it arrives. It temporarily sets timeout to infinity,
because commands may not come in arbitrary long time."""
timeout_orig = self._session.get_timeout()
self._session.set_timeout(0)
try:
msg, env = self._session.group_recvmsg(nonblock)
finally:
self._session.set_timeout(timeout_orig)
# should we default to an answer? success-by-default? unhandled error?
if msg is not None and not 'result' in msg:
answer = None
......
......@@ -23,7 +23,7 @@ import unittest
import os
from isc.config.ccsession import *
from isc.config.config_data import BIND10_CONFIG_DATA_VERSION
from unittest_fakesession import FakeModuleCCSession
from unittest_fakesession import FakeModuleCCSession, WouldBlockForever
class TestHelperFunctions(unittest.TestCase):
def test_parse_answer(self):
......@@ -125,6 +125,8 @@ class TestModuleCCSession(unittest.TestCase):
self.assertTrue("Spec1" in fake_session.subscriptions)
self.assertEqual(len(fake_session.message_queue), 0)
fake_session.group_sendmsg(None, 'Spec1')
fake_session.group_sendmsg(None, 'Spec1')
self.assertRaises(ModuleCCSessionError, mccs.start)
self.assertEqual(len(fake_session.message_queue), 2)
self.assertEqual({'command': ['module_spec', {'module_name': 'Spec1'}]},
......@@ -150,6 +152,8 @@ class TestModuleCCSession(unittest.TestCase):
fake_session = FakeModuleCCSession()
mccs = self.create_session("spec2.spec", None, None, fake_session)
self.assertEqual(len(fake_session.message_queue), 0)
fake_session.group_sendmsg(None, 'Spec2')
fake_session.group_sendmsg(None, 'Spec2')
self.assertRaises(ModuleCCSessionError, mccs.start)
self.assertEqual(len(fake_session.message_queue), 2)
self.assertEqual({'command': ['module_spec', mccs.specification._module_spec]},
......@@ -173,6 +177,8 @@ class TestModuleCCSession(unittest.TestCase):
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)
fake_session.group_sendmsg(None, 'Spec2')
fake_session.group_sendmsg(None, 'Spec2')
self.assertRaises(ModuleCCSessionError, mccs.start)
self.assertEqual(len(fake_session.message_queue), 2)
self.assertEqual({'command': ['module_spec', mccs.specification._module_spec]},
......@@ -196,6 +202,8 @@ class TestModuleCCSession(unittest.TestCase):
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)
fake_session.group_sendmsg(None, 'Spec2')
fake_session.group_sendmsg(None, 'Spec2')
self.assertRaises(ModuleCCSessionError, mccs.start)
self.assertEqual(len(fake_session.message_queue), 2)
self.assertEqual({'command': ['module_spec', mccs.specification._module_spec]},
......@@ -327,30 +335,67 @@ class TestModuleCCSession(unittest.TestCase):
self.assertEqual(len(fake_session.message_queue), 1)
self.assertEqual({'result': [2, 'Spec2 has no command handler']},
fake_session.get_message('Spec2', None))
def test_check_command7(self):
"""Many check_command tests look too similar, this is common body."""
def common_check_command_check(self, cmd_handler,
cmd_check=lambda mccs, _: mccs.check_command()):
fake_session = FakeModuleCCSession()
mccs = self.create_session("spec2.spec", None, None, fake_session)
mccs.set_command_handler(self.my_command_handler_ok)
mccs.set_command_handler(cmd_handler)
self.assertEqual(len(fake_session.message_queue), 0)
cmd = isc.config.ccsession.create_command("print_message", "just a message")
fake_session.group_sendmsg(cmd, 'Spec2')
self.assertEqual(len(fake_session.message_queue), 1)
mccs.check_command()
cmd_check(mccs, fake_session)
return fake_session
def test_check_command7(self):
fake_session = self.common_check_command_check(
self.my_command_handler_ok)
self.assertEqual(len(fake_session.message_queue), 1)
self.assertEqual({'result': [0]},
fake_session.get_message('Spec2', None))
def test_check_command8(self):
fake_session = FakeModuleCCSession()
mccs = self.create_session("spec2.spec", None, None, fake_session)
mccs.set_command_handler(self.my_command_handler_no_answer)
fake_session = self.common_check_command_check(
self.my_command_handler_no_answer)
self.assertEqual(len(fake_session.message_queue), 0)
cmd = isc.config.ccsession.create_command("print_message", "just a message")
fake_session.group_sendmsg(cmd, 'Spec2')
def test_check_command_block(self):
"""See if the message gets there even in blocking mode."""
fake_session = self.common_check_command_check(
self.my_command_handler_ok,
lambda mccs, _: mccs.check_command(False))
self.assertEqual(len(fake_session.message_queue), 1)
mccs.check_command()
self.assertEqual(len(fake_session.message_queue), 0)
self.assertEqual({'result': [0]},
fake_session.get_message('Spec2', None))
def test_check_command_block_timeout(self):
"""Check it works if session has timeout and it sets it back."""
def cmd_check(mccs, session):
session.set_timeout(1)
mccs.check_command(False)
fake_session = self.common_check_command_check(
self.my_command_handler_ok, cmd_check)
self.assertEqual(len(fake_session.message_queue), 1)
self.assertEqual({'result': [0]},
fake_session.get_message('Spec2', None))
self.assertEqual(fake_session.get_timeout(), 1)
def test_check_command_blocks_forever(self):
"""Check it would wait forever checking a command."""
fake_session = FakeModuleCCSession()
mccs = self.create_session("spec2.spec", None, None, fake_session)
mccs.set_command_handler(self.my_command_handler_ok)
self.assertRaises(WouldBlockForever, lambda: mccs.check_command(False))
def test_check_command_blocks_forever_timeout(self):
"""Like above, but it should wait forever even with timeout here."""
fake_session = FakeModuleCCSession()
fake_session.set_timeout(1)
mccs = self.create_session("spec2.spec", None, None, fake_session)
mccs.set_command_handler(self.my_command_handler_ok)
self.assertRaises(WouldBlockForever, lambda: mccs.check_command(False))
def test_remote_module(self):
fake_session = FakeModuleCCSession()
......@@ -360,6 +405,7 @@ class TestModuleCCSession(unittest.TestCase):
self.assertRaises(ModuleCCSessionError, mccs.get_remote_config_value, "Spec2", "item1")
self.assertFalse("Spec2" in fake_session.subscriptions)
fake_session.group_sendmsg(None, 'Spec2')
rmodname = mccs.add_remote_config(self.spec_file("spec2.spec"))
self.assertTrue("Spec2" in fake_session.subscriptions)
self.assertEqual("Spec2", rmodname)
......@@ -373,6 +419,7 @@ class TestModuleCCSession(unittest.TestCase):
self.assertRaises(ModuleCCSessionError, mccs.get_remote_config_value, "Spec2", "item1")
# test if unsubscription is alse sent when object is deleted
fake_session.group_sendmsg({'result' : [0]}, 'Spec2')
rmodname = mccs.add_remote_config(self.spec_file("spec2.spec"))
self.assertTrue("Spec2" in fake_session.subscriptions)
mccs = None
......@@ -383,6 +430,7 @@ class TestModuleCCSession(unittest.TestCase):
fake_session = FakeModuleCCSession()
mccs = self.create_session("spec1.spec", None, None, fake_session)
mccs.set_command_handler(self.my_command_handler_ok)
fake_session.group_sendmsg(None, 'Spec2')
rmodname = mccs.add_remote_config(self.spec_file("spec2.spec"))
# remove the 'get config' from the queue
......
......@@ -255,6 +255,7 @@ class TestConfigManager(unittest.TestCase):
self.fake_session.get_message(self.name, None))
self.assertEqual(len(self.fake_session.message_queue), 0)
self.fake_session.group_sendmsg(None, 'ConfigManager')
self._handle_msg_helper({ "command": [ "set_config", [ ] ] },
{'result': [1, 'Wrong number of arguments']} )
self._handle_msg_helper({ "command": [ "set_config", [ self.name, { "test": 125 }] ] },
......
......@@ -17,6 +17,13 @@
import isc
class WouldBlockForever(Exception):
"""
This is thrown by the FakeModuleCCSession if it would need
to block forever for incoming message.
"""
pass
#
# We can probably use a more general version of this
#
......@@ -64,13 +71,18 @@ class FakeModuleCCSession:
if 'group' in env:
self.message_queue.append([ env['group'], None, msg])
def group_recvmsg(self, blocking, seq = None):
def group_recvmsg(self, nonblock=True, seq = None):
for qm in self.message_queue:
if qm[0] in self.subscriptions and (qm[1] == None or qm[1] in self.subscriptions[qm[0]]):
if qm[0] in self.subscriptions and (qm[1] == None or qm[1] in
self.subscriptions[qm[0]]):
self.message_queue.remove(qm)
return qm[2], {'group': qm[0], 'from': qm[1]}
if self._timeout == 0:
return None, None
if nonblock:
return None, None
else:
raise WouldBlockForever(
"Blocking read without timeout and no message ready")
else:
raise isc.cc.SessionTimeout("Timeout set but no data to "
"return to group_recvmsg()")
......@@ -88,3 +100,6 @@ class FakeModuleCCSession:
def set_timeout(self, timeout):
self._timeout = timeout
def get_timeout(self):
return self._timeout
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment