Files
python-manilaclient/manilaclient/tests/unit/osc/v2/test_share_backups.py
Zachary Goggin 4996e2b867 Add support for out of place share backup restores
Add CLI support and tests for performing a restore operation
with Manilas share backup API that targets a non-source share
i.e. a share other then that used to create the backup.)

Partially-Implements: blueprint out-of-place-restore
Depends-On: I060b0dc579e3057f2cb046ebe3271287f8fbc9f9
Change-Id: I8414c62010cd369e27cc5b693612c59d4e7516a3
Signed-off-by: Zachary Goggin <zachary.goggin@cern.ch>
2025-08-28 19:20:38 +00:00

443 lines
14 KiB
Python

# 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 osc_lib import exceptions
from osc_lib import utils as oscutils
from manilaclient import api_versions
from manilaclient.api_versions import MAX_VERSION
from manilaclient.osc.v2 import share_backups as osc_share_backups
from manilaclient.tests.unit.osc import osc_utils
from manilaclient.tests.unit.osc.v2 import fakes as manila_fakes
class TestShareBackup(manila_fakes.TestShare):
def setUp(self):
super(TestShareBackup, self).setUp()
self.shares_mock = self.app.client_manager.share.shares
self.shares_mock.reset_mock()
self.backups_mock = self.app.client_manager.share.share_backups
self.backups_mock.reset_mock()
self.app.client_manager.share.api_version = api_versions.APIVersion(
MAX_VERSION)
class TestShareBackupCreate(TestShareBackup):
def setUp(self):
super(TestShareBackupCreate, self).setUp()
self.share = manila_fakes.FakeShare.create_one_share()
self.shares_mock.get.return_value = self.share
self.share_backup = (
manila_fakes.FakeShareBackup.create_one_backup(
attrs={'status': 'available'}
))
self.backups_mock.create.return_value = self.share_backup
self.backups_mock.get.return_value = self.share_backup
self.cmd = osc_share_backups.CreateShareBackup(self.app, None)
self.data = tuple(self.share_backup._info.values())
self.columns = tuple(self.share_backup._info.keys())
def test_share_backup_create_missing_args(self):
arglist = []
verifylist = []
self.assertRaises(
osc_utils.ParserException,
self.check_parser, self.cmd, arglist, verifylist)
def test_share_backup_create(self):
arglist = [
self.share.id
]
verifylist = [
('share', self.share.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.backups_mock.create.assert_called_with(
self.share,
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_share_backup_create_name(self):
arglist = [
self.share.id,
'--name', "FAKE_SHARE_BACKUP_NAME"
]
verifylist = [
('share', self.share.id),
('name', "FAKE_SHARE_BACKUP_NAME")
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.backups_mock.create.assert_called_with(
self.share,
name="FAKE_SHARE_BACKUP_NAME",
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
class TestShareBackupDelete(TestShareBackup):
def setUp(self):
super(TestShareBackupDelete, self).setUp()
self.share_backup = (
manila_fakes.FakeShareBackup.create_one_backup())
self.backups_mock.get.return_value = self.share_backup
self.cmd = osc_share_backups.DeleteShareBackup(self.app, None)
def test_share_backup_delete_missing_args(self):
arglist = []
verifylist = []
self.assertRaises(osc_utils.ParserException,
self.check_parser, self.cmd, arglist, verifylist)
def test_share_backup_delete(self):
arglist = [
self.share_backup.id
]
verifylist = [
('backup', [self.share_backup.id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.backups_mock.delete.assert_called_with(self.share_backup)
self.assertIsNone(result)
def test_share_backup_delete_multiple(self):
share_backups = (
manila_fakes.FakeShareBackup.create_share_backups(
count=2))
arglist = [
share_backups[0].id,
share_backups[1].id
]
verifylist = [
('backup', [share_backups[0].id, share_backups[1].id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.assertEqual(self.backups_mock.delete.call_count,
len(share_backups))
self.assertIsNone(result)
def test_share_backup_delete_exception(self):
arglist = [
self.share_backup.id
]
verifylist = [
('backup', [self.share_backup.id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.backups_mock.delete.side_effect = exceptions.CommandError()
self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)
class TestShareBackupList(TestShareBackup):
columns = [
'ID',
'Name',
'Share ID',
'Status',
]
detailed_columns = [
'ID',
'Name',
'Share ID',
'Status',
'Description',
'Size',
'Created At',
'Updated At',
'Availability Zone',
'Progress',
'Restore Progress',
'Host',
'Topic',
]
def setUp(self):
super(TestShareBackupList, self).setUp()
self.share = manila_fakes.FakeShare.create_one_share()
self.shares_mock.get.return_value = self.share
self.backups_list = (
manila_fakes.FakeShareBackup.create_share_backups(
count=2))
self.backups_mock.list.return_value = self.backups_list
self.values = (oscutils.get_dict_properties(
i._info, self.columns) for i in self.backups_list)
self.detailed_values = (oscutils.get_dict_properties(
i._info, self.detailed_columns) for i in self.backups_list)
self.cmd = osc_share_backups.ListShareBackup(self.app, None)
def test_share_backup_list(self):
arglist = []
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.backups_mock.list.assert_called_with(
detailed=0,
search_opts={
'offset': None, 'limit': None, 'name': None,
'description': None, 'name~': None, 'description~': None,
'status': None, 'share_id': None
},
sort_key=None, sort_dir=None
)
self.assertEqual(self.columns, columns)
self.assertEqual(list(self.values), list(data))
def test_share_backup_list_detail(self):
arglist = [
'--detail'
]
verifylist = [
('detail', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.backups_mock.list.assert_called_with(
detailed=1,
search_opts={
'offset': None, 'limit': None, 'name': None,
'description': None, 'name~': None, 'description~': None,
'status': None, 'share_id': None
},
sort_key=None, sort_dir=None
)
self.assertEqual(self.detailed_columns, columns)
self.assertEqual(list(self.detailed_values), list(data))
def test_share_backup_list_for_share(self):
arglist = [
'--share', self.share.id
]
verifylist = [
('share', self.share.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.backups_mock.list.assert_called_with(
detailed=0,
search_opts={
'offset': None, 'limit': None, 'name': None,
'description': None, 'name~': None, 'description~': None,
'status': None, 'share_id': self.share.id
},
sort_key=None, sort_dir=None
)
self.assertEqual(self.columns, columns)
self.assertEqual(list(self.values), list(data))
class TestShareBackupShow(TestShareBackup):
def setUp(self):
super(TestShareBackupShow, self).setUp()
self.share_backup = (
manila_fakes.FakeShareBackup.create_one_backup()
)
self.backups_mock.get.return_value = self.share_backup
self.cmd = osc_share_backups.ShowShareBackup(self.app, None)
self.data = tuple(self.share_backup._info.values())
self.columns = tuple(self.share_backup._info.keys())
def test_share_backup_show_missing_args(self):
arglist = []
verifylist = []
self.assertRaises(
osc_utils.ParserException,
self.check_parser, self.cmd, arglist, verifylist)
def test_share_backup_show(self):
arglist = [
self.share_backup.id
]
verifylist = [
('backup', self.share_backup.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.backups_mock.get.assert_called_with(
self.share_backup.id
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
class TestShareBackupRestore(TestShareBackup):
def setUp(self):
super(TestShareBackupRestore, self).setUp()
self.share_backup = (
manila_fakes.FakeShareBackup.create_one_backup()
)
self.target_share = (
manila_fakes.FakeShare.create_one_share()
)
self.backups_mock.get.return_value = self.share_backup
self.shares_mock.get.return_value = self.target_share
self.cmd = osc_share_backups.RestoreShareBackup(
self.app, None)
def test_share_backup_restore(self):
arglist = [
self.share_backup.id,
]
verifylist = [
('backup', self.share_backup.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.backups_mock.restore.assert_called_with(self.share_backup.id)
self.assertIsNone(result)
def test_share_backup_restore_to_target(self):
arglist = [
self.share_backup.id,
'--target-share', self.target_share.id
]
verifylist = [
('backup', self.share_backup.id),
('target_share', self.target_share.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.backups_mock.restore.assert_called_with(
self.share_backup.id,
target_share_id=self.target_share.id
)
self.assertIsNone(result)
class TestShareBackupSet(TestShareBackup):
def setUp(self):
super(TestShareBackupSet, self).setUp()
self.share_backup = (
manila_fakes.FakeShareBackup.create_one_backup()
)
self.backups_mock.get.return_value = self.share_backup
self.cmd = osc_share_backups.SetShareBackup(self.app, None)
def test_set_share_backup_name(self):
arglist = [
self.share_backup.id,
'--name', "FAKE_SHARE_BACKUP_NAME"
]
verifylist = [
('backup', self.share_backup.id),
('name', "FAKE_SHARE_BACKUP_NAME")
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.backups_mock.update.assert_called_with(self.share_backup,
name=parsed_args.name)
self.assertIsNone(result)
def test_set_backup_status(self):
arglist = [
self.share_backup.id,
'--status', 'available'
]
verifylist = [
('backup', self.share_backup.id),
('status', 'available')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.backups_mock.reset_status.assert_called_with(
self.share_backup,
parsed_args.status)
self.assertIsNone(result)
class TestShareBackupUnset(TestShareBackup):
def setUp(self):
super(TestShareBackupUnset, self).setUp()
self.share_backup = (
manila_fakes.FakeShareBackup.create_one_backup()
)
self.backups_mock.get.return_value = self.share_backup
self.cmd = osc_share_backups.UnsetShareBackup(self.app, None)
def test_unset_backup_name(self):
arglist = [
self.share_backup.id,
'--name'
]
verifylist = [
('backup', self.share_backup.id),
('name', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.backups_mock.update.assert_called_with(
self.share_backup,
name=None)
self.assertIsNone(result)
def test_unset_backup_description(self):
arglist = [
self.share_backup.id,
'--description'
]
verifylist = [
('backup', self.share_backup.id),
('description', True)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.backups_mock.update.assert_called_with(
self.share_backup,
description=None)
self.assertIsNone(result)