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