Coverage for manila/tests/share/drivers/hitachi/hsp/test_rest.py: 100%

155 statements  

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

1# Copyright (c) 2016 Hitachi Data Systems, Inc. 

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 

16import ddt 

17import json 

18import requests 

19import time 

20from unittest import mock 

21 

22from manila import exception 

23from manila.share.drivers.hitachi.hsp import rest 

24from manila import test 

25from manila.tests.share.drivers.hitachi.hsp import fakes 

26 

27 

28class FakeRequests(object): 

29 status_code = 0 

30 headers = {} 

31 content = "" 

32 

33 def __init__(self, status_code, content='null'): 

34 self.status_code = status_code 

35 self.headers = {'location': 'fake_location'} 

36 self.content = content 

37 

38 def json(self): 

39 return {'messages': [{'message': 'fake_msg'}]} 

40 

41 

42@ddt.ddt 

43class HitachiHSPRestTestCase(test.TestCase): 

44 def setUp(self): 

45 super(HitachiHSPRestTestCase, self).setUp() 

46 self.hitachi_hsp_host = '172.24.47.190' 

47 self.hitachi_hsp_username = 'hds_hnas_user' 

48 self.hitachi_hsp_password = 'hds_hnas_password' 

49 

50 self._driver = rest.HSPRestBackend(self.hitachi_hsp_host, 

51 self.hitachi_hsp_username, 

52 self.hitachi_hsp_password) 

53 

54 @ddt.data(202, 500) 

55 def test__send_post(self, code): 

56 self.mock_object(requests, "post", mock.Mock( 

57 return_value=FakeRequests(code))) 

58 

59 if code == 202: 

60 self.mock_object(rest.HSPRestBackend, "_wait_job_status", 

61 mock.Mock()) 

62 self._driver._send_post('fake_url') 

63 

64 rest.HSPRestBackend._wait_job_status.assert_called_once_with( 

65 'fake_location', 'COMPLETE') 

66 else: 

67 self.assertRaises(exception.HSPBackendException, 

68 self._driver._send_post, 'fake_url') 

69 

70 @ddt.data({'code': 200, 'content': 'null'}, 

71 {'code': 200, 'content': 'fake_content'}, 

72 {'code': 500, 'content': 'null'}) 

73 @ddt.unpack 

74 def test__send_get(self, code, content): 

75 self.mock_object(requests, "get", mock.Mock( 

76 return_value=FakeRequests(code, content))) 

77 

78 if code == 200: 

79 result = self._driver._send_get('fake_url') 

80 if content == 'null': 

81 self.assertIsNone(result) 

82 else: 

83 self.assertEqual(FakeRequests(code, content).json(), result) 

84 else: 

85 self.assertRaises(exception.HSPBackendException, 

86 self._driver._send_get, 'fake_url') 

87 

88 @ddt.data(202, 500) 

89 def test__send_delete(self, code): 

90 self.mock_object(requests, "delete", mock.Mock( 

91 return_value=FakeRequests(code))) 

92 

93 if code == 202: 

94 self.mock_object(rest.HSPRestBackend, "_wait_job_status", 

95 mock.Mock()) 

96 self._driver._send_delete('fake_url') 

97 

98 rest.HSPRestBackend._wait_job_status.assert_called_once_with( 

99 'fake_location', 'COMPLETE') 

100 else: 

101 self.assertRaises(exception.HSPBackendException, 

102 self._driver._send_delete, 'fake_url') 

103 

104 def test_add_file_system(self): 

105 url = "https://172.24.47.190/hspapi/file-systems/" 

106 

107 payload = { 

108 'quota': fakes.file_system['properties']['quota'], 

109 'auto-access': False, 

110 'enabled': True, 

111 'description': '', 

112 'record-access-time': True, 

113 'tags': '', 

114 'space-hwm': 90, 

115 'space-lwm': 70, 

116 'name': fakes.file_system['properties']['name'], 

117 } 

118 

119 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock()) 

120 self._driver.add_file_system(fakes.file_system['properties']['name'], 

121 fakes.file_system['properties']['quota']) 

122 

123 rest.HSPRestBackend._send_post.assert_called_once_with( 

124 url, payload=json.dumps(payload)) 

125 

126 def test_get_file_system(self): 

127 url = ("https://172.24.47.190/hspapi/file-systems/list?name=%s" % 

128 fakes.file_system['properties']['name']) 

