From 4c5e5e4bba3d12240edcf41801ffb0f2be37f779 Mon Sep 17 00:00:00 2001 From: John Griffith Date: Thu, 30 Apr 2015 16:58:46 -0600 Subject: [PATCH] Add CLI read-only functional tests First pass at functional tests in cinderclient. This patch just takes some of the basic CLI tests from tempest and moves them into the cinderclient functional tests. These are read-only tests, and just do simple field checks on the tables generated by the basic list commands. Note: to run use "tox -efunctional", this requires that you have a full cinderclient env and credentials are set. You may be either running this locally (say in a devstack env) or you may have a remote cloud handy that you can just source the credentials for and run it that way. Change-Id: I2f09a63be265d6a74cb103d80579068b9ab66bf4 --- .testr.conf | 2 +- cinderclient/tests/functional/__init__.py | 0 cinderclient/tests/functional/base.py | 56 ++++++++++++ .../tests/functional/test_readonly_cli.py | 89 +++++++++++++++++++ test-requirements.txt | 1 + tox.ini | 4 + 6 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 cinderclient/tests/functional/__init__.py create mode 100644 cinderclient/tests/functional/base.py create mode 100644 cinderclient/tests/functional/test_readonly_cli.py diff --git a/.testr.conf b/.testr.conf index 024026b49..2f5f5031f 100644 --- a/.testr.conf +++ b/.testr.conf @@ -1,4 +1,4 @@ [DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./cinderclient/tests} $LISTOPT $IDOPTION +test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./cinderclient/tests/unit} $LISTOPT $IDOPTION test_id_option=--load-list $IDFILE test_list_option=--list diff --git a/cinderclient/tests/functional/__init__.py b/cinderclient/tests/functional/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cinderclient/tests/functional/base.py b/cinderclient/tests/functional/base.py new file mode 100644 index 000000000..02c07f904 --- /dev/null +++ b/cinderclient/tests/functional/base.py @@ -0,0 +1,56 @@ +# 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 os + +from tempest_lib.cli import base +from tempest_lib.cli import output_parser + + +class ClientTestBase(base.ClientTestBase): + """Cinder base class, issues calls to cinderclient. + + """ + def setUp(self): + super(ClientTestBase, self).setUp() + self.clients = self._get_clients() + self.parser = output_parser + + def _get_clients(self): + cli_dir = os.environ.get( + 'OS_CINDERCLIENT_EXEC_DIR', + os.path.join(os.path.abspath('.'), '.tox/functional/bin')) + + return base.CLIClient( + username=os.environ.get('OS_USERNAME'), + password=os.environ.get('OS_PASSWORD'), + tenant_name=os.environ.get('OS_TENANT_NAME'), + uri=os.environ.get('OS_AUTH_URL'), + cli_dir=cli_dir) + + def cinder(self, *args, **kwargs): + return self.clients.cinder(*args, + **kwargs) + + 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 + """ + # Strip off the --- if present + + for item in items: + for field in field_names: + self.assertIn(field, item) diff --git a/cinderclient/tests/functional/test_readonly_cli.py b/cinderclient/tests/functional/test_readonly_cli.py new file mode 100644 index 000000000..64a190b52 --- /dev/null +++ b/cinderclient/tests/functional/test_readonly_cli.py @@ -0,0 +1,89 @@ +# 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. + + +from cinderclient.tests.functional import base + + +class CinderClientReadOnlyTests(base.ClientTestBase): + """Basic read-only test for cinderclient. + + Simple check of base list commands, verify they + respond and include the expected headers in the + resultant table. + + Not intended for testing things that require actual + resource creation/manipulation, thus the name 'read-only'. + + """ + + # Commands in order listed in 'cinder help' + def test_absolute_limits(self): + limits = self.parser.listing(self.cinder('absolute-limits')) + self.assertTableStruct(limits, ['Name', 'Value']) + + def test_availability_zones(self): + zone_list = self.parser.listing(self.cinder('availability-zone-list')) + self.assertTableStruct(zone_list, ['Name', 'Status']) + + def test_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']) + + def test_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']) + + def test_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]) + + def test_list(self): + list = self.parser.listing(self.cinder('list')) + self.assertTableStruct(list, ['ID', 'Status', 'Name', 'Size', + 'Volume Type', 'Bootable', + 'Attached to']) + + def test_qos_list(self): + qos_list = self.parser.listing(self.cinder('qos-list')) + self.assertTableStruct(qos_list, ['ID', 'Name', 'Consumer', 'specs']) + + def test_rate_limits(self): + rate_limits = self.parser.listing(self.cinder('rate-limits')) + self.assertTableStruct(rate_limits, ['Verb', 'URI', 'Value', 'Remain', + 'Unit', 'Next_Available']) + + def test_service_list(self): + service_list = self.parser.listing(self.cinder('service-list')) + self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone', + 'Status', 'State', 'Updated_at']) + + def test_snapshot_list(self): + snapshot_list = self.parser.listing(self.cinder('snapshot-list')) + self.assertTableStruct(snapshot_list, ['ID', 'Volume ID', 'Status', + 'Name', 'Size']) + + def test_transfer_list(self): + transfer_list = self.parser.listing(self.cinder('transfer-list')) + self.assertTableStruct(transfer_list, ['ID', 'Volume ID', 'Name']) + + def test_type_list(self): + type_list = self.parser.listing(self.cinder('type-list')) + self.assertTableStruct(type_list, ['ID', 'Name']) diff --git a/test-requirements.txt b/test-requirements.txt index d8f980095..3ceb21cbb 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -11,5 +11,6 @@ oslosphinx>=2.5.0 # Apache-2.0 python-subunit>=0.0.18 requests-mock>=0.6.0 # Apache-2.0 sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 +tempest-lib>=0.5.0 testtools>=0.9.36,!=1.2.0 testrepository>=0.0.18 diff --git a/tox.ini b/tox.ini index 510cfb5f7..bd966b0a5 100644 --- a/tox.ini +++ b/tox.ini @@ -26,6 +26,10 @@ commands = python setup.py testr --coverage --testr-args='{posargs}' commands= python setup.py build_sphinx +[testenv:functional] +setenv = + OS_TEST_PATH = ./cinderclient/tests/functional + [tox:jenkins] downloadcache = ~/cache/pip