Merge "Modernized mdns tests"
This commit is contained in:
+84
-73
@@ -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())
|
||||
@@ -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
|
||||
)
|
||||
+28
-33
@@ -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)
|
||||
Reference in New Issue
Block a user