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

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.""" 

16 

17import copy 

18import datetime 

19from unittest import mock 

20 

21import ddt 

22from oslo_config import cfg 

23from oslo_utils import timeutils 

24from webob import exc as webob_exc 

25 

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 

35 

36CONF = cfg.CONF 

37 

38 

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 } 

56 

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' 

60 

61 share_group.update(kwargs) 

62 return share_group 

63 

64 

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 

78 

79 

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) 

95 

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') 

124 

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)) 

135 

136 self.api.create(self.context) 

137 

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() 

145 

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)) 

164 

165 self.api.create(self.context) 

166 

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() 

175 

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') 

189 

190 self.api.create(self.context, name=fake_name) 

191 

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() 

202 

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)) 

215 

216 self.api.create(self.context, description=fake_desc) 

217 

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() 

225 

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 } 

266 

267 kwargs = {} if not with_az else az_kwargs 

268 self.api.create(self.context, share_type_ids=fake_share_type_ids, 

269 **kwargs) 

270 

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() 

286 

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']] 

332 

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() 

339 

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)) 

354 

355 self.assertRaises( 

356 exception.InvalidInput, 

357 self.api.create, 

358 self.context, share_type_ids=[self.fake_share_type['id']]) 

359 

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() 

363 

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") 

374 

375 self.assertRaises( 

376 exception.ShareGroupsLimitExceeded, 

377 self.api.create, self.context) 

378 

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) 

384 

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') 

388 

389 self.assertRaises(exception.InvalidInput, self.api.create, 

390 self.context, share_type_ids=fake_share_types, 

391 share_network_id="fake_share_network") 

392 

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])) 

411 

412 self.assertRaises( 

413 exception.InvalidInput, 

414 self.api.create, 

415 self.context, share_type_ids=fake_share_type_ids) 

416 

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() 

420 

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)) 

431 

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") 

437 

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() 

441 

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') 

455 

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' 

476 

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=[])) 

497 

498 self.api.create( 

499 self.context, source_share_group_snapshot_id=snap['id']) 

500 

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() 

510 

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' 

533 

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)) 

539 

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") 

545 

546 db_driver.share_network_get.assert_called_once_with( 

547 self.context, network_id) 

548 

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' 

582 

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') 

606 

607 self.api.create( 

608 self.context, source_share_group_snapshot_id=snap['id']) 

609 

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() 

620 

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' 

657 

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') 

678 

679 self.assertRaises(exception.Error, self.api.create, self.context, 

680 source_share_group_snapshot_id=snap['id']) 

681 

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) 

686 

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) 

692 

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)) 

700 

701 self.assertRaises( 

702 exception.InvalidShareGroupSnapshot, 

703 self.api.create, 

704 self.context, source_share_group_snapshot_id=snap['id']) 

705 

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() 

709 

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'))) 

718 

719 self.assertRaises( 

720 exception.ShareGroupSnapshotNotFound, 

721 self.api.create, 

722 self.context, source_share_group_snapshot_id=snap['id']) 

723 

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() 

727 

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)) 

742 

743 self.api.create(self.context, name=fake_name, 

744 description=fake_desc) 

745 

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() 

753 

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)) 

764 

765 self.assertRaises(exception.Error, self.api.create, self.context) 

766 

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) 

774 

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') 

781 

782 self.api.delete(self.context, share_group) 

783 

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() 

789 

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") 

795 

796 self.assertRaises( 

797 exception.InvalidShareGroup, 

798 self.api.delete, self.context, share_group) 

799 

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)) 

811 

812 self.api.delete(self.context, share_group) 

813 

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() 

829 

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)) 

842 

843 self.api.delete(self.context, share_group) 

844 

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() 

860 

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') 

867 

868 self.api.delete(self.context, share_group) 

869 

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() 

875 

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)) 

884 

885 self.assertRaises( 

886 exception.InvalidShareGroup, 

887 self.api.delete, self.context, share_group) 

888 

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() 

892 

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)) 

901 

902 self.assertRaises( 

903 exception.InvalidShareGroup, 

904 self.api.delete, self.context, share_group) 

905 

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() 

909 

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)) 

920 

921 self.api.update(self.context, share_group, expected_values) 

922 

923 db_driver.share_group_update.assert_called_once_with( 

924 self.context, share_group['id'], expected_values) 

925 

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)) 

933 

934 actual = self.api.get(self.context, expected['id']) 

935 

936 self.assertEqual(expected, actual) 

937 

938 def test_get_all_no_groups(self): 

939 self.mock_object( 

940 db_driver, 'share_group_get_all', mock.Mock(return_value=[])) 

941 

942 actual_group = self.api.get_all(self.context) 

943 

944 self.assertEqual([], actual_group) 

945 

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)) 

954 

955 actual = self.api.get_all(self.context, detailed=True) 

956 

957 self.assertEqual(expected, actual) 

958 

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)) 

967 

968 actual = self.api.get_all(cxt, search_opts={'all_tenants': True}) 

969 

970 self.assertEqual(expected, actual) 

971 

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)) 

979 

980 actual = self.api.get_all( 

981 self.context, search_opts={'all_tenants': True}) 

982 

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) 

987 

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=[])) 

1009 

1010 self.api.create_share_group_snapshot( 

1011 self.context, share_group_id=share_group['id']) 

1012 

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() 

1024 

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=[])) 

1047 

1048 self.api.create_share_group_snapshot( 

1049 self.context, share_group_id=share_group['id'], name=fake_name) 

1050 

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() 

1062 

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=[])) 

1086 

1087 self.api.create_share_group_snapshot( 

1088 self.context, share_group_id=share_group['id'], 

1089 description=fake_description) 

1090 

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() 

1102 

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=[])) 

1124 

1125 self.assertRaises( 

1126 exception.InvalidShareGroup, 

1127 self.api.create_share_group_snapshot, 

1128 self.context, share_group_id=share_group['id']) 

1129 

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() 

1135 

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") 

1159 

1160 self.assertRaises( 

1161 exception.ShareGroupSnapshotsLimitExceeded, 

1162 self.api.create_share_group_snapshot, 

1163 self.context, share_group_id=share_group["id"]) 

1164 

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) 

1172 

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'))) 

1178 

1179 self.assertRaises( 

1180 exception.ShareGroupNotFound, 

1181 self.api.create_share_group_snapshot, 

1182 self.context, share_group_id="fake_id") 

1183 

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() 

1189 

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])) 

1224 

1225 self.api.create_share_group_snapshot( 

1226 self.context, share_group_id=share_group['id']) 

1227 

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() 

1241 

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])) 

1254 

1255 self.assertRaises( 

1256 exception.InvalidShareGroup, 

1257 self.api.create_share_group_snapshot, 

1258 self.context, share_group_id=share_group['id']) 

1259 

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() 

1265 

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') 

1311 

1312 self.api.create_share_group_snapshot( 

1313 self.context, share_group_id=share_group['id']) 

1314 

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() 

1330 

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])) 

1368 

1369 self.assertRaises( 

1370 exception.Error, 

1371 self.api.create_share_group_snapshot, 

1372 self.context, share_group_id=share_group['id']) 

1373 

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) 

1387 

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') 

1396 

1397 self.api.delete_share_group_snapshot(self.context, sg_snap) 

1398 

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() 

1414 

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') 

1426 

1427 self.api.delete_share_group_snapshot(self.context, sg_snap) 

1428 

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) 

1443 

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'))) 

1451 

1452 self.assertRaises( 

1453 exception.ShareGroupNotFound, 

1454 self.api.delete_share_group_snapshot, self.context, snap) 

1455 

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() 

1461 

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') 

1467 

1468 self.assertRaises( 

1469 exception.InvalidShareGroupSnapshot, 

1470 self.api.delete_share_group_snapshot, self.context, snap) 

1471 

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() 

1477 

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)) 

1487 

1488 self.api.update_share_group_snapshot( 

1489 self.context, snap, expected_values) 

1490 

1491 db_driver.share_group_snapshot_update.assert_called_once_with( 

1492 self.context, snap['id'], expected_values) 

1493 

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)) 

1502 

1503 actual = self.api.get_share_group_snapshot( 

1504 self.context, expected['id']) 

1505 

1506 self.assertEqual(expected, actual) 

1507 

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=[])) 

1512 

1513 actual = self.api.get_all_share_group_snapshots(self.context) 

1514 

1515 self.assertEqual([], actual) 

1516 

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)) 

1525 

1526 actual = self.api.get_all_share_group_snapshots( 

1527 self.context, detailed=True) 

1528 

1529 self.assertEqual(expected, actual) 

1530 

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)) 

1540 

1541 actual = self.api.get_all_share_group_snapshots( 

1542 cxt, search_opts={'all_tenants': True}) 

1543 

1544 self.assertEqual(expected, actual) 

1545 

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)) 

1554 

1555 actual = self.api.get_all_share_group_snapshots( 

1556 self.context, search_opts={'all_tenants': True}) 

1557 

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) 

1562 

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=[])) 

1567 

1568 self.api.get_all_share_group_snapshot_members(self.context, 'fake_id') 

1569 

1570 db_driver.share_group_snapshot_members_get_all.assert_called_once_with( 

1571 self.context, 'fake_id')