Coverage for manila/tests/share/drivers/dell_emc/plugins/unity/res_mock.py: 95%

226 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright (c) 2016 EMC Corporation. 

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 

16from unittest import mock 

17 

18from oslo_config import cfg 

19from oslo_log import log 

20 

21from manila.share import configuration as conf 

22from manila.share.drivers.dell_emc.plugins.unity import client 

23from manila.share.drivers.dell_emc.plugins.unity import connection 

24from manila.tests.db import fakes as db_fakes 

25from manila.tests import fake_share 

26from manila.tests.share.drivers.dell_emc.plugins.unity import fake_exceptions 

27from manila.tests.share.drivers.dell_emc.plugins.unity import utils 

28 

29client.storops_ex = fake_exceptions 

30connection.storops_ex = fake_exceptions 

31 

32LOG = log.getLogger(__name__) 

33 

34SYMBOL_TYPE = '_type' 

35SYMBOL_PROPERTIES = '_properties' 

36SYMBOL_METHODS = '_methods' 

37SYMBOL_SIDE_EFFECT = '_side_effect' 

38SYMBOL_RAISE = '_raise' 

39CONF = cfg.CONF 

40 

41 

42def _has_side_effect(node): 

43 return isinstance(node, dict) and SYMBOL_SIDE_EFFECT in node 

44 

45 

46def _has_raise(node): 

47 return isinstance(node, dict) and SYMBOL_RAISE in node 

48 

49 

50def fake_share_server(**kwargs): 

51 share_server = { 

52 'instance_id': 'fake_instance_id', 

53 'backend_details': {}, 

54 } 

55 

56 share_server.update(kwargs) 

57 

58 return db_fakes.FakeModel(share_server) 

59 

60 

61def fake_network_info(**kwargs): 

62 network_info = { 

63 'id': 'fake_net_id', 

64 'name': 'net_name', 

65 'subnet': [], 

66 } 

67 network_info.update(kwargs) 

68 return network_info 

69 

70 

71def fake_server_detail(**kwargs): 

72 server_detail = { 

73 'share_server_name': 'fake_server_name', 

74 } 

75 server_detail.update(kwargs) 

76 return server_detail 

77 

78 

79def fake_security_services(**kwargs): 

80 return kwargs['services'] 

81 

82 

83def fake_access(**kwargs): 

84 access = {} 

85 access.update(kwargs) 

86 return access 

87 

88 

89class FakeEMCShareDriver(object): 

90 def __init__(self, dhss=None): 

91 if dhss in (True, False): 

92 CONF.set_default('driver_handles_share_servers', dhss) 

93 self.configuration = conf.Configuration(None) 

94 self.configuration.emc_share_backend = 'unity' 

95 self.configuration.emc_nas_server = '192.168.1.1' 

96 self.configuration.emc_nas_login = 'fake_user' 

97 self.configuration.emc_nas_password = 'fake_password' 

98 self.configuration.share_backend_name = 'EMC_NAS_Storage' 

99 self.configuration.vnx_server_meta_pool = 'nas_server_pool' 

100 self.configuration.unity_server_meta_pool = 'nas_server_pool' 

101 self.configuration.local_conf.max_over_subscription_ratio = 20 

102 

103 

104class FakeEMCShareDriverIPv6(object): 

105 def __init__(self, dhss=None): 

106 if dhss in (True, False): 106 ↛ 108line 106 didn't jump to line 108 because the condition on line 106 was always true

107 CONF.set_default('driver_handles_share_servers', dhss) 

108 self.configuration = conf.Configuration(None) 

109 self.configuration.emc_share_backend = 'unity' 

110 self.configuration.emc_nas_server = 'fa27:2a95:e734:0:0:0:0:01' 

111 self.configuration.emc_nas_login = 'fake_user' 

112 self.configuration.emc_nas_password = 'fake_password' 

113 self.configuration.share_backend_name = 'EMC_NAS_Storage' 

114 self.configuration.vnx_server_meta_pool = 'nas_server_pool' 

115 self.configuration.unity_server_meta_pool = 'nas_server_pool' 

116 self.configuration.local_conf.max_over_subscription_ratio = 20 

117 

118 

119STATS = dict( 

120 share_backend_name='Unity', 

121 vendor_name='EMC', 

122 storage_protocol='NFS_CIFS', 

123 driver_version='2.0.0,', 

124 pools=[], 

125) 

126 

127 

128class DriverResourceMock(dict): 

129 fake_func_mapping = {} 

130 

131 def __init__(self, yaml_file): 

132 yaml_dict = utils.load_yaml(yaml_file) 

133 if isinstance(yaml_dict, dict): 133 ↛ exitline 133 didn't return from function '__init__' because the condition on line 133 was always true

134 for name, body in yaml_dict.items(): 

135 if isinstance(body, dict): 135 ↛ 134line 135 didn't jump to line 134 because the condition on line 135 was always true

136 props = body[SYMBOL_PROPERTIES] 

