Merge "Modernized mdns tests"

This commit is contained in:
Zuul
2019-06-09 07:50:17 +00:00
committed by Gerrit Code Review
5 changed files with 419 additions and 380 deletions
@@ -13,104 +13,102 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import unittest
from mock import Mock
from oslo_log import log as logging
import dns
import mock
import oslotest.base
from designate import exceptions
from designate import objects
from designate.mdns import handler
LOG = logging.getLogger(__name__)
class TestRequestHandlerCall(unittest.TestCase):
"""
Unit test to assert the dispatching based on the request
operation.
"""
class TestRequestHandlerCall(oslotest.base.BaseTestCase):
def setUp(self):
self.storage = Mock()
self.tg = Mock()
self.handler = handler.RequestHandler(self.storage, self.tg)
super(TestRequestHandlerCall, self).setUp()
self.handler = handler.RequestHandler(mock.Mock(), mock.Mock())
self.handler._central_api = mock.Mock(name='central_api')
# Use a simple handlers that doesn't require a real request
self.handler._handle_query_error = Mock(return_value='Error')
self.handler._handle_axfr = Mock(return_value=['AXFR'])
self.handler._handle_record_query = Mock(return_value=['Record Query'])
self.handler._handle_notify = Mock(return_value=['Notify'])
def assert_error(self, request, error_type):
self.handler._handle_query_error.assert_called_with(
request, error_type
)
self.handler._handle_query_error = mock.Mock(return_value='Error')
self.handler._handle_axfr = mock.Mock(return_value=['AXFR'])
self.handler._handle_record_query = mock.Mock(
return_value=['Record Query'])
self.handler._handle_notify = mock.Mock(return_value=['Notify'])
def test_central_api_property(self):
self.handler._central_api = 'foo'
assert self.handler.central_api == 'foo'
self.assertEqual(self.handler.central_api, 'foo')
def test___call___unhandled_opcodes(self):
def test__call___unhandled_opcodes(self):
unhandled_codes = [
dns.opcode.STATUS,
dns.opcode.IQUERY,
dns.opcode.UPDATE,
]
request = Mock()
request = mock.Mock()
for code in unhandled_codes:
request.opcode.return_value = code # return an error
assert list(self.handler(request)) == ['Error']
self.assert_error(request, dns.rcode.REFUSED)
def test___call__query_error_with_more_than_one_question(self):
request = Mock()
self.assertEqual(['Error'], list(self.handler(request)))
self.handler._handle_query_error.assert_called_with(
request, dns.rcode.REFUSED
)
def test__call__query_error_with_more_than_one_question(self):
request = mock.Mock()
request.opcode.return_value = dns.opcode.QUERY
request.question = [Mock(), Mock()]
request.question = [mock.Mock(), mock.Mock()]
assert list(self.handler(request)) == ['Error']
self.assert_error(request, dns.rcode.REFUSED)
self.assertEqual(['Error'], list(self.handler(request)))
self.handler._handle_query_error.assert_called_with(
request, dns.rcode.REFUSED
)
def test___call__query_error_with_data_claas_not_in(self):
request = Mock()
def test__call__query_error_with_data_claas_not_in(self):
request = mock.Mock()
request.opcode.return_value = dns.opcode.QUERY
request.question = [Mock(rdclass=dns.rdataclass.ANY)]
assert list(self.handler(request)) == ['Error']
self.assert_error(request, dns.rcode.REFUSED)
request.question = [mock.Mock(rdclass=dns.rdataclass.ANY)]
def test___call__axfr(self):
request = Mock()
self.assertEqual(['Error'], list(self.handler(request)))
self.handler._handle_query_error.assert_called_with(
request, dns.rcode.REFUSED
)
def test__call__axfr(self):
request = mock.Mock()
request.opcode.return_value = dns.opcode.QUERY
request.question = [
Mock(rdclass=dns.rdataclass.IN, rdtype=dns.rdatatype.AXFR)
mock.Mock(rdclass=dns.rdataclass.IN, rdtype=dns.rdatatype.AXFR)
]
assert list(self.handler(request)) == ['AXFR']
def test___call__ixfr(self):
request = Mock()
self.assertEqual(['AXFR'], list(self.handler(request)))
def test__call__ixfr(self):
request = mock.Mock()
request.opcode.return_value = dns.opcode.QUERY
request.question = [
Mock(rdclass=dns.rdataclass.IN, rdtype=dns.rdatatype.IXFR)
mock.Mock(rdclass=dns.rdataclass.IN, rdtype=dns.rdatatype.IXFR)
]
assert list(self.handler(request)) == ['AXFR']
def test___call__record_query(self):
request = Mock()
self.assertEqual(['AXFR'], list(self.handler(request)))
def test__call__record_query(self):
request = mock.Mock()
request.opcode.return_value = dns.opcode.QUERY
request.question = [
Mock(rdclass=dns.rdataclass.IN, rdtype=dns.rdatatype.A)
mock.Mock(rdclass=dns.rdataclass.IN, rdtype=dns.rdatatype.A)
]
assert list(self.handler(request)) == ['Record Query']
def test___call__notify(self):
request = Mock()
self.assertEqual(['Record Query'], list(self.handler(request)))
def test__call__notify(self):
request = mock.Mock()
request.opcode.return_value = dns.opcode.NOTIFY
assert list(self.handler(request)) == ['Notify']
def test__convert_to_rrset_no_records(self):
self.assertEqual(['Notify'], list(self.handler(request)))
def test_convert_to_rrset_no_records(self):
zone = objects.Zone.from_dict({'ttl': 1234})
recordset = objects.RecordSet(
name='www.example.org.',
@@ -120,9 +118,10 @@ class TestRequestHandlerCall(unittest.TestCase):
)
r_rrset = self.handler._convert_to_rrset(zone, recordset)
self.assertIsNone(r_rrset)
def test__convert_to_rrset(self):
def test_convert_to_rrset(self):
zone = objects.Zone.from_dict({'ttl': 1234})
recordset = objects.RecordSet(
name='www.example.org.',
@@ -134,17 +133,19 @@ class TestRequestHandlerCall(unittest.TestCase):
)
r_rrset = self.handler._convert_to_rrset(zone, recordset)
self.assertEqual(2, len(r_rrset))
class HandleRecordQueryTest(unittest.TestCase):
class HandleRecordQueryTest(oslotest.base.BaseTestCase):
def setUp(self):
self.storage = Mock()
self.tg = Mock()
self.handler = handler.RequestHandler(self.storage, self.tg)
super(HandleRecordQueryTest, self).setUp()
self.context = mock.Mock()
self.storage = mock.Mock()
self.handler = handler.RequestHandler(self.storage, mock.Mock())
def test__handle_record_query_empty_recordlist(self):
def test_handle_record_query_empty_recordlist(self):
# bug #1550441
self.storage.find_recordset.return_value = objects.RecordSet(
name='www.example.org.',
@@ -152,15 +153,17 @@ class HandleRecordQueryTest(unittest.TestCase):
records=objects.RecordList(objects=[
])
)
request = dns.message.make_query('www.example.org.', dns.rdatatype.A)
request.environ = dict(context='ctx')
request.environ = dict(context=self.context)
response_gen = self.handler._handle_record_query(request)
for r in response_gen:
for response in response_gen:
# This was raising an exception due to bug #1550441
out = r.to_wire(max_size=65535)
out = response.to_wire(max_size=65535)
self.assertEqual(33, len(out))
def test__handle_record_query_zone_not_found(self):
def test_handle_record_query_zone_not_found(self):
self.storage.find_recordset.return_value = objects.RecordSet(
name='www.example.org.',
type='A',
@@ -169,13 +172,15 @@ class HandleRecordQueryTest(unittest.TestCase):
])
)
self.storage.find_zone.side_effect = exceptions.ZoneNotFound
request = dns.message.make_query('www.example.org.', dns.rdatatype.A)
request.environ = dict(context='ctx')
request.environ = dict(context=self.context)
response = tuple(self.handler._handle_record_query(request))
self.assertEqual(1, len(response))
self.assertEqual(dns.rcode.REFUSED, response[0].rcode())
def test__handle_record_query_forbidden(self):
def test_handle_record_query_forbidden(self):
self.storage.find_recordset.return_value = objects.RecordSet(
name='www.example.org.',
type='A',
@@ -184,24 +189,30 @@ class HandleRecordQueryTest(unittest.TestCase):
])
)
self.storage.find_zone.side_effect = exceptions.Forbidden
request = dns.message.make_query('www.example.org.', dns.rdatatype.A)
request.environ = dict(context='ctx')
request.environ = dict(context=self.context)
response = tuple(self.handler._handle_record_query(request))
self.assertEqual(1, len(response))
self.assertEqual(dns.rcode.REFUSED, response[0].rcode())
def test__handle_record_query_find_recordsed_forbidden(self):
def test_handle_record_query_find_recordsed_forbidden(self):
self.storage.find_recordset.side_effect = exceptions.Forbidden
request = dns.message.make_query('www.example.org.', dns.rdatatype.A)
request.environ = dict(context='ctx')
request.environ = dict(context=self.context)
response = tuple(self.handler._handle_record_query(request))
self.assertEqual(1, len(response))
self.assertEqual(dns.rcode.REFUSED, response[0].rcode())
def test__handle_record_query_find_recordsed_not_found(self):
def test_handle_record_query_find_recordsed_not_found(self):
self.storage.find_recordset.side_effect = exceptions.NotFound
request = dns.message.make_query('www.example.org.', dns.rdatatype.A)
request.environ = dict(context='ctx')
request.environ = dict(context=self.context)
response = tuple(self.handler._handle_record_query(request))
self.assertEqual(1, len(response))
self.assertEqual(dns.rcode.REFUSED, response[0].rcode())
+307
View File
@@ -0,0 +1,307 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Federico Ceratto <federico.ceratto@hpe.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import socket
import dns
import dns.rdataclass
import dns.rdatatype
import mock
import designate.mdns.base as mdnsbase
import designate.mdns.notify as notify
import designate.tests
from designate.tests.unit import RoObject
class MdnsNotifyTest(designate.tests.TestCase):
def setUp(self):
super(MdnsNotifyTest, self).setUp()
self.notify = notify.NotifyEndpoint(mock.Mock())
@mock.patch('time.sleep')
def test_notify_zone_changed(self, mock_sleep):
self.notify._make_and_send_dns_message = mock.Mock()
self.notify.notify_zone_changed(*range(8))
self.notify._make_and_send_dns_message.assert_called_with(
1, 2, 3, 4, 5, 6, notify=True
)
@mock.patch.object(mdnsbase.pool_mngr_api.PoolManagerAPI, 'get_instance')
def test_poll_for_serial_number(self, mock_get_instance):
self.notify.get_serial_number = mock.Mock(
return_value=('status', 99, 9)
)
ns = RoObject(host='host', port=1234)
self.notify.poll_for_serial_number(
'c', 'z', ns, 1, 2, 3, 4
)
self.notify.get_serial_number.assert_called_with(
'c', 'z', 'host', 1234, 1, 2, 3, 4
)
self.notify.pool_manager_api.update_status.assert_called_with(
'c', 'z', ns, 'status', 99
)
@mock.patch('time.sleep')
def test_get_serial_number_nxdomain(self, mock_sleep):
# The zone is not found but it was supposed to be there
response = RoObject(
answer=[RoObject(
rdclass=dns.rdataclass.IN,
rdtype=dns.rdatatype.SOA
)],
rcode=mock.Mock(return_value=dns.rcode.NXDOMAIN)
)
zone = RoObject(name='zn', serial=314)
self.notify._make_and_send_dns_message = mock.Mock(
return_value=(response, 1)
)
out = self.notify.get_serial_number(
'c', zone, 'h', 1234, 1, 2, 3, 4
)
self.assertEqual(('NO_ZONE', None, 0), out)
@mock.patch('time.sleep')
def test_get_serial_number_nxdomain_deleted_zone(self, mock_sleep):
# The zone is not found and it's not was supposed be there
response = RoObject(
answer=[RoObject(
rdclass=dns.rdataclass.IN,
rdtype=dns.rdatatype.SOA
)],
rcode=mock.Mock(return_value=dns.rcode.NXDOMAIN)
)
zone = RoObject(name='zn', serial=0, action='DELETE')
self.notify._make_and_send_dns_message = mock.Mock(
return_value=(response, 1)
)
out = self.notify.get_serial_number(
'c', zone, 'h', 1234, 1, 2, 3, 4
)
self.assertEqual(('NO_ZONE', 0, 3), out)
@mock.patch('time.sleep')
def test_get_serial_number_ok(self, mock_sleep):
zone = RoObject(name='zn', serial=314)
ds = RoObject(items=[zone])
response = RoObject(
answer=[RoObject(
name='zn',
rdclass=dns.rdataclass.IN,
rdtype=dns.rdatatype.SOA,
to_rdataset=mock.Mock(return_value=ds)
)],
rcode=mock.Mock(return_value=dns.rcode.NOERROR)
)
self.notify._make_and_send_dns_message = mock.Mock(
return_value=(response, 1)
)
out = self.notify.get_serial_number(
'c', zone, 'h', 1234, 1, 2, 3, 4
)
self.assertEqual(('SUCCESS', 314, 3), out)
@mock.patch('time.sleep')
def test_get_serial_number_too_many_retries(self, mock_sleep):
zone = RoObject(name='zn', serial=314)
ds = RoObject(items=[RoObject(serial=310)])
response = RoObject(
answer=[RoObject(
name='zn',
rdclass=dns.rdataclass.IN,
rdtype=dns.rdatatype.SOA,
to_rdataset=mock.Mock(return_value=ds)
)],
rcode=mock.Mock(return_value=dns.rcode.NOERROR)
)
self.notify._make_and_send_dns_message = mock.Mock(
return_value=(response, 1)
)
out = self.notify.get_serial_number(
'c', zone, 'h', 1234, 1, 2, 3, 4
)
self.assertEqual(('ERROR', 310, 0), out)
@mock.patch('time.sleep')
def test_make_and_send_dns_message_timeout(self, mock_sleep):
zone = RoObject(name='zn')
self.notify._make_dns_message = mock.Mock(return_value='')
self.notify._send_dns_message = mock.Mock(
side_effect=dns.exception.Timeout
)
out = self.notify._make_and_send_dns_message(
zone, 'host', 123, 1, 2, 3
)
self.assertEqual((None, 3), out)
def test_make_and_send_dns_message_bad_response(self):
zone = RoObject(name='zn')
self.notify._make_dns_message = mock.Mock(return_value='')
self.notify._send_dns_message = mock.Mock(
side_effect=notify.dns_query.BadResponse
)
out = self.notify._make_and_send_dns_message(
zone, 'host', 123, 1, 2, 3
)
self.assertEqual((None, 1), out)
@mock.patch('time.sleep')
def test_make_and_send_dns_message_eagain(self, mock_sleep):
# bug #1558096
zone = RoObject(name='zn')
self.notify._make_dns_message = mock.Mock(return_value='')
socket_error = socket.error()
socket_error.errno = socket.errno.EAGAIN
self.notify._send_dns_message = mock.Mock(
side_effect=socket_error
)
out = self.notify._make_and_send_dns_message(
zone, 'host', 123, 1, 2, 3
)
self.assertEqual((None, 3), out)
def test_make_and_send_dns_message_econnrefused(self):
# bug #1558096
zone = RoObject(name='zn')
self.notify._make_dns_message = mock.Mock(return_value='')
socket_error = socket.error()
socket_error.errno = socket.errno.ECONNREFUSED
# socket errors other than EAGAIN should raise
self.notify._send_dns_message = mock.Mock(
side_effect=socket_error)
self.assertRaises(
socket.error,
self.notify._make_and_send_dns_message,
zone, 'host', 123, 1, 2, 3
)
def test_make_and_send_dns_message_nxdomain(self):
zone = RoObject(name='zn')
self.notify._make_dns_message = mock.Mock(return_value='')
response = RoObject(rcode=mock.Mock(return_value=dns.rcode.NXDOMAIN))
self.notify._send_dns_message = mock.Mock(return_value=response)
out = self.notify._make_and_send_dns_message(
zone, 'host', 123, 1, 2, 3
)
self.assertEqual((response, 1), out)
def test_make_and_send_dns_message_missing_AA_flags(self):
zone = RoObject(name='zn')
self.notify._make_dns_message = mock.Mock(return_value='')
response = RoObject(
rcode=mock.Mock(return_value=dns.rcode.NOERROR),
# rcode is NOERROR but (flags & dns.flags.AA) gives 0
flags=0,
answer=['answer'],
)
self.notify._send_dns_message = mock.Mock(return_value=response)
out = self.notify._make_and_send_dns_message(
zone, 'host', 123, 1, 2, 3
)
self.assertEqual((None, 1), out)
def test_make_and_send_dns_message_error_flags(self):
zone = RoObject(name='zn')
self.notify._make_dns_message = mock.Mock(return_value='')
response = RoObject(
rcode=mock.Mock(return_value=dns.rcode.NOERROR),
# rcode is NOERROR but flags are not NOERROR
flags=123,
ednsflags=321,
answer=['answer'],
)
self.notify._send_dns_message = mock.Mock(return_value=response)
out = self.notify._make_and_send_dns_message(
zone, 'host', 123, 1, 2, 3
)
self.assertEqual((None, 1), out)
def test_make_dns_message(self):
msg = self.notify._make_dns_message('zone_name')
txt = msg.to_text().split('\n')[1:]
self.assertEqual([
'opcode QUERY',
'rcode NOERROR',
'flags RD',
';QUESTION',
'zone_name. IN SOA',
';ANSWER',
';AUTHORITY',
';ADDITIONAL'
], txt)
def test_make_dns_message_notify(self):
msg = self.notify._make_dns_message('zone_name', notify=True)
txt = msg.to_text().split('\n')[1:]
self.assertEqual([
'opcode NOTIFY',
'rcode NOERROR',
'flags AA',
';QUESTION',
'zone_name. IN SOA',
';ANSWER',
';AUTHORITY',
';ADDITIONAL',
], txt)
@mock.patch.object(notify.dns_query, 'udp')
def test_send_udp_dns_message(self, mock_udp):
self.CONF.set_override('all_tcp', False, 'service:mdns')
self.notify._send_dns_message('msg', '192.0.2.1', 1234, 1)
mock_udp.assert_called_with(
'msg', '192.0.2.1', port=1234, timeout=1
)
@mock.patch.object(notify.dns_query, 'tcp')
def test_send_tcp_dns_message(self, mock_tcp):
self.CONF.set_override('all_tcp', True, 'service:mdns')
self.notify._send_dns_message('msg', '192.0.2.1', 1234, 1)
mock_tcp.assert_called_with(
'msg', '192.0.2.1', port=1234, timeout=1
)
@@ -13,65 +13,60 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Unit-test MiniDNS service
"""
from oslotest import base
import mock
import oslotest.base
import designate.dnsutils
import designate.rpc
import designate.mdns.service as mdns
import designate.storage.base as storage
import designate.service
import designate.storage.base
import designate.utils
from designate.mdns import handler
from designate.mdns import service
class MdnsServiceTest(base.BaseTestCase):
@mock.patch.object(mdns.service.DNSService, '_start')
class MdnsServiceTest(oslotest.base.BaseTestCase):
@mock.patch.object(designate.rpc, 'get_server')
def test_service_start(self, mock_service_start, mock_rpc_server):
self.mdns = mdns.Service()
self.mdns.start()
def setUp(self, mock_rpc_server):
super(MdnsServiceTest, self).setUp()
self.service = service.Service()
@mock.patch.object(designate.service.DNSService, '_start')
def test_service_start(self, mock_service_start):
self.service.start()
self.assertTrue(mock_service_start.called)
self.assertTrue(mock_rpc_server.called)
def test_service_name(self):
self.mdns = mdns.Service()
self.assertEqual('mdns', self.mdns.service_name)
self.assertEqual('mdns', self.service.service_name)
def test_rpc_endpoints(self):
self.mdns = mdns.Service()
endpoints = self.service._rpc_endpoints
endpoints = self.mdns._rpc_endpoints
self.assertIsInstance(endpoints[0], service.notify.NotifyEndpoint)
self.assertIsInstance(endpoints[1], service.xfr.XfrEndpoint)
self.assertIsInstance(endpoints[0], mdns.notify.NotifyEndpoint)
self.assertIsInstance(endpoints[1], mdns.xfr.XfrEndpoint)
@mock.patch.object(storage.Storage, 'get_driver')
@mock.patch.object(designate.storage.base.Storage, 'get_driver')
def test_storage_driver(self, mock_get_driver):
mock_driver = mock.MagicMock()
mock_driver.name = 'noop_driver'
mock_get_driver.return_value = mock_driver
self.mdns = mdns.Service()
self.assertIsInstance(self.mdns.storage, mock.MagicMock)
self.assertIsInstance(self.service.storage, mock.MagicMock)
self.assertTrue(mock_get_driver.called)
@mock.patch.object(mdns.handler, 'RequestHandler', name='reqh')
@mock.patch.object(mdns.service.DNSService, '_start')
@mock.patch.object(mdns.utils, 'cache_result')
@mock.patch.object(storage.Storage, 'get_driver')
@mock.patch.object(handler, 'RequestHandler', name='reqh')
@mock.patch.object(designate.service.DNSService, '_start')
@mock.patch.object(designate.utils, 'cache_result')
@mock.patch.object(designate.storage.base.Storage, 'get_driver')
def test_dns_application(self, mock_req_handler, mock_cache_result,
mock_service_start, mock_get_driver):
mock_driver = mock.MagicMock()
mock_driver.name = 'noop_driver'
mock_get_driver.return_value = mock_driver
self.mdns = mdns.Service()
app = self.service._dns_application
app = self.mdns._dns_application
self.assertIsInstance(app, mdns.dnsutils.DNSMiddleware)
self.assertIsInstance(app, designate.dnsutils.DNSMiddleware)
@@ -1,274 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Federico Ceratto <federico.ceratto@hpe.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Unit-test MiniDNS service
"""
import socket
from mock import Mock
from oslotest import base
import dns
import dns.rdataclass
import dns.rdatatype
import mock
from designate.tests.unit import RoObject
import designate.mdns.notify as notify
import designate.mdns.base as mdnsbase
@mock.patch.object(notify.time, 'sleep')
@mock.patch.object(mdnsbase.pool_mngr_api.PoolManagerAPI, 'get_instance')
class MdnsNotifyTest(base.BaseTestCase):
@mock.patch.object(mdnsbase.central_api.CentralAPI, 'get_instance')
def setUp(self, *mocks):
super(MdnsNotifyTest, self).setUp()
notify.CONF = RoObject({
'service:mdns': RoObject(all_tcp=False)
})
self.tg = Mock(name='tg')
self.notify = notify.NotifyEndpoint(self.tg)
def test_notify_zone_changed(self, *mocks):
self.notify._make_and_send_dns_message = Mock()
self.notify.notify_zone_changed(*range(8))
self.notify._make_and_send_dns_message.assert_called_with(
1, 2, 3, 4, 5, 6, notify=True)
def test_poll_for_serial_number(self, *mocks):
self.notify.get_serial_number = Mock(
return_value=('status', 99, 9)
)
ns = RoObject(host='host', port=1234)
self.notify.poll_for_serial_number('c', 'z', ns, 1, 2, 3, 4)
self.notify.get_serial_number.assert_called_with(
'c', 'z', 'host', 1234, 1, 2, 3, 4)
self.notify.pool_manager_api.update_status.assert_called_with(
'c', 'z', ns, 'status', 99)
def test_get_serial_number_nxdomain(self, *mocks):
# The zone is not found but it was supposed to be there
response = RoObject(
answer=[RoObject(
rdclass=dns.rdataclass.IN,
rdtype=dns.rdatatype.SOA
)],
rcode=Mock(return_value=dns.rcode.NXDOMAIN)
)
zone = RoObject(name='zn', serial=314)
self.notify._make_and_send_dns_message = Mock(
return_value=(response, 1)
)
out = self.notify.get_serial_number('c', zone, 'h', 1234, 1, 2, 3, 4)
self.assertEqual(('NO_ZONE', None, 0), out)
def test_get_serial_number_nxdomain_deleted_zone(self, *mocks):
# The zone is not found and it's not was supposed be there
response = RoObject(
answer=[RoObject(
rdclass=dns.rdataclass.IN,
rdtype=dns.rdatatype.SOA
)],
rcode=Mock(return_value=dns.rcode.NXDOMAIN)
)
zone = RoObject(name='zn', serial=0, action='DELETE')
self.notify._make_and_send_dns_message = Mock(
return_value=(response, 1)
)
out = self.notify.get_serial_number('c', zone, 'h', 1234, 1, 2, 3, 4)
self.assertEqual(('NO_ZONE', 0, 3), out)
def test_get_serial_number_ok(self, *mocks):
zone = RoObject(name='zn', serial=314)
ds = RoObject(items=[zone])
response = RoObject(
answer=[RoObject(
name='zn',
rdclass=dns.rdataclass.IN,
rdtype=dns.rdatatype.SOA,
to_rdataset=Mock(return_value=ds)
)],
rcode=Mock(return_value=dns.rcode.NOERROR)
)
self.notify._make_and_send_dns_message = Mock(
return_value=(response, 1)
)
out = self.notify.get_serial_number('c', zone, 'h', 1234, 1, 2, 3, 4)
self.assertEqual(('SUCCESS', 314, 3), out)
def test_get_serial_number_too_many_retries(self, *mocks):
zone = RoObject(name='zn', serial=314)
ds = RoObject(items=[RoObject(serial=310)])
response = RoObject(
answer=[RoObject(
name='zn',
rdclass=dns.rdataclass.IN,
rdtype=dns.rdatatype.SOA,
to_rdataset=Mock(return_value=ds)
)],
rcode=Mock(return_value=dns.rcode.NOERROR)
)
self.notify._make_and_send_dns_message = Mock(
return_value=(response, 1)
)
out = self.notify.get_serial_number('c', zone, 'h', 1234, 1, 2, 3, 4)
self.assertEqual(('ERROR', 310, 0), out)
def test_make_and_send_dns_message_timeout(self, *mocks):
zone = RoObject(name='zn')
self.notify._make_dns_message = Mock(return_value='')
self.notify._send_dns_message = Mock(
side_effect=dns.exception.Timeout)
out = self.notify._make_and_send_dns_message(zone, 'host',
123, 1, 2, 3)
self.assertEqual((None, 3), out)
def test_make_and_send_dns_message_bad_response(self, *mocks):
zone = RoObject(name='zn')
self.notify._make_dns_message = Mock(return_value='')
self.notify._send_dns_message = Mock(
side_effect=notify.dns_query.BadResponse)
out = self.notify._make_and_send_dns_message(zone, 'host',
123, 1, 2, 3)
self.assertEqual((None, 1), out)
def test_make_and_send_dns_message_eagain(self, *mocks):
# bug #1558096
zone = RoObject(name='zn')
self.notify._make_dns_message = Mock(return_value='')
socket_error = socket.error()
socket_error.errno = socket.errno.EAGAIN
self.notify._send_dns_message = Mock(
side_effect=socket_error)
out = self.notify._make_and_send_dns_message(zone, 'host',
123, 1, 2, 3)
self.assertEqual((None, 3), out)
def test_make_and_send_dns_message_econnrefused(self, *mocks):
# bug #1558096
zone = RoObject(name='zn')
self.notify._make_dns_message = Mock(return_value='')
socket_error = socket.error()
socket_error.errno = socket.errno.ECONNREFUSED
# socket errors other than EAGAIN should raise
self.notify._send_dns_message = Mock(
side_effect=socket_error)
self.assertRaises(socket.error, self.notify._make_and_send_dns_message,
zone, 'host', 123, 1, 2, 3)
def test_make_and_send_dns_message_nxdomain(self, *mocks):
zone = RoObject(name='zn')
self.notify._make_dns_message = Mock(return_value='')
response = RoObject(rcode=Mock(return_value=dns.rcode.NXDOMAIN))
self.notify._send_dns_message = Mock(return_value=response)
out = self.notify._make_and_send_dns_message(zone, 'host',
123, 1, 2, 3)
self.assertEqual((response, 1), out)
def test_make_and_send_dns_message_missing_AA_flags(self, *mocks):
zone = RoObject(name='zn')
self.notify._make_dns_message = Mock(return_value='')
response = RoObject(
rcode=Mock(return_value=dns.rcode.NOERROR),
# rcode is NOERROR but (flags & dns.flags.AA) gives 0
flags=0,
answer=['answer'],
)
self.notify._send_dns_message = Mock(return_value=response)
out = self.notify._make_and_send_dns_message(zone, 'host',
123, 1, 2, 3)
self.assertEqual((None, 1), out)
def test_make_and_send_dns_message_error_flags(self, *mocks):
zone = RoObject(name='zn')
self.notify._make_dns_message = Mock(return_value='')
response = RoObject(
rcode=Mock(return_value=dns.rcode.NOERROR),
# rcode is NOERROR but flags are not NOERROR
flags=123,
ednsflags=321,
answer=['answer'],
)
self.notify._send_dns_message = Mock(return_value=response)
out = self.notify._make_and_send_dns_message(zone, 'host',
123, 1, 2, 3)
self.assertEqual((None, 1), out)
def test_make_dns_message(self, *mocks):
msg = self.notify._make_dns_message('zone_name')
txt = msg.to_text().split('\n')[1:]
self.assertEqual([
'opcode QUERY',
'rcode NOERROR',
'flags RD',
';QUESTION',
'zone_name. IN SOA',
';ANSWER',
';AUTHORITY',
';ADDITIONAL'
], txt)
def test_make_dns_message_notify(self, *mocks):
msg = self.notify._make_dns_message('zone_name', notify=True)
txt = msg.to_text().split('\n')[1:]
self.assertEqual([
'opcode NOTIFY',
'rcode NOERROR',
'flags AA',
';QUESTION',
'zone_name. IN SOA',
';ANSWER',
';AUTHORITY',
';ADDITIONAL',
], txt)
@mock.patch.object(notify.dns_query, 'tcp')
@mock.patch.object(notify.dns_query, 'udp')
def test_send_dns_message(self, *mocks):
out = self.notify._send_dns_message('msg', '192.0.2.1', 1234, 1)
assert not notify.dns_query.tcp.called
notify.dns_query.udp.assert_called_with('msg', '192.0.2.1', port=1234,
timeout=1)
assert isinstance(out, Mock)