diff --git a/README.rst b/README.rst index ba93712d35..94a5352e9e 100644 --- a/README.rst +++ b/README.rst @@ -18,7 +18,7 @@ Tempest Design Principles that we strive to live by. incorrect assessment of their cloud. Explicit is always better. - Tempest uses OpenStack public interfaces. Tests in Tempest should only touch public interfaces, API calls (native or 3rd party), - public CLI or libraries. + or libraries. - Tempest should not touch private or implementation specific interfaces. This means not directly going to the database, not directly hitting the hypervisors, not testing extensions not diff --git a/doc/source/field_guide/cli.rst b/doc/source/field_guide/cli.rst deleted file mode 120000 index 13caef51b8..0000000000 --- a/doc/source/field_guide/cli.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/cli/README.rst \ No newline at end of file diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample index 2a72635907..c1b5146ecd 100644 --- a/etc/tempest.conf.sample +++ b/etc/tempest.conf.sample @@ -201,27 +201,6 @@ #build_interval = 1 -[cli] - -# -# From tempest.config -# - -# enable cli tests (boolean value) -#enabled = true - -# directory where python client binaries are located (string value) -#cli_dir = /usr/local/bin - -# Whether the tempest run location has access to the *-manage -# commands. In a pure blackbox environment it will not. (boolean -# value) -#has_manage = true - -# Number of seconds to wait on a CLI timeout (integer value) -#timeout = 15 - - [compute] # diff --git a/requirements.txt b/requirements.txt index 174c7c80e5..3a32b696b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,10 +9,8 @@ testtools>=0.9.36,!=1.2.0 boto>=2.32.1 paramiko>=1.13.0 netaddr>=0.7.12 -python-glanceclient>=0.15.0 -python-cinderclient>=1.1.0 -python-heatclient>=0.3.0 testrepository>=0.0.18 +pyOpenSSL>=0.11 oslo.concurrency>=1.8.0,<1.9.0 # Apache-2.0 oslo.config>=1.9.3,<1.10.0 # Apache-2.0 oslo.i18n>=1.5.0,<1.6.0 # Apache-2.0 @@ -24,3 +22,4 @@ iso8601>=0.1.9 fixtures>=0.3.14 testscenarios>=0.4 tempest-lib>=0.5.0 +PyYAML>=3.1.0 diff --git a/tempest/README.rst b/tempest/README.rst index d28c3f9c78..fec28740ec 100644 --- a/tempest/README.rst +++ b/tempest/README.rst @@ -14,7 +14,6 @@ to make this clear. | tempest/ | api/ - API tests -| cli/ - CLI tests | scenario/ - complex scenario tests | stress/ - stress tests | thirdparty/ - 3rd party api tests @@ -38,16 +37,6 @@ projects themselves, possibly as functional tests in their unit test frameworks. -:ref:`cli_field_guide` ----------------------- - -CLI tests use the openstack CLI to interact with the OpenStack -cloud. CLI testing in unit tests is somewhat difficult because unlike -server testing, there is no access to server code to -instantiate. Tempest seems like a logical place for this, as it -prereqs having a running OpenStack cloud. - - :ref:`scenario_field_guide` --------------------------- diff --git a/tempest/cli/README.rst b/tempest/cli/README.rst deleted file mode 100644 index bc180843d4..0000000000 --- a/tempest/cli/README.rst +++ /dev/null @@ -1,50 +0,0 @@ -.. _cli_field_guide: - -Tempest Field Guide to CLI tests -================================ - - -What are these tests? ---------------------- -The cli tests test the various OpenStack command line interface tools -to ensure that they minimally function. The current scope is read only -operations on a cloud that are hard to test via unit tests. - - -Why are these tests in tempest? -------------------------------- -These tests exist here because it is extremely difficult to build a -functional enough environment in the python-\*client unit tests to -provide this kind of testing. Because we already put up a cloud in the -gate with devstack + tempest it was decided it was better to have -these as a side tree in tempest instead of another QA effort which -would split review time. - - -Scope of these tests --------------------- -This should stay limited to the scope of testing the cli. Functional -testing of the cloud should be elsewhere, this is about exercising the -cli code. - - -Example of a good test ----------------------- -Tests should be isolated to a single command in one of the python -clients. - -Tests should not modify the cloud. - -If a test is validating the cli for bad data, it should do it with -assertRaises. - -A reasonable example of an existing test is as follows:: - - def test_admin_list(self): - self.nova('list') - self.nova('list', params='--all-tenants 1') - self.nova('list', params='--all-tenants 0') - self.assertRaises(subprocess.CalledProcessError, - self.nova, - 'list', - params='--all-tenants bad') diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py deleted file mode 100644 index 6733204736..0000000000 --- a/tempest/cli/__init__.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# 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 functools - -from tempest_lib.cli import base -from tempest_lib.cli import output_parser -import testtools - -from tempest.common import credentials -from tempest import config -from tempest import exceptions -from tempest.openstack.common import versionutils -from tempest import test - - -CONF = config.CONF - - -def check_client_version(client, version): - """Checks if the client's version is compatible with the given version - - @param client: The client to check. - @param version: The version to compare against. - @return: True if the client version is compatible with the given version - parameter, False otherwise. - """ - current_version = base.execute(client, '', params='--version', - merge_stderr=True, cli_dir=CONF.cli.cli_dir) - - if not current_version.strip(): - raise exceptions.TempestException('"%s --version" output was empty' % - client) - - return versionutils.is_compatible(version, current_version, - same_major=False) - - -def min_client_version(*args, **kwargs): - """A decorator to skip tests if the client used isn't of the right version. - - @param client: The client command to run. For python-novaclient, this is - 'nova', for python-cinderclient this is 'cinder', etc. - @param version: The minimum version required to run the CLI test. - """ - def decorator(func): - @functools.wraps(func) - def wrapper(*func_args, **func_kwargs): - if not check_client_version(kwargs['client'], kwargs['version']): - msg = "requires %s client version >= %s" % (kwargs['client'], - kwargs['version']) - raise testtools.TestCase.skipException(msg) - return func(*func_args, **func_kwargs) - return wrapper - return decorator - - -class ClientTestBase(test.BaseTestCase): - - @classmethod - def skip_checks(cls): - super(ClientTestBase, cls).skip_checks() - if not CONF.identity_feature_enabled.api_v2: - raise cls.skipException("CLI clients rely on identity v2 API, " - "which is configured as not available") - - @classmethod - def resource_setup(cls): - if not CONF.cli.enabled: - msg = "cli testing disabled" - raise cls.skipException(msg) - super(ClientTestBase, cls).resource_setup() - cls.isolated_creds = credentials.get_isolated_credentials(cls.__name__) - cls.creds = cls.isolated_creds.get_admin_creds() - - def _get_clients(self): - clients = base.CLIClient(self.creds.username, - self.creds.password, - self.creds.tenant_name, - CONF.identity.uri, CONF.cli.cli_dir) - return clients - - # TODO(mtreinish): The following code is basically copied from tempest-lib. - # The base cli test class in tempest-lib 0.0.1 doesn't work as a mixin like - # is needed here. The code below should be removed when tempest-lib - # provides a way to provide this functionality - def setUp(self): - super(ClientTestBase, self).setUp() - self.clients = self._get_clients() - self.parser = output_parser - - def assertTableStruct(self, items, field_names): - """Verify that all items has keys listed in field_names. - - :param items: items to assert are field names in the output table - :type items: list - :param field_names: field names from the output table of the cmd - :type field_names: list - """ - for item in items: - for field in field_names: - self.assertIn(field, item) - - def assertFirstLineStartsWith(self, lines, beginning): - """Verify that the first line starts with a string - - :param lines: strings for each line of output - :type lines: list - :param beginning: verify this is at the beginning of the first line - :type beginning: string - """ - self.assertTrue(lines[0].startswith(beginning), - msg=('Beginning of first line has invalid content: %s' - % lines[:3])) diff --git a/tempest/cli/simple_read_only/README.txt b/tempest/cli/simple_read_only/README.txt deleted file mode 100644 index ca5fa2f6f2..0000000000 --- a/tempest/cli/simple_read_only/README.txt +++ /dev/null @@ -1 +0,0 @@ -This directory consists of simple read only python client tests. diff --git a/tempest/cli/simple_read_only/__init__.py b/tempest/cli/simple_read_only/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml b/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml deleted file mode 100644 index 7dcda396a5..0000000000 --- a/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml +++ /dev/null @@ -1,18 +0,0 @@ -HeatTemplateFormatVersion: '2012-12-12' -Description: Minimal template to test validation -Parameters: - InstanceImage: - Description: Glance image name - Type: String - InstanceType: - Description: Nova instance type - Type: String - Default: m1.small - AllowedValues: [m1.tiny, m1.small, m1.medium, m1.large, m1.nano, m1.xlarge, m1.micro] - ConstraintDescription: must be a valid nova instance type. -Resources: - InstanceResource: - Type: OS::Nova::Server - Properties: - flavor: {Ref: InstanceType} - image: {Ref: InstanceImage} diff --git a/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml b/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml deleted file mode 100644 index 4657bfcd1d..0000000000 --- a/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml +++ /dev/null @@ -1,19 +0,0 @@ -heat_template_version: 2013-05-23 -description: A minimal HOT test template -parameters: - instance_image: - description: Glance image name - type: string - instance_type: - description: Nova instance type - type: string - default: m1.small - constraints: - - allowed_values: [m1.small, m1.medium, m1.large] - description: instance_type must be one of m1.small, m1.medium or m1.large -resources: - instance: - type: OS::Nova::Server - properties: - image: { get_param: instance_image } - flavor: { get_param: instance_type } diff --git a/tempest/cli/simple_read_only/image/__init__.py b/tempest/cli/simple_read_only/image/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tempest/cli/simple_read_only/image/test_glance.py b/tempest/cli/simple_read_only/image/test_glance.py deleted file mode 100644 index e38ca483e7..0000000000 --- a/tempest/cli/simple_read_only/image/test_glance.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# 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 re - -from oslo_log import log as logging -from tempest_lib import exceptions - -from tempest import cli -from tempest import config -from tempest import test - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class SimpleReadOnlyGlanceClientTest(cli.ClientTestBase): - """Basic, read-only tests for Glance CLI client. - - Checks return values and output of read-only commands. - These tests do not presume any content, nor do they create - their own. They only verify the structure of output if present. - """ - - @classmethod - def resource_setup(cls): - if not CONF.service_available.glance: - msg = ("%s skipped as Glance is not available" % cls.__name__) - raise cls.skipException(msg) - super(SimpleReadOnlyGlanceClientTest, cls).resource_setup() - - def glance(self, *args, **kwargs): - return self.clients.glance(*args, - endpoint_type=CONF.image.endpoint_type, - **kwargs) - - @test.idempotent_id('c6bd9bf9-717f-4458-8d74-05b682ea7adf') - def test_glance_fake_action(self): - self.assertRaises(exceptions.CommandFailed, - self.glance, - 'this-does-not-exist') - - @test.idempotent_id('72bcdaf3-11cd-48cb-bb8e-62b329acc1ef') - def test_glance_image_list(self): - out = self.glance('image-list') - endpoints = self.parser.listing(out) - self.assertTableStruct(endpoints, [ - 'ID', 'Name', 'Disk Format', 'Container Format', - 'Size', 'Status']) - - @test.idempotent_id('965d294c-8772-4899-ba33-26ee23406135') - def test_glance_member_list(self): - tenant_name = '--tenant-id %s' % CONF.identity.admin_tenant_name - out = self.glance('member-list', - params=tenant_name) - endpoints = self.parser.listing(out) - self.assertTableStruct(endpoints, - ['Image ID', 'Member ID', 'Can Share']) - - @test.idempotent_id('43b80ee5-4297-47f3-ab4c-6f81b9c6edb3') - def test_glance_help(self): - help_text = self.glance('help') - lines = help_text.split('\n') - self.assertFirstLineStartsWith(lines, 'usage: glance') - - commands = [] - cmds_start = lines.index('Positional arguments:') - cmds_end = lines.index('Optional arguments:') - command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)') - for line in lines[cmds_start:cmds_end]: - match = command_pattern.match(line) - if match: - commands.append(match.group(1)) - commands = set(commands) - wanted_commands = set(('image-create', 'image-delete', 'help', - 'image-download', 'image-show', 'image-update', - 'member-create', 'member-delete', - 'member-list', 'image-list')) - self.assertFalse(wanted_commands - commands) - - # Optional arguments: - - @test.idempotent_id('3b2359ea-3719-4b47-81e5-44a042572b11') - def test_glance_version(self): - self.glance('', flags='--version') - - @test.idempotent_id('1a52d3bd-3edf-4d67-b3da-999a5d9e0c5e') - def test_glance_debug_list(self): - self.glance('image-list', flags='--debug') - - @test.idempotent_id('6f42b076-f9a7-4e2b-a729-579f53e7814e') - def test_glance_timeout(self): - self.glance('image-list', flags='--timeout %d' % CONF.cli.timeout) diff --git a/tempest/cli/simple_read_only/orchestration/__init__.py b/tempest/cli/simple_read_only/orchestration/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tempest/cli/simple_read_only/orchestration/test_heat.py b/tempest/cli/simple_read_only/orchestration/test_heat.py deleted file mode 100644 index 8defe51a24..0000000000 --- a/tempest/cli/simple_read_only/orchestration/test_heat.py +++ /dev/null @@ -1,117 +0,0 @@ -# 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 json -import os - -from oslo_log import log as logging -import yaml - -import tempest.cli -from tempest import config -from tempest import test - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class SimpleReadOnlyHeatClientTest(tempest.cli.ClientTestBase): - """Basic, read-only tests for Heat CLI client. - - Basic smoke test for the heat CLI commands which do not require - creating or modifying stacks. - """ - - @classmethod - def resource_setup(cls): - if (not CONF.service_available.heat): - msg = ("Skipping all Heat cli tests because it is " - "not available") - raise cls.skipException(msg) - super(SimpleReadOnlyHeatClientTest, cls).resource_setup() - cls.heat_template_path = os.path.join(os.path.dirname( - os.path.dirname(os.path.realpath(__file__))), - 'heat_templates/heat_minimal.yaml') - - def heat(self, *args, **kwargs): - return self.clients.heat( - *args, endpoint_type=CONF.orchestration.endpoint_type, **kwargs) - - @test.idempotent_id('0ae034bb-ce35-45e8-b7aa-3e339cd3140f') - def test_heat_stack_list(self): - self.heat('stack-list') - - @test.idempotent_id('a360d069-7250-4aed-9721-0a6f2db7c3fa') - def test_heat_stack_list_debug(self): - self.heat('stack-list', flags='--debug') - - @test.idempotent_id('e1b7c177-5ab4-4d3f-8a26-ea01ebbd2b8c') - def test_heat_resource_template_fmt_default(self): - ret = self.heat('resource-template OS::Nova::Server') - self.assertIn('Type: OS::Nova::Server', ret) - - @test.idempotent_id('93f82f76-aab2-4910-9359-11cf48f2a46b') - def test_heat_resource_template_fmt_arg_short_yaml(self): - ret = self.heat('resource-template -F yaml OS::Nova::Server') - self.assertIn('Type: OS::Nova::Server', ret) - self.assertIsInstance(yaml.safe_load(ret), dict) - - @test.idempotent_id('7356a98c-e14d-43f0-8c25-c9f7daa0aafa') - def test_heat_resource_template_fmt_arg_long_json(self): - ret = self.heat('resource-template --format json OS::Nova::Server') - self.assertIn('"Type": "OS::Nova::Server"', ret) - self.assertIsInstance(json.loads(ret), dict) - - @test.idempotent_id('2fd99d20-beff-4667-b42e-de9095f671d7') - def test_heat_resource_type_list(self): - ret = self.heat('resource-type-list') - rsrc_types = self.parser.listing(ret) - self.assertTableStruct(rsrc_types, ['resource_type']) - - @test.idempotent_id('62f60dbf-d139-4698-b230-a09fb531d643') - def test_heat_resource_type_show(self): - rsrc_schema = self.heat('resource-type-show OS::Nova::Server') - # resource-type-show returns a json resource schema - self.assertIsInstance(json.loads(rsrc_schema), dict) - - @test.idempotent_id('6ca16ff7-9d5f-4448-a8c2-4cecc7b5ba3a') - def test_heat_template_validate_yaml(self): - ret = self.heat('template-validate -f %s' % self.heat_template_path) - # On success template-validate returns a json representation - # of the template parameters - self.assertIsInstance(json.loads(ret), dict) - - @test.idempotent_id('35241014-16ea-4cb6-ad3e-4ee5f41446de') - def test_heat_template_validate_hot(self): - ret = self.heat('template-validate -f %s' % self.heat_template_path) - self.assertIsInstance(json.loads(ret), dict) - - @test.idempotent_id('34d43e0a-36dc-4ea8-9b85-0189e3de89d8') - def test_heat_help(self): - self.heat('help') - - @tempest.cli.min_client_version(client='heat', version='0.2.7') - @test.idempotent_id('c122c08b-839d-49d1-afd1-bc546b2d18d3') - def test_heat_bash_completion(self): - self.heat('bash-completion') - - @test.idempotent_id('1b045e12-2fa0-4895-9282-00668428dfbe') - def test_heat_help_cmd(self): - # Check requesting help for a specific command works - help_text = self.heat('help resource-template') - lines = help_text.split('\n') - self.assertFirstLineStartsWith(lines, 'usage: heat resource-template') - - @test.idempotent_id('c7837f8f-d0a8-47fd-b75b-14ba3e3fa9a2') - def test_heat_version(self): - self.heat('', flags='--version') diff --git a/tempest/cli/simple_read_only/volume/__init__.py b/tempest/cli/simple_read_only/volume/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tempest/cli/simple_read_only/volume/test_cinder.py b/tempest/cli/simple_read_only/volume/test_cinder.py deleted file mode 100644 index cb29cc89d3..0000000000 --- a/tempest/cli/simple_read_only/volume/test_cinder.py +++ /dev/null @@ -1,220 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# 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 logging -import re - -from tempest_lib import exceptions -import testtools - -from tempest import cli -from tempest import clients -from tempest import config -from tempest import test - - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class SimpleReadOnlyCinderClientTest(cli.ClientTestBase): - """Basic, read-only tests for Cinder CLI client. - - Checks return values and output of read-only commands. - These tests do not presume any content, nor do they create - their own. They only verify the structure of output if present. - """ - - @classmethod - def resource_setup(cls): - if not CONF.service_available.cinder: - msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(msg) - super(SimpleReadOnlyCinderClientTest, cls).resource_setup() - id_cl = clients.AdminManager().identity_client - tenant = id_cl.get_tenant_by_name(CONF.identity.admin_tenant_name) - cls.admin_tenant_id = tenant['id'] - - def cinder(self, *args, **kwargs): - return self.clients.cinder(*args, - endpoint_type=CONF.volume.endpoint_type, - **kwargs) - - @test.idempotent_id('229bc6dc-d804-4668-b753-b590caf63061') - def test_cinder_fake_action(self): - self.assertRaises(exceptions.CommandFailed, - self.cinder, - 'this-does-not-exist') - - @test.idempotent_id('77140216-14db-4fc5-a246-e2a587e9e99b') - def test_cinder_absolute_limit_list(self): - roles = self.parser.listing(self.cinder('absolute-limits')) - self.assertTableStruct(roles, ['Name', 'Value']) - - @test.idempotent_id('2206b9ce-1a36-4a0a-a129-e5afc7cee1dd') - def test_cinder_backup_list(self): - backup_list = self.parser.listing(self.cinder('backup-list')) - self.assertTableStruct(backup_list, ['ID', 'Volume ID', 'Status', - 'Name', 'Size', 'Object Count', - 'Container']) - - @test.idempotent_id('c7f50346-cd99-4e0b-953f-796ff5f47295') - def test_cinder_extra_specs_list(self): - extra_specs_list = self.parser.listing(self.cinder('extra-specs-list')) - self.assertTableStruct(extra_specs_list, ['ID', 'Name', 'extra_specs']) - - @test.idempotent_id('9de694cb-b40b-442c-a30c-5f9873e144f7') - def test_cinder_volumes_list(self): - list = self.parser.listing(self.cinder('list')) - self.assertTableStruct(list, ['ID', 'Status', 'Name', 'Size', - 'Volume Type', 'Bootable', - 'Attached to']) - self.cinder('list', params='--all-tenants 1') - self.cinder('list', params='--all-tenants 0') - self.assertRaises(exceptions.CommandFailed, - self.cinder, - 'list', - params='--all-tenants bad') - - @test.idempotent_id('56f7c15c-ee82-4f23-bbe8-ce99b66da493') - def test_cinder_quota_class_show(self): - """This CLI can accept and string as param.""" - roles = self.parser.listing(self.cinder('quota-class-show', - params='abc')) - self.assertTableStruct(roles, ['Property', 'Value']) - - @test.idempotent_id('a919a811-b7f0-47a7-b4e5-f3eb674dd200') - def test_cinder_quota_defaults(self): - """This CLI can accept and string as param.""" - roles = self.parser.listing(self.cinder('quota-defaults', - params=self.admin_tenant_id)) - self.assertTableStruct(roles, ['Property', 'Value']) - - @test.idempotent_id('18166673-ffa8-4df3-b60c-6375532288bc') - def test_cinder_quota_show(self): - """This CLI can accept and string as param.""" - roles = self.parser.listing(self.cinder('quota-show', - params=self.admin_tenant_id)) - self.assertTableStruct(roles, ['Property', 'Value']) - - @test.idempotent_id('b2c66ed9-ca96-4dc4-94cc-8083e664e516') - def test_cinder_rate_limits(self): - rate_limits = self.parser.listing(self.cinder('rate-limits')) - self.assertTableStruct(rate_limits, ['Verb', 'URI', 'Value', 'Remain', - 'Unit', 'Next_Available']) - - @test.idempotent_id('7a19955b-807c-481a-a2ee-9d76733eac28') - @testtools.skipUnless(CONF.volume_feature_enabled.snapshot, - 'Volume snapshot not available.') - def test_cinder_snapshot_list(self): - snapshot_list = self.parser.listing(self.cinder('snapshot-list')) - self.assertTableStruct(snapshot_list, ['ID', 'Volume ID', 'Status', - 'Name', 'Size']) - - @test.idempotent_id('6e54ecd9-7ba9-490d-8e3b-294b67139e73') - def test_cinder_type_list(self): - type_list = self.parser.listing(self.cinder('type-list')) - self.assertTableStruct(type_list, ['ID', 'Name']) - - @test.idempotent_id('2c363583-24a0-4980-b9cb-b50c0d241e82') - def test_cinder_list_extensions(self): - roles = self.parser.listing(self.cinder('list-extensions')) - self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated']) - - @test.idempotent_id('691bd6df-30ad-4be7-927b-a02d62aaa38a') - def test_cinder_credentials(self): - credentials = self.parser.listing(self.cinder('credentials')) - self.assertTableStruct(credentials, ['User Credentials', 'Value']) - - @test.idempotent_id('5c6d71a3-4904-4a3a-aec9-7fd4aa830e95') - def test_cinder_availability_zone_list(self): - zone_list = self.parser.listing(self.cinder('availability-zone-list')) - self.assertTableStruct(zone_list, ['Name', 'Status']) - - @test.idempotent_id('9b0fd5a6-f955-42b9-a42f-6f542a80b9a3') - def test_cinder_endpoints(self): - out = self.cinder('endpoints') - tables = self.parser.tables(out) - for table in tables: - headers = table['headers'] - self.assertTrue(2 >= len(headers)) - self.assertEqual('Value', headers[1]) - - @test.idempotent_id('301b5ae1-9591-4e9f-999c-d525a9bdf822') - def test_cinder_service_list(self): - service_list = self.parser.listing(self.cinder('service-list')) - self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone', - 'Status', 'State', 'Updated_at']) - - @test.idempotent_id('7260ae52-b462-461e-9048-36d0bccf92c6') - def test_cinder_transfer_list(self): - transfer_list = self.parser.listing(self.cinder('transfer-list')) - self.assertTableStruct(transfer_list, ['ID', 'Volume ID', 'Name']) - - @test.idempotent_id('0976dea8-14f3-45a9-8495-3617fc4fbb13') - def test_cinder_bash_completion(self): - self.cinder('bash-completion') - - @test.idempotent_id('b7c00361-be80-4512-8735-5f98fc54f2a9') - def test_cinder_qos_list(self): - qos_list = self.parser.listing(self.cinder('qos-list')) - self.assertTableStruct(qos_list, ['ID', 'Name', 'Consumer', 'specs']) - - @test.idempotent_id('2e92dc6e-22b5-4d94-abfc-b543b0c50a89') - def test_cinder_encryption_type_list(self): - encrypt_list = self.parser.listing(self.cinder('encryption-type-list')) - self.assertTableStruct(encrypt_list, ['Volume Type ID', 'Provider', - 'Cipher', 'Key Size', - 'Control Location']) - - @test.idempotent_id('0ee6cb4c-8de6-4811-a7be-7f4bb75b80cc') - def test_admin_help(self): - help_text = self.cinder('help') - lines = help_text.split('\n') - self.assertFirstLineStartsWith(lines, 'usage: cinder') - - commands = [] - cmds_start = lines.index('Positional arguments:') - cmds_end = lines.index('Optional arguments:') - command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)') - for line in lines[cmds_start:cmds_end]: - match = command_pattern.match(line) - if match: - commands.append(match.group(1)) - commands = set(commands) - wanted_commands = set(('absolute-limits', 'list', 'help', - 'quota-show', 'type-list', 'snapshot-list')) - self.assertFalse(wanted_commands - commands) - - # Optional arguments: - - @test.idempotent_id('2fd6f530-183c-4bda-8918-1e59e36c26b9') - def test_cinder_version(self): - self.cinder('', flags='--version') - - @test.idempotent_id('306bac51-c443-4426-a6cf-583a953fcd68') - def test_cinder_debug_list(self): - self.cinder('list', flags='--debug') - - @test.idempotent_id('6d97fcd2-5dd1-429d-af70-030c949d86cd') - def test_cinder_retries_list(self): - self.cinder('list', flags='--retries 3') - - @test.idempotent_id('95a2850c-35b4-4159-bb93-51647a5ad232') - def test_cinder_region_list(self): - region = CONF.volume.region - if not region: - region = CONF.identity.region - self.cinder('list', flags='--os-region-name ' + region) diff --git a/tempest/config.py b/tempest/config.py index bcbe41f191..46d2c933d4 100644 --- a/tempest/config.py +++ b/tempest/config.py @@ -1091,25 +1091,6 @@ BaremetalGroup = [ help="Timeout for unprovisioning an Ironic node.") ] -cli_group = cfg.OptGroup(name='cli', title="cli Configuration Options") - -CLIGroup = [ - cfg.BoolOpt('enabled', - default=True, - help="enable cli tests"), - cfg.StrOpt('cli_dir', - default='/usr/local/bin', - help="directory where python client binaries are located"), - cfg.BoolOpt('has_manage', - default=True, - help=("Whether the tempest run location has access to the " - "*-manage commands. In a pure blackbox environment " - "it will not.")), - cfg.IntOpt('timeout', - default=15, - help="Number of seconds to wait on a CLI timeout"), -] - negative_group = cfg.OptGroup(name='negative', title="Negative Test Options") NegativeGroup = [ @@ -1148,7 +1129,6 @@ _opts = [ (debug_group, DebugGroup), (baremetal_group, BaremetalGroup), (input_scenario_group, InputScenarioGroup), - (cli_group, CLIGroup), (negative_group, NegativeGroup) ] @@ -1212,7 +1192,6 @@ class TempestConfigPrivate(object): self.debug = _CONF.debug self.baremetal = _CONF.baremetal self.input_scenario = _CONF['input-scenario'] - self.cli = _CONF.cli self.negative = _CONF.negative _CONF.set_default('domain_name', self.identity.admin_domain_name, group='identity') diff --git a/tempest/test_discover/test_discover.py b/tempest/test_discover/test_discover.py index 3fbb8e1336..4a4b43a536 100644 --- a/tempest/test_discover/test_discover.py +++ b/tempest/test_discover/test_discover.py @@ -25,7 +25,7 @@ def load_tests(loader, tests, pattern): suite = unittest.TestSuite() base_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0] base_path = os.path.split(base_path)[0] - for test_dir in ['./tempest/api', './tempest/cli', './tempest/scenario', + for test_dir in ['./tempest/api', './tempest/scenario', './tempest/thirdparty']: if not pattern: suite.addTests(loader.discover(test_dir, top_level_dir=base_path)) diff --git a/tempest/tests/cli/__init__.py b/tempest/tests/cli/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tempest/tests/cli/test_cli.py b/tempest/tests/cli/test_cli.py deleted file mode 100644 index 8f18dfccb7..0000000000 --- a/tempest/tests/cli/test_cli.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 mock -from tempest_lib.cli import base as cli_base -import testtools - -from tempest import cli -from tempest import config -from tempest import exceptions -from tempest.tests import base -from tempest.tests import fake_config - - -class TestMinClientVersion(base.TestCase): - """Tests for the min_client_version decorator. - """ - - def setUp(self): - super(TestMinClientVersion, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate) - - def _test_min_version(self, required, installed, expect_skip): - - @cli.min_client_version(client='nova', version=required) - def fake(self, expect_skip): - if expect_skip: - # If we got here, the decorator didn't raise a skipException as - # expected so we need to fail. - self.fail('Should not have gotten past the decorator.') - - with mock.patch.object(cli_base, 'execute', - return_value=installed) as mock_cmd: - if expect_skip: - self.assertRaises(testtools.TestCase.skipException, fake, - self, expect_skip) - else: - fake(self, expect_skip) - mock_cmd.assert_called_once_with('nova', '', params='--version', - cli_dir='/usr/local/bin', - merge_stderr=True) - - def test_min_client_version(self): - # required, installed, expect_skip - cases = (('2.17.0', '2.17.0', False), - ('2.17.0', '2.18.0', False), - ('2.18.0', '2.17.0', True)) - - for case in cases: - self._test_min_version(*case) - - @mock.patch.object(cli_base, 'execute', return_value=' ') - def test_check_client_version_empty_output(self, mock_execute): - # Tests that an exception is raised if the command output is empty. - self.assertRaises(exceptions.TempestException, - cli.check_client_version, 'nova', '2.18.0') diff --git a/tox.ini b/tox.ini index 2f0aa99e72..88d13024bf 100644 --- a/tox.ini +++ b/tox.ini @@ -47,7 +47,7 @@ deps = {[tempestenv]deps} # See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610 commands = find . -type f -name "*.pyc" -delete - bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}' + bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}' [testenv:full-serial] sitepackages = {[tempestenv]sitepackages} @@ -57,7 +57,7 @@ deps = {[tempestenv]deps} # See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610 commands = find . -type f -name "*.pyc" -delete - bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}' + bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}' [testenv:heat-slow] sitepackages = {[tempestenv]sitepackages}