Skip to content

Commit 6ce53fe

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Support error handling for delete commands in volumev2"
2 parents 13f1aa9 + 9b51127 commit 6ce53fe

9 files changed

Lines changed: 364 additions & 40 deletions

File tree

openstackclient/tests/volume/v2/fakes.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,26 @@ def create_backups(attrs=None, count=2):
418418

419419
return backups
420420

421+
@staticmethod
422+
def get_backups(backups=None, count=2):
423+
"""Get an iterable MagicMock object with a list of faked backups.
424+
425+
If backups list is provided, then initialize the Mock object with the
426+
list. Otherwise create one.
427+
428+
:param List volumes:
429+
A list of FakeResource objects faking backups
430+
:param Integer count:
431+
The number of backups to be faked
432+
:return
433+
An iterable Mock object with side_effect set to a list of faked
434+
backups
435+
"""
436+
if backups is None:
437+
backups = FakeBackup.create_backups(count)
438+
439+
return mock.MagicMock(side_effect=backups)
440+
421441

422442
class FakeExtension(object):
423443
"""Fake one or more extension."""
@@ -529,6 +549,26 @@ def create_qoses(attrs=None, count=2):
529549

530550
return qoses
531551

552+
@staticmethod
553+
def get_qoses(qoses=None, count=2):
554+
"""Get an iterable MagicMock object with a list of faked qoses.
555+
556+
If qoses list is provided, then initialize the Mock object with the
557+
list. Otherwise create one.
558+
559+
:param List volumes:
560+
A list of FakeResource objects faking qoses
561+
:param Integer count:
562+
The number of qoses to be faked
563+
:return
564+
An iterable Mock object with side_effect set to a list of faked
565+
qoses
566+
"""
567+
if qoses is None:
568+
qoses = FakeQos.create_qoses(count)
569+
570+
return mock.MagicMock(side_effect=qoses)
571+
532572

533573
class FakeSnapshot(object):
534574
"""Fake one or more snapshot."""
@@ -582,6 +622,26 @@ def create_snapshots(attrs=None, count=2):
582622

583623
return snapshots
584624

625+
@staticmethod
626+
def get_snapshots(snapshots=None, count=2):
627+
"""Get an iterable MagicMock object with a list of faked snapshots.
628+
629+
If snapshots list is provided, then initialize the Mock object with the
630+
list. Otherwise create one.
631+
632+
:param List volumes:
633+
A list of FakeResource objects faking snapshots
634+
:param Integer count:
635+
The number of snapshots to be faked
636+
:return
637+
An iterable Mock object with side_effect set to a list of faked
638+
snapshots
639+
"""
640+
if snapshots is None:
641+
snapshots = FakeSnapshot.create_snapshots(count)
642+
643+
return mock.MagicMock(side_effect=snapshots)
644+
585645

586646
class FakeType(object):
587647
"""Fake one or more type."""

openstackclient/tests/volume/v2/test_backup.py

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
# under the License.
1313
#
1414

15+
import mock
16+
from mock import call
17+
18+
from osc_lib import exceptions
19+
from osc_lib import utils
20+
1521
from openstackclient.tests.volume.v2 import fakes as volume_fakes
1622
from openstackclient.volume.v2 import backup
1723

@@ -138,47 +144,95 @@ def test_backup_create_without_name(self):
138144

139145
class TestBackupDelete(TestBackup):
140146

141-
backup = volume_fakes.FakeBackup.create_one_backup()
147+
backups = volume_fakes.FakeBackup.create_backups(count=2)
142148

143149
def setUp(self):
144150
super(TestBackupDelete, self).setUp()
145151

146-
self.backups_mock.get.return_value = self.backup
152+
self.backups_mock.get = (
153+
volume_fakes.FakeBackup.get_backups(self.backups))
147154
self.backups_mock.delete.return_value = None
148155

149156
# Get the command object to mock
150157
self.cmd = backup.DeleteBackup(self.app, None)
151158

152159
def test_backup_delete(self):
153160
arglist = [
154-
self.backup.id
161+
self.backups[0].id
155162
]
156163
verifylist = [
157-
("backups", [self.backup.id])
164+
("backups", [self.backups[0].id])
158165
]
159166
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
160167

161168
result = self.cmd.take_action(parsed_args)
162169

163-
self.backups_mock.delete.assert_called_with(self.backup.id, False)
170+
self.backups_mock.delete.assert_called_with(
171+
self.backups[0].id, False)
164172
self.assertIsNone(result)
165173

166174
def test_backup_delete_with_force(self):
167175
arglist = [
168176
'--force',
169-
self.backup.id,
177+
self.backups[0].id,
170178
]
171179
verifylist = [
172180
('force', True),
173-
("backups", [self.backup.id])
181+
("backups", [self.backups[0].id])
174182
]
175183
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
176184

177185
result = self.cmd.take_action(parsed_args)
178186

179-
self.backups_mock.delete.assert_called_with(self.backup.id, True)
187+
self.backups_mock.delete.assert_called_with(self.backups[0].id, True)
180188
self.assertIsNone(result)
181189

