summaryrefslogtreecommitdiff
path: root/openstackclient/tests/functional
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-09-09 19:30:10 +0000
committerGerrit Code Review <review@openstack.org>2016-09-09 19:30:10 +0000
commitbee04914b8e582fb902a8d0cbd2cf6511bfe4b8b (patch)
tree4da08049dd44d7c163056a2bf7b0c3ddd58b6d6d /openstackclient/tests/functional
parent0b203355c41b58f9970149637c20887da692ec75 (diff)
parentc14d3efe6162a58cb3cdcb2834ad2508e2525018 (diff)
downloadpython-openstackclient-bee04914b8e582fb902a8d0cbd2cf6511bfe4b8b.tar.gz
Merge "move all functional tests to tests module"
Diffstat (limited to 'openstackclient/tests/functional')
-rw-r--r--openstackclient/tests/functional/__init__.py0
-rw-r--r--openstackclient/tests/functional/base.py120
-rw-r--r--openstackclient/tests/functional/common/__init__.py0
-rw-r--r--openstackclient/tests/functional/common/test_availability_zone.py25
-rw-r--r--openstackclient/tests/functional/common/test_configuration.py44
-rw-r--r--openstackclient/tests/functional/common/test_help.py66
-rw-r--r--openstackclient/tests/functional/common/test_quota.py42
-rw-r--r--openstackclient/tests/functional/compute/__init__.py0
-rw-r--r--openstackclient/tests/functional/compute/v2/__init__.py0
-rw-r--r--openstackclient/tests/functional/compute/v2/test_agent.py77
-rw-r--r--openstackclient/tests/functional/compute/v2/test_aggregate.py67
-rw-r--r--openstackclient/tests/functional/compute/v2/test_flavor.py69
-rw-r--r--openstackclient/tests/functional/compute/v2/test_keypair.py168
-rw-r--r--openstackclient/tests/functional/compute/v2/test_server.py308
-rw-r--r--openstackclient/tests/functional/compute/v2/test_server_group.py46
-rw-r--r--openstackclient/tests/functional/examples/__init__.py0
-rw-r--r--openstackclient/tests/functional/examples/test_examples.py28
-rw-r--r--openstackclient/tests/functional/identity/__init__.py0
-rw-r--r--openstackclient/tests/functional/identity/v2/__init__.py0
-rw-r--r--openstackclient/tests/functional/identity/v2/common.py181
-rw-r--r--openstackclient/tests/functional/identity/v2/test_catalog.py42
-rw-r--r--openstackclient/tests/functional/identity/v2/test_ec2_credentials.py48
-rw-r--r--openstackclient/tests/functional/identity/v2/test_endpoint.py45
-rw-r--r--openstackclient/tests/functional/identity/v2/test_project.py86
-rw-r--r--openstackclient/tests/functional/identity/v2/test_role.py110
-rw-r--r--openstackclient/tests/functional/identity/v2/test_service.py44
-rw-r--r--openstackclient/tests/functional/identity/v2/test_token.py24
-rw-r--r--openstackclient/tests/functional/identity/v2/test_user.py60
-rw-r--r--openstackclient/tests/functional/identity/v3/__init__.py0
-rw-r--r--openstackclient/tests/functional/identity/v3/common.py289
-rw-r--r--openstackclient/tests/functional/identity/v3/test_catalog.py45
-rw-r--r--openstackclient/tests/functional/identity/v3/test_domain.py69
-rw-r--r--openstackclient/tests/functional/identity/v3/test_endpoint.py67
-rw-r--r--openstackclient/tests/functional/identity/v3/test_group.py178
-rw-r--r--openstackclient/tests/functional/identity/v3/test_idp.py61
-rw-r--r--openstackclient/tests/functional/identity/v3/test_project.py113
-rw-r--r--openstackclient/tests/functional/identity/v3/test_region.py70
-rw-r--r--openstackclient/tests/functional/identity/v3/test_role.py145
-rw-r--r--openstackclient/tests/functional/identity/v3/test_service.py71
-rw-r--r--openstackclient/tests/functional/identity/v3/test_service_provider.py61
-rw-r--r--openstackclient/tests/functional/identity/v3/test_token.py21
-rw-r--r--openstackclient/tests/functional/identity/v3/test_user.py101
-rw-r--r--openstackclient/tests/functional/image/__init__.py0
-rw-r--r--openstackclient/tests/functional/image/v1/__init__.py0
-rw-r--r--openstackclient/tests/functional/image/v1/test_image.py67
-rw-r--r--openstackclient/tests/functional/image/v2/__init__.py0
-rw-r--r--openstackclient/tests/functional/image/v2/test_image.py76
-rw-r--r--openstackclient/tests/functional/network/__init__.py0
-rw-r--r--openstackclient/tests/functional/network/v2/__init__.py0
-rw-r--r--openstackclient/tests/functional/network/v2/test_address_scope.py49
-rw-r--r--openstackclient/tests/functional/network/v2/test_floating_ip.py58
-rw-r--r--openstackclient/tests/functional/network/v2/test_ip_availability.py53
-rw-r--r--openstackclient/tests/functional/network/v2/test_network.py50
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_agent.py41
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_rbac.py69
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_segment.py60
-rw-r--r--openstackclient/tests/functional/network/v2/test_port.py58
-rw-r--r--openstackclient/tests/functional/network/v2/test_router.py50
-rw-r--r--openstackclient/tests/functional/network/v2/test_security_group.py60
-rw-r--r--openstackclient/tests/functional/network/v2/test_security_group_rule.py67
-rw-r--r--openstackclient/tests/functional/network/v2/test_subnet.py66
-rw-r--r--openstackclient/tests/functional/network/v2/test_subnet_pool.py55
-rw-r--r--openstackclient/tests/functional/object/__init__.py0
-rw-r--r--openstackclient/tests/functional/object/v1/__init__.py0
-rw-r--r--openstackclient/tests/functional/object/v1/test_container.py41
-rw-r--r--openstackclient/tests/functional/object/v1/test_object.py81
-rwxr-xr-xopenstackclient/tests/functional/post_test_hook.sh43
-rw-r--r--openstackclient/tests/functional/volume/__init__.py0
-rw-r--r--openstackclient/tests/functional/volume/v1/__init__.py0
-rw-r--r--openstackclient/tests/functional/volume/v1/common.py23
-rw-r--r--openstackclient/tests/functional/volume/v1/test_qos.py55
-rw-r--r--openstackclient/tests/functional/volume/v1/test_volume.py77
-rw-r--r--openstackclient/tests/functional/volume/v1/test_volume_type.py74
-rw-r--r--openstackclient/tests/functional/volume/v2/__init__.py0
-rw-r--r--openstackclient/tests/functional/volume/v2/common.py23
-rw-r--r--openstackclient/tests/functional/volume/v2/test_qos.py62
-rw-r--r--openstackclient/tests/functional/volume/v2/test_snapshot.py83
-rw-r--r--openstackclient/tests/functional/volume/v2/test_volume.py137
-rw-r--r--openstackclient/tests/functional/volume/v2/test_volume_type.py84
79 files changed, 4653 insertions, 0 deletions
diff --git a/openstackclient/tests/functional/__init__.py b/openstackclient/tests/functional/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/__init__.py
diff --git a/openstackclient/tests/functional/base.py b/openstackclient/tests/functional/base.py
new file mode 100644
index 00000000..f7f0361e
--- /dev/null
+++ b/openstackclient/tests/functional/base.py
@@ -0,0 +1,120 @@
+# 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
+import re
+import shlex
+import subprocess
+import testtools
+
+import six
+from tempest.lib.cli import output_parser
+from tempest.lib import exceptions
+
+
+COMMON_DIR = os.path.dirname(os.path.abspath(__file__))
+FUNCTIONAL_DIR = os.path.normpath(os.path.join(COMMON_DIR, '..'))
+ROOT_DIR = os.path.normpath(os.path.join(FUNCTIONAL_DIR, '..'))
+EXAMPLE_DIR = os.path.join(ROOT_DIR, 'examples')
+
+
+def execute(cmd, fail_ok=False, merge_stderr=False):
+ """Executes specified command for the given action."""
+ cmdlist = shlex.split(cmd)
+ result = ''
+ result_err = ''
+ stdout = subprocess.PIPE
+ stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
+ proc = subprocess.Popen(cmdlist, stdout=stdout, stderr=stderr)
+ result, result_err = proc.communicate()
+ result = result.decode('utf-8')
+ if not fail_ok and proc.returncode != 0:
+ raise exceptions.CommandFailed(proc.returncode, cmd, result,
+ result_err)
+ return result
+
+
+class TestCase(testtools.TestCase):
+
+ delimiter_line = re.compile('^\+\-[\+\-]+\-\+$')
+
+ @classmethod
+ def openstack(cls, cmd, fail_ok=False):
+ """Executes openstackclient command for the given action."""
+ return execute('openstack ' + cmd, fail_ok=fail_ok)
+
+ @classmethod
+ def get_openstack_configuration_value(cls, configuration):
+ opts = cls.get_opts([configuration])
+ return cls.openstack('configuration show ' + opts)
+
+ @classmethod
+ def get_opts(cls, fields, format='value'):
+ return ' -f {0} {1}'.format(format,
+ ' '.join(['-c ' + it for it in fields]))
+
+ @classmethod
+ def assertOutput(cls, expected, actual):
+ if expected != actual:
+ raise Exception(expected + ' != ' + actual)
+
+ @classmethod
+ def assertInOutput(cls, expected, actual):
+ if expected not in actual:
+ raise Exception(expected + ' not in ' + actual)
+
+ def assert_table_structure(self, items, field_names):
+ """Verify that all items have keys listed in field_names."""
+ for item in items:
+ for field in field_names:
+ self.assertIn(field, item)
+
+ def assert_show_fields(self, items, field_names):
+ """Verify that all items have keys listed in field_names."""
+ for item in items:
+ for key in six.iterkeys(item):
+ self.assertIn(key, field_names)
+
+ def assert_show_structure(self, items, field_names):
+ """Verify that all field_names listed in keys of all items."""
+ if isinstance(items, list):
+ o = {}
+ for d in items:
+ o.update(d)
+ else:
+ o = items
+ item_keys = o.keys()
+ for field in field_names:
+ self.assertIn(field, item_keys)
+
+ def parse_show_as_object(self, raw_output):
+ """Return a dict with values parsed from cli output."""
+ items = self.parse_show(raw_output)
+ o = {}
+ for item in items:
+ o.update(item)
+ return o
+
+ def parse_show(self, raw_output):
+ """Return list of dicts with item values parsed from cli output."""
+
+ items = []
+ table_ = output_parser.table(raw_output)
+ for row in table_['values']:
+ item = {}
+ item[row[0]] = row[1]
+ items.append(item)
+ return items
+
+ def parse_listing(self, raw_output):
+ """Return list of dicts with basic item parsed from cli output."""
+ return output_parser.listing(raw_output)
diff --git a/openstackclient/tests/functional/common/__init__.py b/openstackclient/tests/functional/common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/common/__init__.py
diff --git a/openstackclient/tests/functional/common/test_availability_zone.py b/openstackclient/tests/functional/common/test_availability_zone.py
new file mode 100644
index 00000000..f73e1ed9
--- /dev/null
+++ b/openstackclient/tests/functional/common/test_availability_zone.py
@@ -0,0 +1,25 @@
+# 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 openstackclient.tests.functional import base
+
+
+class AvailabilityZoneTests(base.TestCase):
+ """Functional tests for availability zone. """
+ HEADERS = ["'Zone Name'"]
+ # So far, all components have the same default availability zone name.
+ DEFAULT_AZ_NAME = 'nova'
+
+ def test_availability_zone_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('availability zone list' + opts)
+ self.assertIn(self.DEFAULT_AZ_NAME, raw_output)
diff --git a/openstackclient/tests/functional/common/test_configuration.py b/openstackclient/tests/functional/common/test_configuration.py
new file mode 100644
index 00000000..f47d3b00
--- /dev/null
+++ b/openstackclient/tests/functional/common/test_configuration.py
@@ -0,0 +1,44 @@
+# 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 openstackclient.common import configuration
+from openstackclient.tests.functional import base
+
+
+BASIC_CONFIG_HEADERS = ['Field', 'Value']
+
+
+class ConfigurationTests(base.TestCase):
+
+ opts = "-f value -c auth.password"
+
+ def test_configuration_show(self):
+ raw_output = self.openstack('configuration show')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, BASIC_CONFIG_HEADERS)
+
+ def test_configuration_show_unmask(self):
+ raw_output = self.openstack('configuration show --unmask ' + self.opts)
+ # If we are using os-client-config, this will not be set. Rather than
+ # parse clouds.yaml to get the right value, just make sure
+ # we are not getting redacted.
+ passwd = os.environ.get('OS_PASSWORD')
+ if passwd:
+ self.assertEqual(passwd + '\n', raw_output)
+ else:
+ self.assertNotEqual(configuration.REDACTED + '\n', raw_output)
+
+ def test_configuration_show_mask(self):
+ raw_output = self.openstack('configuration show --mask ' + self.opts)
+ self.assertEqual(configuration.REDACTED + '\n', raw_output)
diff --git a/openstackclient/tests/functional/common/test_help.py b/openstackclient/tests/functional/common/test_help.py
new file mode 100644
index 00000000..bbc52197
--- /dev/null
+++ b/openstackclient/tests/functional/common/test_help.py
@@ -0,0 +1,66 @@
+# 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 openstackclient.tests.functional import base
+
+
+class HelpTests(base.TestCase):
+ """Functional tests for openstackclient help output."""
+
+ SERVER_COMMANDS = [
+ ('server add security group', 'Add security group to server'),
+ ('server add volume', 'Add volume to server'),
+ ('server backup create', 'Create a server backup image'),
+ ('server create', 'Create a new server'),
+ ('server delete', 'Delete server(s)'),
+ ('server dump create', 'Create a dump file in server(s)'),
+ ('server image create',
+ 'Create a new server disk image from an existing server'),
+ ('server list', 'List servers'),
+ ('server lock',
+ 'Lock server(s). '
+ 'A non-admin user will not be able to execute actions'),
+ ('server migrate', 'Migrate server to different host'),
+ ('server pause', 'Pause server(s)'),
+ ('server reboot', 'Perform a hard or soft server reboot'),
+ ('server rebuild', 'Rebuild server'),
+ ('server remove security group', 'Remove security group from server'),
+ ('server remove volume', 'Remove volume from server'),
+ ('server rescue', 'Put server in rescue mode'),
+ ('server resize', 'Scale server to a new flavor'),
+ ('server resume', 'Resume server(s)'),
+ ('server set', 'Set server properties'),
+ ('server shelve', 'Shelve server(s)'),
+ ('server show', 'Show server details'),
+ ('server ssh', 'SSH to server'),
+ ('server start', 'Start server(s).'),
+ ('server stop', 'Stop server(s).'),
+ ('server suspend', 'Suspend server(s)'),
+ ('server unlock', 'Unlock server(s)'),
+ ('server unpause', 'Unpause server(s)'),
+ ('server unrescue', 'Restore server from rescue mode'),
+ ('server unset', 'Unset server properties'),
+ ('server unshelve', 'Unshelve server(s)')
+ ]
+
+ def test_server_commands_main_help(self):
+ """Check server commands in main help message."""
+ raw_output = self.openstack('help')
+ for command, description in self.SERVER_COMMANDS:
+ self.assertIn(command, raw_output)
+ self.assertIn(description, raw_output)
+
+ def test_server_only_help(self):
+ """Check list of server-related commands only."""
+ raw_output = self.openstack('help server')
+ for command in [row[0] for row in self.SERVER_COMMANDS]:
+ self.assertIn(command, raw_output)
diff --git a/openstackclient/tests/functional/common/test_quota.py b/openstackclient/tests/functional/common/test_quota.py
new file mode 100644
index 00000000..fd45be38
--- /dev/null
+++ b/openstackclient/tests/functional/common/test_quota.py
@@ -0,0 +1,42 @@
+# 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 openstackclient.tests.functional import base
+
+
+class QuotaTests(base.TestCase):
+ """Functional tests for quota. """
+ # Test quota information for compute, network and volume.
+ EXPECTED_FIELDS = ['instances', 'networks', 'volumes']
+ PROJECT_NAME = None
+
+ @classmethod
+ def setUpClass(cls):
+ cls.PROJECT_NAME =\
+ cls.get_openstack_configuration_value('auth.project_name')
+
+ def test_quota_set(self):
+ self.openstack('quota set --instances 11 --volumes 11 --networks 11 '
+ + self.PROJECT_NAME)
+ opts = self.get_opts(self.EXPECTED_FIELDS)
+ raw_output = self.openstack('quota show ' + self.PROJECT_NAME + opts)
+ self.assertEqual("11\n11\n11\n", raw_output)
+
+ def test_quota_show(self):
+ raw_output = self.openstack('quota show ' + self.PROJECT_NAME)
+ for expected_field in self.EXPECTED_FIELDS:
+ self.assertIn(expected_field, raw_output)
+
+ def test_quota_show_default_project(self):
+ raw_output = self.openstack('quota show')
+ for expected_field in self.EXPECTED_FIELDS:
+ self.assertIn(expected_field, raw_output)
diff --git a/openstackclient/tests/functional/compute/__init__.py b/openstackclient/tests/functional/compute/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/compute/__init__.py
diff --git a/openstackclient/tests/functional/compute/v2/__init__.py b/openstackclient/tests/functional/compute/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/compute/v2/__init__.py
diff --git a/openstackclient/tests/functional/compute/v2/test_agent.py b/openstackclient/tests/functional/compute/v2/test_agent.py
new file mode 100644
index 00000000..7115db1f
--- /dev/null
+++ b/openstackclient/tests/functional/compute/v2/test_agent.py
@@ -0,0 +1,77 @@
+# 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 hashlib
+
+from openstackclient.tests.functional import base
+
+
+class ComputeAgentTests(base.TestCase):
+ """Functional tests for compute agent."""
+
+ ID = None
+ MD5HASH = hashlib.md5().hexdigest()
+ URL = "http://localhost"
+ VER = "v1"
+ OS = "TEST_OS"
+ ARCH = "x86_64"
+ HYPER = "kvm"
+
+ HEADERS = ['agent_id', 'md5hash']
+ FIELDS = ['agent_id', 'md5hash']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.HEADERS)
+ raw_output = cls.openstack('compute agent create ' +
+ cls.OS + ' ' + cls.ARCH + ' ' +
+ cls.VER + ' ' + cls.URL + ' ' +
+ cls.MD5HASH + ' ' + cls.HYPER + ' ' +
+ opts)
+
+ # Get agent id because agent can only be deleted by ID
+ output_list = raw_output.split('\n', 1)
+ cls.ID = output_list[0]
+
+ cls.assertOutput(cls.MD5HASH + '\n', output_list[1])
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('compute agent delete ' + cls.ID)
+ cls.assertOutput('', raw_output)
+
+ def test_agent_list(self):
+ raw_output = self.openstack('compute agent list')
+ self.assertIn(self.ID, raw_output)
+ self.assertIn(self.OS, raw_output)
+ self.assertIn(self.ARCH, raw_output)
+ self.assertIn(self.VER, raw_output)
+ self.assertIn(self.URL, raw_output)
+ self.assertIn(self.MD5HASH, raw_output)
+ self.assertIn(self.HYPER, raw_output)
+
+ def test_agent_set(self):
+ ver = 'v2'
+ url = "http://openstack"
+ md5hash = hashlib.md5().hexdigest()
+
+ self.openstack('compute agent set '
+ + self.ID
+ + ' --agent-version ' + ver
+ + ' --url ' + url
+ + ' --md5hash ' + md5hash)
+
+ raw_output = self.openstack('compute agent list')
+ self.assertIn(self.ID, raw_output)
+ self.assertIn(ver, raw_output)
+ self.assertIn(url, raw_output)
+ self.assertIn(md5hash, raw_output)
diff --git a/openstackclient/tests/functional/compute/v2/test_aggregate.py b/openstackclient/tests/functional/compute/v2/test_aggregate.py
new file mode 100644
index 00000000..2bc88e7b
--- /dev/null
+++ b/openstackclient/tests/functional/compute/v2/test_aggregate.py
@@ -0,0 +1,67 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class AggregateTests(base.TestCase):
+ """Functional tests for aggregate."""
+
+ NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ # Use the default 'nova' availability zone for the aggregate.
+ raw_output = cls.openstack(
+ 'aggregate create --zone nova ' + cls.NAME + opts
+ )
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('aggregate delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_aggregate_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('aggregate list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_aggregate_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('aggregate show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_aggregate_properties(self):
+ opts = self.get_opts(['properties'])
+
+ raw_output = self.openstack(
+ 'aggregate set --property a=b --property c=d ' + self.NAME
+ )
+ self.assertEqual('', raw_output)
+
+ raw_output = self.openstack('aggregate show ' + self.NAME + opts)
+ self.assertIn("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack(
+ 'aggregate unset --property a ' + self.NAME
+ )
+ self.assertEqual('', raw_output)
+
+ raw_output = self.openstack('aggregate show ' + self.NAME + opts)
+ self.assertIn("c='d'\n", raw_output)
diff --git a/openstackclient/tests/functional/compute/v2/test_flavor.py b/openstackclient/tests/functional/compute/v2/test_flavor.py
new file mode 100644
index 00000000..794a6cc3
--- /dev/null
+++ b/openstackclient/tests/functional/compute/v2/test_flavor.py
@@ -0,0 +1,69 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class FlavorTests(base.TestCase):
+ """Functional tests for flavor."""
+
+ NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack(
+ 'flavor create --property a=b --property c=d ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('flavor delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_flavor_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('flavor list' + opts)
+ self.assertIn("small", raw_output)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_flavor_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('flavor show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_flavor_properties(self):
+ opts = self.get_opts(['properties'])
+ # check the properties we added in create command.
+ raw_output = self.openstack('flavor show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack(
+ 'flavor set --property e=f --property g=h ' + self.NAME
+ )
+ self.assertEqual('', raw_output)
+
+ raw_output = self.openstack('flavor show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d', e='f', g='h'\n", raw_output)
+
+ raw_output = self.openstack(
+ 'flavor unset --property a --property c ' + self.NAME
+ )
+ self.assertEqual('', raw_output)
+
+ raw_output = self.openstack('flavor show ' + self.NAME + opts)
+ self.assertEqual("e='f', g='h'\n", raw_output)
diff --git a/openstackclient/tests/functional/compute/v2/test_keypair.py b/openstackclient/tests/functional/compute/v2/test_keypair.py
new file mode 100644
index 00000000..01078c61
--- /dev/null
+++ b/openstackclient/tests/functional/compute/v2/test_keypair.py
@@ -0,0 +1,168 @@
+# 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 tempfile
+
+from openstackclient.tests.functional import base
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+
+class KeypairBase(base.TestCase):
+ """Methods for functional tests."""
+
+ def keypair_create(self, name=data_utils.rand_uuid()):
+ """Create keypair and add cleanup."""
+ raw_output = self.openstack('keypair create ' + name)
+ self.addCleanup(self.keypair_delete, name, True)
+ if not raw_output:
+ self.fail('Keypair has not been created!')
+
+ def keypair_list(self, params=''):
+ """Return dictionary with list of keypairs."""
+ raw_output = self.openstack('keypair list')
+ keypairs = self.parse_show_as_object(raw_output)
+ return keypairs
+
+ def keypair_delete(self, name, ignore_exceptions=False):
+ """Try to delete keypair by name."""
+ try:
+ self.openstack('keypair delete ' + name)
+ except exceptions.CommandFailed:
+ if not ignore_exceptions:
+ raise
+
+
+class KeypairTests(KeypairBase):
+ """Functional tests for compute keypairs."""
+
+ PUBLIC_KEY = (
+ 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWNGczJxNaFUrJJVhta4dWsZY6bU'
+ '5HUMPbyfSMu713ca3mYtG848W4dfDCB98KmSQx2Bl0D6Q2nrOszOXEQWAXNdfMadnW'
+ 'c4mNwhZcPBVohIFoC1KZJC8kcBTvFZcoz3mdIijxJtywZNpGNh34VRJlZeHyYjg8/D'
+ 'esHzdoBVd5c/4R36emQSIV9ukY6PHeZ3scAH4B3K9PxItJBwiFtouSRphQG0bJgOv/'
+ 'gjAjMElAvg5oku98cb4QiHZ8T8WY68id804raHR6pJxpVVJN4TYJmlUs+NOVM+pPKb'
+ 'KJttqrIBTkawGK9pLHNfn7z6v1syvUo/4enc1l0Q/Qn2kWiz67 fake@openstack'
+ )
+
+ def setUp(self):
+ """Create keypair with randomized name for tests."""
+ super(KeypairTests, self).setUp()
+ self.KPName = data_utils.rand_name('TestKeyPair')
+ self.keypair = self.keypair_create(self.KPName)
+
+ def test_keypair_create_duplicate(self):
+ """Try to create duplicate name keypair.
+
+ Test steps:
+ 1) Create keypair in setUp
+ 2) Try to create duplicate keypair with the same name
+ """
+ self.assertRaises(exceptions.CommandFailed,
+ self.openstack, 'keypair create ' + self.KPName)
+
+ def test_keypair_create_noname(self):
+ """Try to create keypair without name.
+
+ Test steps:
+ 1) Try to create keypair without a name
+ """
+ self.assertRaises(exceptions.CommandFailed,
+ self.openstack, 'keypair create')
+
+ def test_keypair_create_public_key(self):
+ """Test for create keypair with --public-key option.
+
+ Test steps:
+ 1) Create keypair with given public key
+ 2) Delete keypair
+ """
+ with tempfile.NamedTemporaryFile() as f:
+ f.write(self.PUBLIC_KEY)
+ f.flush()
+
+ raw_output = self.openstack(
+ 'keypair create --public-key %s tmpkey' % f.name,
+ )
+ self.addCleanup(
+ self.openstack,
+ 'keypair delete tmpkey',
+ )
+ self.assertIn('tmpkey', raw_output)
+
+ def test_keypair_create(self):
+ """Test keypair create command.
+
+ Test steps:
+ 1) Create keypair in setUp
+ 2) Check RSA private key in output
+ 3) Check for new keypair in keypairs list
+ """
+ NewName = data_utils.rand_name('TestKeyPairCreated')
+ raw_output = self.openstack('keypair create ' + NewName)
+ self.addCleanup(self.openstack, 'keypair delete ' + NewName)
+ self.assertInOutput('-----BEGIN RSA PRIVATE KEY-----', raw_output)
+ self.assertRegex(raw_output, "[0-9A-Za-z+/]+[=]{0,3}\n")
+ self.assertInOutput('-----END RSA PRIVATE KEY-----', raw_output)
+ self.assertIn(NewName, self.keypair_list())
+
+ def test_keypair_delete_not_existing(self):
+ """Try to delete keypair with not existing name.
+
+ Test steps:
+ 1) Create keypair in setUp
+ 2) Try to delete not existing keypair
+ """
+ self.assertRaises(exceptions.CommandFailed,
+ self.openstack, 'keypair delete not_existing')
+
+ def test_keypair_delete(self):
+ """Test keypair delete command.
+
+ Test steps:
+ 1) Create keypair in setUp
+ 2) Delete keypair
+ 3) Check that keypair not in keypairs list
+ """
+ self.openstack('keypair delete ' + self.KPName)
+ self.assertNotIn(self.KPName, self.keypair_list())
+
+ def test_keypair_list(self):
+ """Test keypair list command.
+
+ Test steps:
+ 1) Create keypair in setUp
+ 2) List keypairs
+ 3) Check output table structure
+ 4) Check keypair name in output
+ """
+ HEADERS = ['Name', 'Fingerprint']
+ raw_output = self.openstack('keypair list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, HEADERS)
+ self.assertIn(self.KPName, raw_output)
+
+ def test_keypair_show(self):
+ """Test keypair show command.
+
+ Test steps:
+ 1) Create keypair in setUp
+ 2) Show keypair
+ 3) Check output table structure
+ 4) Check keypair name in output
+ """
+ HEADERS = ['Field', 'Value']
+ raw_output = self.openstack('keypair show ' + self.KPName)
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, HEADERS)
+ self.assertInOutput(self.KPName, raw_output)
diff --git a/openstackclient/tests/functional/compute/v2/test_server.py b/openstackclient/tests/functional/compute/v2/test_server.py
new file mode 100644
index 00000000..6eedf408
--- /dev/null
+++ b/openstackclient/tests/functional/compute/v2/test_server.py
@@ -0,0 +1,308 @@
+# 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 time
+
+from tempest.lib.common.utils import data_utils
+
+from openstackclient.tests.functional import base
+from tempest.lib import exceptions
+
+
+class ServerTests(base.TestCase):
+ """Functional tests for openstack server commands."""
+
+ @classmethod
+ def get_flavor(cls):
+ # NOTE(rtheis): Get cirros256 or m1.tiny flavors since functional
+ # tests may create other flavors.
+ flavors = cls.openstack('flavor list -c Name -f value').split('\n')
+ server_flavor = None
+ for flavor in flavors:
+ if flavor in ['m1.tiny', 'cirros256']:
+ server_flavor = flavor
+ break
+ return server_flavor
+
+ @classmethod
+ def get_image(cls):
+ # NOTE(rtheis): Get cirros image since functional tests may
+ # create other images.
+ images = cls.openstack('image list -c Name -f value').split('\n')
+ server_image = None
+ for image in images:
+ if image.startswith('cirros-') and image.endswith('-uec'):
+ server_image = image
+ break
+ return server_image
+
+ @classmethod
+ def get_network(cls):
+ try:
+ # NOTE(rtheis): Get private network since functional tests may
+ # create other networks.
+ raw_output = cls.openstack('network show private -c id -f value')
+ except exceptions.CommandFailed:
+ return ''
+ return ' --nic net-id=' + raw_output.strip('\n')
+
+ def server_create(self, name=None):
+ """Create server. Add cleanup."""
+ name = name or data_utils.rand_uuid()
+ opts = self.get_opts(self.FIELDS)
+ flavor = self.get_flavor()
+ image = self.get_image()
+ network = self.get_network()
+ raw_output = self.openstack('--debug server create --flavor ' +
+ flavor +
+ ' --image ' + image + network + ' ' +
+ name + opts)
+ if not raw_output:
+ self.fail('Server has not been created!')
+ self.addCleanup(self.server_delete, name)
+
+ def server_list(self, params=[]):
+ """List servers."""
+ opts = self.get_opts(params)
+ return self.openstack('server list' + opts)
+
+ def server_delete(self, name):
+ """Delete server by name."""
+ self.openstack('server delete ' + name)
+
+ def setUp(self):
+ """Set necessary variables and create server."""
+ super(ServerTests, self).setUp()
+ self.NAME = data_utils.rand_name('TestServer')
+ self.OTHER_NAME = data_utils.rand_name('TestServer')
+ self.HEADERS = ['"Name"']
+ self.FIELDS = ['name']
+ self.IP_POOL = 'public'
+ self.server_create(self.NAME)
+
+ def test_server_rename(self):
+ """Test server rename command.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Rename server
+ 3) Check output
+ 4) Rename server back to original name
+ """
+ raw_output = self.openstack('server set --name ' + self.OTHER_NAME +
+ ' ' + self.NAME)
+ self.assertOutput("", raw_output)
+ self.assertNotIn(self.NAME, self.server_list(['Name']))
+ self.assertIn(self.OTHER_NAME, self.server_list(['Name']))
+ self.openstack('server set --name ' + self.NAME + ' ' +
+ self.OTHER_NAME)
+
+ def test_server_list(self):
+ """Test server list command.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) List servers
+ 3) Check output
+ """
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('server list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_server_show(self):
+ """Test server show command.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Show server
+ 3) Check output
+ """
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('server show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_server_metadata(self):
+ """Test command to set server metadata.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Set properties for server
+ 3) Check server properties in server show output
+ 4) Unset properties for server
+ 5) Check server properties in server show output
+ """
+ self.wait_for_status("ACTIVE")
+ # metadata
+ raw_output = self.openstack(
+ 'server set --property a=b --property c=d ' + self.NAME)
+ opts = self.get_opts(["name", "properties"])
+ raw_output = self.openstack('server show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\na='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack(
+ 'server unset --property a ' + self.NAME)
+ opts = self.get_opts(["name", "properties"])
+ raw_output = self.openstack('server show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\nc='d'\n", raw_output)
+
+ def test_server_suspend_resume(self):
+ """Test server suspend and resume commands.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Suspend server
+ 3) Check for SUSPENDED server status
+ 4) Resume server
+ 5) Check for ACTIVE server status
+ """
+ self.wait_for_status("ACTIVE")
+ # suspend
+ raw_output = self.openstack('server suspend ' + self.NAME)
+ self.assertEqual("", raw_output)
+ self.wait_for_status("SUSPENDED")
+ # resume
+ raw_output = self.openstack('server resume ' + self.NAME)
+ self.assertEqual("", raw_output)
+ self.wait_for_status("ACTIVE")
+
+ def test_server_lock_unlock(self):
+ """Test server lock and unlock commands.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Lock server
+ 3) Check output
+ 4) Unlock server
+ 5) Check output
+ """
+ self.wait_for_status("ACTIVE")
+ # lock
+ raw_output = self.openstack('server lock ' + self.NAME)
+ self.assertEqual("", raw_output)
+ # unlock
+ raw_output = self.openstack('server unlock ' + self.NAME)
+ self.assertEqual("", raw_output)
+
+ def test_server_pause_unpause(self):
+ """Test server pause and unpause commands.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Pause server
+ 3) Check for PAUSED server status
+ 4) Unpause server
+ 5) Check for ACTIVE server status
+ """
+ self.wait_for_status("ACTIVE")
+ # pause
+ raw_output = self.openstack('server pause ' + self.NAME)
+ self.assertEqual("", raw_output)
+ self.wait_for_status("PAUSED")
+ # unpause
+ raw_output = self.openstack('server unpause ' + self.NAME)
+ self.assertEqual("", raw_output)
+ self.wait_for_status("ACTIVE")
+
+ def test_server_rescue_unrescue(self):
+ """Test server rescue and unrescue commands.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Rescue server
+ 3) Check for RESCUE server status
+ 4) Unrescue server
+ 5) Check for ACTIVE server status
+ """
+ self.wait_for_status("ACTIVE")
+ # rescue
+ opts = self.get_opts(["adminPass"])
+ raw_output = self.openstack('server rescue ' + self.NAME + opts)
+ self.assertNotEqual("", raw_output)
+ self.wait_for_status("RESCUE")
+ # unrescue
+ raw_output = self.openstack('server unrescue ' + self.NAME)
+ self.assertEqual("", raw_output)
+ self.wait_for_status("ACTIVE")
+
+ def test_server_attach_detach_floating_ip(self):
+ """Test commands to attach and detach floating IP for server.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Create floating IP
+ 3) Add floating IP to server
+ 4) Check for floating IP in server show output
+ 5) Remove floating IP from server
+ 6) Check that floating IP is not in server show output
+ 7) Delete floating IP
+ 8) Check output
+ """
+ self.wait_for_status("ACTIVE")
+ # attach ip
+ opts = self.get_opts(["id", "floating_ip_address"])
+ raw_output = self.openstack('floating ip create ' +
+ self.IP_POOL +
+ opts)
+ ip, ipid, rol = tuple(raw_output.split('\n'))
+ self.assertNotEqual("", ipid)
+ self.assertNotEqual("", ip)
+ raw_output = self.openstack('server add floating ip ' + self.NAME +
+ ' ' + ip)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('server show ' + self.NAME)
+ self.assertIn(ip, raw_output)
+
+ # detach ip
+ raw_output = self.openstack('server remove floating ip ' + self.NAME +
+ ' ' + ip)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('server show ' + self.NAME)
+ self.assertNotIn(ip, raw_output)
+ raw_output = self.openstack('floating ip delete ' + ipid)
+ self.assertEqual("", raw_output)
+
+ def test_server_reboot(self):
+ """Test server reboot command.
+
+ Test steps:
+ 1) Boot server in setUp
+ 2) Reboot server
+ 3) Check for ACTIVE server status
+ """
+ self.wait_for_status("ACTIVE")
+ # reboot
+ raw_output = self.openstack('server reboot ' + self.NAME)
+ self.assertEqual("", raw_output)
+ self.wait_for_status("ACTIVE")
+
+ def wait_for_status(self, expected_status='ACTIVE', wait=900, interval=30):
+ """Wait until server reaches expected status."""
+ # TODO(thowe): Add a server wait command to osc
+ failures = ['ERROR']
+ total_sleep = 0
+ opts = self.get_opts(['status'])
+ while total_sleep < wait:
+ status = self.openstack('server show ' + self.NAME + opts)
+ status = status.rstrip()
+ print('Waiting for {} current status: {}'.format(expected_status,
+ status))
+ if status == expected_status:
+ break
+ self.assertNotIn(status, failures)
+ time.sleep(interval)
+ total_sleep += interval
+
+ status = self.openstack('server show ' + self.NAME + opts)
+ status = status.rstrip()
+ self.assertEqual(status, expected_status)
+ # give it a little bit more time
+ time.sleep(5)
diff --git a/openstackclient/tests/functional/compute/v2/test_server_group.py b/openstackclient/tests/functional/compute/v2/test_server_group.py
new file mode 100644
index 00000000..3f0a24e5
--- /dev/null
+++ b/openstackclient/tests/functional/compute/v2/test_server_group.py
@@ -0,0 +1,46 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class ServerGroupTests(base.TestCase):
+ """Functional tests for servergroup."""
+
+ NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('server group create --policy affinity ' +
+ cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('server group delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_server_group_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('server group list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_server_group_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('server group show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/examples/__init__.py b/openstackclient/tests/functional/examples/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/examples/__init__.py
diff --git a/openstackclient/tests/functional/examples/test_examples.py b/openstackclient/tests/functional/examples/test_examples.py
new file mode 100644
index 00000000..031f036a
--- /dev/null
+++ b/openstackclient/tests/functional/examples/test_examples.py
@@ -0,0 +1,28 @@
+# 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 openstackclient.tests.functional import base
+
+
+class ExampleTests(base.TestCase):
+ """Functional tests for running examples."""
+
+ def test_common(self):
+ # NOTE(stevemar): If an examples has a non-zero return
+ # code, then execute will raise an error by default.
+ base.execute('python', base.EXAMPLE_DIR + '/common.py --debug')
+
+ def test_object_api(self):
+ base.execute('python', base.EXAMPLE_DIR + '/object_api.py --debug')
+
+ def test_osc_lib(self):
+ base.execute('python', base.EXAMPLE_DIR + '/osc-lib.py --debug')
diff --git a/openstackclient/tests/functional/identity/__init__.py b/openstackclient/tests/functional/identity/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/identity/__init__.py
diff --git a/openstackclient/tests/functional/identity/v2/__init__.py b/openstackclient/tests/functional/identity/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/__init__.py
diff --git a/openstackclient/tests/functional/identity/v2/common.py b/openstackclient/tests/functional/identity/v2/common.py
new file mode 100644
index 00000000..b390c5bc
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/common.py
@@ -0,0 +1,181 @@
+# 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.common.utils import data_utils
+
+from openstackclient.tests.functional import base
+
+BASIC_LIST_HEADERS = ['ID', 'Name']
+
+
+class IdentityTests(base.TestCase):
+ """Functional tests for Identity commands. """
+
+ USER_FIELDS = ['email', 'enabled', 'id', 'name', 'project_id',
+ 'username', 'domain_id', 'default_project_id']
+ PROJECT_FIELDS = ['enabled', 'id', 'name', 'description', 'domain_id']
+ TOKEN_FIELDS = ['expires', 'id', 'project_id', 'user_id']
+ ROLE_FIELDS = ['id', 'name', 'links', 'domain_id']
+ SERVICE_FIELDS = ['id', 'enabled', 'name', 'type', 'description']
+ ENDPOINT_FIELDS = ['id', 'region', 'service_id', 'service_name',
+ 'service_type', 'enabled', 'publicurl',
+ 'adminurl', 'internalurl']
+
+ EC2_CREDENTIALS_FIELDS = ['access', 'project_id', 'secret',
+ 'trust_id', 'user_id']
+ EC2_CREDENTIALS_LIST_HEADERS = ['Access', 'Secret',
+ 'Project ID', 'User ID']
+ CATALOG_LIST_HEADERS = ['Name', 'Type', 'Endpoints']
+ ENDPOINT_LIST_HEADERS = ['ID', 'Region', 'Service Name', 'Service Type']
+
+ @classmethod
+ def setUpClass(cls):
+ # prepare v2 env
+ os.environ['OS_IDENTITY_API_VERSION'] = '2.0'
+ auth_url = os.environ.get('OS_AUTH_URL')
+ auth_url = auth_url.replace('v3', 'v2.0')
+ os.environ['OS_AUTH_URL'] = auth_url
+
+ # create dummy project
+ cls.project_name = data_utils.rand_name('TestProject')
+ cls.project_description = data_utils.rand_name('description')
+ cls.openstack(
+ 'project create '
+ '--description %(description)s '
+ '--enable '
+ '%(name)s' % {'description': cls.project_description,
+ 'name': cls.project_name})
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.openstack('project delete %s' % cls.project_name)
+
+ def _create_dummy_project(self, add_clean_up=True):
+ project_name = data_utils.rand_name('TestProject')
+ project_description = data_utils.rand_name('description')
+ raw_output = self.openstack(
+ 'project create '
+ '--description %(description)s '
+ '--enable %(name)s' % {'description': project_description,
+ 'name': project_name})
+ project = self.parse_show_as_object(raw_output)
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'project delete %s' % project['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.PROJECT_FIELDS)
+ return project_name
+
+ def _create_dummy_user(self, add_clean_up=True):
+ username = data_utils.rand_name('TestUser')
+ password = data_utils.rand_name('password')
+ email = data_utils.rand_name() + '@example.com'
+ raw_output = self.openstack(
+ 'user create '
+ '--project %(project)s '
+ '--password %(password)s '
+ '--email %(email)s '
+ '--enable '
+ '%(name)s' % {'project': self.project_name,
+ 'email': email,
+ 'password': password,
+ 'name': username})
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'user delete %s' % self.parse_show_as_object(raw_output)['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.USER_FIELDS)
+ return username
+
+ def _create_dummy_role(self, add_clean_up=True):
+ role_name = data_utils.rand_name('TestRole')
+ raw_output = self.openstack('role create %s' % role_name)
+ role = self.parse_show_as_object(raw_output)
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'role delete %s' % role['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ROLE_FIELDS)
+ self.assertEqual(role_name, role['name'])
+ return role_name
+
+ def _create_dummy_ec2_credentials(self, add_clean_up=True):
+ raw_output = self.openstack('ec2 credentials create')
+ ec2_credentials = self.parse_show_as_object(raw_output)
+ access_key = ec2_credentials['access']
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'ec2 credentials delete %s' % access_key)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.EC2_CREDENTIALS_FIELDS)
+ return access_key
+
+ def _create_dummy_token(self, add_clean_up=True):
+ raw_output = self.openstack('token issue')
+ token = self.parse_show_as_object(raw_output)
+ if add_clean_up:
+ self.addCleanup(self.openstack,
+ 'token revoke %s' % token['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.TOKEN_FIELDS)
+ return token['id']
+
+ def _create_dummy_service(self, add_clean_up=True):
+ service_name = data_utils.rand_name('TestService')
+ description = data_utils.rand_name('description')
+ type_name = data_utils.rand_name('TestType')
+ raw_output = self.openstack(
+ 'service create '
+ '--name %(name)s '
+ '--description %(description)s '
+ '%(type)s' % {'name': service_name,
+ 'description': description,
+ 'type': type_name})
+ if add_clean_up:
+ service = self.parse_show_as_object(raw_output)
+ self.addCleanup(self.openstack,
+ 'service delete %s' % service['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.SERVICE_FIELDS)
+ return service_name
+
+ def _create_dummy_endpoint(self, add_clean_up=True):
+ region_id = data_utils.rand_name('TestRegion')
+ service_name = self._create_dummy_service()
+ public_url = data_utils.rand_url()
+ admin_url = data_utils.rand_url()
+ internal_url = data_utils.rand_url()
+ raw_output = self.openstack(
+ 'endpoint create '
+ '--publicurl %(publicurl)s '
+ '--adminurl %(adminurl)s '
+ '--internalurl %(internalurl)s '
+ '--region %(region)s '
+ '%(service)s' % {'publicurl': public_url,
+ 'adminurl': admin_url,
+ 'internalurl': internal_url,
+ 'region': region_id,
+ 'service': service_name})
+ endpoint = self.parse_show_as_object(raw_output)
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'endpoint delete %s' % endpoint['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ENDPOINT_FIELDS)
+ return endpoint['id']
diff --git a/openstackclient/tests/functional/identity/v2/test_catalog.py b/openstackclient/tests/functional/identity/v2/test_catalog.py
new file mode 100644
index 00000000..f403fbfc
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/test_catalog.py
@@ -0,0 +1,42 @@
+# 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 openstackclient.tests.functional.identity.v2 import common
+
+
+class CatalogTests(common.IdentityTests):
+
+ def test_catalog_list(self):
+ raw_output = self.openstack('catalog list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, self.CATALOG_LIST_HEADERS)
+
+ def test_catalog_show(self):
+ """test catalog show command
+
+ The output example:
+ +-----------+-------------------------------------------+
+ | Field | Value |
+ +-----------+-------------------------------------------+
+ | endpoints | test1 |
+ | | publicURL: http://localhost:5000/v2.0 |
+ | | internalURL: http://localhost:5000/v2.0 |
+ | | adminURL: http://localhost:5000/v2.0 |
+ | | |
+ | name | keystone |
+ | type | identity |
+ +-----------+-------------------------------------------+
+ """
+ raw_output = self.openstack('catalog show %s' % 'identity')
+ items = self.parse_show(raw_output)
+ # items may have multiple endpoint urls with empty key
+ self.assert_show_fields(items, ['endpoints', 'name', 'type', ''])
diff --git a/openstackclient/tests/functional/identity/v2/test_ec2_credentials.py b/openstackclient/tests/functional/identity/v2/test_ec2_credentials.py
new file mode 100644
index 00000000..43dff91f
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/test_ec2_credentials.py
@@ -0,0 +1,48 @@
+# 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 openstackclient.tests.functional.identity.v2 import common
+
+
+class EC2CredentialsTests(common.IdentityTests):
+
+ def test_ec2_credentials_create(self):
+ self._create_dummy_ec2_credentials()
+
+ def test_ec2_credentials_delete(self):
+ access_key = self._create_dummy_ec2_credentials(add_clean_up=False)
+ raw_output = self.openstack(
+ 'ec2 credentials delete %s' % access_key,
+ )
+ self.assertEqual(0, len(raw_output))
+
+ def test_ec2_credentials_multi_delete(self):
+ access_key_1 = self._create_dummy_ec2_credentials(add_clean_up=False)
+ access_key_2 = self._create_dummy_ec2_credentials(add_clean_up=False)
+ raw_output = self.openstack(
+ 'ec2 credentials delete ' + access_key_1 + ' ' + access_key_2
+ )
+ self.assertEqual(0, len(raw_output))
+
+ def test_ec2_credentials_list(self):
+ self._create_dummy_ec2_credentials()
+ raw_output = self.openstack('ec2 credentials list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, self.EC2_CREDENTIALS_LIST_HEADERS)
+
+ def test_ec2_credentials_show(self):
+ access_key = self._create_dummy_ec2_credentials()
+ show_output = self.openstack(
+ 'ec2 credentials show %s' % access_key,
+ )
+ items = self.parse_show(show_output)
+ self.assert_show_fields(items, self.EC2_CREDENTIALS_FIELDS)
diff --git a/openstackclient/tests/functional/identity/v2/test_endpoint.py b/openstackclient/tests/functional/identity/v2/test_endpoint.py
new file mode 100644
index 00000000..9df5ca8a
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/test_endpoint.py
@@ -0,0 +1,45 @@
+# 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 openstackclient.tests.functional.identity.v2 import common
+
+
+class EndpointTests(common.IdentityTests):
+
+ def test_endpoint_create(self):
+ self._create_dummy_endpoint()
+
+ def test_endpoint_delete(self):
+ endpoint_id = self._create_dummy_endpoint(add_clean_up=False)
+ raw_output = self.openstack(
+ 'endpoint delete %s' % endpoint_id)
+ self.assertEqual(0, len(raw_output))
+
+ def test_endpoint_multi_delete(self):
+ endpoint_id_1 = self._create_dummy_endpoint(add_clean_up=False)
+ endpoint_id_2 = self._create_dummy_endpoint(add_clean_up=False)
+ raw_output = self.openstack(
+ 'endpoint delete ' + endpoint_id_1 + ' ' + endpoint_id_2)
+ self.assertEqual(0, len(raw_output))
+
+ def test_endpoint_list(self):
+ endpoint_id = self._create_dummy_endpoint()
+ raw_output = self.openstack('endpoint list')
+ self.assertIn(endpoint_id, raw_output)
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, self.ENDPOINT_LIST_HEADERS)
+
+ def test_endpoint_show(self):
+ endpoint_id = self._create_dummy_endpoint()
+ raw_output = self.openstack('endpoint show %s' % endpoint_id)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ENDPOINT_FIELDS)
diff --git a/openstackclient/tests/functional/identity/v2/test_project.py b/openstackclient/tests/functional/identity/v2/test_project.py
new file mode 100644
index 00000000..b6222a1b
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/test_project.py
@@ -0,0 +1,86 @@
+# 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 tempest.lib.common.utils import data_utils
+
+from openstackclient.tests.functional.identity.v2 import common
+
+
+class ProjectTests(common.IdentityTests):
+
+ def test_project_create(self):
+ project_name = data_utils.rand_name('TestProject')
+ description = data_utils.rand_name('description')
+ raw_output = self.openstack(
+ 'project create '
+ '--description %(description)s '
+ '--enable '
+ '--property k1=v1 '
+ '--property k2=v2 '
+ '%(name)s' % {'description': description,
+ 'name': project_name})
+ self.addCleanup(
+ self.openstack,
+ 'project delete %s' % project_name
+ )
+ items = self.parse_show(raw_output)
+ show_fields = list(self.PROJECT_FIELDS)
+ show_fields.extend(['k1', 'k2'])
+ self.assert_show_fields(items, show_fields)
+ project = self.parse_show_as_object(raw_output)
+ self.assertEqual('v1', project['k1'])
+ self.assertEqual('v2', project['k2'])
+
+ def test_project_delete(self):
+ project_name = self._create_dummy_project(add_clean_up=False)
+ raw_output = self.openstack(
+ 'project delete %s' % project_name)
+ self.assertEqual(0, len(raw_output))
+
+ def test_project_list(self):
+ raw_output = self.openstack('project list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_project_set(self):
+ project_name = self._create_dummy_project()
+ new_project_name = data_utils.rand_name('NewTestProject')
+ raw_output = self.openstack(
+ 'project set '
+ '--name %(new_name)s '
+ '--disable '
+ '--property k0=v0 '
+ '%(name)s' % {'new_name': new_project_name,
+ 'name': project_name})
+ self.assertEqual(0, len(raw_output))
+ # check project details
+ raw_output = self.openstack(
+ 'project show %s' % new_project_name
+ )
+ items = self.parse_show(raw_output)
+ fields = list(self.PROJECT_FIELDS)
+ fields.extend(['properties'])
+ self.assert_show_fields(items, fields)
+ project = self.parse_show_as_object(raw_output)
+ self.assertEqual(new_project_name, project['name'])
+ self.assertEqual('False', project['enabled'])
+ self.assertEqual("k0='v0'", project['properties'])
+
+ def test_project_show(self):
+ project_name = self._create_dummy_project()
+ raw_output = self.openstack(
+ 'project show %s' % project_name
+ )
+ items = self.parse_show(raw_output)
+ fields = list(self.PROJECT_FIELDS)
+ fields.extend(['properties'])
+ self.assert_show_fields(items, fields)
diff --git a/openstackclient/tests/functional/identity/v2/test_role.py b/openstackclient/tests/functional/identity/v2/test_role.py
new file mode 100644
index 00000000..82e19aab
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/test_role.py
@@ -0,0 +1,110 @@
+# 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 openstackclient.tests.functional.identity.v2 import common
+
+
+class RoleTests(common.IdentityTests):
+
+ def test_role_create(self):
+ self._create_dummy_role()
+
+ def test_role_delete(self):
+ role_name = self._create_dummy_role(add_clean_up=False)
+ raw_output = self.openstack('role delete %s' % role_name)
+ self.assertEqual(0, len(raw_output))
+
+ def test_role_list(self):
+ self._create_dummy_role()
+ raw_output = self.openstack('role list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_role_list_with_user_project(self):
+ project_name = self._create_dummy_project()
+ role_name = self._create_dummy_role()
+ username = self._create_dummy_user()
+ raw_output = self.openstack(
+ 'role add '
+ '--project %(project)s '
+ '--user %(user)s '
+ '%(role)s' % {'project': project_name,
+ 'user': username,
+ 'role': role_name})
+ self.addCleanup(
+ self.openstack,
+ 'role remove '
+ '--project %(project)s '
+ '--user %(user)s '
+ '%(role)s' % {'project': project_name,
+ 'user': username,
+ 'role': role_name})
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ROLE_FIELDS)
+
+ raw_output = self.openstack(
+ 'role list '
+ '--project %(project)s '
+ '--user %(user)s '
+ '' % {'project': project_name,
+ 'user': username})
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+ self.assertEqual(1, len(items))
+
+ def test_role_show(self):
+ role_name = self._create_dummy_role()
+ raw_output = self.openstack('role show %s' % role_name)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ROLE_FIELDS)
+
+ def test_role_add(self):
+ role_name = self._create_dummy_role()
+ username = self._create_dummy_user()
+ raw_output = self.openstack(
+ 'role add '
+ '--project %(project)s '
+ '--user %(user)s '
+ '%(role)s' % {'project': self.project_name,
+ 'user': username,
+ 'role': role_name})
+ self.addCleanup(
+ self.openstack,
+ 'role remove '
+ '--project %(project)s '
+ '--user %(user)s '
+ '%(role)s' % {'project': self.project_name,
+ 'user': username,
+ 'role': role_name})
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ROLE_FIELDS)
+
+ def test_role_remove(self):
+ role_name = self._create_dummy_role()
+ username = self._create_dummy_user()
+ add_raw_output = self.openstack(
+ 'role add '
+ '--project %(project)s '
+ '--user %(user)s '
+ '%(role)s' % {'project': self.project_name,
+ 'user': username,
+ 'role': role_name})
+ del_raw_output = self.openstack(
+ 'role remove '
+ '--project %(project)s '
+ '--user %(user)s '
+ '%(role)s' % {'project': self.project_name,
+ 'user': username,
+ 'role': role_name})
+ items = self.parse_show(add_raw_output)
+ self.assert_show_fields(items, self.ROLE_FIELDS)
+ self.assertEqual(0, len(del_raw_output))
diff --git a/openstackclient/tests/functional/identity/v2/test_service.py b/openstackclient/tests/functional/identity/v2/test_service.py
new file mode 100644
index 00000000..d0e03804
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/test_service.py
@@ -0,0 +1,44 @@
+# 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 openstackclient.tests.functional.identity.v2 import common
+
+
+class ServiceTests(common.IdentityTests):
+
+ def test_service_create(self):
+ self._create_dummy_service()
+
+ def test_service_delete(self):
+ service_name = self._create_dummy_service(add_clean_up=False)
+ raw_output = self.openstack('service delete %s' % service_name)
+ self.assertEqual(0, len(raw_output))
+
+ def test_service_multi_delete(self):
+ service_name_1 = self._create_dummy_service(add_clean_up=False)
+ service_name_2 = self._create_dummy_service(add_clean_up=False)
+ raw_output = self.openstack(
+ 'service delete ' + service_name_1 + ' ' + service_name_2)
+ self.assertEqual(0, len(raw_output))
+
+ def test_service_list(self):
+ self._create_dummy_service()
+ raw_output = self.openstack('service list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_service_show(self):
+ service_name = self._create_dummy_service()
+ raw_output = self.openstack(
+ 'service show %s' % service_name)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.SERVICE_FIELDS)
diff --git a/openstackclient/tests/functional/identity/v2/test_token.py b/openstackclient/tests/functional/identity/v2/test_token.py
new file mode 100644
index 00000000..f8569744
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/test_token.py
@@ -0,0 +1,24 @@
+# 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 openstackclient.tests.functional.identity.v2 import common
+
+
+class TokenTests(common.IdentityTests):
+
+ def test_token_issue(self):
+ self._create_dummy_token()
+
+ def test_token_revoke(self):
+ token_id = self._create_dummy_token(add_clean_up=False)
+ raw_output = self.openstack('token revoke %s' % token_id)
+ self.assertEqual(0, len(raw_output))
diff --git a/openstackclient/tests/functional/identity/v2/test_user.py b/openstackclient/tests/functional/identity/v2/test_user.py
new file mode 100644
index 00000000..ac609b94
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v2/test_user.py
@@ -0,0 +1,60 @@
+# 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 tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from openstackclient.tests.functional.identity.v2 import common
+
+
+class UserTests(common.IdentityTests):
+
+ def test_user_create(self):
+ self._create_dummy_user()
+
+ def test_user_delete(self):
+ username = self._create_dummy_user(add_clean_up=False)
+ raw_output = self.openstack('user delete %s' % username)
+ self.assertEqual(0, len(raw_output))
+
+ def test_user_list(self):
+ raw_output = self.openstack('user list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_user_set(self):
+ username = self._create_dummy_user()
+ raw_output = self.openstack('user show %s' % username)
+ user = self.parse_show_as_object(raw_output)
+ new_username = data_utils.rand_name('NewTestUser')
+ new_email = data_utils.rand_name() + '@example.com'
+ raw_output = self.openstack('user set '
+ '--email %(email)s '
+ '--name %(new_name)s '
+ '%(id)s' % {'email': new_email,
+ 'new_name': new_username,
+ 'id': user['id']})
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack('user show %s' % new_username)
+ new_user = self.parse_show_as_object(raw_output)
+ self.assertEqual(user['id'], new_user['id'])
+ self.assertEqual(new_email, new_user['email'])
+
+ def test_user_show(self):
+ username = self._create_dummy_user()
+ raw_output = self.openstack('user show %s' % username)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.USER_FIELDS)
+
+ def test_bad_user_command(self):
+ self.assertRaises(exceptions.CommandFailed,
+ self.openstack, 'user unlist')
diff --git a/openstackclient/tests/functional/identity/v3/__init__.py b/openstackclient/tests/functional/identity/v3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/__init__.py
diff --git a/openstackclient/tests/functional/identity/v3/common.py b/openstackclient/tests/functional/identity/v3/common.py
new file mode 100644
index 00000000..5dd42e70
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/common.py
@@ -0,0 +1,289 @@
+# 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.common.utils import data_utils
+
+from openstackclient.tests.functional import base
+
+
+BASIC_LIST_HEADERS = ['ID', 'Name']
+
+
+class IdentityTests(base.TestCase):
+ """Functional tests for Identity commands. """
+
+ DOMAIN_FIELDS = ['description', 'enabled', 'id', 'name', 'links']
+ GROUP_FIELDS = ['description', 'domain_id', 'id', 'name', 'links']
+ TOKEN_FIELDS = ['expires', 'id', 'project_id', 'user_id']
+ USER_FIELDS = ['email', 'enabled', 'id', 'name', 'name',
+ 'domain_id', 'default_project_id', 'description',
+ 'password_expires_at']
+ PROJECT_FIELDS = ['description', 'id', 'domain_id', 'is_domain',
+ 'enabled', 'name', 'parent_id', 'links']
+ ROLE_FIELDS = ['id', 'name', 'links', 'domain_id']
+ SERVICE_FIELDS = ['id', 'enabled', 'name', 'type', 'description']
+ REGION_FIELDS = ['description', 'enabled', 'parent_region', 'region']
+ ENDPOINT_FIELDS = ['id', 'region', 'region_id', 'service_id',
+ 'service_name', 'service_type', 'enabled',
+ 'interface', 'url']
+
+ REGION_LIST_HEADERS = ['Region', 'Parent Region', 'Description']
+ ENDPOINT_LIST_HEADERS = ['ID', 'Region', 'Service Name', 'Service Type',
+ 'Enabled', 'Interface', 'URL']
+
+ IDENTITY_PROVIDER_FIELDS = ['description', 'enabled', 'id', 'remote_ids']
+ IDENTITY_PROVIDER_LIST_HEADERS = ['ID', 'Enabled', 'Description']
+
+ SERVICE_PROVIDER_FIELDS = ['auth_url', 'description', 'enabled',
+ 'id', 'relay_state_prefix', 'sp_url']
+ SERVICE_PROVIDER_LIST_HEADERS = ['ID', 'Enabled', 'Description',
+ 'Auth URL']
+
+ @classmethod
+ def setUpClass(cls):
+ # prepare v3 env
+ os.environ['OS_IDENTITY_API_VERSION'] = '3'
+ auth_url = os.environ.get('OS_AUTH_URL')
+ auth_url = auth_url.replace('v2.0', 'v3')
+ os.environ['OS_AUTH_URL'] = auth_url
+
+ # create dummy domain
+ cls.domain_name = data_utils.rand_name('TestDomain')
+ cls.domain_description = data_utils.rand_name('description')
+ cls.openstack(
+ 'domain create '
+ '--description %(description)s '
+ '--enable '
+ '%(name)s' % {'description': cls.domain_description,
+ 'name': cls.domain_name})
+
+ # create dummy project
+ cls.project_name = data_utils.rand_name('TestProject')
+ cls.project_description = data_utils.rand_name('description')
+ cls.openstack(
+ 'project create '
+ '--domain %(domain)s '
+ '--description %(description)s '
+ '--enable '
+ '%(name)s' % {'domain': cls.domain_name,
+ 'description': cls.project_description,
+ 'name': cls.project_name})
+
+ @classmethod
+ def tearDownClass(cls):
+ # delete dummy project
+ cls.openstack('project delete %s' % cls.project_name)
+ # disable and delete dummy domain
+ cls.openstack('domain set --disable %s' % cls.domain_name)
+ cls.openstack('domain delete %s' % cls.domain_name)
+
+ def _create_dummy_user(self, add_clean_up=True):
+ username = data_utils.rand_name('TestUser')
+ password = data_utils.rand_name('password')
+ email = data_utils.rand_name() + '@example.com'
+ description = data_utils.rand_name('description')
+ raw_output = self.openstack(
+ 'user create '
+ '--domain %(domain)s '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '--password %(password)s '
+ '--email %(email)s '
+ '--description %(description)s '
+ '--enable '
+ '%(name)s' % {'domain': self.domain_name,
+ 'project': self.project_name,
+ 'project_domain': self.domain_name,
+ 'email': email,
+ 'password': password,
+ 'description': description,
+ 'name': username})
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'user delete %s' % self.parse_show_as_object(raw_output)['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.USER_FIELDS)
+ return username
+
+ def _create_dummy_role(self, add_clean_up=True):
+ role_name = data_utils.rand_name('TestRole')
+ raw_output = self.openstack('role create %s' % role_name)
+ role = self.parse_show_as_object(raw_output)
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'role delete %s' % role['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ROLE_FIELDS)
+ self.assertEqual(role_name, role['name'])
+ return role_name
+
+ def _create_dummy_group(self, add_clean_up=True):
+ group_name = data_utils.rand_name('TestGroup')
+ description = data_utils.rand_name('description')
+ raw_output = self.openstack(
+ 'group create '
+ '--domain %(domain)s '
+ '--description %(description)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'description': description,
+ 'name': group_name})
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'group delete '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': group_name})
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.GROUP_FIELDS)
+ return group_name
+
+ def _create_dummy_domain(self, add_clean_up=True):
+ domain_name = data_utils.rand_name('TestDomain')
+ domain_description = data_utils.rand_name('description')
+ self.openstack(
+ 'domain create '
+ '--description %(description)s '
+ '--enable %(name)s' % {'description': domain_description,
+ 'name': domain_name})
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'domain delete %s' % domain_name
+ )
+ self.addCleanup(
+ self.openstack,
+ 'domain set --disable %s' % domain_name
+ )
+ return domain_name
+
+ def _create_dummy_project(self, add_clean_up=True):
+ project_name = data_utils.rand_name('TestProject')
+ project_description = data_utils.rand_name('description')
+ self.openstack(
+ 'project create '
+ '--domain %(domain)s '
+ '--description %(description)s '
+ '--enable %(name)s' % {'domain': self.domain_name,
+ 'description': project_description,
+ 'name': project_name})
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'project delete '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': project_name})
+ return project_name
+
+ def _create_dummy_region(self, parent_region=None, add_clean_up=True):
+ region_id = data_utils.rand_name('TestRegion')
+ description = data_utils.rand_name('description')
+ parent_region_arg = ''
+ if parent_region is not None:
+ parent_region_arg = '--parent-region %s' % parent_region
+ raw_output = self.openstack(
+ 'region create '
+ '%(parent_region_arg)s '
+ '--description %(description)s '
+ '%(id)s' % {'parent_region_arg': parent_region_arg,
+ 'description': description,
+ 'id': region_id})
+ if add_clean_up:
+ self.addCleanup(self.openstack,
+ 'region delete %s' % region_id)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.REGION_FIELDS)
+ return region_id
+
+ def _create_dummy_service(self, add_clean_up=True):
+ service_name = data_utils.rand_name('TestService')
+ description = data_utils.rand_name('description')
+ type_name = data_utils.rand_name('TestType')
+ raw_output = self.openstack(
+ 'service create '
+ '--name %(name)s '
+ '--description %(description)s '
+ '--enable '
+ '%(type)s' % {'name': service_name,
+ 'description': description,
+ 'type': type_name})
+ if add_clean_up:
+ service = self.parse_show_as_object(raw_output)
+ self.addCleanup(self.openstack,
+ 'service delete %s' % service['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.SERVICE_FIELDS)
+ return service_name
+
+ def _create_dummy_endpoint(self, interface='public', add_clean_up=True):
+ region_id = self._create_dummy_region()
+ service_name = self._create_dummy_service()
+ endpoint_url = data_utils.rand_url()
+ raw_output = self.openstack(
+ 'endpoint create '
+ '--region %(region)s '
+ '--enable '
+ '%(service)s '
+ '%(interface)s '
+ '%(url)s' % {'region': region_id,
+ 'service': service_name,
+ 'interface': interface,
+ 'url': endpoint_url})
+ endpoint = self.parse_show_as_object(raw_output)
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'endpoint delete %s' % endpoint['id'])
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ENDPOINT_FIELDS)
+ return endpoint['id']
+
+ def _create_dummy_idp(self, add_clean_up=True):
+ identity_provider = data_utils.rand_name('IdentityProvider')
+ description = data_utils.rand_name('description')
+ raw_output = self.openstack(
+ 'identity provider create '
+ ' %(name)s '
+ '--description %(description)s '
+ '--enable ' % {'name': identity_provider,
+ 'description': description})
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'identity provider delete %s' % identity_provider)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.IDENTITY_PROVIDER_FIELDS)
+ return identity_provider
+
+ def _create_dummy_sp(self, add_clean_up=True):
+ service_provider = data_utils.rand_name('ServiceProvider')
+ description = data_utils.rand_name('description')
+ raw_output = self.openstack(
+ 'service provider create '
+ ' %(name)s '
+ '--description %(description)s '
+ '--auth-url https://sp.example.com:35357 '
+ '--service-provider-url https://sp.example.com:5000 '
+ '--enable ' % {'name': service_provider,
+ 'description': description})
+ if add_clean_up:
+ self.addCleanup(
+ self.openstack,
+ 'service provider delete %s' % service_provider)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.SERVICE_PROVIDER_FIELDS)
+ return service_provider
diff --git a/openstackclient/tests/functional/identity/v3/test_catalog.py b/openstackclient/tests/functional/identity/v3/test_catalog.py
new file mode 100644
index 00000000..c8361406
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_catalog.py
@@ -0,0 +1,45 @@
+# 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 openstackclient.tests.functional.identity.v3 import common
+
+
+class CatalogTests(common.IdentityTests):
+
+ def test_catalog_list(self):
+ raw_output = self.openstack('catalog list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, ['Name', 'Type', 'Endpoints'])
+
+ def test_catalog_show(self):
+ """test catalog show command
+
+ The output example:
+ +-----------+----------------------------------------+
+ | Field | Value |
+ +-----------+----------------------------------------+
+ | endpoints | test1 |
+ | | public: http://localhost:5000/v2.0 |
+ | | test1 |
+ | | internal: http://localhost:5000/v2.0 |
+ | | test1 |
+ | | admin: http://localhost:35357/v2.0 |
+ | | |
+ | id | e1e68b5ba21a43a39ff1cf58e736c3aa |
+ | name | keystone |
+ | type | identity |
+ +-----------+----------------------------------------+
+ """
+ raw_output = self.openstack('catalog show %s' % 'identity')
+ items = self.parse_show(raw_output)
+ # items may have multiple endpoint urls with empty key
+ self.assert_show_fields(items, ['endpoints', 'name', 'type', '', 'id'])
diff --git a/openstackclient/tests/functional/identity/v3/test_domain.py b/openstackclient/tests/functional/identity/v3/test_domain.py
new file mode 100644
index 00000000..d8946d1e
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_domain.py
@@ -0,0 +1,69 @@
+# 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 tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions
+
+from openstackclient.tests.functional.identity.v3 import common
+
+
+class DomainTests(common.IdentityTests):
+
+ def test_domain_create(self):
+ domain_name = data_utils.rand_name('TestDomain')
+ raw_output = self.openstack('domain create %s' % domain_name)
+ # disable domain first before deleting it
+ self.addCleanup(self.openstack,
+ 'domain delete %s' % domain_name)
+ self.addCleanup(self.openstack,
+ 'domain set --disable %s' % domain_name)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.DOMAIN_FIELDS)
+
+ def test_domain_list(self):
+ self._create_dummy_domain()
+ raw_output = self.openstack('domain list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_domain_delete(self):
+ domain_name = self._create_dummy_domain(add_clean_up=False)
+ # cannot delete enabled domain, disable it first
+ raw_output = self.openstack('domain set --disable %s' % domain_name)
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack('domain delete %s' % domain_name)
+ self.assertEqual(0, len(raw_output))
+
+ def test_domain_multi_delete(self):
+ domain_1 = self._create_dummy_domain(add_clean_up=False)
+ domain_2 = self._create_dummy_domain(add_clean_up=False)
+ # cannot delete enabled domain, disable it first
+ raw_output = self.openstack('domain set --disable %s' % domain_1)
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack('domain set --disable %s' % domain_2)
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack(
+ 'domain delete %s %s' % (domain_1, domain_2))
+ self.assertEqual(0, len(raw_output))
+
+ def test_domain_delete_failure(self):
+ domain_name = self._create_dummy_domain()
+ # cannot delete enabled domain
+ self.assertRaises(exceptions.CommandFailed,
+ self.openstack,
+ 'domain delete %s' % domain_name)
+
+ def test_domain_show(self):
+ domain_name = self._create_dummy_domain()
+ raw_output = self.openstack('domain show %s' % domain_name)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.DOMAIN_FIELDS)
diff --git a/openstackclient/tests/functional/identity/v3/test_endpoint.py b/openstackclient/tests/functional/identity/v3/test_endpoint.py
new file mode 100644
index 00000000..22dc1b65
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_endpoint.py
@@ -0,0 +1,67 @@
+# 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 tempest.lib.common.utils import data_utils
+
+from openstackclient.tests.functional.identity.v3 import common
+
+
+class EndpointTests(common.IdentityTests):
+
+ def test_endpoint_create(self):
+ self._create_dummy_endpoint(interface='public')
+ self._create_dummy_endpoint(interface='admin')
+ self._create_dummy_endpoint(interface='internal')
+
+ def test_endpoint_delete(self):
+ endpoint_id = self._create_dummy_endpoint(add_clean_up=False)
+ raw_output = self.openstack(
+ 'endpoint delete %s' % endpoint_id)
+ self.assertEqual(0, len(raw_output))
+
+ def test_endpoint_multi_delete(self):
+ endpoint_1 = self._create_dummy_endpoint(add_clean_up=False)
+ endpoint_2 = self._create_dummy_endpoint(add_clean_up=False)
+ raw_output = self.openstack(
+ 'endpoint delete %s %s' % (endpoint_1, endpoint_2))
+ self.assertEqual(0, len(raw_output))
+
+ def test_endpoint_list(self):
+ endpoint_id = self._create_dummy_endpoint()
+ raw_output = self.openstack('endpoint list')
+ self.assertIn(endpoint_id, raw_output)
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, self.ENDPOINT_LIST_HEADERS)
+
+ def test_endpoint_set(self):
+ endpoint_id = self._create_dummy_endpoint()
+ new_endpoint_url = data_utils.rand_url()
+ raw_output = self.openstack(
+ 'endpoint set '
+ '--interface %(interface)s '
+ '--url %(url)s '
+ '--disable '
+ '%(endpoint_id)s' % {'interface': 'admin',
+ 'url': new_endpoint_url,
+ 'endpoint_id': endpoint_id})
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack('endpoint show %s' % endpoint_id)
+ endpoint = self.parse_show_as_object(raw_output)
+ self.assertEqual('admin', endpoint['interface'])
+ self.assertEqual(new_endpoint_url, endpoint['url'])
+ self.assertEqual('False', endpoint['enabled'])
+
+ def test_endpoint_show(self):
+ endpoint_id = self._create_dummy_endpoint()
+ raw_output = self.openstack('endpoint show %s' % endpoint_id)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ENDPOINT_FIELDS)
diff --git a/openstackclient/tests/functional/identity/v3/test_group.py b/openstackclient/tests/functional/identity/v3/test_group.py
new file mode 100644
index 00000000..70491183
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_group.py
@@ -0,0 +1,178 @@
+# 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 tempest.lib.common.utils import data_utils
+
+from openstackclient.tests.functional.identity.v3 import common
+
+
+class GroupTests(common.IdentityTests):
+
+ def test_group_create(self):
+ self._create_dummy_group()
+
+ def test_group_list(self):
+ group_name = self._create_dummy_group()
+ raw_output = self.openstack('group list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+ self.assertIn(group_name, raw_output)
+
+ def test_group_list_with_domain(self):
+ group_name = self._create_dummy_group()
+ raw_output = self.openstack(
+ 'group list --domain %s' % self.domain_name)
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+ self.assertIn(group_name, raw_output)
+
+ def test_group_delete(self):
+ group_name = self._create_dummy_group(add_clean_up=False)
+ raw_output = self.openstack(
+ 'group delete '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': group_name})
+ self.assertEqual(0, len(raw_output))
+
+ def test_group_show(self):
+ group_name = self._create_dummy_group()
+ raw_output = self.openstack(
+ 'group show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': group_name})
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.GROUP_FIELDS)
+
+ def test_group_set(self):
+ group_name = self._create_dummy_group()
+ new_group_name = data_utils.rand_name('NewTestGroup')
+ raw_output = self.openstack(
+ 'group set '
+ '--domain %(domain)s '
+ '--name %(new_group)s '
+ '%(group)s' % {'domain': self.domain_name,
+ 'new_group': new_group_name,
+ 'group': group_name})
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack(
+ 'group show '
+ '--domain %(domain)s '
+ '%(group)s' % {'domain': self.domain_name,
+ 'group': new_group_name})
+ group = self.parse_show_as_object(raw_output)
+ self.assertEqual(new_group_name, group['name'])
+ # reset group name to make sure it will be cleaned up
+ raw_output = self.openstack(
+ 'group set '
+ '--domain %(domain)s '
+ '--name %(new_group)s '
+ '%(group)s' % {'domain': self.domain_name,
+ 'new_group': group_name,
+ 'group': new_group_name})
+ self.assertEqual(0, len(raw_output))
+
+ def test_group_add_user(self):
+ group_name = self._create_dummy_group()
+ username = self._create_dummy_user()
+ raw_output = self.openstack(
+ 'group add user '
+ '--group-domain %(group_domain)s '
+ '--user-domain %(user_domain)s '
+ '%(group)s %(user)s' % {'group_domain': self.domain_name,
+ 'user_domain': self.domain_name,
+ 'group': group_name,
+ 'user': username})
+ self.addCleanup(
+ self.openstack,
+ 'group remove user '
+ '--group-domain %(group_domain)s '
+ '--user-domain %(user_domain)s '
+ '%(group)s %(user)s' % {'group_domain': self.domain_name,
+ 'user_domain': self.domain_name,
+ 'group': group_name,
+ 'user': username})
+ self.assertEqual(
+ '%(user)s added to group %(group)s\n' % {'user': username,
+ 'group': group_name},
+ raw_output
+ )
+
+ def test_group_contains_user(self):
+ group_name = self._create_dummy_group()
+ username = self._create_dummy_user()
+ raw_output = self.openstack(
+ 'group add user '
+ '--group-domain %(group_domain)s '
+ '--user-domain %(user_domain)s '
+ '%(group)s %(user)s' % {'group_domain': self.domain_name,
+ 'user_domain': self.domain_name,
+ 'group': group_name,
+ 'user': username})
+ self.addCleanup(
+ self.openstack,
+ 'group remove user '
+ '--group-domain %(group_domain)s '
+ '--user-domain %(user_domain)s '
+ '%(group)s %(user)s' % {'group_domain': self.domain_name,
+ 'user_domain': self.domain_name,
+ 'group': group_name,
+ 'user': username})
+ self.assertEqual(
+ '%(user)s added to group %(group)s\n' % {'user': username,
+ 'group': group_name},
+ raw_output
+ )
+ raw_output = self.openstack(
+ 'group contains user '
+ '--group-domain %(group_domain)s '
+ '--user-domain %(user_domain)s '
+ '%(group)s %(user)s' % {'group_domain': self.domain_name,
+ 'user_domain': self.domain_name,
+ 'group': group_name,
+ 'user': username})
+ self.assertEqual(
+ '%(user)s in group %(group)s\n' % {'user': username,
+ 'group': group_name},
+ raw_output)
+
+ def test_group_remove_user(self):
+ group_name = self._create_dummy_group()
+ username = self._create_dummy_user()
+ add_raw_output = self.openstack(
+ 'group add user '
+ '--group-domain %(group_domain)s '
+ '--user-domain %(user_domain)s '
+ '%(group)s %(user)s' % {'group_domain': self.domain_name,
+ 'user_domain': self.domain_name,
+ 'group': group_name,
+ 'user': username})
+ remove_raw_output = self.openstack(
+ 'group remove user '
+ '--group-domain %(group_domain)s '
+ '--user-domain %(user_domain)s '
+ '%(group)s %(user)s' % {'group_domain': self.domain_name,
+ 'user_domain': self.domain_name,
+ 'group': group_name,
+ 'user': username})
+ self.assertEqual(
+ '%(user)s added to group %(group)s\n' % {'user': username,
+ 'group': group_name},
+ add_raw_output
+ )
+ self.assertEqual(
+ '%(user)s removed from '
+ 'group %(group)s\n' % {'user': username,
+ 'group': group_name},
+ remove_raw_output
+ )
diff --git a/openstackclient/tests/functional/identity/v3/test_idp.py b/openstackclient/tests/functional/identity/v3/test_idp.py
new file mode 100644
index 00000000..f9d8cb80
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_idp.py
@@ -0,0 +1,61 @@
+# 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 openstackclient.tests.functional.identity.v3 import common
+from tempest.lib.common.utils import data_utils
+
+
+class IdentityProviderTests(common.IdentityTests):
+ # Introduce functional test case for command 'Identity Provider'
+
+ def test_idp_create(self):
+ self._create_dummy_idp()
+
+ def test_idp_delete(self):
+ identity_provider = self._create_dummy_idp(add_clean_up=False)
+ raw_output = self.openstack('identity provider delete %s'
+ % identity_provider)
+ self.assertEqual(0, len(raw_output))
+
+ def test_idp_multi_delete(self):
+ idp_1 = self._create_dummy_idp(add_clean_up=False)
+ idp_2 = self._create_dummy_idp(add_clean_up=False)
+ raw_output = self.openstack(
+ 'identity provider delete %s %s' % (idp_1, idp_2))
+ self.assertEqual(0, len(raw_output))
+
+ def test_idp_show(self):
+ identity_provider = self._create_dummy_idp(add_clean_up=True)
+ raw_output = self.openstack('identity provider show %s'
+ % identity_provider)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.IDENTITY_PROVIDER_FIELDS)
+
+ def test_idp_list(self):
+ self._create_dummy_idp(add_clean_up=True)
+ raw_output = self.openstack('identity provider list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, self.IDENTITY_PROVIDER_LIST_HEADERS)
+
+ def test_idp_set(self):
+ identity_provider = self._create_dummy_idp(add_clean_up=True)
+ new_remoteid = data_utils.rand_name('newRemoteId')
+ raw_output = self.openstack('identity provider set '
+ '%(identity-provider)s '
+ '--remote-id %(remote-id)s '
+ % {'identity-provider': identity_provider,
+ 'remote-id': new_remoteid})
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack('identity provider show %s'
+ % identity_provider)
+ updated_value = self.parse_show_as_object(raw_output)
+ self.assertIn(new_remoteid, updated_value['remote_ids'])
diff --git a/openstackclient/tests/functional/identity/v3/test_project.py b/openstackclient/tests/functional/identity/v3/test_project.py
new file mode 100644
index 00000000..77438841
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_project.py
@@ -0,0 +1,113 @@
+# 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 tempest.lib.common.utils import data_utils
+
+from openstackclient.tests.functional.identity.v3 import common
+
+
+class ProjectTests(common.IdentityTests):
+
+ def test_project_create(self):
+ project_name = data_utils.rand_name('TestProject')
+ description = data_utils.rand_name('description')
+ raw_output = self.openstack(
+ 'project create '
+ '--domain %(domain)s '
+ '--description %(description)s '
+ '--enable '
+ '--property k1=v1 '
+ '--property k2=v2 '
+ '%(name)s' % {'domain': self.domain_name,
+ 'description': description,
+ 'name': project_name})
+ self.addCleanup(
+ self.openstack,
+ 'project delete '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': project_name}
+ )
+ items = self.parse_show(raw_output)
+ show_fields = list(self.PROJECT_FIELDS)
+ show_fields.extend(['k1', 'k2'])
+ self.assert_show_fields(items, show_fields)
+ project = self.parse_show_as_object(raw_output)
+ self.assertEqual('v1', project['k1'])
+ self.assertEqual('v2', project['k2'])
+
+ def test_project_delete(self):
+ project_name = self._create_dummy_project(add_clean_up=False)
+ raw_output = self.openstack(
+ 'project delete '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': project_name})
+ self.assertEqual(0, len(raw_output))
+
+ def test_project_list(self):
+ raw_output = self.openstack('project list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_project_list_with_domain(self):
+ project_name = self._create_dummy_project()
+ raw_output = self.openstack(
+ 'project list --domain %s' % self.domain_name)
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+ self.assertIn(project_name, raw_output)
+ self.assertTrue(len(items) > 0)
+
+ def test_project_set(self):
+ project_name = self._create_dummy_project()
+ new_project_name = data_utils.rand_name('NewTestProject')
+ raw_output = self.openstack(
+ 'project set '
+ '--name %(new_name)s '
+ '--disable '
+ '--property k0=v0 '
+ '%(name)s' % {'new_name': new_project_name,
+ 'domain': self.domain_name,
+ 'name': project_name})
+ self.assertEqual(0, len(raw_output))
+ # check project details
+ raw_output = self.openstack(
+ 'project show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': new_project_name}
+ )
+ items = self.parse_show(raw_output)
+ fields = list(self.PROJECT_FIELDS)
+ fields.extend(['k0'])
+ self.assert_show_fields(items, fields)
+ project = self.parse_show_as_object(raw_output)
+ self.assertEqual(new_project_name, project['name'])
+ self.assertEqual('False', project['enabled'])
+ self.assertEqual('v0', project['k0'])
+ # reset project to make sure it will be cleaned up
+ self.openstack(
+ 'project set '
+ '--name %(new_name)s '
+ '--enable '
+ '%(name)s' % {'new_name': project_name,
+ 'name': new_project_name})
+
+ def test_project_show(self):
+ raw_output = self.openstack(
+ 'project show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': self.project_name})
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.PROJECT_FIELDS)
diff --git a/openstackclient/tests/functional/identity/v3/test_region.py b/openstackclient/tests/functional/identity/v3/test_region.py
new file mode 100644
index 00000000..2a402bd1
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_region.py
@@ -0,0 +1,70 @@
+# 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 openstackclient.tests.functional.identity.v3 import common
+
+
+class RegionTests(common.IdentityTests):
+
+ def test_region_create(self):
+ self._create_dummy_region()
+
+ def test_region_create_with_parent_region(self):
+ parent_region_id = self._create_dummy_region()
+ self._create_dummy_region(parent_region=parent_region_id)
+
+ def test_region_delete(self):
+ region_id = self._create_dummy_region(add_clean_up=False)
+ raw_output = self.openstack('region delete %s' % region_id)
+ self.assertEqual(0, len(raw_output))
+
+ def test_region_multi_delete(self):
+ region_1 = self._create_dummy_region(add_clean_up=False)
+ region_2 = self._create_dummy_region(add_clean_up=False)
+ raw_output = self.openstack(
+ 'region delete %s %s' % (region_1, region_2))
+ self.assertEqual(0, len(raw_output))
+
+ def test_region_list(self):
+ raw_output = self.openstack('region list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, self.REGION_LIST_HEADERS)
+
+ def test_region_set(self):
+ # prepare region with parent-region
+ parent_region_id = self._create_dummy_region()
+ new_parent_region_id = self._create_dummy_region()
+ region_id = self._create_dummy_region(parent_region_id)
+ # check region details
+ raw_output = self.openstack('region show %s' % region_id)
+ region = self.parse_show_as_object(raw_output)
+ self.assertEqual(parent_region_id, region['parent_region'])
+ self.assertEqual(region_id, region['region'])
+ # update parent-region
+ raw_output = self.openstack(
+ 'region set '
+ '--parent-region %(parent_region)s '
+ '%(region)s' % {'parent_region': new_parent_region_id,
+ 'region': region_id})
+ self.assertEqual(0, len(raw_output))
+ # check updated region details
+ raw_output = self.openstack('region show %s' % region_id)
+ region = self.parse_show_as_object(raw_output)
+ self.assertEqual(new_parent_region_id, region['parent_region'])
+ self.assertEqual(region_id, region['region'])
+
+ def test_region_show(self):
+ region_id = self._create_dummy_region()
+ raw_output = self.openstack('region show %s' % region_id)
+ region = self.parse_show_as_object(raw_output)
+ self.assertEqual(region_id, region['region'])
+ self.assertEqual('None', region['parent_region'])
diff --git a/openstackclient/tests/functional/identity/v3/test_role.py b/openstackclient/tests/functional/identity/v3/test_role.py
new file mode 100644
index 00000000..ab8af9c0
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_role.py
@@ -0,0 +1,145 @@
+# 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 tempest.lib.common.utils import data_utils
+
+from openstackclient.tests.functional.identity.v3 import common
+
+
+class RoleTests(common.IdentityTests):
+
+ def test_role_create(self):
+ self._create_dummy_role()
+
+ def test_role_delete(self):
+ role_name = self._create_dummy_role(add_clean_up=False)
+ raw_output = self.openstack('role delete %s' % role_name)
+ self.assertEqual(0, len(raw_output))
+
+ def test_role_list(self):
+ self._create_dummy_role()
+ raw_output = self.openstack('role list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_role_list_with_user_project(self):
+ role_name = self._create_dummy_role()
+ username = self._create_dummy_user()
+ raw_output = self.openstack(
+ 'role add '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '--user %(user)s '
+ '--user-domain %(user_domain)s '
+ '%(role)s' % {'project': self.project_name,
+ 'project_domain': self.domain_name,
+ 'user': username,
+ 'user_domain': self.domain_name,
+ 'role': role_name})
+ self.addCleanup(
+ self.openstack,
+ 'role remove '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '--user %(user)s '
+ '--user-domain %(user_domain)s '
+ '%(role)s' % {'project': self.project_name,
+ 'project_domain': self.domain_name,
+ 'user': username,
+ 'user_domain': self.domain_name,
+ 'role': role_name})
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack(
+ 'role list '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '--user %(user)s '
+ '--user-domain %(user_domain)s '
+ '' % {'project': self.project_name,
+ 'project_domain': self.domain_name,
+ 'user': username,
+ 'user_domain': self.domain_name})
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+ self.assertEqual(1, len(items))
+
+ def test_role_show(self):
+ role_name = self._create_dummy_role()
+ raw_output = self.openstack('role show %s' % role_name)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.ROLE_FIELDS)
+
+ def test_role_set(self):
+ role_name = self._create_dummy_role()
+ new_role_name = data_utils.rand_name('NewTestRole')
+ raw_output = self.openstack(
+ 'role set --name %s %s' % (new_role_name, role_name))
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack('role show %s' % new_role_name)
+ role = self.parse_show_as_object(raw_output)
+ self.assertEqual(new_role_name, role['name'])
+
+ def test_role_add(self):
+ role_name = self._create_dummy_role()
+ username = self._create_dummy_user()
+ raw_output = self.openstack(
+ 'role add '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '--user %(user)s '
+ '--user-domain %(user_domain)s '
+ '%(role)s' % {'project': self.project_name,
+ 'project_domain': self.domain_name,
+ 'user': username,
+ 'user_domain': self.domain_name,
+ 'role': role_name})
+ self.addCleanup(
+ self.openstack,
+ 'role remove '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '--user %(user)s '
+ '--user-domain %(user_domain)s '
+ '%(role)s' % {'project': self.project_name,
+ 'project_domain': self.domain_name,
+ 'user': username,
+ 'user_domain': self.domain_name,
+ 'role': role_name})
+ self.assertEqual(0, len(raw_output))
+
+ def test_role_remove(self):
+ role_name = self._create_dummy_role()
+ username = self._create_dummy_user()
+ add_raw_output = self.openstack(
+ 'role add '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '--user %(user)s '
+ '--user-domain %(user_domain)s '
+ '%(role)s' % {'project': self.project_name,
+ 'project_domain': self.domain_name,
+ 'user': username,
+ 'user_domain': self.domain_name,
+ 'role': role_name})
+ remove_raw_output = self.openstack(
+ 'role remove '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '--user %(user)s '
+ '--user-domain %(user_domain)s '
+ '%(role)s' % {'project': self.project_name,
+ 'project_domain': self.domain_name,
+ 'user': username,
+ 'user_domain': self.domain_name,
+ 'role': role_name})
+ self.assertEqual(0, len(add_raw_output))
+ self.assertEqual(0, len(remove_raw_output))
diff --git a/openstackclient/tests/functional/identity/v3/test_service.py b/openstackclient/tests/functional/identity/v3/test_service.py
new file mode 100644
index 00000000..1ecda45a
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_service.py
@@ -0,0 +1,71 @@
+# 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 tempest.lib.common.utils import data_utils
+
+from openstackclient.tests.functional.identity.v3 import common
+
+
+class ServiceTests(common.IdentityTests):
+
+ def test_service_create(self):
+ self._create_dummy_service()
+
+ def test_service_delete(self):
+ service_name = self._create_dummy_service(add_clean_up=False)
+ raw_output = self.openstack('service delete %s' % service_name)
+ self.assertEqual(0, len(raw_output))
+
+ def test_service_multi_delete(self):
+ service_1 = self._create_dummy_service(add_clean_up=False)
+ service_2 = self._create_dummy_service(add_clean_up=False)
+ raw_output = self.openstack(
+ 'service delete %s %s' % (service_1, service_2))
+ self.assertEqual(0, len(raw_output))
+
+ def test_service_list(self):
+ self._create_dummy_service()
+ raw_output = self.openstack('service list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_service_set(self):
+ service_name = self._create_dummy_service()
+ # set service
+ new_service_name = data_utils.rand_name('NewTestService')
+ new_service_description = data_utils.rand_name('description')
+ new_service_type = data_utils.rand_name('NewTestType')
+ raw_output = self.openstack(
+ 'service set '
+ '--type %(type)s '
+ '--name %(name)s '
+ '--description %(description)s '
+ '--disable '
+ '%(service)s' % {'type': new_service_type,
+ 'name': new_service_name,
+ 'description': new_service_description,
+ 'service': service_name})
+ self.assertEqual(0, len(raw_output))
+ # get service details
+ raw_output = self.openstack('service show %s' % new_service_name)
+ # assert service details
+ service = self.parse_show_as_object(raw_output)
+ self.assertEqual(new_service_type, service['type'])
+ self.assertEqual(new_service_name, service['name'])
+ self.assertEqual(new_service_description, service['description'])
+
+ def test_service_show(self):
+ service_name = self._create_dummy_service()
+ raw_output = self.openstack(
+ 'service show %s' % service_name)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.SERVICE_FIELDS)
diff --git a/openstackclient/tests/functional/identity/v3/test_service_provider.py b/openstackclient/tests/functional/identity/v3/test_service_provider.py
new file mode 100644
index 00000000..e072bc93
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_service_provider.py
@@ -0,0 +1,61 @@
+# 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 openstackclient.tests.functional.identity.v3 import common
+from tempest.lib.common.utils import data_utils
+
+
+class ServiceProviderTests(common.IdentityTests):
+ # Introduce functional test cases for command 'Service Provider'
+
+ def test_sp_create(self):
+ self._create_dummy_sp(add_clean_up=True)
+
+ def test_sp_delete(self):
+ service_provider = self._create_dummy_sp(add_clean_up=False)
+ raw_output = self.openstack('service provider delete %s'
+ % service_provider)
+ self.assertEqual(0, len(raw_output))
+
+ def test_sp_multi_delete(self):
+ sp1 = self._create_dummy_sp(add_clean_up=False)
+ sp2 = self._create_dummy_sp(add_clean_up=False)
+ raw_output = self.openstack(
+ 'service provider delete %s %s' % (sp1, sp2))
+ self.assertEqual(0, len(raw_output))
+
+ def test_sp_show(self):
+ service_provider = self._create_dummy_sp(add_clean_up=True)
+ raw_output = self.openstack('service provider show %s'
+ % service_provider)
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.SERVICE_PROVIDER_FIELDS)
+
+ def test_sp_list(self):
+ self._create_dummy_sp(add_clean_up=True)
+ raw_output = self.openstack('service provider list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, self.SERVICE_PROVIDER_LIST_HEADERS)
+
+ def test_sp_set(self):
+ service_provider = self._create_dummy_sp(add_clean_up=True)
+ new_description = data_utils.rand_name('newDescription')
+ raw_output = self.openstack('service provider set '
+ '%(service-provider)s '
+ '--description %(description)s '
+ % {'service-provider': service_provider,
+ 'description': new_description})
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack('service provider show %s'
+ % service_provider)
+ updated_value = self.parse_show_as_object(raw_output)
+ self.assertIn(new_description, updated_value['description'])
diff --git a/openstackclient/tests/functional/identity/v3/test_token.py b/openstackclient/tests/functional/identity/v3/test_token.py
new file mode 100644
index 00000000..62e90003
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_token.py
@@ -0,0 +1,21 @@
+# 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 openstackclient.tests.functional.identity.v3 import common
+
+
+class TokenTests(common.IdentityTests):
+
+ def test_token_issue(self):
+ raw_output = self.openstack('token issue')
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.TOKEN_FIELDS)
diff --git a/openstackclient/tests/functional/identity/v3/test_user.py b/openstackclient/tests/functional/identity/v3/test_user.py
new file mode 100644
index 00000000..9e9bde96
--- /dev/null
+++ b/openstackclient/tests/functional/identity/v3/test_user.py
@@ -0,0 +1,101 @@
+# 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 tempest.lib.common.utils import data_utils
+
+from openstackclient.tests.functional.identity.v3 import common
+
+
+class UserTests(common.IdentityTests):
+
+ def test_user_create(self):
+ self._create_dummy_user()
+
+ def test_user_delete(self):
+ username = self._create_dummy_user(add_clean_up=False)
+ raw_output = self.openstack('user delete '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': username})
+ self.assertEqual(0, len(raw_output))
+
+ def test_user_list(self):
+ raw_output = self.openstack('user list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, common.BASIC_LIST_HEADERS)
+
+ def test_user_set(self):
+ username = self._create_dummy_user()
+ raw_output = self.openstack('user show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': username})
+ user = self.parse_show_as_object(raw_output)
+ new_username = data_utils.rand_name('NewTestUser')
+ new_email = data_utils.rand_name() + '@example.com'
+ raw_output = self.openstack('user set '
+ '--email %(email)s '
+ '--name %(new_name)s '
+ '%(id)s' % {'email': new_email,
+ 'new_name': new_username,
+ 'id': user['id']})
+ self.assertEqual(0, len(raw_output))
+ raw_output = self.openstack('user show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': new_username})
+ updated_user = self.parse_show_as_object(raw_output)
+ self.assertEqual(user['id'], updated_user['id'])
+ self.assertEqual(new_email, updated_user['email'])
+
+ def test_user_set_default_project_id(self):
+ username = self._create_dummy_user()
+ project_name = self._create_dummy_project()
+ # get original user details
+ raw_output = self.openstack('user show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': username})
+ user = self.parse_show_as_object(raw_output)
+ # update user
+ raw_output = self.openstack('user set '
+ '--project %(project)s '
+ '--project-domain %(project_domain)s '
+ '%(id)s' % {'project': project_name,
+ 'project_domain':
+ self.domain_name,
+ 'id': user['id']})
+ self.assertEqual(0, len(raw_output))
+ # get updated user details
+ raw_output = self.openstack('user show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': username})
+ updated_user = self.parse_show_as_object(raw_output)
+ # get project details
+ raw_output = self.openstack('project show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': project_name})
+ project = self.parse_show_as_object(raw_output)
+ # check updated user details
+ self.assertEqual(user['id'], updated_user['id'])
+ self.assertEqual(project['id'], updated_user['default_project_id'])
+
+ def test_user_show(self):
+ username = self._create_dummy_user()
+ raw_output = self.openstack('user show '
+ '--domain %(domain)s '
+ '%(name)s' % {'domain': self.domain_name,
+ 'name': username})
+ items = self.parse_show(raw_output)
+ self.assert_show_fields(items, self.USER_FIELDS)
diff --git a/openstackclient/tests/functional/image/__init__.py b/openstackclient/tests/functional/image/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/image/__init__.py
diff --git a/openstackclient/tests/functional/image/v1/__init__.py b/openstackclient/tests/functional/image/v1/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/image/v1/__init__.py
diff --git a/openstackclient/tests/functional/image/v1/test_image.py b/openstackclient/tests/functional/image/v1/test_image.py
new file mode 100644
index 00000000..2a2b5734
--- /dev/null
+++ b/openstackclient/tests/functional/image/v1/test_image.py
@@ -0,0 +1,67 @@
+# 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
+import uuid
+
+from openstackclient.tests.functional import base
+
+
+class ImageTests(base.TestCase):
+ """Functional tests for image. """
+
+ NAME = uuid.uuid4().hex
+ OTHER_NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ os.environ['OS_IMAGE_API_VERSION'] = '1'
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('image create ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ # Rename test
+ raw_output = cls.openstack('image set --name ' + cls.OTHER_NAME + ' '
+ + cls.NAME)
+ cls.assertOutput('', raw_output)
+ # Delete test
+ raw_output = cls.openstack('image delete ' + cls.OTHER_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_image_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('image list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_image_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('image show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_image_set(self):
+ opts = self.get_opts([
+ "disk_format", "is_public", "min_disk", "min_ram", "name"])
+ self.openstack('image set --min-disk 4 --min-ram 5 ' +
+ '--disk-format qcow2 --public ' + self.NAME)
+ raw_output = self.openstack('image show ' + self.NAME + opts)
+ self.assertEqual("qcow2\nTrue\n4\n5\n" + self.NAME + '\n', raw_output)
+
+ def test_image_metadata(self):
+ opts = self.get_opts(["name", "properties"])
+ self.openstack('image set --property a=b --property c=d ' + self.NAME)
+ raw_output = self.openstack('image show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\na='b', c='d'\n", raw_output)
diff --git a/openstackclient/tests/functional/image/v2/__init__.py b/openstackclient/tests/functional/image/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/image/v2/__init__.py
diff --git a/openstackclient/tests/functional/image/v2/test_image.py b/openstackclient/tests/functional/image/v2/test_image.py
new file mode 100644
index 00000000..3f432b02
--- /dev/null
+++ b/openstackclient/tests/functional/image/v2/test_image.py
@@ -0,0 +1,76 @@
+# 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
+import uuid
+
+from openstackclient.tests.functional import base
+
+
+class ImageTests(base.TestCase):
+ """Functional tests for image. """
+
+ NAME = uuid.uuid4().hex
+ OTHER_NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ os.environ['OS_IMAGE_API_VERSION'] = '2'
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('image create ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ # Rename test
+ raw_output = cls.openstack('image set --name ' + cls.OTHER_NAME + ' '
+ + cls.NAME)
+ cls.assertOutput('', raw_output)
+ # Delete test
+ raw_output = cls.openstack('image delete ' + cls.OTHER_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_image_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('image list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_image_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('image show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_image_set(self):
+ opts = self.get_opts([
+ "disk_format", "visibility", "min_disk", "min_ram", "name"])
+ self.openstack('image set --min-disk 4 --min-ram 5 ' +
+ '--public ' + self.NAME)
+ raw_output = self.openstack('image show ' + self.NAME + opts)
+ self.assertEqual("raw\n4\n5\n" + self.NAME + '\npublic\n', raw_output)
+
+ def test_image_metadata(self):
+ opts = self.get_opts(["name", "properties"])
+ self.openstack('image set --property a=b --property c=d ' + self.NAME)
+ raw_output = self.openstack('image show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\na='b', c='d'\n", raw_output)
+
+ def test_image_unset(self):
+ opts = self.get_opts(["name", "tags", "properties"])
+ self.openstack('image set --tag 01 ' + self.NAME)
+ self.openstack('image unset --tag 01 ' + self.NAME)
+ # test_image_metadata has set image properties "a" and "c"
+ self.openstack('image unset --property a --property c ' + self.NAME)
+ raw_output = self.openstack('image show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n\n", raw_output)
diff --git a/openstackclient/tests/functional/network/__init__.py b/openstackclient/tests/functional/network/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/network/__init__.py
diff --git a/openstackclient/tests/functional/network/v2/__init__.py b/openstackclient/tests/functional/network/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/__init__.py
diff --git a/openstackclient/tests/functional/network/v2/test_address_scope.py b/openstackclient/tests/functional/network/v2/test_address_scope.py
new file mode 100644
index 00000000..ef4b5756
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_address_scope.py
@@ -0,0 +1,49 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class AddressScopeTests(base.TestCase):
+ """Functional tests for address scope. """
+ NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('address scope create ' + cls.NAME + opts)
+ cls.assertOutput(cls.NAME + "\n", raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('address scope delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_address_scope_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('address scope list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_address_scope_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('address scope show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_address_scope_set(self):
+ self.openstack('address scope set --share ' + self.NAME)
+ opts = self.get_opts(['shared'])
+ raw_output = self.openstack('address scope show ' + self.NAME + opts)
+ self.assertEqual("True\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_floating_ip.py b/openstackclient/tests/functional/network/v2/test_floating_ip.py
new file mode 100644
index 00000000..f3a1971f
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_floating_ip.py
@@ -0,0 +1,58 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class FloatingIpTests(base.TestCase):
+ """Functional tests for floating ip. """
+ SUBNET_NAME = uuid.uuid4().hex
+ NETWORK_NAME = uuid.uuid4().hex
+ ID = None
+ HEADERS = ['ID']
+ FIELDS = ['id']
+
+ @classmethod
+ def setUpClass(cls):
+ # Create a network for the floating ip.
+ cls.openstack('network create --external ' + cls.NETWORK_NAME)
+ # Create a subnet for the network.
+ cls.openstack(
+ 'subnet create --network ' + cls.NETWORK_NAME +
+ ' --subnet-range 10.10.10.0/24 ' +
+ cls.SUBNET_NAME
+ )
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack(
+ 'floating ip create ' + cls.NETWORK_NAME + opts)
+ cls.ID = raw_output.strip('\n')
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('floating ip delete ' + cls.ID)
+ cls.assertOutput('', raw_output)
+ raw_output = cls.openstack('subnet delete ' + cls.SUBNET_NAME)
+ cls.assertOutput('', raw_output)
+ raw_output = cls.openstack('network delete ' + cls.NETWORK_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_floating_ip_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('floating ip list' + opts)
+ self.assertIn(self.ID, raw_output)
+
+ def test_floating_ip_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('floating ip show ' + self.ID + opts)
+ self.assertEqual(self.ID + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_ip_availability.py b/openstackclient/tests/functional/network/v2/test_ip_availability.py
new file mode 100644
index 00000000..b5c908f4
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_ip_availability.py
@@ -0,0 +1,53 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class IPAvailabilityTests(base.TestCase):
+ """Functional tests for IP availability. """
+ NAME = uuid.uuid4().hex
+ NETWORK_NAME = uuid.uuid4().hex
+ FIELDS = ['network_name']
+
+ @classmethod
+ def setUpClass(cls):
+ # Create a network for the subnet.
+ cls.openstack('network create ' + cls.NETWORK_NAME)
+ opts = cls.get_opts(['name'])
+ raw_output = cls.openstack(
+ 'subnet create --network ' + cls.NETWORK_NAME +
+ ' --subnet-range 10.10.10.0/24 ' +
+ cls.NAME + opts
+ )
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_subnet = cls.openstack('subnet delete ' + cls.NAME)
+ raw_network = cls.openstack('network delete ' + cls.NETWORK_NAME)
+ cls.assertOutput('', raw_subnet)
+ cls.assertOutput('', raw_network)
+
+ def test_ip_availability_list(self):
+ opts = ' -f csv -c "Network Name"'
+ raw_output = self.openstack('ip availability list' + opts)
+ self.assertIn(self.NETWORK_NAME, raw_output)
+
+ def test_ip_availability_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack(
+ 'ip availability show ' + self.NETWORK_NAME + opts)
+ self.assertEqual(self.NETWORK_NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_network.py b/openstackclient/tests/functional/network/v2/test_network.py
new file mode 100644
index 00000000..c77ff642
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_network.py
@@ -0,0 +1,50 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class NetworkTests(base.TestCase):
+ """Functional tests for network. """
+ NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('network create ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('network delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_network_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('network list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_network_set(self):
+ raw_output = self.openstack('network set --disable ' + self.NAME)
+ opts = self.get_opts(['name', 'admin_state_up'])
+ raw_output = self.openstack('network show ' + self.NAME + opts)
+ self.assertEqual("DOWN\n" + self.NAME + "\n", raw_output)
+
+ def test_network_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('network show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_network_agent.py b/openstackclient/tests/functional/network/v2/test_network_agent.py
new file mode 100644
index 00000000..dd6112e7
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_network_agent.py
@@ -0,0 +1,41 @@
+# 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 openstackclient.tests.functional import base
+
+
+class NetworkAgentTests(base.TestCase):
+ """Functional tests for network agent. """
+ IDs = None
+ HEADERS = ['ID']
+ FIELDS = ['id']
+
+ @classmethod
+ def test_network_agent_list(cls):
+ opts = cls.get_opts(cls.HEADERS)
+ raw_output = cls.openstack('network agent list' + opts)
+ # get the list of network agent IDs.
+ cls.IDs = raw_output.split('\n')
+
+ def test_network_agent_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('network agent show ' + self.IDs[0] + opts)
+ self.assertEqual(self.IDs[0] + "\n", raw_output)
+
+ def test_network_agent_set(self):
+ opts = self.get_opts(['admin_state_up'])
+ self.openstack('network agent set --disable ' + self.IDs[0])
+ raw_output = self.openstack('network agent show ' + self.IDs[0] + opts)
+ self.assertEqual("DOWN\n", raw_output)
+ self.openstack('network agent set --enable ' + self.IDs[0])
+ raw_output = self.openstack('network agent show ' + self.IDs[0] + opts)
+ self.assertEqual("UP\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_network_rbac.py b/openstackclient/tests/functional/network/v2/test_network_rbac.py
new file mode 100644
index 00000000..6f9f05e7
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_network_rbac.py
@@ -0,0 +1,69 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class NetworkRBACTests(base.TestCase):
+ """Functional tests for network rbac. """
+ NET_NAME = uuid.uuid4().hex
+ PROJECT_NAME = uuid.uuid4().hex
+ OBJECT_ID = None
+ ID = None
+ HEADERS = ['ID']
+ FIELDS = ['id']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('network create ' + cls.NET_NAME + opts)
+ cls.OBJECT_ID = raw_output.strip('\n')
+ opts = cls.get_opts(['id', 'object_id'])
+ raw_output = cls.openstack('network rbac create ' +
+ cls.OBJECT_ID +
+ ' --action access_as_shared' +
+ ' --target-project admin' +
+ ' --type network' + opts)
+ cls.ID, object_id, rol = tuple(raw_output.split('\n'))
+ cls.assertOutput(cls.OBJECT_ID, object_id)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output_rbac = cls.openstack('network rbac delete ' + cls.ID)
+ raw_output_network = cls.openstack('network delete ' + cls.OBJECT_ID)
+ cls.assertOutput('', raw_output_rbac)
+ cls.assertOutput('', raw_output_network)
+
+ def test_network_rbac_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('network rbac list' + opts)
+ self.assertIn(self.ID, raw_output)
+
+ def test_network_rbac_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('network rbac show ' + self.ID + opts)
+ self.assertEqual(self.ID + "\n", raw_output)
+
+ def test_network_rbac_set(self):
+ opts = self.get_opts(self.FIELDS)
+ project_id = self.openstack(
+ 'project create ' + self.PROJECT_NAME + opts)
+ self.openstack('network rbac set ' + self.ID +
+ ' --target-project ' + self.PROJECT_NAME)
+ opts = self.get_opts(['target_project_id'])
+ raw_output_rbac = self.openstack('network rbac show ' + self.ID + opts)
+ raw_output_project = self.openstack(
+ 'project delete ' + self.PROJECT_NAME)
+ self.assertEqual(project_id, raw_output_rbac)
+ self.assertOutput('', raw_output_project)
diff --git a/openstackclient/tests/functional/network/v2/test_network_segment.py b/openstackclient/tests/functional/network/v2/test_network_segment.py
new file mode 100644
index 00000000..f871e88e
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_network_segment.py
@@ -0,0 +1,60 @@
+# 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 testtools
+import uuid
+
+from openstackclient.tests.functional import base
+
+
+# NOTE(rtheis): Routed networks is still a WIP and not enabled by default.
+@testtools.skip("bp/routed-networks")
+class NetworkSegmentTests(base.TestCase):
+ """Functional tests for network segment. """
+ NETWORK_NAME = uuid.uuid4().hex
+ PHYSICAL_NETWORK_NAME = uuid.uuid4().hex
+ NETWORK_SEGMENT_ID = None
+ NETWORK_ID = None
+
+ @classmethod
+ def setUpClass(cls):
+ # Create a network for the segment.
+ opts = cls.get_opts(['id'])
+ raw_output = cls.openstack('network create ' + cls.NETWORK_NAME + opts)
+ cls.NETWORK_ID = raw_output.strip('\n')
+
+ # Get the segment for the network.
+ opts = cls.get_opts(['ID', 'Network'])
+ raw_output = cls.openstack('--os-beta-command '
+ 'network segment list '
+ ' --network ' + cls.NETWORK_NAME +
+ ' ' + opts)
+ raw_output_row = raw_output.split('\n')[0]
+ cls.NETWORK_SEGMENT_ID = raw_output_row.split(' ')[0]
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('network delete ' + cls.NETWORK_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_network_segment_list(self):
+ opts = self.get_opts(['ID'])
+ raw_output = self.openstack('--os-beta-command '
+ 'network segment list' + opts)
+ self.assertIn(self.NETWORK_SEGMENT_ID, raw_output)
+
+ def test_network_segment_show(self):
+ opts = self.get_opts(['network_id'])
+ raw_output = self.openstack('--os-beta-command '
+ 'network segment show ' +
+ self.NETWORK_SEGMENT_ID + opts)
+ self.assertEqual(self.NETWORK_ID + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_port.py b/openstackclient/tests/functional/network/v2/test_port.py
new file mode 100644
index 00000000..decd9553
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_port.py
@@ -0,0 +1,58 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class PortTests(base.TestCase):
+ """Functional tests for port. """
+ NAME = uuid.uuid4().hex
+ NETWORK_NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ # Create a network for the subnet.
+ cls.openstack('network create ' + cls.NETWORK_NAME)
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack(
+ 'port create --network ' + cls.NETWORK_NAME + ' ' +
+ cls.NAME + opts
+ )
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('port delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+ raw_output = cls.openstack('network delete ' + cls.NETWORK_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_port_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('port list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_port_set(self):
+ self.openstack('port set --disable ' + self.NAME)
+ opts = self.get_opts(['name', 'admin_state_up'])
+ raw_output = self.openstack('port show ' + self.NAME + opts)
+ self.assertEqual("DOWN\n" + self.NAME + "\n", raw_output)
+
+ def test_port_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('port show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_router.py b/openstackclient/tests/functional/network/v2/test_router.py
new file mode 100644
index 00000000..789c3825
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_router.py
@@ -0,0 +1,50 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class RouterTests(base.TestCase):
+ """Functional tests for router. """
+ NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('router create ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('router delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_router_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('router list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_router_set(self):
+ self.openstack('router set --disable ' + self.NAME)
+ opts = self.get_opts(['name', 'admin_state_up'])
+ raw_output = self.openstack('router show ' + self.NAME + opts)
+ self.assertEqual("DOWN\n" + self.NAME + "\n", raw_output)
+
+ def test_router_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('router show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_security_group.py b/openstackclient/tests/functional/network/v2/test_security_group.py
new file mode 100644
index 00000000..debd81df
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_security_group.py
@@ -0,0 +1,60 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class SecurityGroupTests(base.TestCase):
+ """Functional tests for security group. """
+ NAME = uuid.uuid4().hex
+ OTHER_NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('security group create ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ # Rename test
+ raw_output = cls.openstack('security group set --name ' +
+ cls.OTHER_NAME + ' ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+ # Delete test
+ raw_output = cls.openstack('security group delete ' + cls.OTHER_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_security_group_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('security group list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_security_group_set(self):
+ raw_output = self.openstack(
+ 'security group set --description NSA ' + self.NAME
+ )
+ self.assertEqual('', raw_output)
+
+ opts = self.get_opts(['description'])
+ raw_output = self.openstack('security group show ' + self.NAME + opts)
+ self.assertEqual("NSA\n", raw_output)
+
+ def test_security_group_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('security group show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_security_group_rule.py b/openstackclient/tests/functional/network/v2/test_security_group_rule.py
new file mode 100644
index 00000000..c91de1a5
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_security_group_rule.py
@@ -0,0 +1,67 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class SecurityGroupRuleTests(base.TestCase):
+ """Functional tests for security group rule. """
+ SECURITY_GROUP_NAME = uuid.uuid4().hex
+ SECURITY_GROUP_RULE_ID = None
+ NAME_FIELD = ['name']
+ ID_FIELD = ['id']
+ ID_HEADER = ['ID']
+
+ @classmethod
+ def setUpClass(cls):
+ # Create the security group to hold the rule.
+ opts = cls.get_opts(cls.NAME_FIELD)
+ raw_output = cls.openstack('security group create ' +
+ cls.SECURITY_GROUP_NAME +
+ opts)
+ expected = cls.SECURITY_GROUP_NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ # Create the security group rule.
+ opts = cls.get_opts(cls.ID_FIELD)
+ raw_output = cls.openstack('security group rule create ' +
+ cls.SECURITY_GROUP_NAME +
+ ' --protocol tcp --dst-port 80:80' +
+ ' --ingress --ethertype IPv4' +
+ opts)
+ cls.SECURITY_GROUP_RULE_ID = raw_output.strip('\n')
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('security group rule delete ' +
+ cls.SECURITY_GROUP_RULE_ID)
+ cls.assertOutput('', raw_output)
+
+ raw_output = cls.openstack('security group delete ' +
+ cls.SECURITY_GROUP_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_security_group_rule_list(self):
+ opts = self.get_opts(self.ID_HEADER)
+ raw_output = self.openstack('security group rule list ' +
+ self.SECURITY_GROUP_NAME +
+ opts)
+ self.assertIn(self.SECURITY_GROUP_RULE_ID, raw_output)
+
+ def test_security_group_rule_show(self):
+ opts = self.get_opts(self.ID_FIELD)
+ raw_output = self.openstack('security group rule show ' +
+ self.SECURITY_GROUP_RULE_ID +
+ opts)
+ self.assertEqual(self.SECURITY_GROUP_RULE_ID + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_subnet.py b/openstackclient/tests/functional/network/v2/test_subnet.py
new file mode 100644
index 00000000..231671f3
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_subnet.py
@@ -0,0 +1,66 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class SubnetTests(base.TestCase):
+ """Functional tests for subnet. """
+ NAME = uuid.uuid4().hex
+ NETWORK_NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ # Create a network for the subnet.
+ cls.openstack('network create ' + cls.NETWORK_NAME)
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack(
+ 'subnet create --network ' + cls.NETWORK_NAME +
+ ' --subnet-range 10.10.10.0/24 ' +
+ cls.NAME + opts
+ )
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('subnet delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+ raw_output = cls.openstack('network delete ' + cls.NETWORK_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_subnet_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('subnet list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_subnet_set(self):
+ self.openstack('subnet set --no-dhcp ' + self.NAME)
+ opts = self.get_opts(['name', 'enable_dhcp'])
+ raw_output = self.openstack('subnet show ' + self.NAME + opts)
+ self.assertEqual("False\n" + self.NAME + "\n", raw_output)
+
+ def test_subnet_set_service_type(self):
+ TYPE = 'network:floatingip_agent_gateway'
+ self.openstack('subnet set --service-type ' + TYPE + ' ' + self.NAME)
+ opts = self.get_opts(['name', 'service_types'])
+ raw_output = self.openstack('subnet show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n" + TYPE + "\n", raw_output)
+
+ def test_subnet_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('subnet show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/network/v2/test_subnet_pool.py b/openstackclient/tests/functional/network/v2/test_subnet_pool.py
new file mode 100644
index 00000000..e52f06fc
--- /dev/null
+++ b/openstackclient/tests/functional/network/v2/test_subnet_pool.py
@@ -0,0 +1,55 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class SubnetPoolTests(base.TestCase):
+ """Functional tests for subnet pool. """
+ NAME = uuid.uuid4().hex
+ CREATE_POOL_PREFIX = '10.100.0.0/24'
+ SET_POOL_PREFIX = '10.100.0.0/16'
+ HEADERS = ['Name']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('subnet pool create --pool-prefix ' +
+ cls.CREATE_POOL_PREFIX + ' ' +
+ cls.NAME + opts)
+ cls.assertOutput(cls.NAME + '\n', raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('subnet pool delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_subnet_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('subnet pool list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_subnet_set(self):
+ self.openstack('subnet pool set --pool-prefix ' +
+ self.SET_POOL_PREFIX + ' ' + self.NAME)
+ opts = self.get_opts(['prefixes', 'name'])
+ raw_output = self.openstack('subnet pool show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + '\n' + self.SET_POOL_PREFIX + '\n',
+ raw_output)
+
+ def test_subnet_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('subnet pool show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + '\n', raw_output)
diff --git a/openstackclient/tests/functional/object/__init__.py b/openstackclient/tests/functional/object/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/object/__init__.py
diff --git a/openstackclient/tests/functional/object/v1/__init__.py b/openstackclient/tests/functional/object/v1/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/object/v1/__init__.py
diff --git a/openstackclient/tests/functional/object/v1/test_container.py b/openstackclient/tests/functional/object/v1/test_container.py
new file mode 100644
index 00000000..af76efd9
--- /dev/null
+++ b/openstackclient/tests/functional/object/v1/test_container.py
@@ -0,0 +1,41 @@
+# 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 uuid
+
+from openstackclient.tests.functional import base
+
+
+class ContainerTests(base.TestCase):
+ """Functional tests for object containers. """
+ NAME = uuid.uuid4().hex
+
+ @classmethod
+ def setUpClass(cls):
+ opts = cls.get_opts(['container'])
+ raw_output = cls.openstack('container create ' + cls.NAME + opts)
+ cls.assertOutput(cls.NAME + '\n', raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('container delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_container_list(self):
+ opts = self.get_opts(['Name'])
+ raw_output = self.openstack('container list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_container_show(self):
+ opts = self.get_opts(['container'])
+ raw_output = self.openstack('container show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/object/v1/test_object.py b/openstackclient/tests/functional/object/v1/test_object.py
new file mode 100644
index 00000000..776cf47c
--- /dev/null
+++ b/openstackclient/tests/functional/object/v1/test_object.py
@@ -0,0 +1,81 @@
+# 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
+import tempfile
+import uuid
+
+from openstackclient.tests.functional import base
+
+BASIC_LIST_HEADERS = ['Name']
+CONTAINER_FIELDS = ['account', 'container', 'x-trans-id']
+OBJECT_FIELDS = ['object', 'container', 'etag']
+
+
+class ObjectTests(base.TestCase):
+ """Functional tests for Object commands. """
+
+ CONTAINER_NAME = uuid.uuid4().hex
+
+ def test_object(self):
+ with tempfile.NamedTemporaryFile() as f:
+ f.write('test content')
+ f.flush()
+ self._test_object(f.name)
+
+ def _test_object(self, object_file):
+ raw_output = self.openstack('container create ' + self.CONTAINER_NAME)
+ items = self.parse_listing(raw_output)
+ self.assert_show_fields(items, CONTAINER_FIELDS)
+
+ raw_output = self.openstack('container list')
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, BASIC_LIST_HEADERS)
+
+ self.openstack('container show ' + self.CONTAINER_NAME)
+ # TODO(stevemar): Assert returned fields
+
+ self.openstack('container save ' + self.CONTAINER_NAME)
+ # TODO(stevemar): Assert returned fields
+
+ raw_output = self.openstack('object create ' + self.CONTAINER_NAME
+ + ' ' + object_file)
+ items = self.parse_listing(raw_output)
+ self.assert_show_fields(items, OBJECT_FIELDS)
+
+ raw_output = self.openstack('object list ' + self.CONTAINER_NAME)
+ items = self.parse_listing(raw_output)
+ self.assert_table_structure(items, BASIC_LIST_HEADERS)
+
+ self.openstack('object save ' + self.CONTAINER_NAME
+ + ' ' + object_file)
+ # TODO(stevemar): Assert returned fields
+
+ tmp_file = 'tmp.txt'
+ self.addCleanup(os.remove, tmp_file)
+ self.openstack('object save ' + self.CONTAINER_NAME
+ + ' ' + object_file + ' --file ' + tmp_file)
+ # TODO(stevemar): Assert returned fields
+
+ self.openstack('object show ' + self.CONTAINER_NAME
+ + ' ' + object_file)
+ # TODO(stevemar): Assert returned fields
+
+ raw_output = self.openstack('object delete ' + self.CONTAINER_NAME
+ + ' ' + object_file)
+ self.assertEqual(0, len(raw_output))
+
+ self.openstack('object create ' + self.CONTAINER_NAME
+ + ' ' + object_file)
+ raw_output = self.openstack('container delete -r ' +
+ self.CONTAINER_NAME)
+ self.assertEqual(0, len(raw_output))
diff --git a/openstackclient/tests/functional/post_test_hook.sh b/openstackclient/tests/functional/post_test_hook.sh
new file mode 100755
index 00000000..e555470d
--- /dev/null
+++ b/openstackclient/tests/functional/post_test_hook.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# This is a script that kicks off a series of functional tests against an
+# OpenStack cloud. It will attempt to create an instance if one is not
+# available. Do not run this script unless you know what you're doing.
+# For more information refer to:
+# http://docs.openstack.org/developer/python-openstackclient/
+
+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 .tox/functional/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 jenkins:jenkins $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
+}
+
+OPENSTACKCLIENT_DIR=$(cd $(dirname "$0") && pwd)
+sudo chown -R jenkins:stack $OPENSTACKCLIENT_DIR
+
+# Run tests
+echo "Running openstackclient functional test suite"
+set +e
+
+# Go to the openstackclient dir
+cd $OPENSTACKCLIENT_DIR
+
+# Source environment variables to kick things off
+source ~stack/devstack/openrc admin admin
+echo 'Running tests with:'
+env | grep OS
+
+# Preserve env for OS_ credentials
+sudo -E -H -u jenkins tox -efunctional
+EXIT_CODE=$?
+set -e
+
+# Collect and parse result
+generate_testr_results
+exit $EXIT_CODE
diff --git a/openstackclient/tests/functional/volume/__init__.py b/openstackclient/tests/functional/volume/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/volume/__init__.py
diff --git a/openstackclient/tests/functional/volume/v1/__init__.py b/openstackclient/tests/functional/volume/v1/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v1/__init__.py
diff --git a/openstackclient/tests/functional/volume/v1/common.py b/openstackclient/tests/functional/volume/v1/common.py
new file mode 100644
index 00000000..a442850d
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v1/common.py
@@ -0,0 +1,23 @@
+# 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 openstackclient.tests.functional import base
+
+
+class BaseVolumeTests(base.TestCase):
+ """Base class for Volume functional tests. """
+
+ @classmethod
+ def setUpClass(cls):
+ os.environ['OS_VOLUME_API_VERSION'] = '1'
diff --git a/openstackclient/tests/functional/volume/v1/test_qos.py b/openstackclient/tests/functional/volume/v1/test_qos.py
new file mode 100644
index 00000000..770d5acb
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v1/test_qos.py
@@ -0,0 +1,55 @@
+# 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 uuid
+
+from openstackclient.tests.functional.volume.v1 import common
+
+
+class QosTests(common.BaseVolumeTests):
+ """Functional tests for volume qos. """
+
+ NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['id', 'name']
+ ID = None
+
+ @classmethod
+ def setUpClass(cls):
+ super(QosTests, cls).setUpClass()
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('volume qos create ' + cls.NAME + opts)
+ cls.ID, name, rol = raw_output.split('\n')
+ cls.assertOutput(cls.NAME, name)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('volume qos delete ' + cls.ID)
+ cls.assertOutput('', raw_output)
+
+ def test_volume_qos_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('volume qos list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_volume_qos_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('volume qos show ' + self.ID + opts)
+ self.assertEqual(self.ID + "\n" + self.NAME + "\n", raw_output)
+
+ def test_volume_qos_metadata(self):
+ raw_output = self.openstack(
+ 'volume qos set --property a=b --property c=d ' + self.ID)
+ self.assertEqual("", raw_output)
+ opts = self.get_opts(['name', 'specs'])
+ raw_output = self.openstack('volume qos show ' + self.ID + opts)
+ self.assertEqual(self.NAME + "\na='b', c='d'\n", raw_output)
diff --git a/openstackclient/tests/functional/volume/v1/test_volume.py b/openstackclient/tests/functional/volume/v1/test_volume.py
new file mode 100644
index 00000000..6ac7f2bf
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v1/test_volume.py
@@ -0,0 +1,77 @@
+# 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 uuid
+
+from openstackclient.tests.functional.volume.v1 import common
+
+
+class VolumeTests(common.BaseVolumeTests):
+ """Functional tests for volume. """
+
+ NAME = uuid.uuid4().hex
+ OTHER_NAME = uuid.uuid4().hex
+ HEADERS = ['"Display Name"']
+ FIELDS = ['display_name']
+
+ @classmethod
+ def setUpClass(cls):
+ super(VolumeTests, cls).setUpClass()
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('volume create --size 1 ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ # Rename test
+ raw_output = cls.openstack(
+ 'volume set --name ' + cls.OTHER_NAME + ' ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+ # Delete test
+ raw_output = cls.openstack('volume delete ' + cls.OTHER_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_volume_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('volume list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_volume_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_volume_properties(self):
+ raw_output = self.openstack(
+ 'volume set --property a=b --property c=d ' + self.NAME)
+ self.assertEqual("", raw_output)
+ opts = self.get_opts(["properties"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack('volume unset --property a ' + self.NAME)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("c='d'\n", raw_output)
+
+ def test_volume_set(self):
+ self.openstack('volume set --description RAMAC ' + self.NAME)
+ opts = self.get_opts(["display_description", "display_name"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("RAMAC\n" + self.NAME + "\n", raw_output)
+
+ def test_volume_set_size(self):
+ self.openstack('volume set --size 2 ' + self.NAME)
+ opts = self.get_opts(["display_name", "size"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n2\n", raw_output)
diff --git a/openstackclient/tests/functional/volume/v1/test_volume_type.py b/openstackclient/tests/functional/volume/v1/test_volume_type.py
new file mode 100644
index 00000000..538545ab
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v1/test_volume_type.py
@@ -0,0 +1,74 @@
+# 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 time
+import uuid
+
+from openstackclient.tests.functional.volume.v1 import common
+
+
+class VolumeTypeTests(common.BaseVolumeTests):
+ """Functional tests for volume type. """
+
+ NAME = uuid.uuid4().hex
+ HEADERS = ['"Name"']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ super(VolumeTypeTests, cls).setUpClass()
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('volume type create ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('volume type delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_volume_type_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('volume type list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_volume_type_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_volume_type_set_unset_properties(self):
+ raw_output = self.openstack(
+ 'volume type set --property a=b --property c=d ' + self.NAME)
+ self.assertEqual("", raw_output)
+
+ opts = self.get_opts(["properties"])
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack('volume type unset --property a '
+ + self.NAME)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual("c='d'\n", raw_output)
+
+ def test_multi_delete(self):
+ vol_type1 = uuid.uuid4().hex
+ vol_type2 = uuid.uuid4().hex
+ self.openstack('volume type create ' + vol_type1)
+ time.sleep(5)
+ self.openstack('volume type create ' + vol_type2)
+ time.sleep(5)
+ cmd = 'volume type delete %s %s' % (vol_type1, vol_type2)
+ time.sleep(5)
+ raw_output = self.openstack(cmd)
+ self.assertOutput('', raw_output)
diff --git a/openstackclient/tests/functional/volume/v2/__init__.py b/openstackclient/tests/functional/volume/v2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v2/__init__.py
diff --git a/openstackclient/tests/functional/volume/v2/common.py b/openstackclient/tests/functional/volume/v2/common.py
new file mode 100644
index 00000000..e279a6f6
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v2/common.py
@@ -0,0 +1,23 @@
+# 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 openstackclient.tests.functional import base
+
+
+class BaseVolumeTests(base.TestCase):
+ """Base class for Volume functional tests. """
+
+ @classmethod
+ def setUpClass(cls):
+ os.environ['OS_VOLUME_API_VERSION'] = '2'
diff --git a/openstackclient/tests/functional/volume/v2/test_qos.py b/openstackclient/tests/functional/volume/v2/test_qos.py
new file mode 100644
index 00000000..a54acbfd
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v2/test_qos.py
@@ -0,0 +1,62 @@
+# 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 uuid
+
+from openstackclient.tests.functional.volume.v2 import common
+
+
+class QosTests(common.BaseVolumeTests):
+ """Functional tests for volume qos. """
+
+ NAME = uuid.uuid4().hex
+ HEADERS = ['Name']
+ FIELDS = ['id', 'name']
+ ID = None
+
+ @classmethod
+ def setUpClass(cls):
+ super(QosTests, cls).setUpClass()
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack('volume qos create ' + cls.NAME + opts)
+ cls.ID, name, rol = raw_output.split('\n')
+ cls.assertOutput(cls.NAME, name)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('volume qos delete ' + cls.ID)
+ cls.assertOutput('', raw_output)
+
+ def test_volume_qos_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('volume qos list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_volume_qos_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('volume qos show ' + self.ID + opts)
+ self.assertEqual(self.ID + "\n" + self.NAME + "\n", raw_output)
+
+ def test_volume_qos_metadata(self):
+ raw_output = self.openstack(
+ 'volume qos set --property a=b --property c=d ' + self.ID)
+ self.assertEqual("", raw_output)
+ opts = self.get_opts(['name', 'specs'])
+ raw_output = self.openstack('volume qos show ' + self.ID + opts)
+ self.assertEqual(self.NAME + "\na='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack(
+ 'volume qos unset --property a ' + self.ID)
+ self.assertEqual("", raw_output)
+ opts = self.get_opts(['name', 'specs'])
+ raw_output = self.openstack('volume qos show ' + self.ID + opts)
+ self.assertEqual(self.NAME + "\nc='d'\n", raw_output)
diff --git a/openstackclient/tests/functional/volume/v2/test_snapshot.py b/openstackclient/tests/functional/volume/v2/test_snapshot.py
new file mode 100644
index 00000000..4582b67d
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v2/test_snapshot.py
@@ -0,0 +1,83 @@
+# 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 time
+import uuid
+
+from openstackclient.tests.functional.volume.v2 import common
+
+
+class SnapshotTests(common.BaseVolumeTests):
+ """Functional tests for snapshot. """
+
+ VOLLY = uuid.uuid4().hex
+ NAME = uuid.uuid4().hex
+ OTHER_NAME = uuid.uuid4().hex
+ HEADERS = ['"Name"']
+
+ @classmethod
+ def wait_for_status(cls, command, status, tries):
+ opts = cls.get_opts(['status'])
+ for attempt in range(tries):
+ time.sleep(1)
+ raw_output = cls.openstack(command + opts)
+ if (raw_output == status):
+ return
+ cls.assertOutput(status, raw_output)
+
+ @classmethod
+ def setUpClass(cls):
+ super(SnapshotTests, cls).setUpClass()
+ cls.openstack('volume create --size 1 ' + cls.VOLLY)
+ cls.wait_for_status('volume show ' + cls.VOLLY, 'available\n', 3)
+ opts = cls.get_opts(['status'])
+ raw_output = cls.openstack('snapshot create --name ' + cls.NAME +
+ ' ' + cls.VOLLY + opts)
+ cls.assertOutput('creating\n', raw_output)
+ cls.wait_for_status('snapshot show ' + cls.NAME, 'available\n', 3)
+
+ @classmethod
+ def tearDownClass(cls):
+ # Rename test
+ raw_output = cls.openstack(
+ 'snapshot set --name ' + cls.OTHER_NAME + ' ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+ # Delete test
+ raw_output = cls.openstack('snapshot delete ' + cls.OTHER_NAME)
+ cls.assertOutput('', raw_output)
+ cls.openstack('volume delete --force ' + cls.VOLLY, fail_ok=True)
+
+ def test_snapshot_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('snapshot list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_snapshot_properties(self):
+ raw_output = self.openstack(
+ 'snapshot set --property a=b --property c=d ' + self.NAME)
+ self.assertEqual("", raw_output)
+ opts = self.get_opts(["properties"])
+ raw_output = self.openstack('snapshot show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack('snapshot unset --property a ' + self.NAME)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('snapshot show ' + self.NAME + opts)
+ self.assertEqual("c='d'\n", raw_output)
+
+ def test_snapshot_set(self):
+ raw_output = self.openstack(
+ 'snapshot set --description backup ' + self.NAME)
+ self.assertEqual("", raw_output)
+ opts = self.get_opts(["description", "name"])
+ raw_output = self.openstack('snapshot show ' + self.NAME + opts)
+ self.assertEqual("backup\n" + self.NAME + "\n", raw_output)
diff --git a/openstackclient/tests/functional/volume/v2/test_volume.py b/openstackclient/tests/functional/volume/v2/test_volume.py
new file mode 100644
index 00000000..73273573
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v2/test_volume.py
@@ -0,0 +1,137 @@
+# 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 time
+import uuid
+
+from openstackclient.tests.functional.volume.v2 import common
+
+
+class VolumeTests(common.BaseVolumeTests):
+ """Functional tests for volume. """
+
+ NAME = uuid.uuid4().hex
+ SNAPSHOT_NAME = uuid.uuid4().hex
+ VOLUME_FROM_SNAPSHOT_NAME = uuid.uuid4().hex
+ OTHER_NAME = uuid.uuid4().hex
+ HEADERS = ['"Display Name"']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ super(VolumeTests, cls).setUpClass()
+ opts = cls.get_opts(cls.FIELDS)
+
+ # Create test volume
+ raw_output = cls.openstack('volume create --size 1 ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ # Rename test volume
+ raw_output = cls.openstack(
+ 'volume set --name ' + cls.OTHER_NAME + ' ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ # Set volume state
+ cls.openstack('volume set --state error ' + cls.OTHER_NAME)
+ opts = cls.get_opts(["status"])
+ raw_output_status = cls.openstack(
+ 'volume show ' + cls.OTHER_NAME + opts)
+
+ # Delete test volume
+ raw_output = cls.openstack('volume delete ' + cls.OTHER_NAME)
+ cls.assertOutput('', raw_output)
+ cls.assertOutput('error\n', raw_output_status)
+
+ def test_volume_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('volume list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_volume_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_volume_properties(self):
+ raw_output = self.openstack(
+ 'volume set --property a=b --property c=d ' + self.NAME)
+ self.assertEqual("", raw_output)
+ opts = self.get_opts(["properties"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack('volume unset --property a ' + self.NAME)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual("c='d'\n", raw_output)
+
+ def test_volume_set(self):
+ discription = uuid.uuid4().hex
+ self.openstack('volume set --description ' + discription + ' ' +
+ self.NAME)
+ opts = self.get_opts(["description", "name"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual(discription + "\n" + self.NAME + "\n", raw_output)
+
+ def test_volume_set_size(self):
+ self.openstack('volume set --size 2 ' + self.NAME)
+ opts = self.get_opts(["name", "size"])
+ raw_output = self.openstack('volume show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n2\n", raw_output)
+
+ def test_volume_snapshot(self):
+ opts = self.get_opts(self.FIELDS)
+
+ # Create snapshot from test volume
+ raw_output = self.openstack('snapshot create ' + self.NAME +
+ ' --name ' + self.SNAPSHOT_NAME + opts)
+ expected = self.SNAPSHOT_NAME + '\n'
+ self.assertOutput(expected, raw_output)
+ self.wait_for("snapshot", self.SNAPSHOT_NAME, "available")
+
+ # Create volume from snapshot
+ raw_output = self.openstack('volume create --size 2 --snapshot ' +
+ self.SNAPSHOT_NAME + ' ' +
+ self.VOLUME_FROM_SNAPSHOT_NAME + opts)
+ expected = self.VOLUME_FROM_SNAPSHOT_NAME + '\n'
+ self.assertOutput(expected, raw_output)
+ self.wait_for("volume", self.VOLUME_FROM_SNAPSHOT_NAME, "available")
+
+ # Delete volume that create from snapshot
+ raw_output = self.openstack('volume delete ' +
+ self.VOLUME_FROM_SNAPSHOT_NAME)
+ self.assertOutput('', raw_output)
+
+ # Delete test snapshot
+ raw_output = self.openstack('snapshot delete ' + self.SNAPSHOT_NAME)
+ self.assertOutput('', raw_output)
+ self.wait_for("volume", self.NAME, "available")
+
+ def wait_for(self, check_type, check_name, desired_status, wait=120,
+ interval=5, failures=['ERROR']):
+ status = "notset"
+ total_sleep = 0
+ opts = self.get_opts(['status'])
+ while total_sleep < wait:
+ status = self.openstack(check_type + ' show ' + check_name + opts)
+ status = status.rstrip()
+ print('Checking {} {} Waiting for {} current status: {}'
+ .format(check_type, check_name, desired_status, status))
+ if status == desired_status:
+ break
+ self.assertNotIn(status, failures)
+ time.sleep(interval)
+ total_sleep += interval
+ self.assertEqual(desired_status, status)
diff --git a/openstackclient/tests/functional/volume/v2/test_volume_type.py b/openstackclient/tests/functional/volume/v2/test_volume_type.py
new file mode 100644
index 00000000..b62cbb39
--- /dev/null
+++ b/openstackclient/tests/functional/volume/v2/test_volume_type.py
@@ -0,0 +1,84 @@
+# 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 time
+import uuid
+
+from openstackclient.tests.functional.volume.v2 import common
+
+
+class VolumeTypeTests(common.BaseVolumeTests):
+ """Functional tests for volume type. """
+
+ NAME = uuid.uuid4().hex
+ HEADERS = ['"Name"']
+ FIELDS = ['name']
+
+ @classmethod
+ def setUpClass(cls):
+ super(VolumeTypeTests, cls).setUpClass()
+ opts = cls.get_opts(cls.FIELDS)
+ raw_output = cls.openstack(
+ 'volume type create --private ' + cls.NAME + opts)
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('volume type delete ' + cls.NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_volume_type_list(self):
+ opts = self.get_opts(self.HEADERS)
+ raw_output = self.openstack('volume type list' + opts)
+ self.assertIn(self.NAME, raw_output)
+
+ def test_volume_type_show(self):
+ opts = self.get_opts(self.FIELDS)
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n", raw_output)
+
+ def test_volume_type_set_unset_properties(self):
+ raw_output = self.openstack(
+ 'volume type set --property a=b --property c=d ' + self.NAME)
+ self.assertEqual("", raw_output)
+
+ opts = self.get_opts(["properties"])
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual("a='b', c='d'\n", raw_output)
+
+ raw_output = self.openstack('volume type unset --property a '
+ + self.NAME)
+ self.assertEqual("", raw_output)
+ raw_output = self.openstack('volume type show ' + self.NAME + opts)
+ self.assertEqual("c='d'\n", raw_output)
+
+ def test_volume_type_set_unset_project(self):
+ raw_output = self.openstack(
+ 'volume type set --project admin ' + self.NAME)
+ self.assertEqual("", raw_output)
+
+ raw_output = self.openstack(
+ 'volume type unset --project admin ' + self.NAME)
+ self.assertEqual("", raw_output)
+
+ def test_multi_delete(self):
+ vol_type1 = uuid.uuid4().hex
+ vol_type2 = uuid.uuid4().hex
+ self.openstack('volume type create ' + vol_type1)
+ time.sleep(5)
+ self.openstack('volume type create ' + vol_type2)
+ time.sleep(5)
+ cmd = 'volume type delete %s %s' % (vol_type1, vol_type2)
+ time.sleep(5)
+ raw_output = self.openstack(cmd)
+ self.assertOutput('', raw_output)