summaryrefslogtreecommitdiff
path: root/openstackclient/tests
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2021-06-18 18:05:39 +0000
committerGerrit Code Review <review@openstack.org>2021-06-18 18:05:39 +0000
commit87369984d1afcd4e7bee280621d43b5023f60eda (patch)
tree82c44866f9f5bc6b81d5fd0c5dc23dd5728b162c /openstackclient/tests
parent779c39f6163c6aebb2c6e7523a21f96c9d642044 (diff)
parent4c2e8523a98a0dd33e0203c47e94384420c14f9c (diff)
downloadpython-openstackclient-87369984d1afcd4e7bee280621d43b5023f60eda.tar.gz
Merge "volume: Add 'volume group *' commands"
Diffstat (limited to 'openstackclient/tests')
-rw-r--r--openstackclient/tests/unit/volume/v3/fakes.py111
-rw-r--r--openstackclient/tests/unit/volume/v3/test_volume_group.py497
2 files changed, 608 insertions, 0 deletions
diff --git a/openstackclient/tests/unit/volume/v3/fakes.py b/openstackclient/tests/unit/volume/v3/fakes.py
index 45cad8c1..b0c96290 100644
--- a/openstackclient/tests/unit/volume/v3/fakes.py
+++ b/openstackclient/tests/unit/volume/v3/fakes.py
@@ -32,10 +32,16 @@ class FakeVolumeClient(object):
self.attachments = mock.Mock()
self.attachments.resource_class = fakes.FakeResource(None, {})
+ self.groups = mock.Mock()
+ self.groups.resource_class = fakes.FakeResource(None, {})
+ self.group_types = mock.Mock()
+ self.group_types.resource_class = fakes.FakeResource(None, {})
self.messages = mock.Mock()
self.messages.resource_class = fakes.FakeResource(None, {})
self.volumes = mock.Mock()
self.volumes.resource_class = fakes.FakeResource(None, {})
+ self.volume_types = mock.Mock()
+ self.volume_types.resource_class = fakes.FakeResource(None, {})
class TestVolume(utils.TestCommand):
@@ -59,6 +65,111 @@ class TestVolume(utils.TestCommand):
# TODO(stephenfin): Check if the responses are actually the same
FakeVolume = volume_v2_fakes.FakeVolume
+FakeVolumeType = volume_v2_fakes.FakeVolumeType
+
+
+class FakeVolumeGroup:
+ """Fake one or more volume groups."""
+
+ @staticmethod
+ def create_one_volume_group(attrs=None):
+ """Create a fake group.
+
+ :param attrs: A dictionary with all attributes of group
+ :return: A FakeResource object with id, name, status, etc.
+ """
+ attrs = attrs or {}
+
+ group_type = attrs.pop('group_type', None) or uuid.uuid4().hex
+ volume_types = attrs.pop('volume_types', None) or [uuid.uuid4().hex]
+
+ # Set default attribute
+ group_info = {
+ 'id': uuid.uuid4().hex,
+ 'status': random.choice([
+ 'available',
+ ]),
+ 'availability_zone': f'az-{uuid.uuid4().hex}',
+ 'created_at': '2015-09-16T09:28:52.000000',
+ 'name': 'first_group',
+ 'description': f'description-{uuid.uuid4().hex}',
+ 'group_type': group_type,
+ 'volume_types': volume_types,
+ 'volumes': [f'volume-{uuid.uuid4().hex}'],
+ 'group_snapshot_id': None,
+ 'source_group_id': None,
+ 'project_id': f'project-{uuid.uuid4().hex}',
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ group_info.update(attrs)
+
+ group = fakes.FakeResource(
+ None,
+ group_info,
+ loaded=True)
+ return group
+
+ @staticmethod
+ def create_volume_groups(attrs=None, count=2):
+ """Create multiple fake groups.
+
+ :param attrs: A dictionary with all attributes of group
+ :param count: The number of groups to be faked
+ :return: A list of FakeResource objects
+ """
+ groups = []
+ for n in range(0, count):
+ groups.append(FakeVolumeGroup.create_one_volume_group(attrs))
+
+ return groups
+
+
+class FakeVolumeGroupType:
+ """Fake one or more volume group types."""
+
+ @staticmethod
+ def create_one_volume_group_type(attrs=None):
+ """Create a fake group type.
+
+ :param attrs: A dictionary with all attributes of group type
+ :return: A FakeResource object with id, name, description, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+ group_type_info = {
+ 'id': uuid.uuid4().hex,
+ 'name': f'group-type-{uuid.uuid4().hex}',
+ 'description': f'description-{uuid.uuid4().hex}',
+ 'is_public': random.choice([True, False]),
+ 'group_specs': {},
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ group_type_info.update(attrs)
+
+ group_type = fakes.FakeResource(
+ None,
+ group_type_info,
+ loaded=True)
+ return group_type
+
+ @staticmethod
+ def create_volume_group_types(attrs=None, count=2):
+ """Create multiple fake group types.
+
+ :param attrs: A dictionary with all attributes of group type
+ :param count: The number of group types to be faked
+ :return: A list of FakeResource objects
+ """
+ group_types = []
+ for n in range(0, count):
+ group_types.append(
+ FakeVolumeGroupType.create_one_volume_group_type(attrs)
+ )
+
+ return group_types
class FakeVolumeMessage:
diff --git a/openstackclient/tests/unit/volume/v3/test_volume_group.py b/openstackclient/tests/unit/volume/v3/test_volume_group.py
new file mode 100644
index 00000000..13ef38d2
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v3/test_volume_group.py
@@ -0,0 +1,497 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from cinderclient import api_versions
+from osc_lib import exceptions
+
+from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
+from openstackclient.volume.v3 import volume_group
+
+
+class TestVolumeGroup(volume_fakes.TestVolume):
+
+ def setUp(self):
+ super().setUp()
+
+ self.volume_groups_mock = self.app.client_manager.volume.groups
+ self.volume_groups_mock.reset_mock()
+
+ self.volume_group_types_mock = \
+ self.app.client_manager.volume.group_types
+ self.volume_group_types_mock.reset_mock()
+
+ self.volume_types_mock = self.app.client_manager.volume.volume_types
+ self.volume_types_mock.reset_mock()
+
+
+class TestVolumeGroupCreate(TestVolumeGroup):
+
+ fake_volume_type = volume_fakes.FakeVolumeType.create_one_volume_type()
+ fake_volume_group_type = \
+ volume_fakes.FakeVolumeGroupType.create_one_volume_group_type()
+ fake_volume_group = volume_fakes.FakeVolumeGroup.create_one_volume_group(
+ attrs={
+ 'group_type': fake_volume_group_type.id,
+ 'volume_types': [fake_volume_type.id],
+ },
+ )
+
+ columns = (
+ 'ID',
+ 'Status',
+ 'Name',
+ 'Description',
+ 'Group Type',
+ 'Volume Types',
+ 'Availability Zone',
+ 'Created At',
+ 'Volumes',
+ 'Group Snapshot ID',
+ 'Source Group ID',
+ )
+ data = (
+ fake_volume_group.id,
+ fake_volume_group.status,
+ fake_volume_group.name,
+ fake_volume_group.description,
+ fake_volume_group.group_type,
+ fake_volume_group.volume_types,
+ fake_volume_group.availability_zone,
+ fake_volume_group.created_at,
+ fake_volume_group.volumes,
+ fake_volume_group.group_snapshot_id,
+ fake_volume_group.source_group_id,
+ )
+
+ def setUp(self):
+ super().setUp()
+
+ self.volume_types_mock.get.return_value = self.fake_volume_type
+ self.volume_group_types_mock.get.return_value = \
+ self.fake_volume_group_type
+ self.volume_groups_mock.create.return_value = self.fake_volume_group
+ self.volume_groups_mock.get.return_value = self.fake_volume_group
+
+ self.cmd = volume_group.CreateVolumeGroup(self.app, None)
+
+ def test_volume_group_create(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.13')
+
+ arglist = [
+ self.fake_volume_group_type.id,
+ self.fake_volume_type.id,
+ ]
+ verifylist = [
+ ('volume_group_type', self.fake_volume_group_type.id),
+ ('volume_types', [self.fake_volume_type.id]),
+ ('name', None),
+ ('description', None),
+ ('availability_zone', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volume_group_types_mock.get.assert_called_once_with(
+ self.fake_volume_group_type.id)
+ self.volume_types_mock.get.assert_called_once_with(
+ self.fake_volume_type.id)
+ self.volume_groups_mock.create.assert_called_once_with(
+ self.fake_volume_group_type.id,
+ self.fake_volume_type.id,
+ None,
+ None,
+ availability_zone=None,
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(self.data, data)
+
+ def test_volume_group_create_with_options(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.13')
+
+ arglist = [
+ self.fake_volume_group_type.id,
+ self.fake_volume_type.id,
+ '--name', 'foo',
+ '--description', 'hello, world',
+ '--availability-zone', 'bar',
+ ]
+ verifylist = [
+ ('volume_group_type', self.fake_volume_group_type.id),
+ ('volume_types', [self.fake_volume_type.id]),
+ ('name', 'foo'),
+ ('description', 'hello, world'),
+ ('availability_zone', 'bar'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volume_group_types_mock.get.assert_called_once_with(
+ self.fake_volume_group_type.id)
+ self.volume_types_mock.get.assert_called_once_with(
+ self.fake_volume_type.id)
+ self.volume_groups_mock.create.assert_called_once_with(
+ self.fake_volume_group_type.id,
+ self.fake_volume_type.id,
+ 'foo',
+ 'hello, world',
+ availability_zone='bar',
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(self.data, data)
+
+ def test_volume_group_create_pre_v313(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.12')
+
+ arglist = [
+ self.fake_volume_group_type.id,
+ self.fake_volume_type.id,
+ ]
+ verifylist = [
+ ('volume_group_type', self.fake_volume_group_type.id),
+ ('volume_types', [self.fake_volume_type.id]),
+ ('name', None),
+ ('description', None),
+ ('availability_zone', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ exc = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-volume-api-version 3.13 or greater is required',
+ str(exc))
+
+
+class TestVolumeGroupDelete(TestVolumeGroup):
+
+ fake_volume_group = \
+ volume_fakes.FakeVolumeGroup.create_one_volume_group()
+
+ def setUp(self):
+ super().setUp()
+
+ self.volume_groups_mock.get.return_value = self.fake_volume_group
+ self.volume_groups_mock.delete.return_value = None
+
+ self.cmd = volume_group.DeleteVolumeGroup(self.app, None)
+
+ def test_volume_group_delete(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.13')
+
+ arglist = [
+ self.fake_volume_group.id,
+ '--force',
+ ]
+ verifylist = [
+ ('group', self.fake_volume_group.id),
+ ('force', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.volume_groups_mock.delete.assert_called_once_with(
+ self.fake_volume_group.id, delete_volumes=True,
+ )
+ self.assertIsNone(result)
+
+ def test_volume_group_delete_pre_v313(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.12')
+
+ arglist = [
+ self.fake_volume_group.id,
+ ]
+ verifylist = [
+ ('group', self.fake_volume_group.id),
+ ('force', False),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ exc = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-volume-api-version 3.13 or greater is required',
+ str(exc))
+
+
+class TestVolumeGroupSet(TestVolumeGroup):
+
+ fake_volume_group = \
+ volume_fakes.FakeVolumeGroup.create_one_volume_group()
+
+ columns = (
+ 'ID',
+ 'Status',
+ 'Name',
+ 'Description',
+ 'Group Type',
+ 'Volume Types',
+ 'Availability Zone',
+ 'Created At',
+ 'Volumes',
+ 'Group Snapshot ID',
+ 'Source Group ID',
+ )
+ data = (
+ fake_volume_group.id,
+ fake_volume_group.status,
+ fake_volume_group.name,
+ fake_volume_group.description,
+ fake_volume_group.group_type,
+ fake_volume_group.volume_types,
+ fake_volume_group.availability_zone,
+ fake_volume_group.created_at,
+ fake_volume_group.volumes,
+ fake_volume_group.group_snapshot_id,
+ fake_volume_group.source_group_id,
+ )
+
+ def setUp(self):
+ super().setUp()
+
+ self.volume_groups_mock.get.return_value = self.fake_volume_group
+ self.volume_groups_mock.update.return_value = self.fake_volume_group
+
+ self.cmd = volume_group.SetVolumeGroup(self.app, None)
+
+ def test_volume_group_set(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.13')
+
+ arglist = [
+ self.fake_volume_group.id,
+ '--name', 'foo',
+ '--description', 'hello, world',
+ ]
+ verifylist = [
+ ('group', self.fake_volume_group.id),
+ ('name', 'foo'),
+ ('description', 'hello, world'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volume_groups_mock.update.assert_called_once_with(
+ self.fake_volume_group.id, name='foo', description='hello, world',
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(self.data, data)
+
+ def test_volume_group_with_enable_replication_option(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.38')
+
+ arglist = [
+ self.fake_volume_group.id,
+ '--enable-replication',
+ ]
+ verifylist = [
+ ('group', self.fake_volume_group.id),
+ ('enable_replication', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volume_groups_mock.enable_replication.assert_called_once_with(
+ self.fake_volume_group.id)
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(self.data, data)
+
+ def test_volume_group_set_pre_v313(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.12')
+
+ arglist = [
+ self.fake_volume_group.id,
+ '--name', 'foo',
+ '--description', 'hello, world',
+ ]
+ verifylist = [
+ ('group', self.fake_volume_group.id),
+ ('name', 'foo'),
+ ('description', 'hello, world'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ exc = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-volume-api-version 3.13 or greater is required',
+ str(exc))
+
+ def test_volume_group_with_enable_replication_option_pre_v338(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.37')
+
+ arglist = [
+ self.fake_volume_group.id,
+ '--enable-replication',
+ ]
+ verifylist = [
+ ('group', self.fake_volume_group.id),
+ ('enable_replication', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ exc = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-volume-api-version 3.38 or greater is required',
+ str(exc))
+
+
+class TestVolumeGroupList(TestVolumeGroup):
+
+ fake_volume_groups = \
+ volume_fakes.FakeVolumeGroup.create_volume_groups()
+
+ columns = (
+ 'ID',
+ 'Status',
+ 'Name',
+ )
+ data = [
+ (
+ fake_volume_group.id,
+ fake_volume_group.status,
+ fake_volume_group.name,
+ ) for fake_volume_group in fake_volume_groups
+ ]
+
+ def setUp(self):
+ super().setUp()
+
+ self.volume_groups_mock.list.return_value = self.fake_volume_groups
+
+ self.cmd = volume_group.ListVolumeGroup(self.app, None)
+
+ def test_volume_group_list(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.13')
+
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('all_projects', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.volume_groups_mock.list.assert_called_once_with(
+ search_opts={
+ 'all_tenants': True,
+ },
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(tuple(self.data), data)
+
+ def test_volume_group_list_pre_v313(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.12')
+
+ arglist = [
+ '--all-projects',
+ ]
+ verifylist = [
+ ('all_projects', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ exc = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-volume-api-version 3.13 or greater is required',
+ str(exc))
+
+
+class TestVolumeGroupFailover(TestVolumeGroup):
+
+ fake_volume_group = \
+ volume_fakes.FakeVolumeGroup.create_one_volume_group()
+
+ def setUp(self):
+ super().setUp()
+
+ self.volume_groups_mock.get.return_value = self.fake_volume_group
+ self.volume_groups_mock.failover_replication.return_value = None
+
+ self.cmd = volume_group.FailoverVolumeGroup(self.app, None)
+
+ def test_volume_group_failover(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.38')
+
+ arglist = [
+ self.fake_volume_group.id,
+ '--allow-attached-volume',
+ '--secondary-backend-id', 'foo',
+ ]
+ verifylist = [
+ ('group', self.fake_volume_group.id),
+ ('allow_attached_volume', True),
+ ('secondary_backend_id', 'foo'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.volume_groups_mock.failover_replication.assert_called_once_with(
+ self.fake_volume_group.id,
+ allow_attached_volume=True,
+ secondary_backend_id='foo',
+ )
+ self.assertIsNone(result)
+
+ def test_volume_group_failover_pre_v338(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.37')
+
+ arglist = [
+ self.fake_volume_group.id,
+ '--allow-attached-volume',
+ '--secondary-backend-id', 'foo',
+ ]
+ verifylist = [
+ ('group', self.fake_volume_group.id),
+ ('allow_attached_volume', True),
+ ('secondary_backend_id', 'foo'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ exc = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-volume-api-version 3.38 or greater is required',
+ str(exc))