190+
def test_delete_multiple_backups(self):
191+
arglist = []
192+
for b in self.backups:
193+
arglist.append(b.id)
194+
verifylist = [
195+
('backups', arglist),
196+
]
197+
198+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
199+
result = self.cmd.take_action(parsed_args)
200+
201+
calls = []
202+
for b in self.backups:
203+
calls.append(call(b.id, False))
204+
self.backups_mock.delete.assert_has_calls(calls)
205+
self.assertIsNone(result)
206+
207+
def test_delete_multiple_backups_with_exception(self):
208+
arglist = [
209+
self.backups[0].id,
210+
'unexist_backup',
211+
]
212+
verifylist = [
213+
('backups', arglist),
214+
]
215+
216+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
217+
218+
find_mock_result = [self.backups[0], exceptions.CommandError]
219+
with mock.patch.object(utils, 'find_resource',
220+
side_effect=find_mock_result) as find_mock:
221+
try:
222+
self.cmd.take_action(parsed_args)
223+
self.fail('CommandError should be raised.')
224+
except exceptions.CommandError as e:
225+
self.assertEqual('1 of 2 backups failed to delete.',
226+
str(e))
227+
228+
find_mock.assert_any_call(self.backups_mock, self.backups[0].id)
229+
find_mock.assert_any_call(self.backups_mock, 'unexist_backup')
230+
231+
self.assertEqual(2, find_mock.call_count)
232+
self.backups_mock.delete.assert_called_once_with(
233+
self.backups[0].id, False
234+
)
235+
182236

183237
class TestBackupList(TestBackup):
184238

openstackclient/tests/volume/v2/test_qos_specs.py

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
# under the License.
1414
#
1515

16+
import mock
17+
from mock import call
18+
19+
from osc_lib import exceptions
1620
from osc_lib import utils
1721

1822
from openstackclient.tests.volume.v2 import fakes as volume_fakes
@@ -156,45 +160,94 @@ def test_qos_create_with_properties(self):
156160

157161
class TestQosDelete(TestQos):
158162

159-
qos_spec = volume_fakes.FakeQos.create_one_qos()
163+
qos_specs = volume_fakes.FakeQos.create_qoses(count=2)
160164

161165
def setUp(self):
162166
super(TestQosDelete, self).setUp()
163167

164-
self.qos_mock.get.return_value = self.qos_spec
168+
self.qos_mock.get = (
169+
volume_fakes.FakeQos.get_qoses(self.qos_specs))
165170
# Get the command object to test
166171
self.cmd = qos_specs.DeleteQos(self.app, None)
167172

168173
def test_qos_delete(self):
169174
arglist = [
170-
self.qos_spec.id
175+
self.qos_specs[0].id
171176
]
172177
verifylist = [
173-
('qos_specs', [self.qos_spec.id])
178+
('qos_specs', [self.qos_specs[0].id])
174179
]
175180
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
176181

177182
result = self.cmd.take_action(parsed_args)
178183

179-
self.qos_mock.delete.assert_called_with(self.qos_spec.id, False)
184+
self.qos_mock.delete.assert_called_with(
185+
self.qos_specs[0].id, False)
180186
self.assertIsNone(result)
181187

182188
def test_qos_delete_with_force(self):
183189
arglist = [
184190
'--force',
185-
self.qos_spec.id
191+
self.qos_specs[0].id
186192
]
187193
verifylist = [
188194
('force', True),
189-
('qos_specs', [self.qos_spec.id])
195+
('qos_specs', [self.qos_specs[0].id])
190196
]
191197
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
192198

193199
result = self.cmd.take_action(parsed_args)
194200

195-
self.qos_mock.delete.assert_called_with(self.qos_spec.id, True)
201+
self.qos_mock.delete.assert_called_with(
202+
self.qos_specs[0].id, True)
196203
self.assertIsNone(result)
197204

205+
def test_delete_multiple_qoses(self):
206+
arglist = []
207+
for q in self.qos_specs:
208+
arglist.append(q.id)
209+
verifylist = [
210+
('qos_specs', arglist),
211+
]
212+
213+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
214+
result = self.cmd.take_action(parsed_args)
215+
216+
calls = []
217+
for q in self.qos_specs:
218+
calls.append(call(q.id, False))
219+
self.qos_mock.delete.assert_has_calls(calls)
220+
self.assertIsNone(result)
221+
222+
def test_delete_multiple_qoses_with_exception(self):
223+
arglist = [
224+
self.qos_specs[0].id,
225+
'unexist_qos',
226+
]
227+
verifylist = [
228+
('qos_specs', arglist),
229+
]
230+
231+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
232+
233+
find_mock_result = [self.qos_specs[0], exceptions.CommandError]
234+
with mock.patch.object(utils, 'find_resource',
235+
side_effect=find_mock_result) as find_mock:
236+
try:
237+
self.cmd.take_action(parsed_args)
238+
self.fail('CommandError should be raised.')
239+
except exceptions.CommandError as e:
240+
self.assertEqual(
241+
'1 of 2 QoS specifications failed to delete.', str(e))
242+
243+
find_mock.assert_any_call(self.qos_mock, self.qos_specs[0].id)
244+
find_mock.assert_any_call(self.qos_mock, 'unexist_qos')
245+
246+
self.assertEqual(2, find_mock.call_count)
247+
self.qos_mock.delete.assert_called_once_with(
248+
self.qos_specs[0].id, False
249+
)
250+
198251

199252
class TestQosDisassociate(TestQos):
200253

0 commit comments

Comments
 (0)