129 

130 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock( 

131 return_value={'list': [fakes.file_system]})) 

132 

133 result = self._driver.get_file_system( 

134 fakes.file_system['properties']['name']) 

135 

136 self.assertEqual(fakes.file_system, result) 

137 

138 rest.HSPRestBackend._send_get.assert_called_once_with(url) 

139 

140 def test_get_file_system_exception(self): 

141 url = ("https://172.24.47.190/hspapi/file-systems/list?name=%s" % 

142 fakes.file_system['properties']['name']) 

143 

144 self.mock_object(rest.HSPRestBackend, "_send_get", 

145 mock.Mock(return_value=None)) 

146 

147 self.assertRaises(exception.HSPItemNotFoundException, 

148 self._driver.get_file_system, 

149 fakes.file_system['properties']['name']) 

150 

151 rest.HSPRestBackend._send_get.assert_called_once_with(url) 

152 

153 def test_delete_file_system(self): 

154 url = ("https://172.24.47.190/hspapi/file-systems/%s" % 

155 fakes.file_system['id']) 

156 

157 self.mock_object(rest.HSPRestBackend, "_send_delete", mock.Mock()) 

158 self._driver.delete_file_system(fakes.file_system['id']) 

159 

160 rest.HSPRestBackend._send_delete.assert_called_once_with(url) 

161 

162 def test_resize_file_system(self): 

163 url = ("https://172.24.47.190/hspapi/file-systems/%s" % 

164 fakes.file_system['id']) 

165 new_size = 53687091200 

166 payload = {'quota': new_size} 

167 

168 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock()) 

169 self._driver.resize_file_system(fakes.file_system['id'], new_size) 

170 

171 rest.HSPRestBackend._send_post.assert_called_once_with( 

172 url, payload=json.dumps(payload)) 

173 

174 def test_rename_file_system(self): 

175 url = ("https://172.24.47.190/hspapi/file-systems/%s" % 

176 fakes.file_system['id']) 

177 new_name = "fs_rename" 

178 payload = {'name': new_name} 

179 

180 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock()) 

181 

182 self._driver.rename_file_system(fakes.file_system['id'], new_name) 

183 

184 rest.HSPRestBackend._send_post.assert_called_once_with( 

185 url, payload=json.dumps(payload)) 

186 

187 def test_add_share(self): 

188 url = "https://172.24.47.190/hspapi/shares/" 

189 payload = { 

190 'description': '', 

191 'type': 'NFS', 

192 'enabled': True, 

193 'tags': '', 

194 'name': fakes.share['name'], 

195 'file-system-id': fakes.share['properties']['file-system-id'], 

196 } 

197 

198 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock()) 

199 

200 self._driver.add_share(fakes.share['name'], 

201 fakes.share['properties']['file-system-id']) 

202 

203 rest.HSPRestBackend._send_post.assert_called_once_with( 

204 url, payload=json.dumps(payload)) 

205 

206 @ddt.data({'fs_id': None, 

207 'name': fakes.share['name'], 

208 'url': 'https://172.24.47.190/hspapi/shares/list?' 

209 'name=aa4a7710-f326-41fb-ad18-b4ad587fc87a'}, 

210 {'fs_id': fakes.share['properties']['file-system-id'], 

211 'name': None, 

212 'url': 'https://172.24.47.190/hspapi/shares/list?' 

213 'file-system-id=33689245-1806-45d0-8507-0700b5f89750'}) 

214 @ddt.unpack 

215 def test_get_share(self, fs_id, name, url): 

216 self.mock_object(rest.HSPRestBackend, "_send_get", 

217 mock.Mock(return_value={'list': [fakes.share]})) 

218 

219 result = self._driver.get_share(fs_id, name) 

220 

221 self.assertEqual(fakes.share, result) 

222 

223 rest.HSPRestBackend._send_get.assert_called_once_with(url) 

224 

225 def test_get_share_exception(self): 

226 url = ("https://172.24.47.190/hspapi/shares/list?" 

227 "name=aa4a7710-f326-41fb-ad18-b4ad587fc87a") 

228 

229 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock( 

230 return_value=None)) 

231 

232 self.assertRaises(exception.HSPItemNotFoundException, 

233 self._driver.get_share, None, fakes.share['name']) 

234 

