From 49db679a7a87f2ebd61116d373d8c0ab1e38869d Mon Sep 17 00:00:00 2001 From: "yolanda.robla@canonical.com" <> Date: Fri, 29 Nov 2013 11:02:56 +0100 Subject: [PATCH] added unit tests --- Makefile | 12 +- hooks/heat_relations.py | 2 +- revision | 2 +- unit_tests/test_heat_relations.py | 181 ++++++++++++++++++++++++++++++ unit_tests/test_heat_utils.py | 63 +++++++++++ 5 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 unit_tests/test_heat_relations.py create mode 100644 unit_tests/test_heat_utils.py diff --git a/Makefile b/Makefile index 71dfd40..80ea4e0 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,18 @@ #!/usr/bin/make lint: + @echo -n "Running flake8 tests: " @flake8 --exclude hooks/charmhelpers hooks + @flake8 unit_tests + @echo "OK" + @echo -n "Running charm proof: " @charm proof + @echo "OK" sync: - @charm-helper-sync -c charm-helpers-sync.yaml + @charm-helper-sync -c charm-helpers.yaml + +test: + @$(PYTHON) /usr/bin/nosetests --nologcapture --with-coverage unit_tests + +all: test lint diff --git a/hooks/heat_relations.py b/hooks/heat_relations.py index 7653079..f7a9f8a 100755 --- a/hooks/heat_relations.py +++ b/hooks/heat_relations.py @@ -123,7 +123,7 @@ def db_changed(): def identity_joined(rid=None): base_url = canonical_url(CONFIGS) api_url = '%s:8004/v1/$(tenant_id)s' % base_url - cfn_url = '%s:8000/v1' % base_url + cfn_url = '%s:8000/v1' relation_data = { 'heat_service': 'heat', 'heat_region': config('region'), diff --git a/revision b/revision index 7ed6ff8..1e8b314 100644 --- a/revision +++ b/revision @@ -1 +1 @@ -5 +6 diff --git a/unit_tests/test_heat_relations.py b/unit_tests/test_heat_relations.py new file mode 100644 index 0000000..09393ff --- /dev/null +++ b/unit_tests/test_heat_relations.py @@ -0,0 +1,181 @@ +from mock import call, patch, MagicMock + +from test_utils import CharmTestCase + +import heat_utils as utils + +_reg = utils.register_configs +_map = utils.restart_map + +utils.register_configs = MagicMock() +utils.restart_map = MagicMock() + +import heat_relations as relations + +utils.register_configs = _reg +utils.restart_map = _map + +TO_PATCH = [ + # charmhelpers.core.hookenv + 'Hooks', + 'canonical_url', + 'config', + 'juju_log', + 'open_port', + 'relation_ids', + 'relation_set', + 'relation_get', + 'service_name', + 'unit_get', + # charmhelpers.core.host + 'apt_install', + 'apt_update', + 'restart_on_change', + 'service_stop', + # charmhelpers.contrib.openstack.utils + 'configure_installation_source', + 'get_os_codename_package', + 'openstack_upgrade_available', + # charmhelpers.contrib.hahelpers.cluster_utils + # heat_utils + 'restart_map', + 'register_configs', + 'do_openstack_upgrade', + # other + 'call', + 'check_call', + 'execd_preinstall', + 'mkdir', + 'lsb_release' +] + + +class HeatRelationTests(CharmTestCase): + + def setUp(self): + super(HeatRelationTests, self).setUp(relations, TO_PATCH) + self.config.side_effect = self.test_config.get + + def test_install_hook(self): + repo = 'cloud:precise-havana' + self.determine_packages.return_value = ['python-keystoneclient', + 'uuid', 'heat-api', + 'heat-api-cfn', + 'heat-engine'] + self.test_config.set('openstack-origin', repo) + relations.install() + self.configure_installation_source.assert_called_with(repo) + self.assertTrue(self.apt_update.called) + self.apt_install.assert_called_with(['python-keystoneclient', + 'uuid', 'heat-api', + 'heat-api-cfn', + 'heat-engine'], fatal=True) + self.execd_preinstall.assert_called() + + + def test_config_changed_no_upgrade(self): + self.openstack_upgrade_available.return_value = False + relations.config_changed() + + + def test_config_changed_with_upgrade(self): + self.openstack_upgrade_available.return_value = True + relations.config_changed() + self.assertTrue(self.do_openstack_upgrade.called) + + + def test_db_joined(self): + self.unit_get.return_value = 'heat.foohost.com' + relations.db_joined() + self.relation_set.assert_called_with(heat_database='heat', + heat_username='heat', + heat_hostname='heat.foohost.com') + self.unit_get.assert_called_with('private-address') + + @patch.object(relations, 'CONFIGS') + def test_db_changed_missing_relation_data(self, configs): + configs.complete_contexts = MagicMock() + configs.complete_contexts.return_value = [] + relations.db_changed() + self.juju_log.assert_called_with( + 'shared-db relation incomplete. Peer not ready?' + ) + + + @patch.object(relations, 'CONFIGS') + def test_identity_changed(self, configs): + configs.complete_contexts.return_value = ['identity-service'] + relations.identity_changed() + self.assertTrue(configs.write.called) + + + @patch.object(relations, 'CONFIGS') + def test_identity_changed_incomplete(self, configs): + configs.complete_contexts.return_value = [] + relations.identity_changed() + self.assertTrue(self.juju_log.called) + self.assertFalse(configs.write.called) + + + def test_amqp_joined(self): + relations.amqp_joined() + self.relation_set.assert_called_with( + username='heat', + vhost='openstack', + relation_id=None) + + def test_amqp_joined_passes_relation_id(self): + ''' Ensures relation_id correct passed to relation_set for out of + hook execution ''' + relations.amqp_joined(relation_id='heat:1') + self.relation_set.assert_called_with(username='heat', + vhost='openstack', + relation_id='heat:1') + + + @patch.object(relations, 'CONFIGS') + def test_amqp_changed_missing_relation_data(self, configs): + configs.complete_contexts = MagicMock() + configs.complete_contexts.return_value = [] + relations.amqp_changed() + self.log.assert_called_with( + 'amqp relation incomplete. Peer not ready?' + ) + + @patch.object(relations, 'CONFIGS') + def test_amqp_changed_relation_data(self, configs): + configs.complete_contexts = MagicMock() + configs.complete_contexts.return_value = ['amqp'] + configs.write = MagicMock() + relations.amqp_changed() + self.assertEquals([call('/etc/heat/heat.conf')], + configs.write.call_args_list) + self.assertFalse(self.juju_log.called) + + + @patch.object(relations, 'CONFIGS') + def test_relation_broken(self, configs): + relations.relation_broken() + self.assertTrue(configs.write_all.called) + + +def test_identity_service_joined(self): + '''It properly requests unclustered endpoint via identity-service''' + self.unit_get.return_value = 'heatnode1' + self.canonical_url.return_value = 'http://heatnode1' + relations.identity_joined() + expected = { + 'heat_service': 'heat', + 'heat_region': 'RegionOne', + 'heat_public_url': 'http://heatnode1:8004/v1/$(tenant_id)s', + 'heat_admin_url': 'http://heatnode1:8004/v1/$(tenant_id)s', + 'heat_internal_url': 'http://heatnode1:8004/v1/$(tenant_id)s', + 'heat-cfn_service': 'heat-cfn', + 'heat-cfn_region': 'RegionOne', + 'heat-cfn_public_url': 'http://heatnode1:8000/v1', + 'heat-cfn_admin_url': 'http://heatnode1:8000/v1', + 'heat-cfn_internal_url': 'http://heatnode1:8000/v1', + 'relation_id': None, + } + self.relation_set.assert_called_with(**expected) + diff --git a/unit_tests/test_heat_utils.py b/unit_tests/test_heat_utils.py new file mode 100644 index 0000000..2378a32 --- /dev/null +++ b/unit_tests/test_heat_utils.py @@ -0,0 +1,63 @@ +from collections import OrderedDict +from mock import patch, MagicMock, call +from copy import deepcopy +from test_utils import CharmTestCase, patch_open + +from charmhelpers.core import hookenv + +_conf = hookenv.config +hookenv.config = MagicMock() + +import heat_utils as utils + +hookenv.config = _conf + +TO_PATCH = [ + 'config', + 'log', + 'os_release', + 'relation_ids' +] + + +# Restart map should be constructed such that API services restart +# before frontends (haproxy/apaceh) to avoid port conflicts. +RESTART_MAP = OrderedDict([ + ('/etc/heat/heat.conf', [ + 'heat-api', 'heat-api-cfn', 'heat-api-engine' + ]), + ('/etc/heat/api-paste.ini', [ + 'heat-api', 'heat-api-cfn', 'heat-api-engine' + ]) +]) + + +class HeatUtilsTests(CharmTestCase): + + def setUp(self): + super(HeatUtilsTests, self).setUp(utils, TO_PATCH) + self.config.side_effect = self.test_config.get + + + @patch('charmhelpers.contrib.openstack.context.SubordinateConfigContext') + def test_determine_packages(self, subcontext): + self.relation_ids.return_value = [] + self.os_release.return_value = 'havana' + pkgs = utils.determine_packages() + ex = list(set(utils.BASE_PACKAGES + utils.BASE_SERVICES)) + self.assertEquals(ex, pkgs) + + + def test_restart_map(self): + self.assertEquals(RESTART_MAP, utils.restart_map()) + + + @patch.object(utils, 'migrate_database') + def test_openstack_upgrade(self, migrate): + self.config.side_effect = None + self.config.return_value = 'cloud:precise-havana' + self.get_os_codename_install_source.return_value = 'havana' + configs = MagicMock() + utils.do_openstack_upgrade(configs) + self.assertTrue(configs.write_all.called) + configs.set_release.assert_called_with(openstack_release='havana')