From 8d6211a75c3ce89e03c328f3481055a08ced52f8 Mon Sep 17 00:00:00 2001 From: Dmitrii Shcherbakov Date: Thu, 26 Jan 2017 00:29:22 +0300 Subject: [PATCH] tests: fix/cleanup functional and unit tests Remove non-working unit tests (left only the ones that pass - let's make it a baseline and add more afterwards). Fix functional tests (dependency + API urls) Repository tidy up: Remove log files from tox from git repo; Fixup gitreview to point to trove repository; Make gate tests executable. Change-Id: Ide6b833f77f76e43ebbc9fbe435cff0bd4060ef8 --- .gitreview | 2 +- src/README.md | 72 ++++++++- src/lib/charm/openstack/trove.py | 55 ++++--- src/reactive/trove_handlers.py | 34 +---- src/test-requirements.txt | 2 +- src/tests/basic_deployment.py | 2 +- src/tests/gate-basic-xenial-mitaka | 0 tox_output.txt | 42 ----- unit_tests/test_lib_charm_openstack_trove.py | 107 +++++++++---- unit_tests/test_trove_handlers.py | 115 +++----------- unit_tests/test_trove_utils.py | 153 ------------------- 11 files changed, 202 insertions(+), 382 deletions(-) mode change 100644 => 100755 src/tests/gate-basic-xenial-mitaka delete mode 100644 tox_output.txt delete mode 100644 unit_tests/test_trove_utils.py diff --git a/.gitreview b/.gitreview index 28fc2e8..556c16b 100644 --- a/.gitreview +++ b/.gitreview @@ -1,4 +1,4 @@ [gerrit] host=review.openstack.org port=29418 -project=openstack/charm-designate.git +project=openstack/charm-trove.git diff --git a/src/README.md b/src/README.md index 2936954..45c423d 100644 --- a/src/README.md +++ b/src/README.md @@ -5,21 +5,85 @@ This charm provides the Trove (DBaaS) for an OpenStack Cloud. # Usage -Designate relies on services from the mysql, rabbitmq-server and keystone -charms: +As described in the installation guide, + +http://docs.openstack.org/developer/trove/dev/manual_install.html + +a running OpenStack environment is required to use Trove, including +the following components: + + - Compute (Nova) + - Image Service (Glance) + - Identity (Keystone) + - Neutron or Nova-Network + - Cinder, if you want to provision datastores on block-storage volumes + - Swift, if you want to do backup/restore and replication + - AMQP service (RabbitMQ or QPID) + - MySQL (SQLite, PostgreSQL) database for Trove's internal needs + - Certain OpenStack services must be accessible from VMs: + - Swift + +OpenStack services must be accessible directly from the environment where +Trove is deployed: + - Nova + - Cinder + - Swift + - Heat + + +A basic setup with using charms would look like the following: juju deploy trove juju deploy mysql juju deploy rabbitmq-server juju deploy keystone - juju deploy heat juju deploy cinder + juju deploy glance + juju deploy nova-compute + juju deploy nova-cloud-controller + juju deploy neutron + juju deploy neutron-openvswitch + juju deploy neutron-gateway + juju add-relation trove mysql juju add-relation trove rabbitmq-server juju add-relation trove keystone + juju add-relation nova-compute rabbitmq-server + juju add-relation nova-compute glance + + juju add-relation cinder keystone + juju add-relation cinder mysql + juju add-relation cinder rabbitmq-server + + juju add-relation glance keystone + juju add-relation glance mysql + + juju add-relation neutron-gateway mysql + juju add-relation neutron-gateway rabbitmq-server + juju add-relation neutron-gateway:amqp rabbitmq-server:amqp + juju add-relation neutron-openvswitch nova-compute + juju add-relation neutron-openvswitch neutron-api + juju add-relation neutron-openvswitch rabbitmq-server + juju add-relation neutron-api mysql + juju add-relation neutron-api keystone + juju add-relation neutron-api rabbitmq-server + + juju add-relation nova-cloud-controller keystone + juju add-relation nova-cloud-controller rabbitmq-server + juju add-relation nova-cloud-controller nova-compute + juju add-relation nova-cloud-controller mysql + juju add-relation nova-cloud-controller glance + juju add-relation nova-cloud-controller cinder + juju add-relation nova-cloud-controller neutron-api + +This will get the necessary services deployed, however, you will still need +to create images, flavors and data stores for your specific needs. + +http://docs.openstack.org/admin-guide/database.html + # Bugs -Please report bugs on [Launchpad](https://bugs.launchpad.net/charm-designate/+filebug). +Please report bugs on [Launchpad](https://bugs.launchpad.net/charm-trove/+filebug). For general questions please refer to the OpenStack [Charm Guide](http://docs.openstack.org/developer/charm-guide/). diff --git a/src/lib/charm/openstack/trove.py b/src/lib/charm/openstack/trove.py index 6407f3f..3dbfff6 100644 --- a/src/lib/charm/openstack/trove.py +++ b/src/lib/charm/openstack/trove.py @@ -17,12 +17,10 @@ # needed on the class. from __future__ import absolute_import -# import subprocess +import collections import charmhelpers.contrib.openstack.utils as ch_utils -# import charmhelpers.core.hookenv as hookenv import charmhelpers.core.unitdata as unitdata -# import charmhelpers.fetch import charms_openstack.charm import charms_openstack.adapters @@ -50,6 +48,15 @@ def install(): TroveCharm.singleton.install() +def db_sync_done(): + """Use the singleton from the TroveCharm to check if db migration has + been run + + @returns: str or None. Str if sync has been done otherwise None + """ + return TroveCharm.singleton.db_sync_done() + + def restart_all(): """Use the singleton from the TroveCharm to restart services on the unit @@ -110,23 +117,15 @@ def configure_ssl(keystone=None): TroveCharm.singleton.configure_ssl(keystone) -def configure_cloud_compute(): - # TODO - pass +def update_peers(hacluster): + """Use the singleton from the TroveCharm to update peers with details + of this unit. + @param hacluster: OpenstackHAPeers() interface class + @returns: None + """ + TroveCharm.singleton.update_peers(hacluster) -def configure_cinder(): - # TODO - pass - - -def configure_image_service(): - # TODO - pass - - -### -# Implementation of the Trove Charm classes class TroveConfigurationAdapter( charms_openstack.adapters.APIConfigurationAdapter): @@ -150,9 +149,7 @@ class TroveAdapters(charms_openstack.adapters.OpenStackAPIRelationAdapters): class TroveCharm(charms_openstack.charm.HAOpenStackCharm): - service_name = 'trove' - - name = 'trove' + service_name = name = 'trove' release = 'mitaka' @@ -189,14 +186,14 @@ class TroveCharm(charms_openstack.charm.HAOpenStackCharm): ha_resources = ['vips', 'haproxy'] - def __init__(self, release=None, **kwargs): - """ - Copied out of the github congress example. Checks to make sure a - release is give, if not it pull the one out of keystone. - """ - if release is None: - release = ch_utils.os_release('python-keystonemiddleware') - super(TroveCharm, self).__init__(release=release, **kwargs) + release_pkg = 'trove-common' + package_codenames = { + 'aodh-common': collections.OrderedDict([ + ('2', 'mitaka'), + ('3', 'newton'), + ('4', 'ocata'), + ]), + } def install(self): """Customise the installation, configure the source and then call the diff --git a/src/reactive/trove_handlers.py b/src/reactive/trove_handlers.py index b1cda52..a5da90b 100644 --- a/src/reactive/trove_handlers.py +++ b/src/reactive/trove_handlers.py @@ -36,8 +36,7 @@ def setup_amqp_req(amqp): Use the amqp interface to request access to the amqp broker using our local configuration. """ - amqp.request_access(username=hookenv.config('rabbit-user'), - vhost=hookenv.config('rabbit-vhost')) + amqp.request_access(username='trove', vhost='openstack') trove.assess_status() @@ -83,6 +82,12 @@ def run_db_migration(): trove.assess_status() +@reactive.when('cluster.available') +def update_peers(cluster): + """Inform designate peers about this unit""" + trove.update_peers(cluster) + + @reactive.when('config.changed') def config_changed(): trove.assess_status() @@ -91,28 +96,3 @@ def config_changed(): @reactive.when('identity-service.available') def configure_ssl(keystone): trove.configure_ssl(keystone) - - -# when cloud-compute.available -@reactive.when('cloud-compute.available') -def configure_cloud_compute(): - trove.configure_cloud_compute() - trove.assess_status() - - -# when image-service.available -@reactive.when('image-service.available') -def configure_image_service(): - trove.configure_image_service() - trove.assess_status() - - -# when cinder-volume-service -@reactive.when('cinder-volume-service.available') -def configure_cinder(): - trove.configure_cinder() - trove.assess_status() - -# when heat - I need to find out what juju calls this - -# when ceph.available diff --git a/src/test-requirements.txt b/src/test-requirements.txt index 3ffd9c2..7427bcf 100644 --- a/src/test-requirements.txt +++ b/src/test-requirements.txt @@ -7,7 +7,7 @@ bzr+lp:charm-helpers#egg=charmhelpers amulet>=1.14.3,<2.0 bundletester>=0.6.1,<1.0 python-keystoneclient>=1.7.1,<2.0 -python-designateclient>=1.5,<2.0 +python-troveclient>=1.5,<=2.7.0 python-cinderclient>=1.4.0,<2.0 python-glanceclient>=1.1.0,<2.0 python-heatclient>=0.8.0,<1.0 diff --git a/src/tests/basic_deployment.py b/src/tests/basic_deployment.py index b95c313..887db81 100644 --- a/src/tests/basic_deployment.py +++ b/src/tests/basic_deployment.py @@ -216,7 +216,7 @@ class TroveBasicDeployment(amulet_deployment.OpenStackAmuletDeployment): trove_ip = unit.relation( 'identity-service', 'keystone:identity-service')['private-address'] - trove_endpoint = "http://%s:8779" % (trove_ip) + trove_endpoint = "http://{}:8779/v1.0/%(tenant_id)s".format(trove_ip) expected = { 'admin_url': trove_endpoint, diff --git a/src/tests/gate-basic-xenial-mitaka b/src/tests/gate-basic-xenial-mitaka old mode 100644 new mode 100755 diff --git a/tox_output.txt b/tox_output.txt deleted file mode 100644 index 2ab5681..0000000 --- a/tox_output.txt +++ /dev/null @@ -1,42 +0,0 @@ -pep8 installed: blessings==1.6,charm-tools==2.1.4,Cheetah==2.4.4,colander==1.3.1,configparser==3.5.0,ecdsa==0.13,enum34==1.1.6,flake8==3.0.4,functools32==3.2.3.post2,httplib2==0.9.2,iso8601==0.1.11,jsonschema==2.5.1,jujubundlelib==0.5.2,keyring==9.3.1,launchpadlib==1.10.4,lazr.authentication==0.1.3,lazr.restfulclient==0.13.1,lazr.uri==1.0.3,libcharmstore==0.0.3,Markdown==2.6.7,mccabe==0.5.2,oauth==1.0.1,otherstuf==1.1.0,paramiko==1.17.2,parse==1.6.6,path.py==8.2.1,pathspec==0.5.0,pbr==1.10.0,pkg-resources==0.0.0,pycodestyle==2.0.0,pycrypto==2.6.1,pyflakes==1.2.3,PyYAML==3.12,requests==2.11.1,ruamel.ordereddict==0.4.9,ruamel.yaml==0.12.14,SecretStorage==2.2.1,simplejson==3.8.2,six==1.10.0,stuf==0.9.16,testresources==2.0.1,theblues==0.3.6,translationstring==1.3,typing==3.5.2.2,virtualenv==15.0.3,wadllib==1.3.2,wsgi-intercept==1.4.1,zope.interface==4.3.2 -pep8 runtests: PYTHONHASHSEED='0' -pep8 runtests: commands[0] | flake8 src/reactive src/lib unit_tests -py34 create: /home/charm/charms/layers/charm-trove/.tox/py34 -ERROR: InterpreterNotFound: python3.4 -py35 installed: Babel==2.3.4,charmhelpers==0.9.1,charms.openstack==0.0.1.dev1,charms.reactive==0.4.4,coverage==4.2,extras==1.0.0,fixtures==3.0.0,flake8==2.4.1,Jinja2==2.8,linecache2==1.0.0,MarkupSafe==0.23,mccabe==0.3.1,mock==2.0.0,netaddr==0.7.18,os-testr==0.8.0,pbr==1.10.0,pep8==1.7.0,pkg-resources==0.0.0,pyaml==16.9.0,pyflakes==0.8.1,python-mimeparse==1.5.5,python-subunit==1.2.0,pytz==2016.7,PyYAML==3.12,six==1.10.0,Tempita==0.5.2,testrepository==0.0.20,testtools==2.2.0,traceback2==1.4.0,unittest2==1.1.0 -py35 runtests: PYTHONHASHSEED='0' -py35 runtests: commands[0] | ostestr -running=ONon-zero exit code (2) from test listing. -S_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ -OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ -OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ -${PYTHON:-python} -m subunit.run discover -t ./ ./unit_tests --list ---- import errors --- -Failed to import test module: unit_tests.test_trove_handlers -Traceback (most recent call last): - File "/home/charm/charms/layers/charm-trove/.tox/py35/lib/python3.5/site-packages/unittest2/loader.py", line 456, in _find_test_path - module = self._get_module_from_name(name) - File "/home/charm/charms/layers/charm-trove/.tox/py35/lib/python3.5/site-packages/unittest2/loader.py", line 395, in _get_module_from_name - __import__(name) - File "/home/charm/charms/layers/charm-trove/unit_tests/test_trove_handlers.py", line 8, in - import reactive.designate_handlers as handlers -ImportError: No module named 'reactive.designate_handlers' - -Failed to import test module: unit_tests.test_trove_utils -Traceback (most recent call last): - File "/home/charm/charms/layers/charm-trove/.tox/py35/lib/python3.5/site-packages/unittest2/loader.py", line 456, in _find_test_path - module = self._get_module_from_name(name) - File "/home/charm/charms/layers/charm-trove/.tox/py35/lib/python3.5/site-packages/unittest2/loader.py", line 395, in _get_module_from_name - __import__(name) - File "/home/charm/charms/layers/charm-trove/unit_tests/test_trove_utils.py", line 4, in - import reactive.designate_utils as dutils -ImportError: No module named 'reactive.designate_utils' -The test run didn't actually run any tests - -Slowest Tests: - -ERROR: InvocationError: '/home/charm/charms/layers/charm-trove/.tox/py35/bin/ostestr' -___________________________________ summary ____________________________________ - pep8: commands succeeded -SKIPPED: py34: InterpreterNotFound: python3.4 -ERROR: py35: commands failed diff --git a/unit_tests/test_lib_charm_openstack_trove.py b/unit_tests/test_lib_charm_openstack_trove.py index 6f36353..ce82479 100644 --- a/unit_tests/test_lib_charm_openstack_trove.py +++ b/unit_tests/test_lib_charm_openstack_trove.py @@ -15,42 +15,87 @@ from __future__ import absolute_import from __future__ import print_function -# import contextlib -import unittest - import mock -# import charm.openstack.designate as designate +import charm.openstack.trove as trove + +import charms_openstack.test_utils as test_utils -def FakeConfig(init_dict): - - def _config(key=None): - return init_dict[key] if key else init_dict - - return _config - - -class Helper(unittest.TestCase): +class Helper(test_utils.PatchHelper): def setUp(self): - self._patches = {} - self._patches_start = {} - self.ch_config_patch = mock.patch('charmhelpers.core.hookenv.config') - self.ch_config = self.ch_config_patch.start() - self.ch_config.side_effect = lambda: {'ssl_param': None} + super().setUp() + self.patch_release(trove.TroveCharm.release) - def tearDown(self): - for k, v in self._patches.items(): - v.stop() - setattr(self, k, None) - self._patches = None - self._patches_start = None - self.ch_config_patch.stop() - def patch(self, obj, attr, return_value=None, **kwargs): - mocked = mock.patch.object(obj, attr, **kwargs) - self._patches[attr] = mocked - started = mocked.start() - started.return_value = return_value - self._ +class TestOpenStackTrove(Helper): + + def test_install(self): + self.patch_object(trove.TroveCharm.singleton, 'install') + trove.install() + self.install.assert_called_once_with() + + def test_setup_endpoint(self): + self.patch_object(trove.TroveCharm, 'service_name', + new_callable=mock.PropertyMock) + self.patch_object(trove.TroveCharm, 'region', + new_callable=mock.PropertyMock) + self.patch_object(trove.TroveCharm, 'public_url', + new_callable=mock.PropertyMock) + self.patch_object(trove.TroveCharm, 'internal_url', + new_callable=mock.PropertyMock) + self.patch_object(trove.TroveCharm, 'admin_url', + new_callable=mock.PropertyMock) + self.service_name.return_value = 'type1' + self.region.return_value = 'region1' + self.public_url.return_value = 'public_url' + self.internal_url.return_value = 'internal_url' + self.admin_url.return_value = 'admin_url' + keystone = mock.MagicMock() + trove.setup_endpoint(keystone) + keystone.register_endpoints.assert_called_once_with( + 'trove', 'region1', 'public_url/v1.0/%(tenant_id)s', + 'internal_url/v1.0/%(tenant_id)s', + 'admin_url/v1.0/%(tenant_id)s') + + def test_render_configs(self): + self.patch_object(trove.TroveCharm.singleton, 'render_with_interfaces') + trove.render_configs('interfaces-list') + self.render_with_interfaces.assert_called_once_with( + 'interfaces-list') + + def test_db_sync_done(self): + self.patch_object(trove.TroveCharm, 'db_sync_done') + trove.db_sync_done() + self.db_sync_done.assert_called_once_with() + + def test_db_sync(self): + self.patch_object(trove.TroveCharm.singleton, 'db_sync') + trove.db_sync() + self.db_sync.assert_called_once_with() + + def test_configure_ha_resources(self): + self.patch_object(trove.TroveCharm.singleton, 'db_sync') + trove.db_sync() + self.db_sync.assert_called_once_with() + + def test_restart_all(self): + self.patch_object(trove.TroveCharm.singleton, 'restart_all') + trove.restart_all() + self.restart_all.assert_called_once_with() + + def test_configure_ssl(self): + self.patch_object(trove.TroveCharm.singleton, 'configure_ssl') + trove.configure_ssl() + self.configure_ssl.assert_called_once_with(None) + + def test_update_peers(self): + self.patch_object(trove.TroveCharm.singleton, 'update_peers') + trove.update_peers('cluster') + self.update_peers.assert_called_once_with('cluster') + + def test_assess_status(self): + self.patch_object(trove.TroveCharm.singleton, 'assess_status') + trove.assess_status() + self.assess_status.assert_called_once_with() diff --git a/unit_tests/test_trove_handlers.py b/unit_tests/test_trove_handlers.py index f5ce47b..befa4ab 100644 --- a/unit_tests/test_trove_handlers.py +++ b/unit_tests/test_trove_handlers.py @@ -5,7 +5,7 @@ import unittest import mock -import reactive.designate_handlers as handlers +import reactive.trove_handlers as handlers _when_args = {} @@ -29,7 +29,7 @@ def mock_hook_factory(d): return mock_hook -class TestDesignateHandlers(unittest.TestCase): +class TestTroveHandlers(unittest.TestCase): @classmethod def setUpClass(cls): @@ -86,11 +86,6 @@ class TestDesignateHandlers(unittest.TestCase): # test that the hooks actually registered the relation expressions that # are meaningful for this interface: this is to handle regressions. # The keys are the function names that the hook attaches to. - all_interfaces = ( - 'dns-backend.available', - 'shared-db.available', - 'identity-service.available', - 'amqp.available') when_patterns = { 'setup_amqp_req': [('amqp.connected', )], 'setup_database': [('shared-db.connected', )], @@ -99,136 +94,70 @@ class TestDesignateHandlers(unittest.TestCase): 'update_peers': [('cluster.available', )], 'config_changed': [('config.changed', )], 'cluster_connected': [('ha.connected', )], - 'create_servers_and_domains': [ - all_interfaces, - ('base-config.rendered', ), - ('db.synched', ), - ], - 'configure_designate_full': [ - all_interfaces, - ('db.synched', ), - ], - 'run_db_migration': [ - all_interfaces, - ('base-config.rendered', ), - ], - 'configure_designate_basic': [ - all_interfaces, - ], + 'render_stuff': [('amqp.available',), + ('identity-service.available',), + ('shared-db.available',)], + 'run_db_migration': [('config.complete',)] } when_not_patterns = { - 'install_packages': [('installed', )], - 'run_db_migration': [('db.synched', )], - 'configure_designate_basic': [('base-config.rendered', )], - 'create_servers_and_domains': [('domains.created', )], + 'install_packages': [('charm.installed', )], + 'run_db_migration': [('db.synced',)], } # check the when hooks are attached to the expected functions for t, p in [(_when_args, when_patterns), (_when_not_args, when_not_patterns)]: for f, args in t.items(): # check that function is in patterns - print(f) + print('f: {}'.format(f)) self.assertTrue(f in p.keys()) # check that the lists are equal l = [a['args'] for a in args] self.assertEqual(l, p[f]) def test_install_packages(self): - self.patch(handlers.designate, 'install') + self.patch(handlers.trove, 'install') self.patch(handlers.reactive, 'set_state') handlers.install_packages() self.install.assert_called_once_with() - self.set_state.assert_called_once_with('installed') + self.set_state.assert_called_once_with('charm.installed') def test_setup_amqp_req(self): - self.patch(handlers.designate, 'assess_status') + self.patch(handlers.trove, 'assess_status') amqp = mock.MagicMock() handlers.setup_amqp_req(amqp) amqp.request_access.assert_called_once_with( - username='designate', vhost='openstack') + username='trove', vhost='openstack') self.assess_status.assert_called_once_with() def test_database(self): - self.patch(handlers.designate, 'assess_status') + self.patch(handlers.trove, 'assess_status') database = mock.MagicMock() self.patch(handlers.hookenv, 'unit_private_ip', 'private_ip') handlers.setup_database(database) calls = [ mock.call( - 'designate', - 'designate', + 'trove', + 'trove', 'private_ip', - prefix='designate'), - mock.call( - 'dpm', - 'dpm', - 'private_ip', - prefix='dpm'), + prefix='trove'), ] database.configure.has_calls(calls) self.assess_status.assert_called_once_with() def test_setup_endpoint(self): - self.patch(handlers.designate, 'assess_status') - self.patch(handlers.designate, 'register_endpoints') + self.patch(handlers.trove, 'assess_status') + self.patch(handlers.trove, 'setup_endpoint') handlers.setup_endpoint('endpoint_object') - self.register_endpoints.assert_called_once_with('endpoint_object') + self.setup_endpoint.assert_called_once_with('endpoint_object') self.assess_status.assert_called_once_with() - def test_configure_designate_basic(self): - self.patch(handlers.reactive, 'set_state') - self.patch(handlers.designate, 'render_base_config') - self.patch(handlers.reactive.RelationBase, 'from_state') - handlers.configure_designate_basic('arg1', 'arg2') - self.render_base_config.assert_called_once_with(('arg1', 'arg2', )) - self.set_state.assert_called_once_with('base-config.rendered') - - def test_run_db_migration(self): - self.patch(handlers.reactive, 'set_state') - self.patch(handlers.designate, 'db_sync') - self.patch(handlers.designate, 'db_sync_done') - self.db_sync_done.return_value = False - handlers.run_db_migration('arg1', 'arg2') - self.db_sync.assert_called_once_with() - self.assertFalse(self.set_state.called) - self.db_sync.reset_mock() - self.db_sync_done.return_value = True - handlers.run_db_migration('arg1', 'arg2') - self.db_sync.assert_called_once_with() - self.set_state.assert_called_once_with('db.synched') - def test_update_peers(self): cluster = mock.MagicMock() - self.patch(handlers.designate, 'update_peers') + self.patch(handlers.trove, 'update_peers') handlers.update_peers(cluster) self.update_peers.assert_called_once_with(cluster) - def test_configure_designate_full(self): - self.patch(handlers.reactive.RelationBase, 'from_state', - return_value=None) - self.patch(handlers.designate, 'configure_ssl') - self.patch(handlers.designate, 'render_full_config') - self.patch(handlers.designate, 'create_initial_servers_and_domains') - self.patch(handlers.designate, 'render_sink_configs') - self.patch(handlers.designate, 'render_rndc_keys') - self.patch(handlers.designate, 'update_pools') - handlers.configure_designate_full('arg1', 'arg2') - self.configure_ssl.assert_called_once_with() - self.render_full_config.assert_called_once_with(('arg1', 'arg2', )) - self.create_initial_servers_and_domains.assert_called_once_with() - self.render_sink_configs.assert_called_once_with(('arg1', 'arg2', )) - self.render_rndc_keys.assert_called_once_with() - self.update_pools.assert_called_once_with() - - def test_cluster_connected(self): - hacluster = mock.MagicMock() - self.patch(handlers.designate, 'configure_ha_resources') - self.patch(handlers.designate, 'assess_status') - handlers.cluster_connected(hacluster) - self.configure_ha_resources.assert_called_once_with(hacluster) - self.assess_status.assert_called_once_with() - def test_config_changed(self): - self.patch(handlers.designate, 'assess_status') + self.patch(handlers.trove, 'assess_status') handlers.config_changed() self.assess_status.assert_called_once_with() diff --git a/unit_tests/test_trove_utils.py b/unit_tests/test_trove_utils.py deleted file mode 100644 index e84e3b7..0000000 --- a/unit_tests/test_trove_utils.py +++ /dev/null @@ -1,153 +0,0 @@ -import mock -import unittest - -import reactive.designate_utils as dutils - -DOMAIN_LIST = b""" -b78d458c-2a69-47e7-aa40-a1f9ff8809e3 frodo.com. 1467534540 -fa5111a7-5659-45c6-a101-525b4259e8f0 bilbo.com. 1467534855 -""" - -SERVER_LIST = b""" -77eee1aa-27fc-49b9-acca-3faf68126530 ns1.www.example.com. -""" - - -class TestTroveUtils(unittest.TestCase): - - def setUp(self): - self._patches = {} - self._patches_start = {} - - def tearDown(self): - for k, v in self._patches.items(): - v.stop() - setattr(self, k, None) - self._patches = None - self._patches_start = None - - def patch(self, obj, attr, return_value=None): - mocked = mock.patch.object(obj, attr) - self._patches[attr] = mocked - started = mocked.start() - started.return_value = return_value - self._patches_start[attr] = started - setattr(self, attr, started) - - def test_run_command(self): - self.patch(dutils, 'get_environment') - self.patch(dutils.subprocess, 'Popen') - process_mock = mock.Mock() - attrs = { - 'communicate.return_value': ('ouput', 'error'), - 'returncode': 0} - process_mock.configure_mock(**attrs) - self.Popen.return_value = process_mock - self.Popen.returncode.return_value = 0 - dutils.run_command(['ls']) - self.Popen.assert_called_once_with( - ['ls'], - env=None, - stderr=-1, - stdout=-1) - - def test_run_command_fail(self): - self.patch(dutils, 'get_environment') - self.patch(dutils.subprocess, 'Popen') - process_mock = mock.Mock() - attrs = { - 'communicate.return_value': ('ouput', 'error'), - 'returncode': 1} - process_mock.configure_mock(**attrs) - self.Popen.return_value = process_mock - self.Popen.returncode.return_value = 0 - with self.assertRaises(RuntimeError): - dutils.run_command(['ls']) - - def test_get_environment(self): - text_file_data = '\n'.join(["export a=b", "export c=d"]) - with mock.patch('builtins.open', - mock.mock_open(read_data=text_file_data), - create=True) as m: - m.return_value.__iter__.return_value = text_file_data.splitlines() - with open('filename', 'rU'): - self.assertEqual( - dutils.get_environment({}), - {'a': 'b', 'c': 'd'}) - - def test_get_server_id(self): - self.patch(dutils, 'get_servers') - self.get_servers.return_value = {'server1': {'id': 'servid1'}} - self.assertEquals(dutils.get_server_id('server1'), 'servid1') - self.assertEquals(dutils.get_server_id('server2'), None) - - def test_get_domain_id(self): - self.patch(dutils, 'get_domains') - self.get_domains.return_value = {'domain1': {'id': 'domainid1'}} - self.assertEquals(dutils.get_domain_id('domain1'), 'domainid1') - self.assertEquals(dutils.get_domain_id('domain2'), None) - - def test_create_server(self): - _server_ids = ['servid1', None] - self.patch(dutils, 'get_server_id') - self.patch(dutils, 'display') - self.get_server_id.side_effect = lambda x: _server_ids.pop() - self.patch(dutils, 'run_command') - self.run_command.return_value = ('out', 'err') - dutils.create_server('server1') - cmd = [ - 'designate', 'server-create', - '--name', 'server1', - '-f', 'value', - ] - self.run_command.assert_called_with(cmd) - self.display.assert_called_with('servid1') - - def test_create_domain(self): - _domain_ids = ['domainid1', None] - self.patch(dutils, 'get_domain_id') - self.patch(dutils, 'display') - self.get_domain_id.side_effect = lambda x: _domain_ids.pop() - self.patch(dutils, 'run_command') - self.run_command.return_value = ('out', 'err') - dutils.create_domain('dom1', 'email1') - cmd = [ - 'designate', 'domain-create', - '--name', 'dom1', - '--email', 'email1', - '-f', 'value', - ] - self.run_command.assert_called_with(cmd) - self.display.assert_called_with('domainid1') - - def test_delete_domain(self): - self.patch(dutils, 'get_domain_id', return_value='dom1') - self.patch(dutils, 'run_command') - dutils.delete_domain('dom1') - self.run_command.assert_called_with(['domain-delete', 'dom1']) - - def test_get_domains(self): - self.patch(dutils, 'run_command') - self.run_command.return_value = (DOMAIN_LIST, 'err') - expect = { - 'bilbo.com.': - { - 'id': 'fa5111a7-5659-45c6-a101-525b4259e8f0', - 'serial': '1467534855'}, - 'frodo.com.': - { - 'id': 'b78d458c-2a69-47e7-aa40-a1f9ff8809e3', - 'serial': '1467534540'}} - self.assertEqual(dutils.get_domains(), expect) - self.run_command.assert_called_with( - ['designate', 'domain-list', '-f', 'value']) - - def test_get_servers(self): - self.patch(dutils, 'run_command') - self.run_command.return_value = (SERVER_LIST, 'err') - expect = { - 'ns1.www.example.com.': { - 'id': '77eee1aa-27fc-49b9-acca-3faf68126530'}} - self.assertEqual(dutils.get_servers(), expect) - self.run_command.assert_called_with( - ['designate', 'server-list', '-f', 'value'])