Coverage for manila/tests/share_group/test_api.py: 99%
677 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright 2016 Alex Meade
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15"""Unit tests for the Share API module."""
17import copy
18import datetime
19from unittest import mock
21import ddt
22from oslo_config import cfg
23from oslo_utils import timeutils
24from webob import exc as webob_exc
26from manila.common import constants
27from manila import context
28from manila import db as db_driver
29from manila import exception
30from manila.share import share_types
31from manila.share_group import api as share_group_api
32from manila import test
33from manila.tests.api.contrib import stubs
34from manila.tests import utils as test_utils
36CONF = cfg.CONF
39def fake_share_group(id, **kwargs):
40 share_group = {
41 'id': id,
42 'user_id': 'fakeuser',
43 'project_id': 'fakeproject',
44 'status': constants.STATUS_CREATING,
45 'name': None,
46 'description': None,
47 'host': None,
48 'availability_zone_id': None,
49 'share_group_type_id': None,
50 'source_share_group_snapshot_id': None,
51 'share_network_id': None,
52 'share_server_id': None,
53 'share_types': mock.ANY,
54 'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
55 }
57 if 'source_share_group_snapshot_id' in kwargs: 57 ↛ 58line 57 didn't jump to line 58 because the condition on line 57 was never true
58 share_group['share_network_id'] = 'fake_share_network_id'
59 share_group['share_server_id'] = 'fake_share_server_id'
61 share_group.update(kwargs)
62 return share_group
65def fake_share_group_snapshot(id, **kwargs):
66 snap = {
67 'id': id,
68 'user_id': 'fakeuser',
69 'project_id': 'fakeproject',
70 'status': constants.STATUS_CREATING,
71 'name': None,
72 'description': None,
73 'share_group_id': None,
74 'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
75 }
76 snap.update(kwargs)
77 return snap
80@ddt.ddt
81class ShareGroupsAPITestCase(test.TestCase):
82 def setUp(self):
83 super(ShareGroupsAPITestCase, self).setUp()
84 self.user_id = 'fake_user_id'
85 self.project_id = 'fake_project_id'
86 self.context = context.RequestContext(
87 user_id=self.user_id, project_id=self.project_id, is_admin=True)
88 self.scheduler_rpcapi = mock.Mock()
89 self.share_rpcapi = mock.Mock()
90 self.share_api = mock.Mock()
91 self.api = share_group_api.API()
92 self.mock_object(self.api, 'share_rpcapi', self.share_rpcapi)
93 self.mock_object(self.api, 'share_api', self.share_api)
94 self.mock_object(self.api, 'scheduler_rpcapi', self.scheduler_rpcapi)
96 dt_utc = timeutils.utcnow()
97 self.mock_object(timeutils, 'utcnow', mock.Mock(return_value=dt_utc))
98 self.fake_share_type = {
99 'name': 'default',
100 'extra_specs': {'driver_handles_share_servers': 'False'},
101 'is_public': True,
102 'id': 'c01990c1-448f-435a-9de6-c7c894bb6df9'
103 }
104 self.fake_share_type_2 = {
105 'name': 'default2',
106 'extra_specs': {'driver_handles_share_servers': 'False'},
107 'is_public': True,
108 'id': 'c01990c1-448f-435a-9de6-c7c894bb7dfd'
109 }
110 self.fake_share_group_type = {
111 'share_types': [
112 {'share_type_id': self.fake_share_type['id']},
113 {'share_type_id': self.fake_share_type_2['id']},
114 ]
115 }
116 self.mock_object(share_types, 'get_share_type',
117 mock.Mock(return_value=self.fake_share_type))
118 self.mock_object(
119 db_driver, 'share_group_type_get',
120 mock.Mock(return_value=self.fake_share_group_type))
121 self.mock_object(share_group_api.QUOTAS, 'reserve')
122 self.mock_object(share_group_api.QUOTAS, 'commit')
123 self.mock_object(share_group_api.QUOTAS, 'rollback')
125 def test_create_empty_request(self):
126 share_group = fake_share_group(
127 'fakeid', user_id=self.context.user_id,
128 project_id=self.context.project_id,
129 status=constants.STATUS_CREATING)
130 expected_values = share_group.copy()
131 for name in ('id', 'host', 'created_at'):
132 expected_values.pop(name, None)
133 self.mock_object(db_driver, 'share_group_create',
134 mock.Mock(return_value=share_group))
136 self.api.create(self.context)
138 db_driver.share_group_create.assert_called_once_with(
139 self.context, expected_values)
140 share_group_api.QUOTAS.reserve.assert_called_once_with(
141 self.context, share_groups=1)
142 share_group_api.QUOTAS.commit.assert_called_once_with(
143 self.context, share_group_api.QUOTAS.reserve.return_value)
144 share_group_api.QUOTAS.rollback.assert_not_called()
146 def test_create_request_spec(self):
147 """Ensure the correct values are sent to the scheduler."""
148 share_group = fake_share_group(
149 'fakeid', user_id=self.context.user_id,
150 project_id=self.context.project_id,
151 status=constants.STATUS_CREATING)
152 expected_values = share_group.copy()
153 for name in ('id', 'host', 'created_at'):
154 expected_values.pop(name, None)
155 expected_request_spec = {'share_group_id': share_group['id']}
156 expected_request_spec.update(share_group)
157 expected_request_spec['availability_zones'] = set([])
158 del expected_request_spec['id']
159 del expected_request_spec['created_at']
160 del expected_request_spec['host']
161 expected_request_spec['resource_type'] = self.fake_share_group_type
162 self.mock_object(db_driver, 'share_group_create',
163 mock.Mock(return_value=share_group))
165 self.api.create(self.context)
167 self.scheduler_rpcapi.create_share_group.assert_called_once_with(
168 self.context, share_group_id=share_group['id'],
169 request_spec=expected_request_spec, filter_properties={})
170 share_group_api.QUOTAS.reserve.assert_called_once_with(
171 self.context, share_groups=1)
172 share_group_api.QUOTAS.commit.assert_called_once_with(
173 self.context, share_group_api.QUOTAS.reserve.return_value)
174 share_group_api.QUOTAS.rollback.assert_not_called()
176 def test_create_with_name(self):
177 fake_name = 'fake_name'
178 share_group = fake_share_group(
179 'fakeid', user_id=self.context.user_id,
180 project_id=self.context.project_id,
181 status=constants.STATUS_CREATING)
182 expected_values = share_group.copy()
183 for name in ('id', 'host', 'created_at'):
184 expected_values.pop(name, None)
185 expected_values['name'] = fake_name
186 self.mock_object(db_driver, 'share_group_create',
187 mock.Mock(return_value=share_group))
188 self.mock_object(db_driver, 'share_network_get')
190 self.api.create(self.context, name=fake_name)
192 db_driver.share_group_create.assert_called_once_with(
193 self.context, expected_values)
194 self.scheduler_rpcapi.create_share_group.assert_called_once_with(
195 self.context, share_group_id=share_group['id'],
196 request_spec=mock.ANY, filter_properties={})
197 share_group_api.QUOTAS.reserve.assert_called_once_with(
198 self.context, share_groups=1)
199 share_group_api.QUOTAS.commit.assert_called_once_with(
200 self.context, share_group_api.QUOTAS.reserve.return_value)
201 share_group_api.QUOTAS.rollback.assert_not_called()
203 def test_create_with_description(self):
204 fake_desc = 'fake_desc'
205 share_group = fake_share_group(
206 'fakeid', user_id=self.context.user_id,
207 project_id=self.context.project_id,
208 status=constants.STATUS_CREATING)
209 expected_values = share_group.copy()
210 for name in ('id', 'host', 'created_at'):
211 expected_values.pop(name, None)
212 expected_values['description'] = fake_desc
213 self.mock_object(db_driver, 'share_group_create',
214 mock.Mock(return_value=share_group))
216 self.api.create(self.context, description=fake_desc)
218 db_driver.share_group_create.assert_called_once_with(
219 self.context, expected_values)
220 share_group_api.QUOTAS.reserve.assert_called_once_with(
221 self.context, share_groups=1)
222 share_group_api.QUOTAS.commit.assert_called_once_with(
223 self.context, share_group_api.QUOTAS.reserve.return_value)
224 share_group_api.QUOTAS.rollback.assert_not_called()
226 @ddt.data(True, False)
227 def test_create_with_multiple_share_types_with_az(self, with_az):
228 share_type_1 = copy.deepcopy(self.fake_share_type)
229 share_type_2 = copy.deepcopy(self.fake_share_type_2)
230 share_type_1['extra_specs']['availability_zones'] = 'nova,supernova'
231 share_type_2['extra_specs']['availability_zones'] = 'nova'
232 fake_share_types = [share_type_1, share_type_2]
233 fake_share_type_ids = [x['id'] for x in fake_share_types]
234 share_group_type = {
235 'share_types': [
236 {'share_type_id': share_type_1['id']},
237 {'share_type_id': share_type_2['id']},
238 {'share_type_id': self.fake_share_type['id']},
239 ]
240 }
241 self.mock_object(
242 db_driver, 'share_group_type_get',
243 mock.Mock(return_value=share_group_type))
244 self.mock_object(share_types, 'get_share_type', mock.Mock(
245 side_effect=[share_type_1, share_type_2,
246 share_type_1, share_type_2, self.fake_share_type]))
247 share_group = fake_share_group(
248 'fakeid', user_id=self.context.user_id,
249 project_id=self.context.project_id,
250 status=constants.STATUS_CREATING,
251 availability_zone_id=('e030620e-892c-4ff4-8764-9f3f2b560bd1'
252 if with_az else None)
253 )
254 expected_values = share_group.copy()
255 for name in ('id', 'host', 'created_at'):
256 expected_values.pop(name, None)
257 expected_values['share_types'] = fake_share_type_ids
258 self.mock_object(
259 db_driver, 'share_group_create',
260 mock.Mock(return_value=share_group))
261 self.mock_object(db_driver, 'share_network_get')
262 az_kwargs = {
263 'availability_zone': 'nova',
264 'availability_zone_id': share_group['availability_zone_id'],
265 }
267 kwargs = {} if not with_az else az_kwargs
268 self.api.create(self.context, share_type_ids=fake_share_type_ids,
269 **kwargs)
271 scheduler_request_spec = (
272 self.scheduler_rpcapi.create_share_group.call_args_list[
273 0][1]['request_spec']
274 )
275 az_id = az_kwargs['availability_zone_id'] if with_az else None
276 self.assertEqual({'nova', 'supernova'},
277 scheduler_request_spec['availability_zones'])
278 self.assertEqual(az_id, scheduler_request_spec['availability_zone_id'])
279 db_driver.share_group_create.assert_called_once_with(
280 self.context, expected_values)
281 share_group_api.QUOTAS.reserve.assert_called_once_with(
282 self.context, share_groups=1)
283 share_group_api.QUOTAS.commit.assert_called_once_with(
284 self.context, share_group_api.QUOTAS.reserve.return_value)
285 share_group_api.QUOTAS.rollback.assert_not_called()
287 @ddt.data(
288 test_utils.annotated('specified_stypes_one_unsupported_in_AZ',
289 (True, True)),
290 test_utils.annotated('specified_stypes_all_unsupported_in_AZ',
291 (True, False)),
292 test_utils.annotated('group_type_stypes_one_unsupported_in_AZ',
293 (False, True)),
294 test_utils.annotated('group_type_stypes_all_unsupported_in_AZ',
295 (False, False)))
296 @ddt.unpack
297 def test_create_unsupported_az(self, specify_stypes, all_unsupported):
298 share_type_1 = copy.deepcopy(self.fake_share_type)
299 share_type_2 = copy.deepcopy(self.fake_share_type_2)
300 share_type_1['extra_specs']['availability_zones'] = 'nova,supernova'
301 share_type_2['extra_specs']['availability_zones'] = (
302 'nova' if all_unsupported else 'nova,hypernova'
303 )
304 share_group_type = {
305 'share_types': [
306 {'share_type_id': share_type_1['id'], },
307 {'share_type_id': share_type_2['id']},
308 ]
309 }
310 share_group = fake_share_group(
311 'fakeid', user_id=self.context.user_id,
312 project_id=self.context.project_id,
313 status=constants.STATUS_CREATING,
314 availability_zone_id='e030620e-892c-4ff4-8764-9f3f2b560bd1')
315 self.mock_object(
316 db_driver, 'share_group_create',
317 mock.Mock(return_value=share_group))
318 self.mock_object(db_driver, 'share_network_get')
319 self.mock_object(
320 db_driver, 'share_group_type_get',
321 mock.Mock(return_value=share_group_type))
322 self.mock_object(share_types, 'get_share_type',
323 mock.Mock(side_effect=[share_type_1,
324 share_type_1] * 2))
325 self.mock_object(db_driver, 'share_group_snapshot_get')
326 kwargs = {
327 'availability_zone': 'hypernova',
328 'availability_zone_id': share_group['availability_zone_id'],
329 }
330 if specify_stypes:
331 kwargs['share_type_ids'] = [share_type_1['id'], share_type_2['id']]
333 self.assertRaises(
334 exception.InvalidInput,
335 self.api.create,
336 self.context, **kwargs)
337 db_driver.share_group_snapshot_get.assert_not_called()
338 db_driver.share_network_get.assert_not_called()
340 def test_create_with_share_type_not_found(self):
341 self.mock_object(share_types, 'get_share_type',
342 mock.Mock(side_effect=exception.ShareTypeNotFound(
343 share_type_id=self.fake_share_type['id'])))
344 share_group = fake_share_group(
345 'fakeid', user_id=self.context.user_id,
346 project_id=self.context.project_id,
347 status=constants.STATUS_CREATING)
348 expected_values = share_group.copy()
349 for name in ('id', 'host', 'created_at'):
350 expected_values.pop(name, None)
351 expected_values['share_types'] = self.fake_share_type['id']
352 self.mock_object(db_driver, 'share_group_create',
353 mock.Mock(return_value=share_group))
355 self.assertRaises(
356 exception.InvalidInput,
357 self.api.create,
358 self.context, share_type_ids=[self.fake_share_type['id']])
360 share_group_api.QUOTAS.reserve.assert_not_called()
361 share_group_api.QUOTAS.commit.assert_not_called()
362 share_group_api.QUOTAS.rollback.assert_not_called()
364 def test_create_with_error_on_quota_reserve(self):
365 overs = ["share_groups"]
366 usages = {"share_groups": {"reserved": 1, "in_use": 3, "limit": 4}}
367 quotas = {"share_groups": 5}
368 share_group_api.QUOTAS.reserve.side_effect = exception.OverQuota(
369 overs=overs,
370 usages=usages,
371 quotas=quotas,
372 )
373 self.mock_object(share_group_api.LOG, "warning")
375 self.assertRaises(
376 exception.ShareGroupsLimitExceeded,
377 self.api.create, self.context)
379 share_group_api.QUOTAS.reserve.assert_called_once_with(
380 self.context, share_groups=1)
381 share_group_api.QUOTAS.commit.assert_not_called()
382 share_group_api.QUOTAS.rollback.assert_not_called()
383 share_group_api.LOG.warning.assert_called_once_with(mock.ANY, mock.ANY)
385 def test_create_driver_handles_share_servers_is_false_with_net_id(self):
386 fake_share_types = [self.fake_share_type]
387 self.mock_object(share_types, 'get_share_type')
389 self.assertRaises(exception.InvalidInput, self.api.create,
390 self.context, share_type_ids=fake_share_types,
391 share_network_id="fake_share_network")
393 def test_create_with_conflicting_share_types(self):
394 fake_share_type = {
395 'name': 'default',
396 'extra_specs': {'driver_handles_share_servers': 'True'},
397 'is_public': True,
398 'id': 'c01990c1-448f-435a-9de6-c7c894bb6df9',
399 }
400 fake_share_type_2 = {
401 'name': 'default2',
402 'extra_specs': {'driver_handles_share_servers': 'False'},
403 'is_public': True,
404 'id': 'c01990c1-448f-435a-9de6-c7c894bb7df9',
405 }
406 fake_share_types = [fake_share_type, fake_share_type_2]
407 fake_share_type_ids = [x['id'] for x in fake_share_types]
408 self.mock_object(share_types, 'get_share_type',
409 mock.Mock(side_effect=[fake_share_type,
410 fake_share_type_2]))
412 self.assertRaises(
413 exception.InvalidInput,
414 self.api.create,
415 self.context, share_type_ids=fake_share_type_ids)
417 share_group_api.QUOTAS.reserve.assert_not_called()
418 share_group_api.QUOTAS.commit.assert_not_called()
419 share_group_api.QUOTAS.rollback.assert_not_called()
421 def test_create_with_conflicting_share_type_and_share_network(self):
422 fake_share_type = {
423 'name': 'default',
424 'extra_specs': {'driver_handles_share_servers': 'False'},
425 'is_public': True,
426 'id': 'c01990c1-448f-435a-9de6-c7c894bb6df9',
427 }
428 fake_share_types = [fake_share_type]
429 self.mock_object(share_types, 'get_share_type',
430 mock.Mock(return_value=fake_share_type))
432 self.assertRaises(
433 exception.InvalidInput,
434 self.api.create,
435 self.context, share_type_ids=fake_share_types,
436 share_network_id="fake_sn")
438 share_group_api.QUOTAS.reserve.assert_not_called()
439 share_group_api.QUOTAS.commit.assert_not_called()
440 share_group_api.QUOTAS.rollback.assert_not_called()
442 def test_create_with_source_share_group_snapshot_id(self):
443 snap = fake_share_group_snapshot(
444 "fake_source_share_group_snapshot_id",
445 status=constants.STATUS_AVAILABLE)
446 fake_share_type_mapping = {'share_type_id': self.fake_share_type['id']}
447 orig_share_group = fake_share_group(
448 'fakeorigid', user_id=self.context.user_id,
449 project_id=self.context.project_id,
450 share_types=[fake_share_type_mapping],
451 status=constants.STATUS_AVAILABLE,
452 host='fake_original_host',
453 share_network_id='fake_network_id',
454 share_server_id='fake_server_id')
456 share_group = fake_share_group(
457 'fakeid', user_id=self.context.user_id,
458 project_id=self.context.project_id,
459 share_types=[fake_share_type_mapping],
460 status=constants.STATUS_CREATING,
461 host='fake_original_host',
462 share_network_id='fake_network_id',
463 share_server_id='fake_server_id')
464 share_network = {
465 'id': 'fakeid',
466 'status': constants.STATUS_NETWORK_ACTIVE
467 }
468 expected_values = share_group.copy()
469 for name in ('id', 'created_at', 'share_network_id',
470 'share_server_id'):
471 expected_values.pop(name, None)
472 expected_values['source_share_group_snapshot_id'] = snap['id']
473 expected_values['share_types'] = [self.fake_share_type['id']]
474 expected_values['share_network_id'] = 'fake_network_id'
475 expected_values['share_server_id'] = 'fake_server_id'
477 self.mock_object(
478 db_driver, 'share_group_snapshot_get',
479 mock.Mock(return_value=snap))
480 self.mock_object(
481 db_driver, 'share_group_get',
482 mock.Mock(return_value=orig_share_group))
483 self.mock_object(
484 db_driver, 'share_group_create',
485 mock.Mock(return_value=share_group))
486 self.mock_object(
487 db_driver, 'share_get',
488 mock.Mock(return_value=stubs.stub_share('fake_share')))
489 self.mock_object(
490 share_types, 'get_share_type',
491 mock.Mock(return_value={"id": self.fake_share_type['id']}))
492 self.mock_object(db_driver, 'share_network_get',
493 mock.Mock(return_value=share_network))
494 self.mock_object(
495 db_driver, 'share_group_snapshot_members_get_all',
496 mock.Mock(return_value=[]))
498 self.api.create(
499 self.context, source_share_group_snapshot_id=snap['id'])
501 db_driver.share_group_create.assert_called_once_with(
502 self.context, expected_values)
503 self.share_rpcapi.create_share_group.assert_called_once_with(
504 self.context, share_group, orig_share_group['host'])
505 share_group_api.QUOTAS.reserve.assert_called_once_with(
506 self.context, share_groups=1)
507 share_group_api.QUOTAS.commit.assert_called_once_with(
508 self.context, share_group_api.QUOTAS.reserve.return_value)
509 share_group_api.QUOTAS.rollback.assert_not_called()
511 def test_create_share_group_network_not_active(self):
512 fake_share_type_mapping = {'share_type_id': self.fake_share_type['id']}
513 share_group = fake_share_group(
514 'fakeid', user_id=self.context.user_id,
515 project_id=self.context.project_id,
516 share_types=[fake_share_type_mapping],
517 status=constants.STATUS_CREATING,
518 host='fake_original_host',
519 share_network_id='fake_network_id',
520 share_server_id='fake_server_id')
521 network_id = 'fake_sn'
522 share_network = {
523 'id': network_id,
524 'status': constants.STATUS_SERVER_NETWORK_CHANGE
525 }
526 expected_values = share_group.copy()
527 for name in ('id', 'created_at', 'share_network_id',
528 'share_server_id'):
529 expected_values.pop(name, None)
530 expected_values['share_types'] = [self.fake_share_type['id']]
531 expected_values['share_network_id'] = 'fake_network_id'
532 expected_values['share_server_id'] = 'fake_server_id'
534 self.mock_object(
535 share_types, 'get_share_type',
536 mock.Mock(return_value={"id": self.fake_share_type['id']}))
537 self.mock_object(db_driver, 'share_network_get',
538 mock.Mock(return_value=share_network))
540 self.assertRaises(
541 webob_exc.HTTPBadRequest,
542 self.api.create,
543 self.context, share_type_ids=[fake_share_type_mapping],
544 share_network_id="fake_sn")
546 db_driver.share_network_get.assert_called_once_with(
547 self.context, network_id)
549 def test_create_with_source_share_group_snapshot_id_with_member(self):
550 snap = fake_share_group_snapshot(
551 "fake_source_share_group_snapshot_id",
552 status=constants.STATUS_AVAILABLE)
553 share = stubs.stub_share('fakeshareid')
554 member = stubs.stub_share_group_snapshot_member('fake_member_id')
555 fake_share_type_mapping = {'share_type_id': self.fake_share_type['id']}
556 orig_share_group = fake_share_group(
557 'fakeorigid', user_id=self.context.user_id,
558 project_id=self.context.project_id,
559 share_types=[fake_share_type_mapping],
560 status=constants.STATUS_AVAILABLE,
561 share_network_id='fake_network_id',
562 share_server_id='fake_server_id')
563 share_group = fake_share_group(
564 'fakeid', user_id=self.context.user_id,
565 project_id=self.context.project_id,
566 share_types=[fake_share_type_mapping],
567 status=constants.STATUS_CREATING,
568 share_network_id='fake_network_id',
569 share_server_id='fake_server_id')
570 expected_values = share_group.copy()
571 share_network = {
572 'id': 'fakeid',
573 'status': constants.STATUS_NETWORK_ACTIVE
574 }
575 for name in ('id', 'created_at', 'fake_network_id',
576 'fake_share_server_id'):
577 expected_values.pop(name, None)
578 expected_values['source_share_group_snapshot_id'] = snap['id']
579 expected_values['share_types'] = [self.fake_share_type['id']]
580 expected_values['share_network_id'] = 'fake_network_id'
581 expected_values['share_server_id'] = 'fake_server_id'
583 self.mock_object(
584 db_driver, 'share_group_snapshot_get',
585 mock.Mock(return_value=snap))
586 self.mock_object(
587 db_driver, 'share_group_get',
588 mock.Mock(return_value=orig_share_group))
589 self.mock_object(
590 db_driver, 'share_group_create',
591 mock.Mock(return_value=share_group))
592 self.mock_object(
593 db_driver, 'share_get',
594 mock.Mock(return_value=stubs.stub_share('fakeshare')))
595 self.mock_object(
596 share_types, 'get_share_type',
597 mock.Mock(return_value={"id": self.fake_share_type['id']}))
598 self.mock_object(db_driver, 'share_network_get',
599 mock.Mock(return_value=share_network))
600 self.mock_object(
601 db_driver, 'share_instance_get', mock.Mock(return_value=share))
602 self.mock_object(
603 db_driver, 'share_group_snapshot_members_get_all',
604 mock.Mock(return_value=[member]))
605 self.mock_object(self.share_api, 'create')
607 self.api.create(
608 self.context, source_share_group_snapshot_id=snap['id'])
610 db_driver.share_group_create.assert_called_once_with(
611 self.context, expected_values)
612 self.assertTrue(self.share_api.create.called)
613 self.share_rpcapi.create_share_group.assert_called_once_with(
614 self.context, share_group, orig_share_group['host'])
615 share_group_api.QUOTAS.reserve.assert_called_once_with(
616 self.context, share_groups=1)
617 share_group_api.QUOTAS.commit.assert_called_once_with(
618 self.context, share_group_api.QUOTAS.reserve.return_value)
619 share_group_api.QUOTAS.rollback.assert_not_called()
621 def test_create_with_source_sg_snapshot_id_with_members_error(self):
622 snap = fake_share_group_snapshot(
623 "fake_source_share_group_snapshot_id",
624 status=constants.STATUS_AVAILABLE)
625 member = stubs.stub_share_group_snapshot_member('fake_member_id')
626 member_2 = stubs.stub_share_group_snapshot_member('fake_member2_id')
627 share = stubs.stub_share('fakeshareid')
628 fake_share_type_mapping = {'share_type_id': self.fake_share_type['id']}
629 orig_share_group = fake_share_group(
630 'fakeorigid',
631 user_id=self.context.user_id,
632 project_id=self.context.project_id,
633 share_types=[fake_share_type_mapping],
634 status=constants.STATUS_AVAILABLE,
635 share_network_id='fake_network_id',
636 share_server_id='fake_server_id')
637 share_group = fake_share_group(
638 'fakeid',
639 user_id=self.context.user_id,
640 project_id=self.context.project_id,
641 share_types=[fake_share_type_mapping],
642 status=constants.STATUS_CREATING,
643 share_network_id='fake_network_id',
644 share_server_id='fake_server_id')
645 share_network = {
646 'id': 'fakeid',
647 'status': constants.STATUS_NETWORK_ACTIVE
648 }
649 expected_values = share_group.copy()
650 for name in ('id', 'created_at', 'share_network_id',
651 'share_server_id'):
652 expected_values.pop(name, None)
653 expected_values['source_share_group_snapshot_id'] = snap['id']
654 expected_values['share_types'] = [self.fake_share_type['id']]
655 expected_values['share_network_id'] = 'fake_network_id'
656 expected_values['share_server_id'] = 'fake_server_id'
658 self.mock_object(db_driver, 'share_group_snapshot_get',
659 mock.Mock(return_value=snap))
660 self.mock_object(db_driver, 'share_group_get',
661 mock.Mock(return_value=orig_share_group))
662 self.mock_object(db_driver, 'share_network_get',
663 mock.Mock(return_value=share_network))
664 self.mock_object(db_driver, 'share_instance_get',
665 mock.Mock(return_value=share))
666 self.mock_object(db_driver, 'share_group_create',
667 mock.Mock(return_value=share_group))
668 self.mock_object(db_driver, 'share_get',
669 mock.Mock(return_value=stubs.stub_share('fakeshare')))
670 self.mock_object(share_types, 'get_share_type',
671 mock.Mock(return_value={
672 "id": self.fake_share_type['id']}))
673 self.mock_object(db_driver, 'share_group_snapshot_members_get_all',
674 mock.Mock(return_value=[member, member_2]))
675 self.mock_object(self.share_api, 'create',
676 mock.Mock(side_effect=[None, exception.Error]))
677 self.mock_object(db_driver, 'share_group_destroy')
679 self.assertRaises(exception.Error, self.api.create, self.context,
680 source_share_group_snapshot_id=snap['id'])
682 db_driver.share_group_create.assert_called_once_with(
683 self.context, expected_values)
684 self.assertEqual(2, self.share_api.create.call_count)
685 self.assertEqual(1, db_driver.share_group_destroy.call_count)
687 share_group_api.QUOTAS.reserve.assert_called_once_with(
688 self.context, share_groups=1)
689 share_group_api.QUOTAS.commit.assert_not_called()
690 share_group_api.QUOTAS.rollback.assert_called_once_with(
691 self.context, share_group_api.QUOTAS.reserve.return_value)
693 def test_create_with_source_sg_snapshot_id_error_snapshot_status(self):
694 snap = fake_share_group_snapshot(
695 "fake_source_share_group_snapshot_id",
696 status=constants.STATUS_ERROR)
697 self.mock_object(
698 db_driver, 'share_group_snapshot_get',
699 mock.Mock(return_value=snap))
701 self.assertRaises(
702 exception.InvalidShareGroupSnapshot,
703 self.api.create,
704 self.context, source_share_group_snapshot_id=snap['id'])
706 share_group_api.QUOTAS.reserve.assert_not_called()
707 share_group_api.QUOTAS.commit.assert_not_called()
708 share_group_api.QUOTAS.rollback.assert_not_called()
710 def test_create_with_source_sg_snapshot_id_snap_not_found(self):
711 snap = fake_share_group_snapshot(
712 "fake_source_share_group_snapshot_id",
713 status=constants.STATUS_ERROR)
714 self.mock_object(
715 db_driver, 'share_group_snapshot_get',
716 mock.Mock(side_effect=exception.ShareGroupSnapshotNotFound(
717 share_group_snapshot_id='fake_source_sg_snapshot_id')))
719 self.assertRaises(
720 exception.ShareGroupSnapshotNotFound,
721 self.api.create,
722 self.context, source_share_group_snapshot_id=snap['id'])
724 share_group_api.QUOTAS.reserve.assert_not_called()
725 share_group_api.QUOTAS.commit.assert_not_called()
726 share_group_api.QUOTAS.rollback.assert_not_called()
728 def test_create_with_multiple_fields(self):
729 fake_desc = 'fake_desc'
730 fake_name = 'fake_name'
731 share_group = fake_share_group(
732 'fakeid', user_id=self.context.user_id,
733 project_id=self.context.project_id,
734 status=constants.STATUS_CREATING)
735 expected_values = share_group.copy()
736 for name in ('id', 'host', 'created_at'):
737 expected_values.pop(name, None)
738 expected_values['name'] = fake_name
739 expected_values['description'] = fake_desc
740 self.mock_object(db_driver, 'share_group_create',
741 mock.Mock(return_value=share_group))
743 self.api.create(self.context, name=fake_name,
744 description=fake_desc)
746 db_driver.share_group_create.assert_called_once_with(
747 self.context, expected_values)
748 share_group_api.QUOTAS.reserve.assert_called_once_with(
749 self.context, share_groups=1)
750 share_group_api.QUOTAS.commit.assert_called_once_with(
751 self.context, share_group_api.QUOTAS.reserve.return_value)
752 share_group_api.QUOTAS.rollback.assert_not_called()
754 def test_create_with_error_on_creation(self):
755 share_group = fake_share_group(
756 'fakeid', user_id=self.context.user_id,
757 project_id=self.context.project_id,
758 status=constants.STATUS_CREATING)
759 expected_values = share_group.copy()
760 for name in ('id', 'host', 'created_at'):
761 expected_values.pop(name, None)
762 self.mock_object(db_driver, 'share_group_create',
763 mock.Mock(side_effect=exception.Error))
765 self.assertRaises(exception.Error, self.api.create, self.context)
767 db_driver.share_group_create.assert_called_once_with(
768 self.context, expected_values)
769 share_group_api.QUOTAS.reserve.assert_called_once_with(
770 self.context, share_groups=1)
771 share_group_api.QUOTAS.commit.assert_not_called()
772 share_group_api.QUOTAS.rollback.assert_called_once_with(
773 self.context, share_group_api.QUOTAS.reserve.return_value)
775 def test_delete_creating_no_host(self):
776 share_group = fake_share_group(
777 'fakeid', user_id=self.user_id + '_different_user',
778 project_id=self.project_id + '_in_different_project',
779 status=constants.STATUS_CREATING)
780 self.mock_object(db_driver, 'share_group_destroy')
782 self.api.delete(self.context, share_group)
784 db_driver.share_group_destroy.assert_called_once_with(
785 mock.ANY, share_group['id'])
786 share_group_api.QUOTAS.reserve.assert_not_called()
787 share_group_api.QUOTAS.commit.assert_not_called()
788 share_group_api.QUOTAS.rollback.assert_not_called()
790 def test_delete_creating_with_host(self):
791 share_group = fake_share_group(
792 'fakeid', user_id=self.context.user_id,
793 project_id=self.context.project_id,
794 status=constants.STATUS_CREATING, host="fake_host")
796 self.assertRaises(
797 exception.InvalidShareGroup,
798 self.api.delete, self.context, share_group)
800 def test_delete_available(self):
801 share_group = fake_share_group(
802 'fakeid', user_id=self.user_id + '_different_user',
803 project_id=self.project_id + '_in_different_project',
804 status=constants.STATUS_AVAILABLE, host="fake_host")
805 deleted_share_group = copy.deepcopy(share_group)
806 deleted_share_group['status'] = constants.STATUS_DELETING
807 self.mock_object(db_driver, 'share_group_update',
808 mock.Mock(return_value=deleted_share_group))
809 self.mock_object(db_driver, 'count_shares_in_share_group',
810 mock.Mock(return_value=0))
812 self.api.delete(self.context, share_group)
814 db_driver.share_group_update.assert_called_once_with(
815 self.context, share_group['id'],
816 {'status': constants.STATUS_DELETING})
817 self.share_rpcapi.delete_share_group.assert_called_once_with(
818 self.context, deleted_share_group)
819 share_group_api.QUOTAS.reserve.assert_called_once_with(
820 self.context, share_groups=-1,
821 project_id=share_group['project_id'],
822 user_id=share_group['user_id'])
823 share_group_api.QUOTAS.commit.assert_called_once_with(
824 self.context,
825 share_group_api.QUOTAS.reserve.return_value,
826 project_id=share_group['project_id'],
827 user_id=share_group['user_id'])
828 share_group_api.QUOTAS.rollback.assert_not_called()
830 def test_delete_error_with_host(self):
831 share_group = fake_share_group(
832 'fakeid', user_id=self.context.user_id,
833 project_id=self.context.project_id,
834 status=constants.STATUS_ERROR, host="fake_host")
835 deleted_share_group = copy.deepcopy(share_group)
836 deleted_share_group['status'] = constants.STATUS_DELETING
837 self.mock_object(self.api, 'share_rpcapi')
838 self.mock_object(db_driver, 'share_group_update',
839 mock.Mock(return_value=deleted_share_group))
840 self.mock_object(db_driver, 'count_shares_in_share_group',
841 mock.Mock(return_value=0))
843 self.api.delete(self.context, share_group)
845 db_driver.share_group_update.assert_called_once_with(
846 self.context, share_group['id'],
847 {'status': constants.STATUS_DELETING})
848 self.api.share_rpcapi.delete_share_group.assert_called_once_with(
849 self.context, deleted_share_group)
850 share_group_api.QUOTAS.reserve.assert_called_once_with(
851 self.context, share_groups=-1,
852 project_id=share_group['project_id'],
853 user_id=share_group['user_id'])
854 share_group_api.QUOTAS.commit.assert_called_once_with(
855 self.context,
856 share_group_api.QUOTAS.reserve.return_value,
857 project_id=share_group['project_id'],
858 user_id=share_group['user_id'])
859 share_group_api.QUOTAS.rollback.assert_not_called()
861 def test_delete_error_without_host(self):
862 share_group = fake_share_group(
863 'fakeid', user_id=self.context.user_id,
864 project_id=self.context.project_id,
865 status=constants.STATUS_ERROR)
866 self.mock_object(db_driver, 'share_group_destroy')
868 self.api.delete(self.context, share_group)
870 db_driver.share_group_destroy.assert_called_once_with(
871 mock.ANY, share_group['id'])
872 share_group_api.QUOTAS.reserve.assert_not_called()
873 share_group_api.QUOTAS.commit.assert_not_called()
874 share_group_api.QUOTAS.rollback.assert_not_called()
876 def test_delete_with_shares(self):
877 share_group = fake_share_group(
878 'fakeid', user_id=self.context.user_id,
879 project_id=self.context.project_id,
880 status=constants.STATUS_AVAILABLE, host="fake_host")
881 self.mock_object(
882 db_driver, 'count_shares_in_share_group',
883 mock.Mock(return_value=1))
885 self.assertRaises(
886 exception.InvalidShareGroup,
887 self.api.delete, self.context, share_group)
889 share_group_api.QUOTAS.reserve.assert_not_called()
890 share_group_api.QUOTAS.commit.assert_not_called()
891 share_group_api.QUOTAS.rollback.assert_not_called()
893 def test_delete_with_share_group_snapshots(self):
894 share_group = fake_share_group(
895 'fakeid', user_id=self.context.user_id,
896 project_id=self.context.project_id,
897 status=constants.STATUS_AVAILABLE, host="fake_host")
898 self.mock_object(
899 db_driver, 'count_share_group_snapshots_in_share_group',
900 mock.Mock(return_value=1))
902 self.assertRaises(
903 exception.InvalidShareGroup,
904 self.api.delete, self.context, share_group)
906 share_group_api.QUOTAS.reserve.assert_not_called()
907 share_group_api.QUOTAS.commit.assert_not_called()
908 share_group_api.QUOTAS.rollback.assert_not_called()
910 @ddt.data({}, {"name": "fake_name"}, {"description": "fake_description"})
911 def test_update(self, expected_values):
912 share_group = fake_share_group(
913 'fakeid',
914 user_id=self.context.user_id,
915 project_id=self.context.project_id,
916 status=constants.STATUS_CREATING)
917 self.mock_object(
918 db_driver, 'share_group_update',
919 mock.Mock(return_value=share_group))
921 self.api.update(self.context, share_group, expected_values)
923 db_driver.share_group_update.assert_called_once_with(
924 self.context, share_group['id'], expected_values)
926 def test_get(self):
927 expected = fake_share_group(
928 'fakeid', user_id=self.context.user_id,
929 project_id=self.context.project_id,
930 status=constants.STATUS_CREATING)
931 self.mock_object(
932 db_driver, 'share_group_get', mock.Mock(return_value=expected))
934 actual = self.api.get(self.context, expected['id'])
936 self.assertEqual(expected, actual)
938 def test_get_all_no_groups(self):
939 self.mock_object(
940 db_driver, 'share_group_get_all', mock.Mock(return_value=[]))
942 actual_group = self.api.get_all(self.context)
944 self.assertEqual([], actual_group)
946 def test_get_all(self):
947 expected = [fake_share_group(
948 'fakeid', user_id=self.context.user_id,
949 project_id=self.context.project_id,
950 status=constants.STATUS_CREATING)]
951 self.mock_object(
952 db_driver, 'share_group_get_all_by_project',
953 mock.Mock(return_value=expected))
955 actual = self.api.get_all(self.context, detailed=True)
957 self.assertEqual(expected, actual)
959 def test_get_all_all_tenants_not_admin(self):
960 cxt = context.RequestContext(
961 user_id=None, project_id=None, is_admin=False)
962 expected = [fake_share_group(
963 'fakeid', user_id=cxt.user_id, project_id=cxt.project_id,
964 status=constants.STATUS_CREATING)]
965 self.mock_object(db_driver, 'share_group_get_all_by_project',
966 mock.Mock(return_value=expected))
968 actual = self.api.get_all(cxt, search_opts={'all_tenants': True})
970 self.assertEqual(expected, actual)
972 def test_get_all_all_tenants_as_admin(self):
973 expected = [fake_share_group(
974 'fakeid', user_id=self.context.user_id,
975 project_id=self.context.project_id,
976 status=constants.STATUS_CREATING)]
977 self.mock_object(db_driver, 'share_group_get_all',
978 mock.Mock(return_value=expected))
980 actual = self.api.get_all(
981 self.context, search_opts={'all_tenants': True})
983 self.assertEqual(expected, actual)
984 db_driver.share_group_get_all.assert_called_once_with(
985 self.context, detailed=True, filters={},
986 sort_dir=None, sort_key=None)
988 def test_create_share_group_snapshot_minimal_request_no_members(self):
989 share_group = fake_share_group(
990 'fake_group_id', user_id=self.context.user_id,
991 project_id=self.context.project_id,
992 status=constants.STATUS_AVAILABLE)
993 snap = fake_share_group_snapshot(
994 'fakeid', user_id=self.context.user_id,
995 project_id=self.context.project_id,
996 share_group_id=share_group['id'],
997 status=constants.STATUS_CREATING)
998 expected_values = snap.copy()
999 for name in ('id', 'created_at'):
1000 expected_values.pop(name, None)
1001 self.mock_object(
1002 db_driver, 'share_group_get', mock.Mock(return_value=share_group))
1003 self.mock_object(
1004 db_driver, 'share_group_snapshot_create',
1005 mock.Mock(return_value=snap))
1006 self.mock_object(
1007 db_driver, 'share_get_all_by_share_group_id',
1008 mock.Mock(return_value=[]))
1010 self.api.create_share_group_snapshot(
1011 self.context, share_group_id=share_group['id'])
1013 db_driver.share_group_get.assert_called_once_with(
1014 self.context, share_group['id'])
1015 db_driver.share_group_snapshot_create.assert_called_once_with(
1016 self.context, expected_values)
1017 self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
1018 self.context, snap, share_group['host'])
1019 share_group_api.QUOTAS.reserve.assert_called_once_with(
1020 self.context, share_group_snapshots=1)
1021 share_group_api.QUOTAS.commit.assert_called_once_with(
1022 self.context, share_group_api.QUOTAS.reserve.return_value)
1023 share_group_api.QUOTAS.rollback.assert_not_called()
1025 def test_create_sg_snapshot_minimal_request_no_members_with_name(self):
1026 fake_name = 'fake_name'
1027 share_group = fake_share_group(
1028 'fake_group_id', user_id=self.context.user_id,
1029 project_id=self.context.project_id,
1030 status=constants.STATUS_AVAILABLE)
1031 snap = fake_share_group_snapshot(
1032 'fakeid', user_id=self.context.user_id,
1033 project_id=self.context.project_id,
1034 share_group_id=share_group['id'], name=fake_name,
1035 status=constants.STATUS_CREATING)
1036 expected_values = snap.copy()
1037 for name in ('id', 'created_at'):
1038 expected_values.pop(name, None)
1039 self.mock_object(
1040 db_driver, 'share_group_get', mock.Mock(return_value=share_group))
1041 self.mock_object(
1042 db_driver, 'share_group_snapshot_create',
1043 mock.Mock(return_value=snap))
1044 self.mock_object(
1045 db_driver, 'share_get_all_by_share_group_id',
1046 mock.Mock(return_value=[]))
1048 self.api.create_share_group_snapshot(
1049 self.context, share_group_id=share_group['id'], name=fake_name)
1051 db_driver.share_group_get.assert_called_once_with(
1052 self.context, share_group['id'])
1053 db_driver.share_group_snapshot_create.assert_called_once_with(
1054 self.context, expected_values)
1055 self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
1056 self.context, snap, share_group['host'])
1057 share_group_api.QUOTAS.reserve.assert_called_once_with(
1058 self.context, share_group_snapshots=1)
1059 share_group_api.QUOTAS.commit.assert_called_once_with(
1060 self.context, share_group_api.QUOTAS.reserve.return_value)
1061 share_group_api.QUOTAS.rollback.assert_not_called()
1063 def test_create_group_snapshot_minimal_request_no_members_with_desc(self):
1064 fake_description = 'fake_description'
1065 share_group = fake_share_group(
1066 'fake_group_id', user_id=self.context.user_id,
1067 project_id=self.context.project_id,
1068 status=constants.STATUS_AVAILABLE)
1069 snap = fake_share_group_snapshot(
1070 'fakeid', user_id=self.context.user_id,
1071 project_id=self.context.project_id,
1072 share_group_id=share_group['id'],
1073 description=fake_description,
1074 status=constants.STATUS_CREATING)
1075 expected_values = snap.copy()
1076 for name in ('id', 'created_at'):
1077 expected_values.pop(name, None)
1078 self.mock_object(
1079 db_driver, 'share_group_get', mock.Mock(return_value=share_group))
1080 self.mock_object(
1081 db_driver, 'share_group_snapshot_create',
1082 mock.Mock(return_value=snap))
1083 self.mock_object(
1084 db_driver, 'share_get_all_by_share_group_id',
1085 mock.Mock(return_value=[]))
1087 self.api.create_share_group_snapshot(
1088 self.context, share_group_id=share_group['id'],
1089 description=fake_description)
1091 db_driver.share_group_get.assert_called_once_with(
1092 self.context, share_group['id'])
1093 db_driver.share_group_snapshot_create.assert_called_once_with(
1094 self.context, expected_values)
1095 self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
1096 self.context, snap, share_group['host'])
1097 share_group_api.QUOTAS.reserve.assert_called_once_with(
1098 self.context, share_group_snapshots=1)
1099 share_group_api.QUOTAS.commit.assert_called_once_with(
1100 self.context, share_group_api.QUOTAS.reserve.return_value)
1101 share_group_api.QUOTAS.rollback.assert_not_called()
1103 def test_create_share_group_snapshot_group_does_not_exist(self):
1104 share_group = fake_share_group(
1105 'fake_group_id', user_id=self.context.user_id,
1106 project_id=self.context.project_id,
1107 status=constants.STATUS_CREATING)
1108 snap = fake_share_group_snapshot(
1109 'fakeid', user_id=self.context.user_id,
1110 project_id=self.context.project_id,
1111 share_group_id=share_group['id'],
1112 status=constants.STATUS_CREATING)
1113 expected_values = snap.copy()
1114 for name in ('id', 'created_at'):
1115 expected_values.pop(name, None)
1116 self.mock_object(
1117 db_driver, 'share_group_get', mock.Mock(return_value=share_group))
1118 self.mock_object(
1119 db_driver, 'share_group_snapshot_create',
1120 mock.Mock(return_value=snap))
1121 self.mock_object(
1122 db_driver, 'share_get_all_by_share_group_id',
1123 mock.Mock(return_value=[]))
1125 self.assertRaises(
1126 exception.InvalidShareGroup,
1127 self.api.create_share_group_snapshot,
1128 self.context, share_group_id=share_group['id'])
1130 db_driver.share_group_get.assert_called_once_with(
1131 self.context, share_group['id'])
1132 share_group_api.QUOTAS.reserve.assert_not_called()
1133 share_group_api.QUOTAS.commit.assert_not_called()
1134 share_group_api.QUOTAS.rollback.assert_not_called()
1136 def test_create_share_group_snapshot_failure_reserving_quota(self):
1137 overs = ["share_group_snapshots"]
1138 usages = {"share_group_snapshots": {
1139 "reserved": 1,
1140 "in_use": 3,
1141 "limit": 4,
1142 }}
1143 quotas = {"share_group_snapshots": 5}
1144 share_group = fake_share_group(
1145 "fake_group_id", user_id=self.context.user_id,
1146 project_id=self.context.project_id,
1147 status=constants.STATUS_AVAILABLE)
1148 self.mock_object(
1149 db_driver, "share_group_get", mock.Mock(return_value=share_group))
1150 self.mock_object(
1151 db_driver, "share_get_all_by_share_group_id",
1152 mock.Mock(return_value=[]))
1153 share_group_api.QUOTAS.reserve.side_effect = exception.OverQuota(
1154 overs=overs,
1155 usages=usages,
1156 quotas=quotas,
1157 )
1158 self.mock_object(share_group_api.LOG, "warning")
1160 self.assertRaises(
1161 exception.ShareGroupSnapshotsLimitExceeded,
1162 self.api.create_share_group_snapshot,
1163 self.context, share_group_id=share_group["id"])
1165 db_driver.share_group_get.assert_called_once_with(
1166 self.context, share_group["id"])
1167 share_group_api.QUOTAS.reserve.assert_called_once_with(
1168 self.context, share_group_snapshots=1)
1169 share_group_api.QUOTAS.commit.assert_not_called()
1170 share_group_api.QUOTAS.rollback.assert_not_called()
1171 share_group_api.LOG.warning.assert_called_once_with(mock.ANY, mock.ANY)
1173 def test_create_share_group_snapshot_group_in_creating(self):
1174 self.mock_object(
1175 db_driver, 'share_group_get',
1176 mock.Mock(side_effect=exception.ShareGroupNotFound(
1177 share_group_id='fake_id')))
1179 self.assertRaises(
1180 exception.ShareGroupNotFound,
1181 self.api.create_share_group_snapshot,
1182 self.context, share_group_id="fake_id")
1184 db_driver.share_group_get.assert_called_once_with(
1185 self.context, "fake_id")
1186 share_group_api.QUOTAS.reserve.assert_not_called()
1187 share_group_api.QUOTAS.commit.assert_not_called()
1188 share_group_api.QUOTAS.rollback.assert_not_called()
1190 def test_create_share_group_snapshot_with_member(self):
1191 share_group = fake_share_group(
1192 'fake_group_id', user_id=self.context.user_id,
1193 project_id=self.context.project_id,
1194 status=constants.STATUS_AVAILABLE)
1195 snap = fake_share_group_snapshot(
1196 'fakeid', user_id=self.context.user_id,
1197 project_id=self.context.project_id,
1198 share_group_id=share_group['id'],
1199 status=constants.STATUS_CREATING)
1200 share = stubs.stub_share(
1201 'fake_share_id', status=constants.STATUS_AVAILABLE)
1202 expected_values = snap.copy()
1203 for name in ('id', 'created_at'):
1204 expected_values.pop(name, None)
1205 expected_member_values = {
1206 'share_group_snapshot_id': snap['id'],
1207 'user_id': self.context.user_id,
1208 'project_id': self.context.project_id,
1209 'status': constants.STATUS_CREATING,
1210 'size': share['size'],
1211 'share_proto': share['share_proto'],
1212 'share_instance_id': mock.ANY,
1213 }
1214 self.mock_object(
1215 db_driver, 'share_group_get',
1216 mock.Mock(return_value=share_group))
1217 self.mock_object(
1218 db_driver, 'share_group_snapshot_create',
1219 mock.Mock(return_value=snap))
1220 self.mock_object(db_driver, 'share_group_snapshot_member_create')
1221 self.mock_object(
1222 db_driver, 'share_get_all_by_share_group_id',
1223 mock.Mock(return_value=[share]))
1225 self.api.create_share_group_snapshot(
1226 self.context, share_group_id=share_group['id'])
1228 db_driver.share_group_get.assert_called_once_with(
1229 self.context, share_group['id'])
1230 db_driver.share_group_snapshot_create.assert_called_once_with(
1231 self.context, expected_values)
1232 db_driver.share_group_snapshot_member_create.assert_called_once_with(
1233 self.context, expected_member_values)
1234 self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
1235 self.context, snap, share_group['host'])
1236 share_group_api.QUOTAS.reserve.assert_called_once_with(
1237 self.context, share_group_snapshots=1)
1238 share_group_api.QUOTAS.commit.assert_called_once_with(
1239 self.context, share_group_api.QUOTAS.reserve.return_value)
1240 share_group_api.QUOTAS.rollback.assert_not_called()
1242 def test_create_share_group_snapshot_with_member_share_in_creating(self):
1243 share_group = fake_share_group(
1244 'fake_group_id', user_id=self.context.user_id,
1245 project_id=self.context.project_id,
1246 status=constants.STATUS_AVAILABLE)
1247 share = stubs.stub_share(
1248 'fake_share_id', status=constants.STATUS_CREATING)
1249 self.mock_object(
1250 db_driver, 'share_group_get', mock.Mock(return_value=share_group))
1251 self.mock_object(
1252 db_driver, 'share_get_all_by_share_group_id',
1253 mock.Mock(return_value=[share]))
1255 self.assertRaises(
1256 exception.InvalidShareGroup,
1257 self.api.create_share_group_snapshot,
1258 self.context, share_group_id=share_group['id'])
1260 db_driver.share_group_get.assert_called_once_with(
1261 self.context, share_group['id'])
1262 share_group_api.QUOTAS.reserve.assert_not_called()
1263 share_group_api.QUOTAS.commit.assert_not_called()
1264 share_group_api.QUOTAS.rollback.assert_not_called()
1266 def test_create_share_group_snapshot_with_two_members(self):
1267 share_group = fake_share_group(
1268 'fake_group_id', user_id=self.context.user_id,
1269 project_id=self.context.project_id,
1270 status=constants.STATUS_AVAILABLE)
1271 snap = fake_share_group_snapshot(
1272 'fakeid', user_id=self.context.user_id,
1273 project_id=self.context.project_id,
1274 share_group_id=share_group['id'],
1275 status=constants.STATUS_CREATING)
1276 share = stubs.stub_share(
1277 'fake_share_id', status=constants.STATUS_AVAILABLE)
1278 share_2 = stubs.stub_share(
1279 'fake_share2_id', status=constants.STATUS_AVAILABLE)
1280 expected_values = snap.copy()
1281 for name in ('id', 'created_at'):
1282 expected_values.pop(name, None)
1283 expected_member_1_values = {
1284 'share_group_snapshot_id': snap['id'],
1285 'user_id': self.context.user_id,
1286 'project_id': self.context.project_id,
1287 'status': constants.STATUS_CREATING,
1288 'size': share['size'],
1289 'share_proto': share['share_proto'],
1290 'share_instance_id': mock.ANY,
1291 }
1292 expected_member_2_values = {
1293 'share_group_snapshot_id': snap['id'],
1294 'user_id': self.context.user_id,
1295 'project_id': self.context.project_id,
1296 'status': constants.STATUS_CREATING,
1297 'size': share_2['size'],
1298 'share_proto': share_2['share_proto'],
1299 'share_instance_id': mock.ANY,
1300 }
1301 self.mock_object(
1302 db_driver, 'share_group_get',
1303 mock.Mock(return_value=share_group))
1304 self.mock_object(
1305 db_driver, 'share_group_snapshot_create',
1306 mock.Mock(return_value=snap))
1307 self.mock_object(
1308 db_driver, 'share_get_all_by_share_group_id',
1309 mock.Mock(return_value=[share, share_2]))
1310 self.mock_object(db_driver, 'share_group_snapshot_member_create')
1312 self.api.create_share_group_snapshot(
1313 self.context, share_group_id=share_group['id'])
1315 db_driver.share_group_get.assert_called_once_with(
1316 self.context, share_group['id'])
1317 db_driver.share_group_snapshot_create.assert_called_once_with(
1318 self.context, expected_values)
1319 db_driver.share_group_snapshot_member_create.assert_any_call(
1320 self.context, expected_member_1_values)
1321 db_driver.share_group_snapshot_member_create.assert_any_call(
1322 self.context, expected_member_2_values)
1323 self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
1324 self.context, snap, share_group['host'])
1325 share_group_api.QUOTAS.reserve.assert_called_once_with(
1326 self.context, share_group_snapshots=1)
1327 share_group_api.QUOTAS.commit.assert_called_once_with(
1328 self.context, share_group_api.QUOTAS.reserve.return_value)
1329 share_group_api.QUOTAS.rollback.assert_not_called()
1331 def test_create_share_group_snapshot_error_creating_member(self):
1332 share_group = fake_share_group(
1333 'fake_group_id', user_id=self.context.user_id,
1334 project_id=self.context.project_id,
1335 status=constants.STATUS_AVAILABLE)
1336 snap = fake_share_group_snapshot(
1337 'fakeid', user_id=self.context.user_id,
1338 project_id=self.context.project_id,
1339 share_group_id=share_group['id'],
1340 status=constants.STATUS_CREATING)
1341 share = stubs.stub_share(
1342 'fake_share_id', status=constants.STATUS_AVAILABLE)
1343 expected_values = snap.copy()
1344 for name in ('id', 'created_at'):
1345 expected_values.pop(name, None)
1346 expected_member_values = {
1347 'share_group_snapshot_id': snap['id'],
1348 'user_id': self.context.user_id,
1349 'project_id': self.context.project_id,
1350 'status': constants.STATUS_CREATING,
1351 'size': share['size'],
1352 'share_proto': share['share_proto'],
1353 'share_instance_id': mock.ANY,
1354 }
1355 self.mock_object(
1356 db_driver, 'share_group_get',
1357 mock.Mock(return_value=share_group))
1358 self.mock_object(
1359 db_driver, 'share_group_snapshot_create',
1360 mock.Mock(return_value=snap))
1361 self.mock_object(db_driver, 'share_group_snapshot_destroy')
1362 self.mock_object(
1363 db_driver, 'share_group_snapshot_member_create',
1364 mock.Mock(side_effect=exception.Error))
1365 self.mock_object(
1366 db_driver, 'share_get_all_by_share_group_id',
1367 mock.Mock(return_value=[share]))
1369 self.assertRaises(
1370 exception.Error,
1371 self.api.create_share_group_snapshot,
1372 self.context, share_group_id=share_group['id'])
1374 db_driver.share_group_get.assert_called_once_with(
1375 self.context, share_group['id'])
1376 db_driver.share_group_snapshot_create.assert_called_once_with(
1377 self.context, expected_values)
1378 db_driver.share_group_snapshot_member_create.assert_called_once_with(
1379 self.context, expected_member_values)
1380 db_driver.share_group_snapshot_destroy.assert_called_once_with(
1381 self.context, snap['id'])
1382 share_group_api.QUOTAS.reserve.assert_called_once_with(
1383 self.context, share_group_snapshots=1)
1384 share_group_api.QUOTAS.commit.assert_not_called()
1385 share_group_api.QUOTAS.rollback.assert_called_once_with(
1386 self.context, share_group_api.QUOTAS.reserve.return_value)
1388 def test_delete_share_group_snapshot(self):
1389 share_group = fake_share_group('fake_id', host="fake_host")
1390 sg_snap = fake_share_group_snapshot(
1391 'fake_groupsnap_id', share_group_id='fake_id',
1392 status=constants.STATUS_AVAILABLE)
1393 self.mock_object(db_driver, 'share_group_get',
1394 mock.Mock(return_value=share_group))
1395 self.mock_object(db_driver, 'share_group_snapshot_update')
1397 self.api.delete_share_group_snapshot(self.context, sg_snap)
1399 db_driver.share_group_get.assert_called_once_with(
1400 self.context, "fake_id")
1401 db_driver.share_group_snapshot_update.assert_called_once_with(
1402 self.context, sg_snap['id'], {'status': constants.STATUS_DELETING})
1403 self.share_rpcapi.delete_share_group_snapshot.assert_called_once_with(
1404 self.context, sg_snap, share_group['host'])
1405 share_group_api.QUOTAS.reserve.assert_called_once_with(
1406 self.context, share_group_snapshots=-1,
1407 project_id=share_group['project_id'],
1408 user_id=share_group['user_id'])
1409 share_group_api.QUOTAS.commit.assert_called_once_with(
1410 self.context, share_group_api.QUOTAS.reserve.return_value,
1411 project_id=share_group['project_id'],
1412 user_id=share_group['user_id'])
1413 share_group_api.QUOTAS.rollback.assert_not_called()
1415 def test_delete_share_group_snapshot_fail_on_quota_reserve(self):
1416 share_group = fake_share_group('fake_id', host="fake_host")
1417 sg_snap = fake_share_group_snapshot(
1418 'fake_groupsnap_id', share_group_id='fake_id',
1419 status=constants.STATUS_AVAILABLE)
1420 self.mock_object(db_driver, 'share_group_get',
1421 mock.Mock(return_value=share_group))
1422 self.mock_object(db_driver, 'share_group_snapshot_update')
1423 share_group_api.QUOTAS.reserve.side_effect = exception.OverQuota(
1424 'Failure')
1425 self.mock_object(share_group_api.LOG, 'exception')
1427 self.api.delete_share_group_snapshot(self.context, sg_snap)
1429 db_driver.share_group_get.assert_called_once_with(
1430 self.context, "fake_id")
1431 db_driver.share_group_snapshot_update.assert_called_once_with(
1432 self.context, sg_snap['id'], {'status': constants.STATUS_DELETING})
1433 self.share_rpcapi.delete_share_group_snapshot.assert_called_once_with(
1434 self.context, sg_snap, share_group['host'])
1435 share_group_api.QUOTAS.reserve.assert_called_once_with(
1436 self.context, share_group_snapshots=-1,
1437 project_id=share_group['project_id'],
1438 user_id=share_group['user_id'])
1439 share_group_api.QUOTAS.commit.assert_not_called()
1440 share_group_api.QUOTAS.rollback.assert_not_called()
1441 share_group_api.LOG.exception.assert_called_once_with(
1442 mock.ANY, mock.ANY)
1444 def test_delete_share_group_snapshot_group_does_not_exist(self):
1445 snap = fake_share_group_snapshot(
1446 'fake_groupsnap_id', share_group_id='fake_id')
1447 self.mock_object(
1448 db_driver, 'share_group_get',
1449 mock.Mock(side_effect=exception.ShareGroupNotFound(
1450 share_group_id='fake_id')))
1452 self.assertRaises(
1453 exception.ShareGroupNotFound,
1454 self.api.delete_share_group_snapshot, self.context, snap)
1456 db_driver.share_group_get.assert_called_once_with(
1457 self.context, "fake_id")
1458 share_group_api.QUOTAS.reserve.assert_not_called()
1459 share_group_api.QUOTAS.commit.assert_not_called()
1460 share_group_api.QUOTAS.rollback.assert_not_called()
1462 def test_delete_share_group_snapshot_creating_status(self):
1463 snap = fake_share_group_snapshot(
1464 'fake_groupsnap_id', share_group_id='fake_id',
1465 status=constants.STATUS_CREATING)
1466 self.mock_object(db_driver, 'share_group_get')
1468 self.assertRaises(
1469 exception.InvalidShareGroupSnapshot,
1470 self.api.delete_share_group_snapshot, self.context, snap)
1472 db_driver.share_group_get.assert_called_once_with(
1473 self.context, snap['share_group_id'])
1474 share_group_api.QUOTAS.reserve.assert_not_called()
1475 share_group_api.QUOTAS.commit.assert_not_called()
1476 share_group_api.QUOTAS.rollback.assert_not_called()
1478 @ddt.data({}, {"name": "fake_name"})
1479 def test_update_share_group_snapshot_no_values(self, expected_values):
1480 snap = fake_share_group_snapshot(
1481 'fakeid', user_id=self.context.user_id,
1482 project_id=self.context.project_id,
1483 status=constants.STATUS_CREATING)
1484 self.mock_object(
1485 db_driver, 'share_group_snapshot_update',
1486 mock.Mock(return_value=snap))
1488 self.api.update_share_group_snapshot(
1489 self.context, snap, expected_values)
1491 db_driver.share_group_snapshot_update.assert_called_once_with(
1492 self.context, snap['id'], expected_values)
1494 def test_share_group_snapshot_get(self):
1495 expected = fake_share_group_snapshot(
1496 'fakeid', user_id=self.context.user_id,
1497 project_id=self.context.project_id,
1498 status=constants.STATUS_CREATING)
1499 self.mock_object(
1500 db_driver, 'share_group_snapshot_get',
1501 mock.Mock(return_value=expected))
1503 actual = self.api.get_share_group_snapshot(
1504 self.context, expected['id'])
1506 self.assertEqual(expected, actual)
1508 def test_share_group_snapshot_get_all_no_groups(self):
1509 self.mock_object(
1510 db_driver, 'share_group_snapshot_get_all',
1511 mock.Mock(return_value=[]))
1513 actual = self.api.get_all_share_group_snapshots(self.context)
1515 self.assertEqual([], actual)
1517 def test_share_group_snapshot_get_all(self):
1518 expected = [fake_share_group(
1519 'fakeid', user_id=self.context.user_id,
1520 project_id=self.context.project_id,
1521 status=constants.STATUS_CREATING)]
1522 self.mock_object(
1523 db_driver, 'share_group_snapshot_get_all_by_project',
1524 mock.Mock(return_value=expected))
1526 actual = self.api.get_all_share_group_snapshots(
1527 self.context, detailed=True)
1529 self.assertEqual(expected, actual)
1531 def test_share_group_snapshot_get_all_all_tenants_not_admin(self):
1532 cxt = context.RequestContext(
1533 user_id=None, project_id=None, is_admin=False)
1534 expected = [fake_share_group(
1535 'fakeid', user_id=cxt.user_id, project_id=cxt.project_id,
1536 status=constants.STATUS_CREATING)]
1537 self.mock_object(
1538 db_driver, 'share_group_snapshot_get_all_by_project',
1539 mock.Mock(return_value=expected))
1541 actual = self.api.get_all_share_group_snapshots(
1542 cxt, search_opts={'all_tenants': True})
1544 self.assertEqual(expected, actual)
1546 def test_share_group_snapshot_get_all_all_tenants_as_admin(self):
1547 expected = [fake_share_group(
1548 'fakeid', user_id=self.context.user_id,
1549 project_id=self.context.project_id,
1550 status=constants.STATUS_CREATING)]
1551 self.mock_object(
1552 db_driver, 'share_group_snapshot_get_all',
1553 mock.Mock(return_value=expected))
1555 actual = self.api.get_all_share_group_snapshots(
1556 self.context, search_opts={'all_tenants': True})
1558 self.assertEqual(expected, actual)
1559 db_driver.share_group_snapshot_get_all.assert_called_once_with(
1560 self.context, detailed=True, filters={},
1561 sort_dir=None, sort_key=None)
1563 def test_get_all_share_group_snapshot_members(self):
1564 self.mock_object(
1565 db_driver, 'share_group_snapshot_members_get_all',
1566 mock.Mock(return_value=[]))
1568 self.api.get_all_share_group_snapshot_members(self.context, 'fake_id')
1570 db_driver.share_group_snapshot_members_get_all.assert_called_once_with(
1571 self.context, 'fake_id')