diff --git a/setup.cfg b/setup.cfg index 0b271c4..771d0b7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,7 +26,7 @@ packages = console_scripts = watcher = watcherclient.shell:main tempest.test_plugins = - watcherclient_tests = watcherclient.tests.functional.plugin:WatcherClientTempestPlugin + watcherclient_tests = watcherclient.plugin:WatcherClientTempestPlugin openstack.cli.extension = infra_optim = watcherclient.osc.plugin diff --git a/watcherclient/tests/functional/config.py b/watcherclient/config.py similarity index 100% rename from watcherclient/tests/functional/config.py rename to watcherclient/config.py diff --git a/watcherclient/tests/functional/plugin.py b/watcherclient/plugin.py similarity index 90% rename from watcherclient/tests/functional/plugin.py rename to watcherclient/plugin.py index 30339bd..a8f78e4 100644 --- a/watcherclient/tests/functional/plugin.py +++ b/watcherclient/plugin.py @@ -15,14 +15,14 @@ import os from tempest.test_discover import plugins -from watcherclient.tests.functional import config as watcher_config +from watcherclient import config as watcher_config class WatcherClientTempestPlugin(plugins.TempestPlugin): def load_tests(self): base_path = os.path.split(os.path.dirname( os.path.abspath(__file__)))[0] - test_dir = "watcherclient/tests/functional" + test_dir = "watcherclient/tests/functional/v1" full_test_dir = os.path.join(base_path, test_dir) return full_test_dir, base_path diff --git a/watcherclient/tests/functional/hooks/post_test_hook.sh b/watcherclient/tests/functional/hooks/post_test_hook.sh deleted file mode 100755 index 9c82a80..0000000 --- a/watcherclient/tests/functional/hooks/post_test_hook.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -xe - -# 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. - -# This script is executed inside post_test_hook function in devstack gate. - -# Default gate uses /opt/stack/new... but some of us may install differently -STACK_DIR=$BASE/new/devstack - -function generate_testr_results { - if [ -f .testrepository/0 ]; then - sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit - sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit - sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html - sudo gzip -9 $BASE/logs/testrepository.subunit - sudo gzip -9 $BASE/logs/testr_results.html - sudo chown $USER:$USER $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz - sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz - fi -} - -export WATCHERCLIENT_DIR="$BASE/new/python-watcherclient" - -sudo chown -R $USER:stack $WATCHERCLIENT_DIR - -# Get admin credentials -cd $STACK_DIR -source openrc admin admin - -# Go to the watcherclient dir -cd $WATCHERCLIENT_DIR - -# Run tests -echo "Running watcherclient functional test suite" -set +e -# Preserve env for OS_ credentials -sudo -E -H -u $USER tox -efunctional -EXIT_CODE=$? -set -e - -# Collect and parse result -generate_testr_results -exit $EXIT_CODE \ No newline at end of file diff --git a/watcherclient/tests/functional/v1/base.py b/watcherclient/tests/functional/v1/base.py index 24006b6..229a16d 100644 --- a/watcherclient/tests/functional/v1/base.py +++ b/watcherclient/tests/functional/v1/base.py @@ -18,22 +18,31 @@ import subprocess import testtools import six +from tempest import clients +from tempest.common import credentials_factory as creds_factory from tempest.lib.cli import output_parser from tempest.lib import exceptions def credentials(): - creds = { - '--os-username': os.environ.get('OS_USERNAME', 'admin'), - '--os-password': os.environ.get('OS_PASSWORD', 'secretadmin'), - '--os-project-name': os.environ.get('OS_PROJECT_NAME', 'admin'), + # You can get credentials either from tempest.conf file or + # from OS environment. + tempest_creds = clients.get_auth_provider( + creds_factory.get_configured_admin_credentials()) + creds = tempest_creds.credentials + creds_dict = { + '--os-username': os.environ.get('OS_USERNAME', creds.username), + '--os-password': os.environ.get('OS_PASSWORD', creds.password), + '--os-project-name': os.environ.get('OS_PROJECT_NAME', + creds.project_name), '--os-auth-url': os.environ.get('OS_AUTH_URL', - 'http://10.0.1.94/identity'), - '--os-project-domain-id': os.environ.get('OS_PROJECT_DOMAIN_ID', - 'default'), - '--os-user-domain-id': os.environ.get('OS_USER_DOMAIN_ID', 'default'), + tempest_creds.auth_url), + '--os-project-domain-name': os.environ.get('OS_PROJECT_DOMAIN_ID', + creds.project_domain_name), + '--os-user-domain-name': os.environ.get('OS_USER_DOMAIN_ID', + creds.user_domain_name), } - return [x for sub in creds.items() for x in sub] + return [x for sub in creds_dict.items() for x in sub] def execute(cmd, fail_ok=False, merge_stderr=False): @@ -123,3 +132,13 @@ class TestCase(testtools.TestCase): def parse_listing(self, raw_output): """Return list of dicts with basic item parsed from cli output.""" return output_parser.listing(raw_output) + + def has_actionplan_succeeded(self, ap_uuid): + return self.parse_show_as_object( + self.watcher('actionplan show %s' % ap_uuid) + )['State'] == 'SUCCEEDED' + + @classmethod + def has_audit_created(cls, audit_uuid): + return cls.parse_show_as_object( + cls.watcher('audit show %s' % audit_uuid))['State'] == 'SUCCEEDED' diff --git a/watcherclient/tests/functional/v1/test_action.py b/watcherclient/tests/functional/v1/test_action.py index 042aec8..03f0ca0 100644 --- a/watcherclient/tests/functional/v1/test_action.py +++ b/watcherclient/tests/functional/v1/test_action.py @@ -15,6 +15,10 @@ from oslo_utils import uuidutils +import functools + +from tempest.lib.common.utils import test_utils + from watcherclient.tests.functional.v1 import base @@ -33,17 +37,22 @@ class ActionTests(base.TestCase): template_raw_output = cls.watcher( 'audittemplate create %s dummy -s dummy' % cls.audit_template_name) template_output = cls.parse_show_as_object(template_raw_output) - audit_raw_output = cls.watcher( - 'audit create -a %s' % template_output['Name']) - audit_output = cls.parse_show_as_object(audit_raw_output) + audit_output = cls.parse_show_as_object(cls.watcher( + 'audit create -a %s' % template_output['Name'])) cls.audit_uuid = audit_output['UUID'] + audit_created = test_utils.call_until_true( + func=functools.partial(cls.has_audit_created, cls.audit_uuid), + duration=600, + sleep_for=2) + if not audit_created: + raise Exception('Audit has not been succeeded') @classmethod def tearDownClass(cls): # Delete Action Plan and all related actions. output = cls.parse_show( cls.watcher('actionplan list --audit %s' % cls.audit_uuid)) - action_plan_uuid = output[0].keys()[0] + action_plan_uuid = list(output[0])[0] raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid) cls.assertOutput('', raw_output) # Delete audit @@ -63,9 +72,10 @@ class ActionTests(base.TestCase): self.assert_table_structure([raw_output], self.detailed_list_fields) def test_action_show(self): - action_list = self.parse_show(self.watcher('action list')) - action_uuid = action_list[0].keys()[0] - action = self.watcher('action show ' + action_uuid) + action_list = self.parse_show(self.watcher('action list --audit %s' + % self.audit_uuid)) + action_uuid = list(action_list[0])[0] + action = self.watcher('action show %s' % action_uuid) self.assertIn(action_uuid, action) self.assert_table_structure([action], self.detailed_list_fields) diff --git a/watcherclient/tests/functional/v1/test_action_plan.py b/watcherclient/tests/functional/v1/test_action_plan.py index c974db7..f38c02d 100644 --- a/watcherclient/tests/functional/v1/test_action_plan.py +++ b/watcherclient/tests/functional/v1/test_action_plan.py @@ -13,10 +13,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import time - from oslo_utils import uuidutils +import functools + +from tempest.lib.common.utils import test_utils + from watcherclient.tests.functional.v1 import base @@ -39,22 +41,19 @@ class ActionPlanTests(base.TestCase): % template_output['Name']) audit_output = cls.parse_show_as_object(audit_raw_output) cls.audit_uuid = audit_output['UUID'] + audit_created = test_utils.call_until_true( + func=functools.partial(cls.has_audit_created, cls.audit_uuid), + duration=600, + sleep_for=2) + if not audit_created: + raise Exception('Audit has not been succeeded') @classmethod def tearDownClass(cls): # Delete action plan output = cls.parse_show( cls.watcher('actionplan list --audit %s' % cls.audit_uuid)) - action_plan_uuid = output[0].keys()[0] - retry = 10 - while retry > 0: - output = cls.parse_show( - cls.watcher('actionplan show %s' % action_plan_uuid)) - state = [x for x in output if x.keys()[0] == 'State'][0]['State'] - if state == 'SUCCEEDED': - break - time.sleep(1) - retry -= 1 + action_plan_uuid = list(output[0])[0] raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid) cls.assertOutput('', raw_output) # Delete audit @@ -75,7 +74,7 @@ class ActionPlanTests(base.TestCase): def test_action_plan_show(self): action_plan_list = self.parse_show(self.watcher('actionplan list')) - action_plan_uuid = action_plan_list[0].keys()[0] + action_plan_uuid = list(action_plan_list[0])[0] actionplan = self.watcher('actionplan show %s' % action_plan_uuid) self.assertIn(action_plan_uuid, actionplan) self.assert_table_structure([actionplan], @@ -84,11 +83,18 @@ class ActionPlanTests(base.TestCase): def test_action_plan_start(self): output = self.parse_show(self.watcher('actionplan list --audit %s' % self.audit_uuid)) - action_plan_uuid = output[0].keys()[0] + action_plan_uuid = list(output[0])[0] self.watcher('actionplan start %s' % action_plan_uuid) raw_output = self.watcher('actionplan show %s' % action_plan_uuid) self.assert_table_structure([raw_output], self.detailed_list_fields) + self.assertTrue(test_utils.call_until_true( + func=functools.partial( + self.has_actionplan_succeeded, action_plan_uuid), + duration=600, + sleep_for=2 + )) + class ActionPlanActiveTests(base.TestCase): @@ -100,9 +106,15 @@ class ActionPlanActiveTests(base.TestCase): 'Strategy', 'Efficacy indicators'] def _delete_action_plan(self): + self.assertTrue(test_utils.call_until_true( + func=functools.partial( + self.has_audit_created, self.audit_uuid), + duration=600, + sleep_for=2 + )) output = self.parse_show( self.watcher('actionplan list --audit %s' % self.audit_uuid)) - action_plan_uuid = output[0].keys()[0] + action_plan_uuid = list(output[0])[0] raw_output = self.watcher('actionplan delete %s' % action_plan_uuid) self.assertOutput('', raw_output) diff --git a/watcherclient/tests/functional/v1/test_audit.py b/watcherclient/tests/functional/v1/test_audit.py index 11b26e3..c545b08 100644 --- a/watcherclient/tests/functional/v1/test_audit.py +++ b/watcherclient/tests/functional/v1/test_audit.py @@ -15,6 +15,10 @@ from oslo_utils import uuidutils +import functools + +from tempest.lib.common.utils import test_utils + from watcherclient.tests.functional.v1 import base @@ -44,7 +48,7 @@ class AuditTests(base.TestCase): def tearDownClass(cls): output = cls.parse_show( cls.watcher('actionplan list --audit %s' % cls.audit_uuid)) - action_plan_uuid = output[0].keys()[0] + action_plan_uuid = list(output[0])[0] cls.watcher('actionplan delete %s' % action_plan_uuid) cls.watcher('audit delete %s' % cls.audit_uuid) cls.watcher('audittemplate delete %s' % cls.audit_template_name) @@ -76,39 +80,51 @@ class AuditActiveTests(base.TestCase): 'Deleted At', 'Parameters', 'Interval', 'Audit Scope'] audit_template_name = 'a' + uuidutils.generate_uuid() - audit_uuid = None + + @classmethod + def setUpClass(cls): + cls.watcher('audittemplate create %s dummy -s dummy' + % cls.audit_template_name) + + @classmethod + def tearDownClass(cls): + cls.watcher('audittemplate delete %s' % cls.audit_template_name) def _create_audit(self): - raw_output = self.watcher('audittemplate create %s dummy -s dummy' - % self.audit_template_name) - template_output = self.parse_show_as_object(raw_output) - self.audit_uuid = self.parse_show_as_object( + return self.parse_show_as_object( self.watcher('audit create -a %s' - % template_output['Name']))['UUID'] + % self.audit_template_name))['UUID'] - def _delete_audit(self): + def _delete_audit(self, audit_uuid): + self.assertTrue(test_utils.call_until_true( + func=functools.partial( + self.has_audit_created, audit_uuid), + duration=600, + sleep_for=2 + )) output = self.parse_show( - self.watcher('actionplan list --audit %s' % self.audit_uuid)) - action_plan_uuid = output[0].keys()[0] + self.watcher('actionplan list --audit %s' % audit_uuid)) + action_plan_uuid = list(output[0])[0] self.watcher('actionplan delete %s' % action_plan_uuid) - self.watcher('audit delete %s' % self.audit_uuid) - self.watcher('audittemplate delete %s' % self.audit_template_name) + self.watcher('audit delete %s' % audit_uuid) def test_create_audit(self): - raw_output = self.watcher('audittemplate create %s dummy -s dummy' - % self.audit_template_name) - template_output = self.parse_show_as_object(raw_output) - audit = self.watcher('audit create -a %s' % template_output['Name']) - self.audit_uuid = self.parse_show_as_object(audit)['UUID'] + audit = self.watcher('audit create -a %s' % self.audit_template_name) + audit_uuid = self.parse_show_as_object(audit)['UUID'] self.assert_table_structure([audit], self.detailed_list_fields) - self._delete_audit() + self._delete_audit(audit_uuid) def test_delete_audit(self): - self._create_audit() - raw_output = self.watcher('audit delete %s' % self.audit_uuid) + audit_uuid = self._create_audit() + self.assertTrue(test_utils.call_until_true( + func=functools.partial( + self.has_audit_created, audit_uuid), + duration=600, + sleep_for=2 + )) + raw_output = self.watcher('audit delete %s' % audit_uuid) self.assertOutput('', raw_output) output = self.parse_show( - self.watcher('actionplan list --audit %s' % self.audit_uuid)) - action_plan_uuid = output[0].keys()[0] + self.watcher('actionplan list --audit %s' % audit_uuid)) + action_plan_uuid = list(output[0])[0] self.watcher('actionplan delete %s' % action_plan_uuid) - self.watcher('audittemplate delete %s' % self.audit_template_name) diff --git a/watcherclient/tests/functional/v1/test_service.py b/watcherclient/tests/functional/v1/test_service.py index e8e6eac..d943a6b 100644 --- a/watcherclient/tests/functional/v1/test_service.py +++ b/watcherclient/tests/functional/v1/test_service.py @@ -37,6 +37,8 @@ class ServiceTests(base.TestCase): self.list_fields + ['Last seen up']) def test_service_show(self): + # TODO(alexchadin): this method should be refactored since Watcher will + # get HA support soon. raw_output = self.watcher('service show %s' % self.decision_engine_name) self.assertIn(self.decision_engine_name, raw_output)