Refactor NSD4 UT for using upstream eventlet

This patch refactor NSD4 UT by mocking out instead of using eventlet
for fake NSD4 backend.

This patch also remove pinned eventlet version and use upper constraint
of eventlet for UT.

Closes-Bug: 1686601
Change-Id: Iabc7fe6a1f6932959f4531a333bcbd1ad6f06e4f
This commit is contained in:
Hieu LE 2017-04-27 12:53:50 +07:00
parent 7f4a9a65ea
commit cbdec03b82
9 changed files with 74 additions and 180 deletions

View File

@ -55,6 +55,10 @@ cfg.CONF.import_opt('cache_driver', 'designate.pool_manager',
cfg.CONF.import_opt('connection',
'designate.pool_manager.cache.impl_sqlalchemy',
group='pool_manager_cache:sqlalchemy')
cfg.CONF.import_opt('emitter_type', 'designate.service_status',
group="heartbeat_emitter")
cfg.CONF.import_opt('scheduler_filters', 'designate.scheduler',
group="service:central")
default_pool_id = cfg.CONF['service:central'].default_pool_id
_TRUE_VALUES = ('true', '1', 'yes', 'y')

View File

@ -1,21 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIDfQIBAAKBwQClNN7DMvEDNh9g6KCpmBCT/liwH1CyUjwG2fEjrRaRkWztjmrK
Rfjt8xYukze1OFlaiVmOFaW0Mg5dJ8VWpusah8DzhL5sjg547ZbSfZhe/yA26hA/
7P2MBd9Zv9w32ErYQkJzyvgKBmivU1lyGIoVEf4jDr5rGZgz9mh5hiFPfyvnV2NW
3gk22JhEltP1XB6ERzKCMlpUAL62wErOiMUJX8YBMNoZ3jgYcjGFJENqYr6BkLz5
w5PJCGz1lN656yECAwEAAQKBwD9B3UIU0WAPazhqGoqVpVNlgoP9maKOBloBPWoR
rqCSdIkJjS5iWIyUFZxD1oLXTq9yBA55j3dN614UCmXBiCgibulPnLJoOnZnUubK
HHvTaHxeZ1Zy4iqpXPo6kpH3iSNbw1UtYJXYn9xy8lZdeMoNxMkRYSVesluIPVaA
69ro33kYUSFLRR8YQMOiHSGkOGkLu4U+7nrkbkbQjoaTv5qZquHFCnLlBpM7adYM
981fDP1dgie5qk4ND1c5nQ4AAQJhANcGNlu3yJdeK+jfpKcuHCO2+j40p9hBoZFd
oCCBjw7Q9vn4RTnVjMSGYTdBhCnLoeIuCeHySOKVf0UMOGRoOkMOUVC3U0IaOGMM
GEFDMFEEGrUbEB1n62Oq9dKMOYy3IQJhAMSwVsKuEa/6I6CdtWQv6UkVfh8aAm2M
Slj0jDYv0pX/5ciBRTsAYbwliIYHtdBoFns/vEuCxO66A1LIr5w8GuZhEdIe2jDf
Q1fErWs6mxAouw3eFW93sQzClxsbiSq0AQJgZR2rxFfZwazsUzeQc3nQi88JQOV8
JMtAUl7H5WFnx9zmt8hTrY3KA8T5xIVPxGPZPcbOqO1J7xvEXNERV85Xz57VCHMd
eRFhgNp4MYCKIR8f/Bi87EcpP5ZuwVNl4NFhAmEAh8nqC/tasLAzeoaGnUVKfC8/
ZD9zn6e0CFfEmQBJFU+WludQIVyxHNCYwVd/WQMTSkGFQGhmhx2af8OXIXiJZbVs
NTEhl437kxNwWlAaj3xfL0K8b7klXVbWNVu8ReQBAmEAj2o92RFlyTLbvfeXsGAs
Q5UTFDIzAS9MVMEp65HD8w6dZ02ruBre0KsIJs/6aEeGORH88IUrEKPPb0C12a0e
kftUBf5JemuDKFV/L5CGpaQyFA4HSjhzlSF5QahRU3oF
-----END RSA PRIVATE KEY-----

View File

@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICGzCCAUQCCQDPu3EY2nVlnDANBgkqhkiG9w0BAQsFADAOMQwwCgYDVQQDEwNu
c2QwHhcNMTMxMTE1MTkwMjA1WhcNMzMwODAyMTkwMjA1WjAWMRQwEgYDVQQDEwtu
c2QtY29udHJvbDCB3zANBgkqhkiG9w0BAQEFAAOBzQAwgckCgcEApTTewzLxAzYf
YOigqZgQk/5YsB9QslI8BtnxI60WkZFs7Y5qykX47fMWLpM3tThZWolZjhWltDIO
XSfFVqbrGofA84S+bI4OeO2W0n2YXv8gNuoQP+z9jAXfWb/cN9hK2EJCc8r4CgZo
r1NZchiKFRH+Iw6+axmYM/ZoeYYhT38r51djVt4JNtiYRJbT9VwehEcygjJaVAC+
tsBKzojFCV/GATDaGd44GHIxhSRDamK+gZC8+cOTyQhs9ZTeueshAgMBAAEwDQYJ
KoZIhvcNAQELBQADgcEAtuHD0nCV7atGnipcukBpgydxwWDN7/4Mwcw1EAOQ8B2L
Z4ckFRKXzgtlkg98FgvEcELBUK6TqrpEhYs0ADfPogyFhcwozqmngFHXY21caHgL
FA56nebJysDH+AoyMEJHpEDqPZA/ZIwB7XsmPFs71USiqnihhfUGA01TxF1P853m
yd7iIx926gCHvzbReJBbnxdnzcjon4m13/O8y7sBGCRiw/orKUe4CW6ubAKfwpQF
qGDccgTl9x9R6EGRW5bx
-----END CERTIFICATE-----

View File

@ -1,21 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIDfQIBAAKBwQDIAkIPjr2dajz/LwViY9w7OgT4eR8FhL/KwTjh4oMHpUosMyJl
12nyp/3ylCjJLJAcTfsmDUhvQKw5o+0hUOv/FBfJ43hotdn1YLq0iD+UUhzhmavV
baMM0shPrRGYDf/mHkGDkS11qsXRrUlxWr1/qjUf6ss/CbnvwQtyL/76TAtNl5Zi
MQCqrGbXmA6NOgpH51W048FD6hg0KlXEAgKV2dm+wRMNSY0Wy7b3di21bhuvst2r
5MXFxqsXTWK65qcCAwEAAQKBwQCyo8mrKZvUSHpYlf/iJD0lLSoZX91ESZAgITqU
DoNnxcsc9UMI4UEA+ejIzGotXL8OeNwT3ZNPwtzQ0shOlH9koeapbKE0LRCSqKW5
72OSL1Eacu3WQAl8v5soBvWK8RyFQCThWG9KJexh7aGjEakeMrFBSOz7PcMAY71f
2sher/Yk71DqbB/GwuBZZ5VIr3IoDrhz35URJtvzDfJ1KdIwUbKb3b54Rn61qx/i
MQiqC1EA8EwqnUtNVObJKx5L7hkCYQDrSddKhAK02zHYCH8ah1mx6qjiKxWHRNiX
PnSo4Z58jGg3ygbOTRXh+EbwbGwhF1uqdD1EQ8+uHOqaS8Nmscr/quW0zGQFMDzu
55xmmXxBQmul+6TUmT1YErENSbsLB2UCYQDZnWaU/j30VoKDO4F8zbHe1O6Yinq5
P5gIbLJQi7RxIlQ/8YvYCqgCuSzr6nrqdH83vbsGWGqIvQExgrSELLQCwB8fqOGv
U6M0+0NeaQmyU4Q3AGF0CH4eGLkY8Pg4MxsCYF1dodbp54EI8hB93qIST59wNK/6
1MImqaPqnrRdQ1y9AqYQvv6iTCqtMMk63PWMpU1QbvdlyUWYJ+guZE2eA6XMlPZX
nOEKMUPEGKYGBe6HgtwMrW3HmTYXxLY3KcfImQJgIagObYzE2D1pAhL5++t0Txpv
rHf+cxg601K8YWi6B6VfkmQxVMCRK5qoL/Sb/hb2dhCKFHkoQO26eYXVlXu0e5hr
N+JOxWcSHuedi8SDE2mHUVpluCR4HP+F4S2jtk1xAmEAoii5Rghoh/MMzHdn2loE
pTZAy0mM+Iw5Cba3QXfGA1wrM/Kyg/nJm8LYZqiRzR8smOiM3TL7+qBtN2LA36Pb
n4ryn2L3f5dBOYYuESUpmy/HHsiuzZU3Ljt333tse9cg
-----END RSA PRIVATE KEY-----

View File

@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICEzCCATwCCQDmQwk4gt2rdDANBgkqhkiG9w0BAQsFADAOMQwwCgYDVQQDEwNu
c2QwHhcNMTMxMTE1MTkwMjA1WhcNMzMwODAyMTkwMjA1WjAOMQwwCgYDVQQDEwNu
c2Qwgd8wDQYJKoZIhvcNAQEBBQADgc0AMIHJAoHBAMgCQg+OvZ1qPP8vBWJj3Ds6
BPh5HwWEv8rBOOHigwelSiwzImXXafKn/fKUKMkskBxN+yYNSG9ArDmj7SFQ6/8U
F8njeGi12fVgurSIP5RSHOGZq9VtowzSyE+tEZgN/+YeQYORLXWqxdGtSXFavX+q
NR/qyz8Jue/BC3Iv/vpMC02XlmIxAKqsZteYDo06CkfnVbTjwUPqGDQqVcQCApXZ
2b7BEw1JjRbLtvd2LbVuG6+y3avkxcXGqxdNYrrmpwIDAQABMA0GCSqGSIb3DQEB
CwUAA4HBAFKKQBBSAZXQaHTdRl/MuBOzIqCkzOIk0igTOLBYdwGO/xx2moo77CgD
VsYS5gHl4w211d0B8IMQKWKcNfjiPJyAOCdMGS/8NAK3Bz1umLHQn/C8ScOB0Xzc
kwUdewVTNo+7kEu8HgkJhlkXgP/PKSseZ+R8VD3ozlFQS8uojmQjzMs5ne1zkph2
KiRTZ/JvM0Q7c3RTq24JasobOQ5Rih7tFhbqCOw0DaFhEggzNwzRgonPfdW3Ntgp
v2ZWOfkYNQ==
-----END CERTIFICATE-----

View File

@ -14,115 +14,90 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
import socket
import ssl
import eventlet
import fixtures
from mock import MagicMock
import mock
from designate import exceptions
from designate import objects
from designate.tests.test_backend import BackendTestCase
from designate.tests import resources
from designate.backend import impl_nsd4
class NSD4ServerStub(object):
recved_command = None
response = 'ok'
keyfile = os.path.join(resources.path, 'ssl', 'nsd_server.key')
certfile = os.path.join(resources.path, 'ssl', 'nsd_server.pem')
def handle(self, client_sock, client_addr):
stream = client_sock.makefile()
self.recved_command = stream.readline()
stream.write(self.response)
stream.flush()
def start(self):
self.port = 1025
while True:
try:
eventlet.spawn_n(eventlet.serve,
eventlet.wrap_ssl(
eventlet.listen(('127.0.0.1', self.port)),
keyfile=self.keyfile,
certfile=self.certfile,
server_side=True),
self.handle)
break
except socket.error:
self.port = self.port + 1
def stop(self):
eventlet.StopServe()
class NSD4Fixture(fixtures.Fixture):
def setUp(self):
super(NSD4Fixture, self).setUp()
self.server = NSD4ServerStub()
self.server.start()
self.addCleanup(self.tearDown)
def tearDown(self):
self.server.stop()
# NOTE: We'll only test the specifics to the nsd4 backend here.
# Rest is handled via scenarios
class NSD4BackendTestCase(BackendTestCase):
def setUp(self):
super(NSD4BackendTestCase, self).setUp()
self.server_fixture = NSD4Fixture()
self.useFixture(self.server_fixture)
keyfile = os.path.join(resources.path, 'ssl', 'nsd_control.key')
certfile = os.path.join(resources.path, 'ssl', 'nsd_control.pem')
# NOTE(hieulq): we mock out NSD4 back-end with random port
self.port = 6969
self.target = objects.PoolTarget.from_dict({
'id': '4588652b-50e7-46b9-b688-a9bad40a873e',
'type': 'nsd4',
'masters': [{'host': '192.0.2.1', 'port': 53},
{'host': '192.0.2.2', 'port': 35}],
'options': [
{'key': 'keyfile', 'value': keyfile},
{'key': 'certfile', 'value': certfile},
{'key': 'keyfile', 'value': mock.sentinel.key},
{'key': 'certfile', 'value': mock.sentinel.cert},
{'key': 'pattern', 'value': 'test-pattern'},
{'key': 'port', 'value': self.server_fixture.server.port}
{'key': 'port', 'value': self.port}
],
})
self.backend = impl_nsd4.NSD4Backend(self.target)
def test_create_zone(self):
@mock.patch.object(eventlet, 'connect')
@mock.patch.object(eventlet, 'wrap_ssl')
def _test_command(self, mock_ssl, mock_connect, command_context):
sock = mock.MagicMock()
stream = mock.MagicMock()
mock_connect.return_value = mock.sentinel.client
mock_ssl.return_value = sock
sock.makefile.return_value = stream
if command_context is 'create_fail':
stream.read.return_value = 'goat'
else:
stream.read.return_value = 'ok'
context = self.get_context()
zone = self.get_zone_fixture()
self.backend.create_zone(context, zone)
command = 'NSDCT1 addzone %s test-pattern\n' % zone['name']
self.assertEqual(command, self.server_fixture.server.recved_command)
if command_context is 'create':
self.backend.create_zone(context, zone)
command = 'NSDCT1 addzone %s test-pattern\n' % zone['name']
elif command_context is 'delete':
self.backend.delete_zone(context, zone)
command = 'NSDCT1 delzone %s\n' % zone['name']
elif command_context is 'create_fail':
self.assertRaises(exceptions.Backend,
self.backend.create_zone,
context, zone)
command = 'NSDCT1 addzone %s test-pattern\n' % zone['name']
stream.write.assert_called_once_with(command)
mock_ssl.assert_called_once_with(mock.sentinel.client,
certfile=mock.sentinel.cert,
keyfile=mock.sentinel.key)
mock_connect.assert_called_once_with(('127.0.0.1', self.port))
sock.makefile.assert_called_once_with()
sock.close.assert_called_once_with()
stream.close.assert_called_once_with()
stream.flush.assert_called_once_with()
stream.read.assert_called_once_with()
def test_create_zone(self):
self._test_command(command_context='create')
def test_delete_zone(self):
context = self.get_context()
zone = self.get_zone_fixture()
self.backend.delete_zone(context, zone)
command = 'NSDCT1 delzone %s\n' % zone['name']
self.assertEqual(command, self.server_fixture.server.recved_command)
self._test_command(command_context='delete')
def test_server_not_ok(self):
self.server_fixture.server.response = 'goat'
context = self.get_context()
zone = self.get_zone_fixture()
self.assertRaises(exceptions.Backend,
self.backend.create_zone,
context, zone)
self._test_command(command_context='create_fail')
def test_ssl_error(self):
self.backend._command = MagicMock(side_effect=ssl.SSLError)
self.backend._command = mock.MagicMock(side_effect=ssl.SSLError)
context = self.get_context()
zone = self.get_zone_fixture()
self.assertRaises(exceptions.Backend,
@ -130,7 +105,7 @@ class NSD4BackendTestCase(BackendTestCase):
context, zone)
def test_socket_error(self):
self.backend._command = MagicMock(side_effect=socket.error)
self.backend._command = mock.MagicMock(side_effect=socket.error)
context = self.get_context()
zone = self.get_zone_fixture()
self.assertRaises(exceptions.Backend,

View File

@ -20,3 +20,23 @@ designate.tests.unit.test_central.test_basic
designate.tests.unit.test_pool
designate.tests.unit.test_producer.test_tasks
# Eventlet 0.20.1 in upper-constraint remove variable EVENTLET_GREEN_DNS
# and cause below tests failure.
# https://github.com/eventlet/eventlet/issues/390
# We should blacklist theses tests until openstack upper-constraint upgrade
# eventlet to 0.21.0.
designate.tests.test_agent.test_backends.test_denominator.DenominatorAgentBackendTestCase.test_create_zone
designate.tests.test_agent.test_backends.test_denominator.DenominatorAgentBackendTestCase.test_update_zone
designate.tests.test_agent.test_backends.test_gdnsd.GdnsdAgentBackendTestCase.test_create_zone
designate.tests.test_agent.test_backends.test_gdnsd.GdnsdAgentBackendTestCase.test_update_zone
designate.tests.test_agent.test_handler.AgentRequestHandlerTest.test_transfer_source
designate.tests.test_api.test_v2.test_import_export.APIV2ZoneImportExportTest.test_import_export
designate.tests.unit.test_agent.test_backends.test_djbdns.DjbdnsAgentBackendUnitTestCase.test_create_zone
designate.tests.unit.test_agent.test_backends.test_djbdns.DjbdnsAgentBackendUnitTestCase.test_update_zone
designate.tests.unit.test_agent.test_backends.test_knot2.Knot2AgentBackendUnitTestCase.test_create_zone
designate.tests.unit.test_agent.test_backends.test_knot2.Knot2AgentBackendUnitTestCase.test_create_zone_already_there
designate.tests.unit.test_agent.test_backends.test_knot2.Knot2AgentBackendUnitTestCase.test_update_zone
designate.tests.unit.test_agent.test_backends.test_msdns.MSDNSAgentBackendUnitTestCase.test_create_zone
designate.tests.unit.test_agent.test_backends.test_msdns.MSDNSAgentBackendUnitTestCase.test_create_zone_already_existing_diff
designate.tests.unit.test_agent.test_backends.test_msdns.MSDNSAgentBackendUnitTestCase.test_create_zone_already_existing_identical
designate.tests.unit.test_agent.test_backends.test_msdns.MSDNSAgentBackendUnitTestCase.test_update_zone

View File

@ -1,32 +0,0 @@
#!/usr/bin/env bash
# Client constraint file contains this client version pin that is in conflict
# with installing the client from source. We should remove the version pin in
# the constraints file before applying it for from-source installation.
CONSTRAINTS_FILE=$1
shift 1
set -e
# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
# published to logs.openstack.org for easy debugging.
localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
if [[ $CONSTRAINTS_FILE != http* ]]; then
CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE
fi
# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
curl $CONSTRAINTS_FILE --insecure --progress-bar --output $localfile
pip install -c$localfile openstack-requirements
# This is the main purpose of the script: Allow local installation of
# the current repo. It is listed in constraints file and thus any
# install will be constrained and we need to unconstrain it.
edit-constraints $localfile -- $CLIENT_NAME
pip install -c$localfile -U $*
# NOTE(hieulq): eventlet workaround, remove when fixed in upper constraint
pip install eventlet===0.19.0
exit $?

View File

@ -5,13 +5,10 @@ skipsdist = True
[testenv]
usedevelop = True
install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=master} {opts} {packages}
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=master} {opts} {packages}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
setenv =
VIRTUAL_ENV={envdir}
BRANCH_NAME=master
CLIENT_NAME=eventlet
PYTHONDONTWRITEBYTECODE=1
whitelist_externals = sh
find