From 8a8e408d251346fa668931887931324a8f037bf6 Mon Sep 17 00:00:00 2001 From: ydehtiarov Date: Mon, 22 Aug 2016 15:08:50 +0300 Subject: [PATCH] Add ccp show dependency tests - Add ccp show-dep component tests - Add ccp show-dep error code tests - Add string helpers for simpler command execution result processing Change-Id: I84d3329060f225e91c2e5ace3ebbdf441824e794 --- fuel_ccp_tests/helpers/utils.py | 21 +- .../component/ccp/test_ccp_cli_messages.py | 222 ++++++++++++++++++ .../tests/system/test_ccp_errexit_codes.py | 33 +++ test-requirements.txt | 2 +- 4 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 fuel_ccp_tests/tests/component/ccp/test_ccp_cli_messages.py diff --git a/fuel_ccp_tests/helpers/utils.py b/fuel_ccp_tests/helpers/utils.py index 7440813..dc28539 100644 --- a/fuel_ccp_tests/helpers/utils.py +++ b/fuel_ccp_tests/helpers/utils.py @@ -25,7 +25,6 @@ import yaml from fuel_ccp_tests import logger from fuel_ccp_tests import settings - LOG = logger.logger @@ -35,7 +34,6 @@ def get_test_method_name(): def update_yaml(yaml_tree=None, yaml_value='', is_uniq=True, yaml_file=settings.TIMESTAT_PATH_YAML): - """Store/update a variable in YAML file. yaml_tree - path to the variable in YAML file, will be created if absent, @@ -122,6 +120,25 @@ class TimeStat(object): return time.time() - self.begin_time +def reduce_occurrences(items, text): + """ Return string without items(substrings) + Args: + items: iterable of strings + test: string + Returns: + string + Raise: + AssertionError if any substing not present in source text + """ + for item in items: + LOG.debug( + "Verifying string {} is shown in " + "\"\"\"\n{}\n\"\"\"".format(item, text)) + assert text.count(item) != 0 + text = text.replace(item, "", 1) + return text + + def generate_keys(): key = paramiko.RSAKey.generate(1024) public = key.get_base64() diff --git a/fuel_ccp_tests/tests/component/ccp/test_ccp_cli_messages.py b/fuel_ccp_tests/tests/component/ccp/test_ccp_cli_messages.py new file mode 100644 index 0000000..13e9bc1 --- /dev/null +++ b/fuel_ccp_tests/tests/component/ccp/test_ccp_cli_messages.py @@ -0,0 +1,222 @@ +# Copyright 2016 Mirantis, Inc. +# +# 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 pytest + +from fuel_ccp_tests.helpers import ext +from fuel_ccp_tests.helpers import utils +from fuel_ccp_tests.logger import logger + + +class CliMessages(object): + error_message = "ccp show-dep: error: too few arguments" + usage_message = "usage: ccp [-h] " + usage_show_dep_message = \ + "usage: ccp show-dep [-h] components [components ...]" + help_message = [ + "positional arguments:", + "components CCP components to show dependencies", + "optional arguments:", + "-h, --help show this help message and exit"] + error_message_bad_component_name = "Wrong component name '{}'" + error_message_unrecognized_arguments = \ + "ccp: error: unrecognized arguments: {}" + + +@pytest.yield_fixture(scope='module') +def admin_node(config, underlay, ccpcluster): + logger.info("Get SSH access to admin node") + with underlay.remote(host=config.k8s.kube_host) as remote: + yield remote + + +@pytest.mark.revert_snapshot(ext.SNAPSHOT.ccp_deployed) +class TestCppCliNormalMessageInShowDep(object): + """Check info messages when show-dep is success""" + + @pytest.mark.fail_snapshot + def test_component_have_single_dependency(self, admin_node): + """Test for ccp show-dep with component having single dependency + + Scenario: + 1. exec ccp show-dep memcached + 2. Verify that only etcd component name returned + """ + logger.info("Show info for component with single dependency") + component = ["memcached"] + dependencies = ["etcd"] + cmd = "ccp show-dep {}".format(component[0]) + result = admin_node.check_call(cmd, expected=[0]) + result_no_fetch = filter( + lambda s: "fuel_ccp.fetch" not in s, result['stdout']) + result_normalized = \ + " ".join(result_no_fetch).replace("\n", " ").strip().split(' ') + assert set(dependencies) == set(result_normalized) + + @pytest.mark.fail_snapshot + def test_component_have_multiple_dependencies(self, admin_node): + """Test for ccp show-dep with component having multiple dependencies + + Scenario: + 1. exec ccp show-dep keystone + 2. Verify that only etcd and mariadn component names are returned + """ + logger.info("Show info for component with multiple dependencies") + component = ["keystone"] + dependencies = ["mariadb", "etcd"] + cmd = "ccp show-dep {}".format(component[0]) + result = admin_node.check_call(cmd, expected=[0]) + result_no_fetch = filter( + lambda s: "fuel_ccp.fetch" not in s, result['stdout']) + result_normalized = \ + " ".join(result_no_fetch).replace("\n", " ").strip().split(' ') + assert set(dependencies) == set(result_normalized) + + @pytest.mark.fail_snapshot + def test_component_have_no_dependencies(self, admin_node): + """Test for ccp show-dep with component having no dependencies + + Scenario: + 1. exec ccp show-dep etcd + 2. Verify that no component names returned + """ + logger.info("Show info for component without dependencies") + component = ["etcd"] + dependencies = [""] + cmd = "ccp show-dep {}".format(component[0]) + result = admin_node.check_call(cmd, expected=[0]) + result_no_fetch = filter( + lambda s: "fuel_ccp.fetch" not in s, result['stdout']) + result_normalized = \ + " ".join(result_no_fetch).replace("\n", " ").strip().split(' ') + assert set(dependencies) == set(result_normalized) + + @pytest.mark.fail_snapshot + def test_component_help_message_via_short(self, admin_node): + """Test for help message with short option + + Scenario: + 1. exec ccp show-dep -h + 2. Verify ccp show-dep help message returned + """ + logger.info("Show help message with short option") + cmd = "ccp show-dep -h" + result = admin_node.check_call(cmd, expected=[0]) + assert len(utils.reduce_occurrences( + [CliMessages.usage_show_dep_message] + CliMessages.help_message, + " ".join(result['stdout'])).strip()) == 0 + + @pytest.mark.fail_snapshot + def test_component_help_message_via_long(self, admin_node): + """Test for help message with long option + + Scenario: + 1. exec ccp show-dep --help + 2. Verify ccp show-dep help message returned + """ + logger.info("Show help message with long option") + cmd = "ccp show-dep --help" + result = admin_node.check_call(cmd, expected=[0]) + assert len(utils.reduce_occurrences( + [CliMessages.usage_show_dep_message] + CliMessages.help_message, + " ".join(result['stdout'])).strip()) == 0 + + @pytest.mark.fail_snapshot + def test_multiple_components_given(self, admin_node): + """Test for ccp show-dep multiple components(no cross-referenced) + + Scenario: + 1. exec ccp show-dep keystone memcached + 2. Verify that only mariadb and etcd component names returned + """ + logger.info( + "Show info for several components" + " with dependencies no cross-referenced") + component = ["keystone", "memcached"] + dependencies = ["mariadb", "etcd"] + cmd = "ccp show-dep {}".format(" ".join(component)) + result = admin_node.check_call(cmd, expected=[0]) + result_no_fetch = filter( + lambda s: "fuel_ccp.fetch" not in s, result['stdout']) + result_normalized = \ + " ".join(result_no_fetch).replace("\n", " ").strip().split(' ') + assert set(dependencies) == set(result_normalized) + + @pytest.mark.fail_snapshot + def test_multiple_components_given_cross_reference(self, admin_node): + """Test for ccp show-dep multiple components(cross-referenced) + + Scenario: + 1. exec ccp show-dep keystone etcd + 2. Verify that only mariadb component name returned + """ + logger.info( + "Show info for component with multiple dependencies with" + "cross referenced dependecies") + component = ["keystone", "etcd"] + dependencies = ["mariadb"] + cmd = "ccp show-dep {}".format(" ".join(component)) + result = admin_node.check_call(cmd, expected=[0]) + result_no_fetch = filter( + lambda s: "fuel_ccp.fetch" not in s, result['stdout']) + result_normalized = \ + " ".join(result_no_fetch).replace("\n", " ").strip().split(' ') + assert set(dependencies) == set(result_normalized) + + +@pytest.mark.revert_snapshot(ext.SNAPSHOT.ccp_deployed) +class TestCppCliErrorMessageInShowDep(object): + """Check error messages when show-dep is failing""" + + @pytest.mark.fail_snapshot + def test_nonexistent_component_given(self, admin_node): + """Test for ccp show-dep non-existent component + + Scenario: + 1. exec ccp show-dep wrong_component + 2. Verify exit code is 1 + 3. Verify message "Wrong component name 'wrong_component' displayed + """ + logger.info("Show error message for nonexistent component name") + component = ["wrong_component"] + expected = 1 + error_message = CliMessages.error_message_bad_component_name.format( + component[0]) + cmd = "ccp show-dep {}".format(component[0]) + result = admin_node.check_call(cmd, expected=[expected]) + assert error_message in " ".join(result['stderr']) + + @pytest.mark.fail_snapshot + def test_no_components_given(self, admin_node): + """Test for ccp show-dep no components + + Scenario: + 1. exec ccp show-dep wrong_component + 2. Verify exit code is 2 + 3. Verify message "ccp show-dep: error: too few arguments' is shown + 4. Verify ccp show-dep usage message displayed + 5. Verify that no output in stdout + """ + logger.info("Show error message for no component") + cmd = "ccp show-dep" + expected = 2 + result = admin_node.check_call(cmd, expected=[expected]) + assert len( + utils.reduce_occurrences( + [CliMessages.error_message, + CliMessages.usage_show_dep_message], + "".join( + result['stderr'])).strip()) == 0 + assert len( + " ".join(result['stdout']).strip()) == 0 diff --git a/fuel_ccp_tests/tests/system/test_ccp_errexit_codes.py b/fuel_ccp_tests/tests/system/test_ccp_errexit_codes.py index 7172e93..0457c2c 100644 --- a/fuel_ccp_tests/tests/system/test_ccp_errexit_codes.py +++ b/fuel_ccp_tests/tests/system/test_ccp_errexit_codes.py @@ -103,3 +103,36 @@ class TestCppCliDeploy(object): cmd = 'ccp deploy --components example' admin_node.check_call(cmd, expected=[1], verbose=True) clean_repos(admin_node) + + +class TestCppCliErrorInShowDep(object): + """Check exit codes when show-dep is failing""" + + @pytest.mark.ccp_cli_errexit_codes + @pytest.mark.ccp_cli_deploy_exit_code + @pytest.mark.revert_snapshot(ext.SNAPSHOT.ccp_deployed) + def test_nonexistent_component_given(self, admin_node): + """Test for ccp show-dep with non existing component exit code + Scenario: + 1. exec ccp show-dep wrong_component + 2. Verify that exit code 1 + """ + logger.info("Error code for nonexistent component name") + component = ["wrong_component"] + expected = 1 + cmd = "ccp show-dep {}".format(component[0]) + admin_node.check_call(cmd, expected=[expected]) + + @pytest.mark.ccp_cli_errexit_codes + @pytest.mark.ccp_cli_deploy_exit_code + @pytest.mark.revert_snapshot(ext.SNAPSHOT.ccp_deployed) + def test_no_components_given(self, admin_node): + """Test for ccp show-dep with no component given + Scenario: + 1. exec ccp show-dep + 2. Verify that exit code 2 + """ + logger.info("Error code for no component") + cmd = "ccp show-dep" + expected = 2 + admin_node.check_call(cmd, expected=[expected]) diff --git a/test-requirements.txt b/test-requirements.txt index 6d5294e..816c131 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -3,4 +3,4 @@ doc8 oslosphinx>=2.5.0,!=3.4.0 # Apache-2.0 sphinx>=1.2.1,!=1.3b1,<1.3 # BSD -hacking>=0.10.2 +hacking>=0.10.2 \ No newline at end of file