235 rest.HSPRestBackend._send_get.assert_called_once_with(url) 

236 

237 def test_delete_share(self): 

238 url = "https://172.24.47.190/hspapi/shares/%s" % fakes.share['id'] 

239 

240 self.mock_object(rest.HSPRestBackend, "_send_delete") 

241 

242 self._driver.delete_share(fakes.share['id']) 

243 

244 rest.HSPRestBackend._send_delete.assert_called_once_with(url) 

245 

246 def test_add_access_rule(self): 

247 url = "https://172.24.47.190/hspapi/shares/%s/" % fakes.share['id'] 

248 payload = { 

249 "action": "add-access-rule", 

250 "name": fakes.share['id'] + fakes.access_rule['access_to'], 

251 "host-specification": fakes.access_rule['access_to'], 

252 "read-write": fakes.access_rule['access_level'], 

253 } 

254 

255 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock()) 

256 

257 self._driver.add_access_rule(fakes.share['id'], 

258 fakes.access_rule['access_to'], 

259 fakes.access_rule['access_level']) 

260 

261 rest.HSPRestBackend._send_post.assert_called_once_with( 

262 url, payload=json.dumps(payload)) 

263 

264 def test_delete_access_rule(self): 

265 url = "https://172.24.47.190/hspapi/shares/%s/" % fakes.share['id'] 

266 payload = { 

267 "action": "delete-access-rule", 

268 "name": fakes.hsp_rules[0]['name'], 

269 } 

270 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock()) 

271 

272 self._driver.delete_access_rule(fakes.share['id'], 

273 fakes.hsp_rules[0]['name']) 

274 

275 rest.HSPRestBackend._send_post.assert_called_once_with( 

276 url, payload=json.dumps(payload)) 

277 

278 @ddt.data({'value': {'list': fakes.hsp_rules}, 'res': fakes.hsp_rules}, 

279 {'value': None, 'res': []}) 

280 @ddt.unpack 

281 def test_get_access_rules(self, value, res): 

282 url = ("https://172.24.47.190/hspapi/shares/%s/access-rules" % 

283 fakes.share['id']) 

284 

285 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock( 

286 return_value=value)) 

287 

288 result = self._driver.get_access_rules(fakes.share['id']) 

289 

290 self.assertEqual(res, result) 

291 

292 rest.HSPRestBackend._send_get.assert_called_once_with(url) 

293 

294 @ddt.data({'list': [fakes.hsp_cluster]}, None) 

295 def test_get_clusters(self, value): 

296 url = "https://172.24.47.190/hspapi/clusters/list" 

297 

298 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock( 

299 return_value=value)) 

300 

301 if value: 

302 result = self._driver.get_cluster() 

303 

304 self.assertEqual(fakes.hsp_cluster, result) 

305 else: 

306 self.assertRaises(exception.HSPBackendException, 

307 self._driver.get_cluster) 

308 

309 rest.HSPRestBackend._send_get.assert_called_once_with(url) 

310 

311 @ddt.data('COMPLETE', 'ERROR', 'RUNNING') 

312 def test__wait_job_status(self, stat): 

313 url = "fake_job_url" 

314 json = { 

315 'id': 'fake_id', 

316 'properties': { 

317 'completion-details': 'Duplicate NFS access rule exists', 

318 'completion-status': stat, 

319 }, 

320 'messages': [{ 

321 'id': 'fake_id', 

322 'message': 'fake_msg', 

323 }] 

324 } 

325 

326 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock( 

327 return_value=json)) 

328 self.mock_object(time, "sleep") 

329 

330 if stat == 'COMPLETE': 

331 self._driver._wait_job_status(url, 'COMPLETE') 

332 

333 rest.HSPRestBackend._send_get.assert_called_once_with(url) 

334 elif stat == 'ERROR': 

335 self.assertRaises(exception.HSPBackendException, 

336 self._driver._wait_job_status, url, 'COMPLETE') 

337 

338 rest.HSPRestBackend._send_get.assert_called_once_with(url) 

339 else: 

340 self.assertRaises(exception.HSPTimeoutException, 

341 self._driver._wait_job_status, url, 'COMPLETE') 

342 

343 rest.HSPRestBackend._send_get.assert_has_calls([ 

344 mock.call(url), mock.call(url), mock.call(url), mock.call(url), 

345 mock.call(url), 

346 ])