137 if isinstance(props, dict): 

138 for prop_name, prop_value in props.items(): 

139 if isinstance(prop_value, dict) and prop_value: 

140 # get the first key as the convert function 

141 func_name = list(prop_value.keys())[0] 

142 if func_name.startswith('_'): 142 ↛ 143line 142 didn't jump to line 143 because the condition on line 142 was never true

143 func = getattr(self, func_name) 

144 props[prop_name] = ( 

145 func(**prop_value[func_name])) 

146 if body[SYMBOL_TYPE] in self.fake_func_mapping: 

147 self[name] = ( 

148 self.fake_func_mapping[body[SYMBOL_TYPE]](**props)) 

149 

150 

151class ManilaResourceMock(DriverResourceMock): 

152 fake_func_mapping = { 

153 'share': fake_share.fake_share, 

154 'snapshot': fake_share.fake_snapshot, 

155 'network_info': fake_network_info, 

156 'share_server': fake_share_server, 

157 'server_detail': fake_server_detail, 

158 'security_services': fake_security_services, 

159 'access': fake_access, 

160 } 

161 

162 def __init__(self, yaml_file): 

163 super(ManilaResourceMock, self).__init__(yaml_file) 

164 

165 

166class StorageObjectMock(object): 

167 PROPS = 'props' 

168 

169 def __init__(self, yaml_dict): 

170 self.__dict__[StorageObjectMock.PROPS] = {} 

171 props = yaml_dict.get(SYMBOL_PROPERTIES, None) 

172 if props: 

173 for k, v in props.items(): 

174 setattr(self, k, StoragePropertyMock(k, v)()) 

175 

176 methods = yaml_dict.get(SYMBOL_METHODS, None) 

177 if methods: 

178 for k, v in methods.items(): 

179 setattr(self, k, StorageMethodMock(k, v)) 

180 

181 def __setattr__(self, key, value): 

182 self.__dict__[StorageObjectMock.PROPS][key] = value 

183 

184 def __getattr__(self, item): 

185 try: 

186 super(StorageObjectMock, self).__getattr__(item) 

187 except AttributeError: 

188 return self.__dict__[StorageObjectMock.PROPS][item] 

189 except KeyError: 

190 raise KeyError('No such method or property for mock object.') 

191 

192 

193class StoragePropertyMock(mock.PropertyMock): 

194 def __init__(self, name, property_body): 

195 return_value = property_body 

196 side_effect = None 

197 

198 # only support return_value and side_effect for property 

199 if _has_side_effect(property_body): 199 ↛ 200line 199 didn't jump to line 200 because the condition on line 199 was never true

200 side_effect = property_body[SYMBOL_SIDE_EFFECT] 

201 return_value = None 

202 

203 if side_effect: 203 ↛ 204line 203 didn't jump to line 204 because the condition on line 203 was never true

204 super(StoragePropertyMock, self).__init__( 

205 name=name, 

206 side_effect=side_effect) 

207 elif return_value: 

208 super(StoragePropertyMock, self).__init__( 

209 name=name, 

210 return_value=_build_mock_object(return_value)) 

211 else: 

212 super(StoragePropertyMock, self).__init__( 

213 name=name, 

214 return_value=return_value) 

215 

216 

217class StorageMethodMock(mock.Mock): 

218 def __init__(self, name, method_body): 

219 return_value = method_body 

220 exception = None 

221 side_effect = None 

222 

223 # support return_value, side_effect and exception for method 

224 if _has_side_effect(method_body) or _has_raise(method_body): 

225 exception = method_body.get(SYMBOL_RAISE, None) 

226 side_effect = method_body.get(SYMBOL_SIDE_EFFECT, None) 

227 return_value = None 

228 

229 if exception: 

230 if isinstance(exception, dict) and exception: 230 ↛ 233line 230 didn't jump to line 233 because the condition on line 230 was always true

231 ex_name = list(exception.keys())[0] 

232 ex = getattr(fake_exceptions, ex_name) 

233 super(StorageMethodMock, self).__init__( 

234 name=name, 

235 side_effect=ex(exception[ex_name])) 

236 elif side_effect: 

237 super(StorageMethodMock, self).__init__( 

238 name=name, 

239 side_effect=_build_mock_object(side_effect)) 

240 elif return_value is not None: 

241 super(StorageMethodMock, self).__init__( 

242 name=name, 

243 return_value=_build_mock_object(return_value)) 

244 else: 

245 super(StorageMethodMock, self).__init__( 

246 name=name, return_value=None) 

247 

248 

249class StorageResourceMock(dict): 

250 def __init__(self, yaml_file): 

251 yaml_dict = utils.load_yaml(yaml_file) 

252 if isinstance(yaml_dict, dict): 252 ↛ exitline 252 didn't return from function '__init__' because the condition on line 252 was always true

253 for section, sec_body in yaml_dict.items(): 

254 self[section] = {} 

