From 6c29349c0cd83aadcfcd542bb3ec2b48d929916c Mon Sep 17 00:00:00 2001 From: Ryan Beisner Date: Sat, 1 Aug 2015 02:34:37 +0000 Subject: [PATCH] update amulet test --- Makefile | 18 +-- metadata.yaml | 4 +- tests/00-setup | 7 +- tests/019-basic-vivid-kilo | 0 tests/basic_deployment.py | 225 +++++++++++++++++++++---------------- 5 files changed, 146 insertions(+), 108 deletions(-) mode change 100644 => 100755 tests/019-basic-vivid-kilo diff --git a/Makefile b/Makefile index 52b6dfbf..72066d81 100644 --- a/Makefile +++ b/Makefile @@ -2,13 +2,20 @@ PYTHON := /usr/bin/env python lint: - @flake8 --exclude hooks/charmhelpers actions hooks unit_tests tests + @flake8 --exclude hooks/charmhelpers,tests/charmhelpers \ + actions hooks unit_tests tests @charm proof -unit_test: +test: + @# Bundletester expects unit tests here. @echo Starting tests... @$(PYTHON) /usr/bin/nosetests --nologcapture unit_tests +functional_test: + @echo Starting Amulet tests... + # https://bugs.launchpad.net/amulet/+bug/1320357 + @juju test -v -p AMULET_HTTP_PROXY,AMULET_OS_VIP --timeout 2700 + bin/charm_helpers_sync.py: @mkdir -p bin @bzr cat lp:charm-helpers/tools/charm_helpers_sync/charm_helpers_sync.py \ @@ -18,13 +25,6 @@ sync: bin/charm_helpers_sync.py @$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-hooks.yaml @$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-tests.yaml -test: - @echo Starting Amulet tests... - # coreycb note: The -v should only be temporary until Amulet sends - # raise_status() messages to stderr: - # https://bugs.launchpad.net/amulet/+bug/1320357 - @juju test -v -p AMULET_HTTP_PROXY,AMULET_OS_VIP --timeout 2700 - publish: lint test bzr push lp:charms/openstack-dashboard bzr push lp:charms/trusty/openstack-dashboard diff --git a/metadata.yaml b/metadata.yaml index 4ee536a8..cd661dd1 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -4,7 +4,9 @@ maintainer: Adam Gandelman description: | The OpenStack Dashboard provides a full feature web interface for interacting with instances, images, volumes and networks within an OpenStack deployment. -categories: ["misc"] +tags: + - openstack + - misc provides: nrpe-external-master: interface: nrpe-external-master diff --git a/tests/00-setup b/tests/00-setup index 27476744..5c0d1b49 100755 --- a/tests/00-setup +++ b/tests/00-setup @@ -5,8 +5,11 @@ set -ex sudo add-apt-repository --yes ppa:juju/stable sudo apt-get update --yes sudo apt-get install --yes python-amulet \ + python-cinderclient \ python-distro-info \ - python-neutronclient \ + python-glanceclient \ + python-heatclient \ python-keystoneclient \ + python-neutronclient \ python-novaclient \ - python-glanceclient + python-swiftclient diff --git a/tests/019-basic-vivid-kilo b/tests/019-basic-vivid-kilo old mode 100644 new mode 100755 diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index 91e755ad..0f988170 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -12,8 +12,8 @@ from charmhelpers.contrib.openstack.amulet.deployment import ( from charmhelpers.contrib.openstack.amulet.utils import ( OpenStackAmuletUtils, - DEBUG, # flake8: noqa - ERROR + DEBUG, + #ERROR ) # Use DEBUG to turn on debug logging @@ -26,8 +26,8 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): def __init__(self, series, openstack=None, source=None, git=False, stable=False): """Deploy the entire test environment.""" - super(OpenstackDashboardBasicDeployment, self).__init__(series, openstack, - source, stable) + super(OpenstackDashboardBasicDeployment, + self).__init__(series, openstack, source, stable) self.git = git self._add_services() self._add_relations() @@ -38,22 +38,24 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): def _add_services(self): """Add services - Add the services that we're testing, where openstack-dashboard is local, - and the rest of the service are from lp branches that are - compatible with the local charm (e.g. stable or next). - """ + Add the services that we're testing, where openstack-dashboard + is local, and the rest of the service are from lp branches that are + compatible with the local charm (e.g. stable or next). + """ this_service = {'name': 'openstack-dashboard'} other_services = [{'name': 'keystone'}, {'name': 'mysql'}] - super(OpenstackDashboardBasicDeployment, self)._add_services(this_service, - other_services) + super(OpenstackDashboardBasicDeployment, + self)._add_services(this_service, other_services) def _add_relations(self): """Add all of the relations for the services.""" relations = { - 'openstack-dashboard:identity-service': 'keystone:identity-service', - 'keystone:shared-db': 'mysql:shared-db', + 'openstack-dashboard:identity-service': + 'keystone:identity-service', + 'keystone:shared-db': 'mysql:shared-db', } - super(OpenstackDashboardBasicDeployment, self)._add_relations(relations) + super(OpenstackDashboardBasicDeployment, + self)._add_relations(relations) def _configure_services(self): """Configure all of the services.""" @@ -72,7 +74,7 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): openstack_origin_git = { 'repositories': [ {'name': 'requirements', - 'repository': reqs_repo, + 'repository': reqs_repo, 'branch': branch}, {'name': 'horizon', 'repository': horizon_repo, @@ -82,7 +84,8 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): 'http_proxy': amulet_http_proxy, 'https_proxy': amulet_http_proxy, } - horizon_config['openstack-origin-git'] = yaml.dump(openstack_origin_git) + horizon_config['openstack-origin-git'] = \ + yaml.dump(openstack_origin_git) keystone_config = {'admin-password': 'openstack', 'admin-token': 'ubuntutesting'} @@ -90,99 +93,53 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): configs = {'openstack-dashboard': horizon_config, 'mysql': mysql_config, 'keystone': keystone_config} - super(OpenstackDashboardBasicDeployment, self)._configure_services(configs) + super(OpenstackDashboardBasicDeployment, + self)._configure_services(configs) def _initialize_tests(self): """Perform final initialization before tests get run.""" # Access the sentries for inspecting service units self.keystone_sentry = self.d.sentry.unit['keystone/0'] - self.openstack_dashboard_sentry = self.d.sentry.unit['openstack-dashboard/0'] + self.openstack_dashboard_sentry = \ + self.d.sentry.unit['openstack-dashboard/0'] - def test_services(self): - """Verify the expected services are running on the corresponding - service units.""" - dashboard_services = ['service apache2 status'] - - commands = { - self.keystone_sentry: ['status keystone'], - self.openstack_dashboard_sentry: dashboard_services - } - - ret = u.validate_services(commands) - if ret: - amulet.raise_status(amulet.FAIL, msg=ret) + u.log.debug('openstack release val: {}'.format( + self._get_openstack_release())) + u.log.debug('openstack release str: {}'.format( + self._get_openstack_release_string())) + # Let things settle a bit before moving forward + time.sleep(30) def crude_py_parse(self, file_contents, expected): for line in file_contents.split('\n'): if '=' in line: - args = line.split('=') - if len(args) <= 1: - continue - key = args[0].strip() - value = args[1].strip() - if key in expected.keys(): - if expected[key] != value: - msg="Mismatch %s != %s" % (expected[key], value) - amulet.raise_status(amulet.FAIL, msg=msg) + args = line.split('=') + if len(args) <= 1: + continue + key = args[0].strip() + value = args[1].strip() + if key in expected.keys(): + if expected[key] != value: + msg = "Mismatch %s != %s" % (expected[key], value) + amulet.raise_status(amulet.FAIL, msg=msg) + def test_100_services(self): + """Verify the expected services are running on the corresponding + service units.""" - def test_local_settings(self): - unit = self.openstack_dashboard_sentry - ksentry = self.keystone_sentry - conf = '/etc/openstack-dashboard/local_settings.py' - file_contents = unit.file_contents(conf) - rdata = ksentry.relation('identity-service', 'openstack-dashboard:identity-service') - expected = { - 'LOGIN_REDIRECT_URL': """'/horizon'""", - 'OPENSTACK_HOST': '"%s"' % (rdata['private-address']), - 'OPENSTACK_KEYSTONE_DEFAULT_ROLE': '"Member"' + services = { + self.keystone_sentry: ['keystone'], + self.openstack_dashboard_sentry: ['apache2'] } - self.crude_py_parse(file_contents, expected) - def test_router_settings(self): - if self.openstack > "icehouse": - unit = self.openstack_dashboard_sentry - conf = ('/usr/share/openstack-dashboard/openstack_dashboard/' - 'enabled/_40_router.py') - file_contents = unit.file_contents(conf) - expected = { - 'DISABLED': "True", - } - self.crude_py_parse(file_contents, expected) + ret = u.validate_services_by_name(services) + if ret: + amulet.raise_status(amulet.FAIL, msg=ret) - def test_connection(self): - unit = self.openstack_dashboard_sentry - dashboard_relation = unit.relation('identity-service', - 'keystone:identity-service') - dashboard_ip = dashboard_relation['private-address'] - response = urllib2.urlopen('http://%s/horizon' % (dashboard_ip)) - html = response.read() - if 'OpenStack Dashboard' not in html: - msg="Dashboard frontpage check failed" - amulet.raise_status(amulet.FAIL, msg=msg) - - def test_z_restart_on_config_change(self): - """Verify that the specified services are restarted when the config - is changed. - - Note(coreycb): The method name with the _z_ is a little odd - but it forces the test to run last. It just makes things - easier because restarting services requires re-authorization. - """ - conf = '/etc/openstack-dashboard/local_settings.py' - services = ['apache2'] - self.d.configure('openstack-dashboard', {'use-syslog': 'True'}) - time = 120 - for s in services: - if not u.service_restarted(self.openstack_dashboard_sentry, s, conf, - pgrep_full=True, sleep_time=time): - self.d.configure('openstack-dashboard', {'use-syslog': 'False'}) - msg = "service {} didn't restart after config change".format(s) - time = 0 - self.d.configure('openstack-dashboard', {'use-syslog': 'False'}) - - def test_openstack_dashboard_identity_service_relation(self): - """Verify the openstack-dashboard to keystone identity-service relation data.""" + def test_200_openstack_dashboard_identity_service_relation(self): + """Verify the openstack-dashboard to keystone identity-service + relation data.""" + u.log.debug('Checking dashboard:keystone id relation data...') unit = self.openstack_dashboard_sentry relation = ['identity-service', 'keystone:identity-service'] expected = { @@ -192,11 +149,14 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): ret = u.validate_relation_data(unit, relation, expected) if ret: - message = u.relation_error('openstack-dashboard identity-service', ret) + message = u.relation_error('openstack-dashboard identity-service', + ret) amulet.raise_status(amulet.FAIL, msg=message) - def test_keystone_identity_service_relation(self): - """Verify the keystone to openstack-dashboard identity-service relation data.""" + def test_202_keystone_identity_service_relation(self): + """Verify the keystone to openstack-dashboard identity-service + relation data.""" + u.log.debug('Checking keystone:dashboard id relation data...') unit = self.keystone_sentry relation = ['identity-service', 'openstack-dashboard:identity-service'] expected = { @@ -214,3 +174,76 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): if ret: message = u.relation_error('keystone identity-service', ret) amulet.raise_status(amulet.FAIL, msg=message) + + def test_300_local_settings(self): + u.log.debug('Checking dashboard local settings...') + unit = self.openstack_dashboard_sentry + ksentry = self.keystone_sentry + conf = '/etc/openstack-dashboard/local_settings.py' + file_contents = unit.file_contents(conf) + rdata = ksentry.relation('identity-service', + 'openstack-dashboard:identity-service') + expected = { + 'LOGIN_REDIRECT_URL': """'/horizon'""", + 'OPENSTACK_HOST': '"%s"' % (rdata['private-address']), + 'OPENSTACK_KEYSTONE_DEFAULT_ROLE': '"Member"' + } + self.crude_py_parse(file_contents, expected) + + def test_302_router_settings(self): + u.log.debug('Checking dashboard router settings...') + if self.openstack > "icehouse": + unit = self.openstack_dashboard_sentry + conf = ('/usr/share/openstack-dashboard/openstack_dashboard/' + 'enabled/_40_router.py') + file_contents = unit.file_contents(conf) + expected = { + 'DISABLED': "True", + } + self.crude_py_parse(file_contents, expected) + + def test_400_connection(self): + u.log.debug('Checking dashboard http response...') + unit = self.openstack_dashboard_sentry + dashboard_relation = unit.relation('identity-service', + 'keystone:identity-service') + dashboard_ip = dashboard_relation['private-address'] + response = urllib2.urlopen('http://%s/horizon' % (dashboard_ip)) + html = response.read() + if 'OpenStack Dashboard' not in html: + msg = "Dashboard frontpage check failed" + amulet.raise_status(amulet.FAIL, msg=msg) + + def test_900_restart_on_config_change(self): + """Verify that the specified services are restarted when the + config is changed.""" + + sentry = self.openstack_dashboard_sentry + juju_service = 'openstack-dashboard' + + # Expected default and alternate values + set_default = {'use-syslog': 'False'} + set_alternate = {'use-syslog': 'True'} + + # Config file affected by juju set config change + conf_file = '/etc/openstack-dashboard/local_settings.py' + + # Services which are expected to restart upon config change + services = ['apache2'] + + # Make config change, check for service restarts + u.log.debug('Making config change on {}...'.format(juju_service)) + self.d.configure(juju_service, set_alternate) + + sleep_time = 180 + for s in services: + u.log.debug("Checking that service restarted: {}".format(s)) + if not u.service_restarted(sentry, s, + conf_file, sleep_time=sleep_time, + pgrep_full=True): + self.d.configure(juju_service, set_default) + msg = "service {} didn't restart after config change".format(s) + amulet.raise_status(amulet.FAIL, msg=msg) + sleep_time = 0 + + self.d.configure(juju_service, set_default)