BIND 10 trac2879, updated. 8076ec59d2a4efa5e7bc2b28d47749819acdb32f [2879] adjusted lettuce tests that are affected by the fix of the branch.
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Apr 23 22:37:50 UTC 2013
The branch, trac2879 has been updated
via 8076ec59d2a4efa5e7bc2b28d47749819acdb32f (commit)
via 27cae0d6fd4b8f5c0fa205aa67e236e9572b8e64 (commit)
via 23b8228fb4b4fc431a12f1f13668f16c2c7517a2 (commit)
via 29b74f8137e19df1e0389df99d9b20f0fa231f35 (commit)
via f217f1e62497393d63fde870191c9aeda6d75d14 (commit)
via 3b86761e66244e8536b3fbb46ba1d74bbb8dd526 (commit)
via eab6ead64d7f7d78b024988bc29e95bb28426a37 (commit)
from eacf5511e4a005c343b78430c9f749ba46a84c3a (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 8076ec59d2a4efa5e7bc2b28d47749819acdb32f
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Apr 23 15:35:25 2013 -0700
[2879] adjusted lettuce tests that are affected by the fix of the branch.
note: this is not a regression. the original expected value has never made
sense, so this is actually a "correction". in fact, we should have noticed
the bug of this ticket when we noticed notifyoutv6 was counted 5 times even
it should be a successful notify response.
commit 27cae0d6fd4b8f5c0fa205aa67e236e9572b8e64
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Apr 23 15:31:57 2013 -0700
[2879] more documentation
commit 23b8228fb4b4fc431a12f1f13668f16c2c7517a2
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Apr 23 15:26:04 2013 -0700
[2879] (unrelated) cleanup: use common address,port format for logging
commit 29b74f8137e19df1e0389df99d9b20f0fa231f35
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Apr 23 15:25:11 2013 -0700
[2879] more documentation
commit f217f1e62497393d63fde870191c9aeda6d75d14
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Apr 23 15:22:00 2013 -0700
[2879] fixed the main defect with revised tests.
commit 3b86761e66244e8536b3fbb46ba1d74bbb8dd526
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Tue Apr 23 14:06:02 2013 -0700
[2879] added more test cases for notify_handler (timeout case)
with some cleanups:
- removed unnecessary setup
- use 192.0.2.1 instead of 1.1.1.1; former should be a bit better
- removed meaninglessly repeated test cases
- use faked time.time() to test timeout value more reliably
commit eab6ead64d7f7d78b024988bc29e95bb28426a37
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Mon Apr 22 15:00:28 2013 -0700
[2879] simplification: removed EVENT_NONE as it's simply unused
-----------------------------------------------------------------------
Summary of changes:
src/lib/python/isc/notify/notify_out.py | 29 ++++-
src/lib/python/isc/notify/notify_out_messages.mes | 2 +-
src/lib/python/isc/notify/tests/notify_out_test.py | 126 ++++++++++++++++----
.../lettuce/features/xfrin_notify_handling.feature | 8 +-
4 files changed, 130 insertions(+), 35 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/python/isc/notify/notify_out.py b/src/lib/python/isc/notify/notify_out.py
index 8f669b4..070973a 100644
--- a/src/lib/python/isc/notify/notify_out.py
+++ b/src/lib/python/isc/notify/notify_out.py
@@ -41,7 +41,6 @@ ZONE_XFRIN_FAILED = 'zone_xfrin_failed'
_MAX_NOTIFY_NUM = 30
_MAX_NOTIFY_TRY_NUM = 5
-_EVENT_NONE = 0
_EVENT_READ = 1
_EVENT_TIMEOUT = 2
_NOTIFY_TIMEOUT = 1
@@ -424,6 +423,18 @@ class NotifyOut:
def _zone_notify_handler(self, zone_notify_info, event_type):
"""Notify handler for one zone.
+ For the event type of _EVENT_READ, this method reads a new notify
+ response message from the corresponding socket. If it succeeds
+ and the response is the expected one, it will send another notify
+ to the next slave for the zone (if any) or the next zone (if any)
+ waiting for its turn of sending notifies.
+
+ In the case of _EVENT_TIMEOUT, or if the read fails or the response
+ is not an expected one in the case of _EVENT_READ, this method will
+ resend the notify request to the same slave up to _MAX_NOTIFY_TRY_NUM
+ times. If it reaches the max, it will swith to the next slave or
+ the next zone like the successful case above.
+
The first notify message is always triggered by the event
"_EVENT_TIMEOUT" since when one zone prepares to notify its slaves,
its notify_timeout is set to now, which is used to trigger sending
@@ -436,13 +447,19 @@ class NotifyOut:
"""
tgt = zone_notify_info.get_current_notify_target()
if event_type == _EVENT_READ:
+ # Note: _get_notify_reply() should also check the response's
+ # source address (see #2924). When it's done the following code
+ # should also be adjusted a bit.
reply = self._get_notify_reply(zone_notify_info.get_socket(), tgt)
if reply is not None:
- if self._handle_notify_reply(zone_notify_info, reply, tgt):
+ if (self._handle_notify_reply(zone_notify_info, reply, tgt) ==
+ _REPLY_OK):
self._notify_next_target(zone_notify_info)
- elif event_type == _EVENT_TIMEOUT and zone_notify_info.notify_try_num > 0:
- logger.info(NOTIFY_OUT_TIMEOUT, AddressFormatter(tgt))
+ else:
+ assert event_type == _EVENT_TIMEOUT
+ if zone_notify_info.notify_try_num > 0:
+ logger.info(NOTIFY_OUT_TIMEOUT, AddressFormatter(tgt))
tgt = zone_notify_info.get_current_notify_target()
if tgt:
@@ -452,7 +469,7 @@ class NotifyOut:
_MAX_NOTIFY_TRY_NUM)
self._notify_next_target(zone_notify_info)
else:
- # set exponential backoff according rfc1996 section 3.6
+ # set exponential backoff according to rfc1996 section 3.6
retry_timeout = (_NOTIFY_TIMEOUT *
pow(2, zone_notify_info.notify_try_num))
zone_notify_info.notify_timeout = time.time() + retry_timeout
@@ -586,7 +603,7 @@ class NotifyOut:
logger.debug(logger.DBGLVL_TRACE_BASIC, NOTIFY_OUT_REPLY_RECEIVED,
zone_notify_info.zone_name, zone_notify_info.zone_class,
- from_addr[0], from_addr[1], msg.get_rcode())
+ AddressFormatter(from_addr), msg.get_rcode())
return _REPLY_OK
diff --git a/src/lib/python/isc/notify/notify_out_messages.mes b/src/lib/python/isc/notify/notify_out_messages.mes
index 30fb087..fd08f43 100644
--- a/src/lib/python/isc/notify/notify_out_messages.mes
+++ b/src/lib/python/isc/notify/notify_out_messages.mes
@@ -60,7 +60,7 @@ given address, but the reply did not have the QR bit set to one.
Since there was a response, no more notifies will be sent to this
server for this notification event.
-% NOTIFY_OUT_REPLY_RECEIVED Zone %1/%2: notify response from %3:%4: %5
+% NOTIFY_OUT_REPLY_RECEIVED Zone %1/%2: notify response from %3: %4
The notify_out library sent a notify message to the nameserver at
the given address, and received a response. Its Rcode will be shown,
too.
diff --git a/src/lib/python/isc/notify/tests/notify_out_test.py b/src/lib/python/isc/notify/tests/notify_out_test.py
index 3f2c908..e2b8d27 100644
--- a/src/lib/python/isc/notify/tests/notify_out_test.py
+++ b/src/lib/python/isc/notify/tests/notify_out_test.py
@@ -25,10 +25,32 @@ from isc.dns import *
TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
+def get_notify_msgdata(zone_name, qid=0):
+ """A helper function to generate a notify response in wire format.
+
+ Parameters:
+ zone_name(isc.dns.Name()) The zone name for the notify. Used as the
+ question name.
+ qid (int): The QID of the response. In most test cases a value of 0 is
+ expected.
+
+ """
+ m = Message(Message.RENDER)
+ m.set_opcode(Opcode.NOTIFY)
+ m.set_rcode(Rcode.NOERROR)
+ m.set_qid(qid)
+ m.set_header_flag(Message.HEADERFLAG_QR)
+ m.add_question(Question(zone_name, RRClass.IN, RRType.SOA))
+
+ renderer = MessageRenderer()
+ m.to_wire(renderer)
+ return renderer.get_data()
+
# our fake socket, where we can read and insert messages
class MockSocket():
def __init__(self):
self._local_sock, self._remote_sock = socket.socketpair()
+ self.__raise_on_recv = False # see set_raise_on_recv()
def connect(self, to):
pass
@@ -44,6 +66,8 @@ class MockSocket():
return self._local_sock.send(data)
def recvfrom(self, length):
+ if self.__raise_on_recv:
+ raise socket.error('fake error')
data = self._local_sock.recv(length)
return (data, None)
@@ -51,6 +75,14 @@ class MockSocket():
def remote_end(self):
return self._remote_sock
+ def set_raise_on_recv(self, on):
+ """A helper to force recvfrom() to raise an exception or cancel it.
+
+ The next call to recvfrom() will result in an exception iff parameter
+ 'on' (bool) is set to True.
+ """
+ self.__raise_on_recv = on
+
# We subclass the ZoneNotifyInfo class we're testing here, only
# to override the create_socket() method.
class MockZoneNotifyInfo(notify_out.ZoneNotifyInfo):
@@ -79,12 +111,12 @@ class TestZoneNotifyInfo(unittest.TestCase):
def test_set_next_notify_target(self):
self.info.notify_slaves.append(('127.0.0.1', 53))
- self.info.notify_slaves.append(('1.1.1.1', 5353))
+ self.info.notify_slaves.append(('192.0.2.1', 5353))
self.info.prepare_notify_out()
self.assertEqual(self.info.get_current_notify_target(), ('127.0.0.1', 53))
self.info.set_next_notify_target()
- self.assertEqual(self.info.get_current_notify_target(), ('1.1.1.1', 5353))
+ self.assertEqual(self.info.get_current_notify_target(), ('192.0.2.1', 5353))
self.info.set_next_notify_target()
self.assertIsNone(self.info.get_current_notify_target())
@@ -105,14 +137,18 @@ class TestNotifyOut(unittest.TestCase):
net_info = self._notify._notify_infos[('example.net.', 'IN')]
net_info.notify_slaves.append(('127.0.0.1', 53))
- net_info.notify_slaves.append(('1.1.1.1', 5353))
+ net_info.notify_slaves.append(('192.0.2.1', 5353))
com_info = self._notify._notify_infos[('example.com.', 'IN')]
- com_info.notify_slaves.append(('1.1.1.1', 5353))
+ com_info.notify_slaves.append(('192.0.2.1', 5353))
com_ch_info = self._notify._notify_infos[('example.com.', 'CH')]
- com_ch_info.notify_slaves.append(('1.1.1.1', 5353))
+ com_ch_info.notify_slaves.append(('192.0.2.1', 5353))
+ # Keep the original library version in case a test case replaces it
+ self.__time_time_orig = notify_out.time.time
def tearDown(self):
self._notify._counters.clear_all()
+ # restore the original time.time() in case it was replaced.
+ notify_out.time.time = self.__time_time_orig
def test_send_notify(self):
notify_out._MAX_NOTIFY_NUM = 2
@@ -221,7 +257,7 @@ class TestNotifyOut(unittest.TestCase):
info = self._notify._notify_infos[('example.net.', 'IN')]
self._notify._notify_next_target(info)
self.assertEqual(0, info.notify_try_num)
- self.assertEqual(info.get_current_notify_target(), ('1.1.1.1', 5353))
+ self.assertEqual(info.get_current_notify_target(), ('192.0.2.1', 5353))
self.assertEqual(2, self._notify.notify_num)
self.assertEqual(1, len(self._notify._waiting_zones))
@@ -328,44 +364,86 @@ class TestNotifyOut(unittest.TestCase):
'zones', 'example.net.', 'notifyoutv4')
def test_zone_notify_handler(self):
- old_send_msg = self._notify._send_notify_message_udp
- def _fake_send_notify_message_udp(va1, va2):
+ sent_addrs = []
+ def _fake_send_notify_message_udp(notify_info, addrinfo):
+ sent_addrs.append(addrinfo)
pass
+ notify_out.time.time = lambda: 42
self._notify._send_notify_message_udp = _fake_send_notify_message_udp
self._notify.send_notify('example.net.')
- self._notify.send_notify('example.com.')
- notify_out._MAX_NOTIFY_NUM = 2
- self._notify.send_notify('example.org.')
example_net_info = self._notify._notify_infos[('example.net.', 'IN')]
- example_net_info.prepare_notify_out()
+ # On timeout, the request will be resent until try_num reaches the max
+ self.assertEqual([], sent_addrs)
example_net_info.notify_try_num = 2
self._notify._zone_notify_handler(example_net_info,
notify_out._EVENT_TIMEOUT)
self.assertEqual(3, example_net_info.notify_try_num)
+ self.assertEqual([('127.0.0.1', 53)], sent_addrs)
+ # the timeout time will be set to "current time(=42)"+2**(new try_num)
+ self.assertEqual(42 + 2**3, example_net_info.notify_timeout)
- time1 = example_net_info.notify_timeout
+ # If try num exceeds max, the next slave will be tried (and then
+ # next zone, but for this test it sufficies to check the former case)
+ example_net_info.notify_try_num = 5
self._notify._zone_notify_handler(example_net_info,
notify_out._EVENT_TIMEOUT)
- self.assertEqual(4, example_net_info.notify_try_num)
- # bigger than 2 seconds:
- self.assertGreater(example_net_info.notify_timeout, time1 + 2)
+ self.assertEqual(0, example_net_info.notify_try_num) # should be reset
+ self.assertEqual(('192.0.2.1', 5353), example_net_info._notify_current)
+ # Possible event is "read" or "timeout".
cur_tgt = example_net_info._notify_current
example_net_info.notify_try_num = notify_out._MAX_NOTIFY_TRY_NUM
- self._notify._zone_notify_handler(example_net_info,
- notify_out._EVENT_NONE)
- self.assertNotEqual(cur_tgt, example_net_info._notify_current)
+ self.assertRaises(AssertionError, self._notify._zone_notify_handler,
+ example_net_info, notify_out._EVENT_TIMEOUT + 1)
- cur_tgt = example_net_info._notify_current
+ def test_zone_notify_read_handler(self):
+ """Similar to the previous test, but focus on the READ events.
+
+ """
+ sent_addrs = []
+ def _fake_send_notify_message_udp(notify_info, addrinfo):
+ sent_addrs.append(addrinfo)
+ pass
+ self._notify._send_notify_message_udp = _fake_send_notify_message_udp
+ self._notify.send_notify('example.net.')
+
+ example_net_info = self._notify._notify_infos[('example.net.', 'IN')]
example_net_info.create_socket('127.0.0.1')
- # dns message, will result in bad_qid, but what we are testing
- # here is whether handle_notify_reply is called correctly
- example_net_info._sock.remote_end().send(b'\x2f\x18\xa0\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\03com\x00\x00\x06\x00\x01')
+
+ # A successful case: an expected notify response is received, and
+ # another notify will be sent to the next slave immediately.
+ example_net_info._sock.remote_end().send(
+ get_notify_msgdata(Name('example.net')))
self._notify._zone_notify_handler(example_net_info,
notify_out._EVENT_READ)
- self.assertNotEqual(cur_tgt, example_net_info._notify_current)
+ self.assertEqual(1, example_net_info.notify_try_num)
+ expected_sent_addrs = [('192.0.2.1', 5353)]
+ self.assertEqual(expected_sent_addrs, sent_addrs)
+ self.assertEqual(('192.0.2.1', 5353), example_net_info._notify_current)
+
+ # response's QID doesn't match. the request will be resent.
+ example_net_info._sock.remote_end().send(
+ get_notify_msgdata(Name('example.net'), qid=1))
+ self._notify._zone_notify_handler(example_net_info,
+ notify_out._EVENT_READ)
+ self.assertEqual(2, example_net_info.notify_try_num)
+ expected_sent_addrs.append(('192.0.2.1', 5353))
+ self.assertEqual(expected_sent_addrs, sent_addrs)
+ self.assertEqual(('192.0.2.1', 5353), example_net_info._notify_current)
+
+ # emulate exception from socket.recvfrom(). It will have the same
+ # effect as a bad response.
+ example_net_info._sock.set_raise_on_recv(True)
+ example_net_info._sock.remote_end().send(
+ get_notify_msgdata(Name('example.net')))
+ self._notify._zone_notify_handler(example_net_info,
+ notify_out._EVENT_READ)
+ self.assertEqual(3, example_net_info.notify_try_num)
+ expected_sent_addrs.append(('192.0.2.1', 5353))
+ self.assertEqual(expected_sent_addrs, sent_addrs)
+ self.assertEqual(('192.0.2.1', 5353), example_net_info._notify_current)
def test_get_notify_slaves_from_ns(self):
records = self._notify._get_notify_slaves_from_ns(Name('example.net.'),
diff --git a/tests/lettuce/features/xfrin_notify_handling.feature b/tests/lettuce/features/xfrin_notify_handling.feature
index a17ce42..c14254f 100644
--- a/tests/lettuce/features/xfrin_notify_handling.feature
+++ b/tests/lettuce/features/xfrin_notify_handling.feature
@@ -81,8 +81,8 @@ Feature: Xfrin incoming notify handling
last bindctl output should not contain "error"
Then the statistics counter notifyoutv4 for the zone _SERVER_ should be 0
Then the statistics counter notifyoutv4 for the zone example.org. should be 0
- Then the statistics counter notifyoutv6 for the zone _SERVER_ should be 5
- Then the statistics counter notifyoutv6 for the zone example.org. should be 5
+ Then the statistics counter notifyoutv6 for the zone _SERVER_ should be 1
+ Then the statistics counter notifyoutv6 for the zone example.org. should be 1
Then the statistics counter xfrrej for the zone _SERVER_ should be 0
Then the statistics counter xfrrej for the zone example.org. should be 0
Then the statistics counter xfrreqdone for the zone _SERVER_ should be 1
@@ -184,8 +184,8 @@ Feature: Xfrin incoming notify handling
last bindctl output should not contain "error"
Then the statistics counter notifyoutv4 for the zone _SERVER_ should be 0
Then the statistics counter notifyoutv4 for the zone example.org. should be 0
- Then the statistics counter notifyoutv6 for the zone _SERVER_ should be 5
- Then the statistics counter notifyoutv6 for the zone example.org. should be 5
+ Then the statistics counter notifyoutv6 for the zone _SERVER_ should be 1
+ Then the statistics counter notifyoutv6 for the zone example.org. should be 1
# The counts of rejection would be between 1 and 2. They are not
# fixed. It would depend on timing or the platform.
Then the statistics counter xfrrej for the zone _SERVER_ should be greater than 0
More information about the bind10-changes
mailing list