TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
+def get_notify_msgdata(zone_name, qid=0):
+ 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
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)
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):
self._notify.send_notify('example.net.')
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)
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.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.assertNotEqual(cur_tgt, example_net_info._notify_current)
+ 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.'),