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
« 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.
16import ddt
17import json
18import requests
19import time
20from unittest import mock
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
28class FakeRequests(object):
29 status_code = 0
30 headers = {}
31 content = ""
33 def __init__(self, status_code, content='null'):
34 self.status_code = status_code
35 self.headers = {'location': 'fake_location'}
36 self.content = content
38 def json(self):
39 return {'messages': [{'message': 'fake_msg'}]}
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'
50 self._driver = rest.HSPRestBackend(self.hitachi_hsp_host,
51 self.hitachi_hsp_username,
52 self.hitachi_hsp_password)
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)))
59 if code == 202:
60 self.mock_object(rest.HSPRestBackend, "_wait_job_status",
61 mock.Mock())
62 self._driver._send_post('fake_url')
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')
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)))
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')
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)))
93 if code == 202:
94 self.mock_object(rest.HSPRestBackend, "_wait_job_status",
95 mock.Mock())
96 self._driver._send_delete('fake_url')
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')
104 def test_add_file_system(self):
105 url = "https://172.24.47.190/hspapi/file-systems/"
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 }
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'])
123 rest.HSPRestBackend._send_post.assert_called_once_with(
124 url, payload=json.dumps(payload))
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'])
130 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock(
131 return_value={'list': [fakes.file_system]}))
133 result = self._driver.get_file_system(
134 fakes.file_system['properties']['name'])
136 self.assertEqual(fakes.file_system, result)
138 rest.HSPRestBackend._send_get.assert_called_once_with(url)
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'])
144 self.mock_object(rest.HSPRestBackend, "_send_get",
145 mock.Mock(return_value=None))
147 self.assertRaises(exception.HSPItemNotFoundException,
148 self._driver.get_file_system,
149 fakes.file_system['properties']['name'])
151 rest.HSPRestBackend._send_get.assert_called_once_with(url)
153 def test_delete_file_system(self):
154 url = ("https://172.24.47.190/hspapi/file-systems/%s" %
155 fakes.file_system['id'])
157 self.mock_object(rest.HSPRestBackend, "_send_delete", mock.Mock())
158 self._driver.delete_file_system(fakes.file_system['id'])
160 rest.HSPRestBackend._send_delete.assert_called_once_with(url)
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}
168 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock())
169 self._driver.resize_file_system(fakes.file_system['id'], new_size)
171 rest.HSPRestBackend._send_post.assert_called_once_with(
172 url, payload=json.dumps(payload))
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}
180 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock())
182 self._driver.rename_file_system(fakes.file_system['id'], new_name)
184 rest.HSPRestBackend._send_post.assert_called_once_with(
185 url, payload=json.dumps(payload))
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 }
198 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock())
200 self._driver.add_share(fakes.share['name'],
201 fakes.share['properties']['file-system-id'])
203 rest.HSPRestBackend._send_post.assert_called_once_with(
204 url, payload=json.dumps(payload))
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]}))
219 result = self._driver.get_share(fs_id, name)
221 self.assertEqual(fakes.share, result)
223 rest.HSPRestBackend._send_get.assert_called_once_with(url)
225 def test_get_share_exception(self):
226 url = ("https://172.24.47.190/hspapi/shares/list?"
227 "name=aa4a7710-f326-41fb-ad18-b4ad587fc87a")
229 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock(
230 return_value=None))
232 self.assertRaises(exception.HSPItemNotFoundException,
233 self._driver.get_share, None, fakes.share['name'])
235 rest.HSPRestBackend._send_get.assert_called_once_with(url)
237 def test_delete_share(self):
238 url = "https://172.24.47.190/hspapi/shares/%s" % fakes.share['id']
240 self.mock_object(rest.HSPRestBackend, "_send_delete")
242 self._driver.delete_share(fakes.share['id'])
244 rest.HSPRestBackend._send_delete.assert_called_once_with(url)
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 }
255 self.mock_object(rest.HSPRestBackend, "_send_post", mock.Mock())
257 self._driver.add_access_rule(fakes.share['id'],
258 fakes.access_rule['access_to'],
259 fakes.access_rule['access_level'])
261 rest.HSPRestBackend._send_post.assert_called_once_with(
262 url, payload=json.dumps(payload))
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())
272 self._driver.delete_access_rule(fakes.share['id'],
273 fakes.hsp_rules[0]['name'])
275 rest.HSPRestBackend._send_post.assert_called_once_with(
276 url, payload=json.dumps(payload))
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'])
285 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock(
286 return_value=value))
288 result = self._driver.get_access_rules(fakes.share['id'])
290 self.assertEqual(res, result)
292 rest.HSPRestBackend._send_get.assert_called_once_with(url)
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"
298 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock(
299 return_value=value))
301 if value:
302 result = self._driver.get_cluster()
304 self.assertEqual(fakes.hsp_cluster, result)
305 else:
306 self.assertRaises(exception.HSPBackendException,
307 self._driver.get_cluster)
309 rest.HSPRestBackend._send_get.assert_called_once_with(url)
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 }
326 self.mock_object(rest.HSPRestBackend, "_send_get", mock.Mock(
327 return_value=json))
328 self.mock_object(time, "sleep")
330 if stat == 'COMPLETE':
331 self._driver._wait_job_status(url, 'COMPLETE')
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')
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')
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 ])