255 if isinstance(sec_body, dict): 255 ↛ 253line 255 didn't jump to line 253 because the condition on line 255 was always true

256 for obj_name, obj_body in sec_body.items(): 

257 self[section][obj_name] = _build_mock_object(obj_body) 

258 

259 

260def _is_mock_object(yaml_info): 

261 return (isinstance(yaml_info, dict) and 

262 (SYMBOL_PROPERTIES in yaml_info or SYMBOL_METHODS in yaml_info)) 

263 

264 

265def _build_mock_object(yaml_dict): 

266 if _is_mock_object(yaml_dict): 

267 return StorageObjectMock(yaml_dict) 

268 elif isinstance(yaml_dict, dict): 

269 return {k: _build_mock_object(v) for k, v in yaml_dict.items()} 

270 elif isinstance(yaml_dict, list): 

271 return [_build_mock_object(each) for each in yaml_dict] 

272 else: 

273 return yaml_dict 

274 

275 

276manila_res = ManilaResourceMock('mocked_manila.yaml') 

277unity_res = StorageResourceMock('mocked_unity.yaml') 

278STORAGE_RES_MAPPING = { 

279 'TestClient': unity_res, 

280 'TestConnection': unity_res, 

281 'TestConnectionDHSSFalse': unity_res, 

282} 

283 

284 

285def mock_input(resource): 

286 def inner_dec(func): 

287 def decorated(cls, *args, **kwargs): 

288 if cls._testMethodName in resource: 

289 storage_res = resource[cls._testMethodName] 

290 return func(cls, storage_res, *args, **kwargs) 

291 

292 return decorated 

293 

294 return inner_dec 

295 

296 

297mock_client_input = mock_input(unity_res) 

298 

299 

300def patch_client(func): 

301 def client_decorator(cls, *args, **kwargs): 

302 storage_res = {} 

303 if func.__name__ in STORAGE_RES_MAPPING[cls.__class__.__name__]: 

304 storage_res = ( 

305 STORAGE_RES_MAPPING[cls.__class__.__name__][func.__name__]) 

306 with utils.patch_system as patched_system: 

307 if 'unity' in storage_res: 

308 patched_system.return_value = storage_res['unity'] 

309 _client = client.UnityClient(host='fake_host', 

310 username='fake_user', 

311 password='fake_passwd') 

312 return func(cls, _client, *args, **kwargs) 

313 

314 return client_decorator 

315 

316 

317def mock_driver_input(resource): 

318 def inner_dec(func): 

319 def decorated(cls, *args, **kwargs): 

320 return func(cls, resource, *args, **kwargs) 

321 

322 return decorated 

323 

324 return inner_dec 

325 

326 

327mock_manila_input = mock_driver_input(manila_res) 

328 

329 

330def patch_connection_init(func): 

331 def connection_decorator(cls, *args, **kwargs): 

332 storage_res = {} 

333 if func.__name__ in STORAGE_RES_MAPPING[cls.__class__.__name__]: 

334 storage_res = ( 

335 STORAGE_RES_MAPPING[cls.__class__.__name__][func.__name__]) 

336 with utils.patch_system as patched_system: 

337 if 'unity' in storage_res: 

338 patched_system.return_value = storage_res['unity'] 

339 conn = connection.UnityStorageConnection(LOG) 

340 return func(cls, conn, *args, **kwargs) 

341 

342 return connection_decorator 

343 

344 

345def do_connection_connect(conn, res): 

346 conn.config = None 

347 conn.client = client.UnityClient(host='fake_host', 

348 username='fake_user', 

349 password='fake_passwd') 

350 conn.pool_conf = ['pool_1', 'pool_2'] 

351 conn.pool_set = set(['pool_1', 'pool_2']) 

352 conn.reserved_percentage = 0 

353 conn.reserved_snapshot_percentage = 0 

354 conn.reserved_share_extend_percentage = 0 

355 conn.max_over_subscription_ratio = 20 

356 conn.port_set = set(['spa_eth1', 'spa_eth2']) 

357 conn.nas_server_pool = StorageObjectMock(res['nas_server_pool']) 

358 conn.storage_processor = StorageObjectMock(res['sp_a']) 

359 conn.report_default_filter_function = False 

360 

361 

362def patch_connection(func): 

363 def connection_decorator(cls, *args, **kwargs): 

364 storage_res = {} 

365 if func.__name__ in STORAGE_RES_MAPPING[cls.__class__.__name__]: 

366 storage_res = ( 

367 STORAGE_RES_MAPPING[cls.__class__.__name__][func.__name__]) 

368 with utils.patch_system as patched_system: 

369 conn = connection.UnityStorageConnection(LOG) 

370 if 'unity' in storage_res: 

371 patched_system.return_value = storage_res['unity'] 

372 do_connection_connect( 

373 conn, STORAGE_RES_MAPPING[cls.__class__.__name__]) 

374 return func(cls, conn, *args, **kwargs) 

375 

376 return connection_decorator