PowerDNS Backend Tests

Add unit tests for the PowerDNS create_domain and delete_domain
methods.

Change-Id: I306f333a6ce10a51b29787234041bc27b9934c97
Closes-Bug: 1411398
Closes-Bug: 1411400
This commit is contained in:
Kiall Mac Innes 2015-01-15 12:16:24 -08:00
parent ad3dd46384
commit 5e4ed06d70
3 changed files with 187 additions and 5 deletions

View File

@ -16,7 +16,6 @@
import copy
import threading
from oslo.config import cfg
from oslo_db import options
from oslo.utils import excutils
from sqlalchemy.sql import select
@ -29,7 +28,6 @@ from designate.backend.impl_powerdns import tables
from designate.sqlalchemy import session
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
def _map_col(keys, col):
@ -51,10 +49,11 @@ class PowerDNSBackend(base.PoolBackend):
return opts
def __init__(self, *args, **kwargs):
super(PowerDNSBackend, self).__init__(*args, **kwargs)
def __init__(self, backend_options):
super(PowerDNSBackend, self).__init__(backend_options)
self.local_store = threading.local()
self.masters = [m for m in self.get_backend_option('masters')]
@property
def session(self):
@ -118,7 +117,7 @@ class PowerDNSBackend(base.PoolBackend):
domain_values = {
'designate_id': domain['id'],
'name': domain['name'].rstrip('.'),
'master': ','.join(CONF['backend:powerdns'].masters),
'master': ','.join(self.masters),
'type': 'SLAVE',
'account': context.tenant
}
@ -131,6 +130,8 @@ class PowerDNSBackend(base.PoolBackend):
self.session.commit()
def delete_domain(self, context, domain):
# TODO(kiall): We should make this match create_domain with regard to
# transactions.
try:
self._get(tables.domains, domain['id'], exceptions.DomainNotFound,
id_col=tables.domains.c.designate_id)

View File

@ -0,0 +1,20 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.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.
from designate.tests import TestCase
class BackendTestCase(TestCase):
pass

View File

@ -0,0 +1,161 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.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 mock
import testtools
import sqlalchemy
from designate.tests.test_backend import BackendTestCase
from designate import objects
from designate import exceptions
from designate.backend import impl_powerdns
from designate.backend.impl_powerdns import tables
class PowerDNSBackendTestCase(BackendTestCase):
def setUp(self):
super(PowerDNSBackendTestCase, self).setUp()
self.masters = [
'127.0.1.1:53',
'127.0.1.2:53',
]
self.domain = objects.Domain(id='e2bed4dc-9d01-11e4-89d3-123b93f75cba',
name='example.com.',
email='example@example.com')
backend_options = [
objects.BackendOption(key="host", value="127.0.0.1"),
objects.BackendOption(key="port", value=5353),
objects.BackendOption(key="masters", value=self.masters),
]
self.backend = impl_powerdns.PowerDNSBackend(backend_options)
# Helper Methpds
def assertSessionTransactionCalls(self, session_mock, begin=0, commit=0,
rollback=0):
# Ensure the Sessions Transactions functions are called correctly
self.assertEqual(begin, session_mock.begin.call_count)
self.assertEqual(commit, session_mock.commit.call_count)
self.assertEqual(rollback, session_mock.rollback.call_count)
# Tests for Public Methpds
@mock.patch.object(impl_powerdns.PowerDNSBackend, 'session',
new_callable=mock.MagicMock)
def test_create_domain(self, session_mock):
context = self.get_context()
self.backend.create_domain(context, self.domain)
self.assertSessionTransactionCalls(
session_mock, begin=1, commit=1, rollback=0)
# Ensure we have two queries, one INSERT, one SELECT
self.assertEqual(2, session_mock.execute.call_count)
self.assertIsInstance(
session_mock.execute.call_args_list[0][0][0],
sqlalchemy.sql.dml.Insert)
self.assertDictContainsSubset(
{'type': 'SLAVE',
'designate_id': self.domain.id,
'master': ','.join(self.masters),
'name': self.domain.name.rstrip('.')},
session_mock.execute.call_args_list[0][0][1])
self.assertIsInstance(
session_mock.execute.call_args_list[1][0][0],
sqlalchemy.sql.selectable.Select)
@mock.patch.object(impl_powerdns.PowerDNSBackend, 'session',
new_callable=mock.Mock)
@mock.patch.object(impl_powerdns.PowerDNSBackend, '_create',
side_effect=Exception)
def test_create_domain_failure_on_create(self, create_mock, session_mock):
with testtools.ExpectedException(Exception):
self.backend.create_domain(self.get_context(), self.domain)
self.assertSessionTransactionCalls(
session_mock, begin=1, commit=0, rollback=1)
# Ensure we called out into the _create method exactly once
self.assertEqual(1, create_mock.call_count)
@mock.patch.object(impl_powerdns.PowerDNSBackend, 'session',
new_callable=mock.Mock)
@mock.patch.object(impl_powerdns.PowerDNSBackend, '_create',
return_value=None)
def test_create_domain_failure_on_commit(self, create_mock, session_mock):
# Configure the Session mocks's commit method to raise an exception
session_mock.commit.side_effect = Exception
with testtools.ExpectedException(Exception):
self.backend.create_domain(self.get_context(), self.domain)
self.assertSessionTransactionCalls(
session_mock, begin=1, commit=1, rollback=0)
# Ensure we called out into the _create method exactly once
self.assertEqual(1, create_mock.call_count)
@mock.patch.object(impl_powerdns.PowerDNSBackend, 'session',
new_callable=mock.Mock)
@mock.patch.object(impl_powerdns.PowerDNSBackend, '_get',
return_value=None)
def test_delete_domain(self, get_mock, session_mock):
# Configure the Session mocks's execute method to return a fudged
# resultproxy.
rp_mock = mock.Mock()
rp_mock.rowcount = 1
session_mock.execute.return_value = rp_mock
context = self.get_context()
self.backend.delete_domain(context, self.domain)
# Ensure the _get method was called with the correct arguments
get_mock.assert_called_once_with(
tables.domains, self.domain.id, exceptions.DomainNotFound,
id_col=tables.domains.c.designate_id)
# Ensure we have one query, a DELETE
self.assertEqual(1, session_mock.execute.call_count)
self.assertIsInstance(
session_mock.execute.call_args_list[0][0][0],
sqlalchemy.sql.dml.Delete)
# TODO(kiall): Validate the ID being deleted
@mock.patch.object(impl_powerdns.PowerDNSBackend, 'session',
new_callable=mock.Mock)
@mock.patch.object(impl_powerdns.PowerDNSBackend, '_get',
side_effect=exceptions.DomainNotFound)
@mock.patch.object(impl_powerdns.PowerDNSBackend, '_delete',
return_value=None)
def test_delete_domain_domain_not_found(self, delete_mock, get_mock,
session_mock):
context = self.get_context()
self.backend.delete_domain(context, self.domain)
# Ensure the _get method was called with the correct arguments
get_mock.assert_called_once_with(
tables.domains, self.domain.id, exceptions.DomainNotFound,
id_col=tables.domains.c.designate_id)
# Ensure the _delete method was not called
self.assertFalse(delete_mock.called)