Coverage for manila/tests/share/drivers/nexenta/ns5/test_jsonrpc.py: 99%
930 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 2019 Nexenta by DDN, 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"""
16Unit tests for NexentaStor 5 REST API helper
17"""
19import copy
20import hashlib
21import json
22import posixpath
23from unittest import mock
24from urllib import parse as urlparse
25import uuid
27import requests
29from manila.share import configuration as conf
30from manila.share.drivers.nexenta.ns5 import jsonrpc
31from manila import test
34class FakeNefProxy(object):
36 def __init__(self):
37 self.scheme = 'https'
38 self.port = 8443
39 self.hosts = ['1.1.1.1', '2.2.2.2']
40 self.host = self.hosts[0]
41 self.root = 'pool/share'
42 self.username = 'username'
43 self.password = 'password'
44 self.retries = 3
45 self.timeout = 5
46 self.session = mock.Mock()
47 self.session.headers = {}
49 def __getattr__(self, name):
50 pass
52 def delay(self, interval):
53 pass
55 def delete_bearer(self):
56 pass
58 def update_lock(self):
59 pass
61 def update_token(self, token):
62 pass
64 def update_host(self, host):
65 pass
67 def url(self, path):
68 return '%s://%s:%s/%s' % (self.scheme, self.host, self.port, path)
71class TestNefException(test.TestCase):
73 def test_message(self):
74 message = 'test message 1'
75 result = jsonrpc.NefException(message)
76 self.assertIn(message, result.msg)
78 def test_message_kwargs(self):
79 code = 'EAGAIN'
80 message = 'test message 2'
81 result = jsonrpc.NefException(message, code=code)
82 self.assertEqual(code, result.code)
83 self.assertIn(message, result.msg)
85 def test_no_message_kwargs(self):
86 code = 'ESRCH'
87 message = 'test message 3'
88 result = jsonrpc.NefException(None, code=code, message=message)
89 self.assertEqual(code, result.code)
90 self.assertIn(message, result.msg)
92 def test_message_plus_kwargs(self):
93 code = 'ENODEV'
94 message1 = 'test message 4'
95 message2 = 'test message 5'
96 result = jsonrpc.NefException(message1, code=code, message=message2)
97 self.assertEqual(code, result.code)
98 self.assertIn(message2, result.msg)
100 def test_dict(self):
101 code = 'ENOENT'
102 message = 'test message 4'
103 result = jsonrpc.NefException({'code': code, 'message': message})
104 self.assertEqual(code, result.code)
105 self.assertIn(message, result.msg)
107 def test_kwargs(self):
108 code = 'EPERM'
109 message = 'test message 5'
110 result = jsonrpc.NefException(code=code, message=message)
111 self.assertEqual(code, result.code)
112 self.assertIn(message, result.msg)
114 def test_dict_kwargs(self):
115 code = 'EINVAL'
116 message = 'test message 6'
117 result = jsonrpc.NefException({'code': code}, message=message)
118 self.assertEqual(code, result.code)
119 self.assertIn(message, result.msg)
121 def test_defaults(self):
122 code = 'EBADMSG'
123 message = 'NexentaError'
124 result = jsonrpc.NefException()
125 self.assertEqual(code, result.code)
126 self.assertIn(message, result.msg)
129class TestNefRequest(test.TestCase):
131 def setUp(self):
132 super(TestNefRequest, self).setUp()
133 self.proxy = FakeNefProxy()
135 def fake_response(self, method, path, payload, code, content):
136 request = requests.PreparedRequest()
137 request.method = method
138 request.url = self.proxy.url(path)
139 request.headers = {'Content-Type': 'application/json'}
140 request.body = None
141 if method in ['get', 'delete']:
142 request.params = payload
143 elif method in ['put', 'post']: 143 ↛ 145line 143 didn't jump to line 145 because the condition on line 143 was always true
144 request.data = json.dumps(payload)
145 response = requests.Response()
146 response.request = request
147 response.status_code = code
148 response._content = json.dumps(content) if content else ''
149 return response
151 def test___call___invalid_method(self):
152 method = 'unsupported'
153 instance = jsonrpc.NefRequest(self.proxy, method)
154 path = 'parent/child'
155 self.assertRaises(jsonrpc.NefException, instance, path)
157 def test___call___none_path(self):
158 method = 'get'
159 instance = jsonrpc.NefRequest(self.proxy, method)
160 self.assertRaises(jsonrpc.NefException, instance, None)
162 def test___call___empty_path(self):
163 method = 'get'
164 instance = jsonrpc.NefRequest(self.proxy, method)
165 self.assertRaises(jsonrpc.NefException, instance, '')
167 @mock.patch('manila.share.drivers.nexenta.ns5.'
168 'jsonrpc.NefRequest.request')
169 def test___call___get(self, request):
170 method = 'get'
171 instance = jsonrpc.NefRequest(self.proxy, method)
172 path = 'parent/child'
173 payload = {}
174 content = {'name': 'snapshot'}
175 response = self.fake_response(method, path, payload, 200, content)
176 request.return_value = response
177 result = instance(path, payload)
178 request.assert_called_with(method, path)
179 self.assertEqual(content, result)
181 @mock.patch('manila.share.drivers.nexenta.ns5.'
182 'jsonrpc.NefRequest.request')
183 def test___call___get_payload(self, request):
184 method = 'get'
185 instance = jsonrpc.NefRequest(self.proxy, method)
186 path = 'parent/child'
187 payload = {'key': 'value'}
188 content = {'name': 'snapshot'}
189 response = self.fake_response(method, path, payload, 200, content)
190 request.return_value = response
191 result = instance(path, payload)
192 params = {'params': payload}
193 request.assert_called_with(method, path, **params)
194 self.assertEqual(content, result)
196 @mock.patch('manila.share.drivers.nexenta.ns5.'
197 'jsonrpc.NefRequest.request')
198 def test___call___get_data_payload(self, request):
199 method = 'get'
200 instance = jsonrpc.NefRequest(self.proxy, method)
201 path = 'parent/child'
202 payload = {'key': 'value'}
203 data = [
204 {
205 'name': 'fs1',
206 'path': 'pool/fs1'
207 },
208 {
209 'name': 'fs2',
210 'path': 'pool/fs2'
211 }
212 ]
213 content = {'data': data}
214 response = self.fake_response(method, path, payload, 200, content)
215 request.return_value = response
216 instance.data = data
217 result = instance(path, payload)
218 params = {'params': payload}
219 request.assert_called_with(method, path, **params)
220 self.assertEqual(data, result)
222 def test___call___get_invalid_payload(self):
223 method = 'get'
224 instance = jsonrpc.NefRequest(self.proxy, method)
225 path = 'parent/child'
226 payload = 'bad data'
227 self.assertRaises(jsonrpc.NefException, instance, path, payload)
229 @mock.patch('manila.share.drivers.nexenta.ns5.'
230 'jsonrpc.NefRequest.request')
231 def test___call___delete(self, request):
232 method = 'delete'
233 instance = jsonrpc.NefRequest(self.proxy, method)
234 path = 'parent/child'
235 payload = {}
236 content = {'name': 'snapshot'}
237 response = self.fake_response(method, path, payload, 200, content)
238 request.return_value = response
239 result = instance(path, payload)
240 request.assert_called_with(method, path)
241 self.assertEqual(content, result)
243 @mock.patch('manila.share.drivers.nexenta.ns5.'
244 'jsonrpc.NefRequest.request')
245 def test___call___delete_payload(self, request):
246 method = 'delete'
247 instance = jsonrpc.NefRequest(self.proxy, method)
248 path = 'parent/child'
249 payload = {'key': 'value'}
250 content = {'name': 'snapshot'}
251 response = self.fake_response(method, path, payload, 200, content)
252 request.return_value = response
253 result = instance(path, payload)
254 params = {'params': payload}
255 request.assert_called_with(method, path, **params)
256 self.assertEqual(content, result)
258 def test___call___delete_invalid_payload(self):
259 method = 'delete'
260 instance = jsonrpc.NefRequest(self.proxy, method)
261 path = 'parent/child'
262 payload = 'bad data'
263 self.assertRaises(jsonrpc.NefException, instance, path, payload)
265 @mock.patch('manila.share.drivers.nexenta.ns5.'
266 'jsonrpc.NefRequest.request')
267 def test___call___post(self, request):
268 method = 'post'
269 instance = jsonrpc.NefRequest(self.proxy, method)
270 path = 'parent/child'
271 payload = {}
272 content = None
273 response = self.fake_response(method, path, payload, 200, content)
274 request.return_value = response
275 result = instance(path, payload)
276 request.assert_called_with(method, path)
277 self.assertEqual(content, result)
279 @mock.patch('manila.share.drivers.nexenta.ns5.'
280 'jsonrpc.NefRequest.request')
281 def test___call___post_payload(self, request):
282 method = 'post'
283 instance = jsonrpc.NefRequest(self.proxy, method)
284 path = 'parent/child'
285 payload = {'key': 'value'}
286 content = None
287 response = self.fake_response(method, path, payload, 200, content)
288 request.return_value = response
289 result = instance(path, payload)
290 params = {'data': json.dumps(payload)}
291 request.assert_called_with(method, path, **params)
292 self.assertEqual(content, result)
294 def test___call___post_invalid_payload(self):
295 method = 'post'
296 instance = jsonrpc.NefRequest(self.proxy, method)
297 path = 'parent/child'
298 payload = 'bad data'
299 self.assertRaises(jsonrpc.NefException, instance, path, payload)
301 @mock.patch('manila.share.drivers.nexenta.ns5.'
302 'jsonrpc.NefRequest.request')
303 def test___call___put(self, request):
304 method = 'put'
305 instance = jsonrpc.NefRequest(self.proxy, method)
306 path = 'parent/child'
307 payload = {}
308 content = None
309 response = self.fake_response(method, path, payload, 200, content)
310 request.return_value = response
311 result = instance(path, payload)
312 request.assert_called_with(method, path)
313 self.assertEqual(content, result)
315 @mock.patch('manila.share.drivers.nexenta.ns5.'
316 'jsonrpc.NefRequest.request')
317 def test___call___put_payload(self, request):
318 method = 'put'
319 instance = jsonrpc.NefRequest(self.proxy, method)
320 path = 'parent/child'
321 payload = {'key': 'value'}
322 content = None
323 response = self.fake_response(method, path, payload, 200, content)
324 request.return_value = response
325 result = instance(path, payload)
326 params = {'data': json.dumps(payload)}
327 request.assert_called_with(method, path, **params)
328 self.assertEqual(content, result)
330 def test___call___put_invalid_payload(self):
331 method = 'put'
332 instance = jsonrpc.NefRequest(self.proxy, method)
333 path = 'parent/child'
334 payload = 'bad data'
335 self.assertRaises(jsonrpc.NefException, instance, path, payload)
337 @mock.patch('manila.share.drivers.nexenta.ns5.'
338 'jsonrpc.NefRequest.request')
339 def test___call___non_ok_response(self, request):
340 method = 'get'
341 instance = jsonrpc.NefRequest(self.proxy, method)
342 path = 'parent/child'
343 payload = {'key': 'value'}
344 content = {'code': 'ENOENT', 'message': 'error'}
345 response = self.fake_response(method, path, payload, 500, content)
346 request.return_value = response
347 self.assertRaises(jsonrpc.NefException, instance, path, payload)
349 @mock.patch('manila.share.drivers.nexenta.ns5.'
350 'jsonrpc.NefRequest.failover')
351 @mock.patch('manila.share.drivers.nexenta.ns5.'
352 'jsonrpc.NefRequest.request')
353 def test___call___request_after_failover(self, request, failover):
354 method = 'post'
355 instance = jsonrpc.NefRequest(self.proxy, method)
356 path = 'parent/child'
357 payload = {'key': 'value'}
358 content = None
359 response = self.fake_response(method, path, payload, 200, content)
360 request.side_effect = [requests.exceptions.Timeout, response]
361 failover.return_value = True
362 result = instance(path, payload)
363 params = {'data': json.dumps(payload)}
364 request.assert_called_with(method, path, **params)
365 self.assertEqual(content, result)
367 @mock.patch('manila.share.drivers.nexenta.ns5.'
368 'jsonrpc.NefRequest.failover')
369 @mock.patch('manila.share.drivers.nexenta.ns5.'
370 'jsonrpc.NefRequest.request')
371 def test___call___request_failover_error(self, request, failover):
372 method = 'put'
373 instance = jsonrpc.NefRequest(self.proxy, method)
374 path = 'parent/child'
375 payload = {'key': 'value'}
376 request.side_effect = requests.exceptions.Timeout
377 failover.return_value = False
378 self.assertRaises(requests.exceptions.Timeout, instance, path, payload)
380 def test_hook_default(self):
381 method = 'post'
382 instance = jsonrpc.NefRequest(self.proxy, method)
383 path = 'parent/child'
384 payload = {'key': 'value'}
385 content = {'name': 'dataset'}
386 response = self.fake_response(method, path, payload, 303, content)
387 result = instance.hook(response)
388 self.assertEqual(response, result)
390 def test_hook_200_empty(self):
391 method = 'delete'
392 instance = jsonrpc.NefRequest(self.proxy, method)
393 path = 'storage/filesystems'
394 payload = {'force': True}
395 content = None
396 response = self.fake_response(method, path, payload, 200, content)
397 result = instance.hook(response)
398 self.assertEqual(response, result)
400 def test_hook_201_empty(self):
401 method = 'post'
402 instance = jsonrpc.NefRequest(self.proxy, method)
403 path = 'storage/snapshots'
404 payload = {'path': 'parent/child@name'}
405 content = None
406 response = self.fake_response(method, path, payload, 201, content)
407 result = instance.hook(response)
408 self.assertEqual(response, result)
410 def test_hook_500_empty(self):
411 method = 'get'
412 instance = jsonrpc.NefRequest(self.proxy, method)
413 path = 'storage/pools'
414 payload = {'poolName': 'tank'}
415 content = None
416 response = self.fake_response(method, path, payload, 500, content)
417 self.assertRaises(jsonrpc.NefException, instance.hook, response)
419 def test_hook_200_bad_content(self):
420 method = 'get'
421 instance = jsonrpc.NefRequest(self.proxy, method)
422 path = 'storage/volumes'
423 payload = {'name': 'test'}
424 content = None
425 response = self.fake_response(method, path, payload, 200, content)
426 response._content = 'bad_content'
427 self.assertRaises(jsonrpc.NefException, instance.hook, response)
429 @mock.patch('manila.share.drivers.nexenta.ns5.'
430 'jsonrpc.NefRequest.request')
431 @mock.patch('manila.share.drivers.nexenta.ns5.'
432 'jsonrpc.NefRequest.auth')
433 def test_hook_401(self, auth, request):
434 method = 'get'
435 instance = jsonrpc.NefRequest(self.proxy, method)
436 path = 'parent/child'
437 payload = {'key': 'value'}
438 content = {'code': 'EAUTH'}
439 response = self.fake_response(method, path, payload, 401, content)
440 auth.return_value = True
441 content2 = {'name': 'test'}
442 response2 = self.fake_response(method, path, payload, 200, content2)
443 request.return_value = response2
444 self.proxy.session.send.return_value = content2
445 result = instance.hook(response)
446 self.assertEqual(content2, result)
448 def test_hook_401_max_retries(self):
449 method = 'get'
450 instance = jsonrpc.NefRequest(self.proxy, method)
451 instance.stat[401] = self.proxy.retries
452 path = 'parent/child'
453 payload = {'key': 'value'}
454 content = {'code': 'EAUTH'}
455 response = self.fake_response(method, path, payload, 401, content)
456 self.assertRaises(jsonrpc.NefException, instance.hook, response)
458 def test_hook_404_nested(self):
459 method = 'get'
460 instance = jsonrpc.NefRequest(self.proxy, method)
461 instance.lock = True
462 path = 'parent/child'
463 payload = {'key': 'value'}
464 content = {'code': 'ENOENT'}
465 response = self.fake_response(method, path, payload, 404, content)
466 result = instance.hook(response)
467 self.assertEqual(response, result)
469 def test_hook_404_max_retries(self):
470 method = 'get'
471 instance = jsonrpc.NefRequest(self.proxy, method)
472 instance.stat[404] = self.proxy.retries
473 path = 'parent/child'
474 payload = {'key': 'value'}
475 content = {'code': 'ENOENT'}
476 response = self.fake_response(method, path, payload, 404, content)
477 self.assertRaises(jsonrpc.NefException, instance.hook, response)
479 @mock.patch('manila.share.drivers.nexenta.ns5.'
480 'jsonrpc.NefRequest.failover')
481 def test_hook_404_failover_error(self, failover):
482 method = 'get'
483 instance = jsonrpc.NefRequest(self.proxy, method)
484 path = 'parent/child'
485 payload = {'key': 'value'}
486 content = {'code': 'ENOENT'}
487 response = self.fake_response(method, path, payload, 404, content)
488 failover.return_value = False
489 result = instance.hook(response)
490 self.assertEqual(response, result)
492 @mock.patch('manila.share.drivers.nexenta.ns5.'
493 'jsonrpc.NefRequest.request')
494 @mock.patch('manila.share.drivers.nexenta.ns5.'
495 'jsonrpc.NefRequest.failover')
496 def test_hook_404_failover_ok(self, failover, request):
497 method = 'get'
498 instance = jsonrpc.NefRequest(self.proxy, method)
499 path = 'parent/child'
500 payload = {'key': 'value'}
501 content = {'code': 'ENOENT'}
502 response = self.fake_response(method, path, payload, 404, content)
503 failover.return_value = True
504 content2 = {'name': 'test'}
505 response2 = self.fake_response(method, path, payload, 200, content2)
506 request.return_value = response2
507 result = instance.hook(response)
508 self.assertEqual(response2, result)
510 def test_hook_500_permanent(self):
511 method = 'get'
512 instance = jsonrpc.NefRequest(self.proxy, method)
513 path = 'parent/child'
514 payload = {'key': 'value'}
515 content = {'code': 'EINVAL'}
516 response = self.fake_response(method, path, payload, 500, content)
517 self.assertRaises(jsonrpc.NefException, instance.hook, response)
519 def test_hook_500_busy_max_retries(self):
520 method = 'get'
521 instance = jsonrpc.NefRequest(self.proxy, method)
522 instance.stat[500] = self.proxy.retries
523 path = 'parent/child'
524 payload = {'key': 'value'}
525 content = {'code': 'EBUSY'}
526 response = self.fake_response(method, path, payload, 500, content)
527 self.assertRaises(jsonrpc.NefException, instance.hook, response)
529 @mock.patch('manila.share.drivers.nexenta.ns5.'
530 'jsonrpc.NefRequest.request')
531 def test_hook_500_busy_ok(self, request):
532 method = 'get'
533 instance = jsonrpc.NefRequest(self.proxy, method)
534 path = 'parent/child'
535 payload = {'key': 'value'}
536 content = {'code': 'EBUSY'}
537 response = self.fake_response(method, path, payload, 500, content)
538 content2 = {'name': 'test'}
539 response2 = self.fake_response(method, path, payload, 200, content2)
540 request.return_value = response2
541 result = instance.hook(response)
542 self.assertEqual(response2, result)
544 def test_hook_201_no_monitor(self):
545 method = 'get'
546 instance = jsonrpc.NefRequest(self.proxy, method)
547 path = 'parent/child'
548 payload = {'key': 'value'}
549 content = {'monitor': 'unknown'}
550 response = self.fake_response(method, path, payload, 202, content)
551 self.assertRaises(jsonrpc.NefException, instance.hook, response)
553 @mock.patch('manila.share.drivers.nexenta.ns5.'
554 'jsonrpc.NefRequest.request')
555 def test_hook_201_ok(self, request):
556 method = 'delete'
557 instance = jsonrpc.NefRequest(self.proxy, method)
558 path = 'parent/child'
559 payload = {'key': 'value'}
560 content = {
561 'links': [{
562 'rel': 'monitor',
563 'href': '/jobStatus/jobID'
564 }]
565 }
566 response = self.fake_response(method, path, payload, 202, content)
567 content2 = None
568 response2 = self.fake_response(method, path, payload, 201, content2)
569 request.return_value = response2
570 result = instance.hook(response)
571 self.assertEqual(response2, result)
573 def test_200_no_data(self):
574 method = 'get'
575 instance = jsonrpc.NefRequest(self.proxy, method)
576 path = 'parent/child'
577 payload = {'key': 'value'}
578 content = {'name': 'test'}
579 response = self.fake_response(method, path, payload, 200, content)
580 result = instance.hook(response)
581 self.assertEqual(response, result)
583 def test_200_pagination_end(self):
584 method = 'get'
585 instance = jsonrpc.NefRequest(self.proxy, method)
586 path = 'parent/child'
587 payload = {'key': 'value'}
588 content = {'data': 'value'}
589 response = self.fake_response(method, path, payload, 200, content)
590 result = instance.hook(response)
591 self.assertEqual(response, result)
593 @mock.patch('manila.share.drivers.nexenta.ns5.'
594 'jsonrpc.NefRequest.request')
595 def test_200_pagination_next(self, request):
596 method = 'get'
597 instance = jsonrpc.NefRequest(self.proxy, method)
598 path = 'parent/child'
599 payload = {'key': 'value'}
600 content = {
601 'data': [{
602 'name': 'test'
603 }],
604 'links': [{
605 'rel': 'next',
606 'href': path
607 }]
608 }
609 response = self.fake_response(method, path, payload, 200, content)
610 response2 = self.fake_response(method, path, payload, 200, content)
611 request.return_value = response2
612 result = instance.hook(response)
613 self.assertEqual(response2, result)
615 def test_request(self):
616 method = 'get'
617 instance = jsonrpc.NefRequest(self.proxy, method)
618 path = 'parent/child'
619 payload = {'key': 'value'}
620 expected = {'name': 'dataset'}
621 url = self.proxy.url(path)
622 kwargs = payload.copy()
623 kwargs['timeout'] = self.proxy.timeout
624 kwargs['hooks'] = {'response': instance.hook}
625 self.proxy.session.request.return_value = expected
626 result = instance.request(method, path, **payload)
627 self.proxy.session.request.assert_called_with(method, url, **kwargs)
628 self.assertEqual(expected, result)
630 @mock.patch('manila.share.drivers.nexenta.ns5.'
631 'jsonrpc.NefRequest.request')
632 def test_auth(self, request):
633 method = 'get'
634 instance = jsonrpc.NefRequest(self.proxy, method)
635 method = 'post'
636 path = 'auth/login'
637 payload = {
638 'data': json.dumps({
639 'username': self.proxy.username,
640 'password': self.proxy.password
641 })
642 }
643 content = {'token': 'test'}
644 response = self.fake_response(method, path, payload, 200, content)
645 request.return_value = response
646 instance.auth()
647 request.assert_called_once_with(method, path, **payload)
649 @mock.patch('manila.share.drivers.nexenta.ns5.'
650 'jsonrpc.NefRequest.request')
651 def test_auth_error(self, request):
652 method = 'get'
653 instance = jsonrpc.NefRequest(self.proxy, method)
654 method = 'post'
655 path = 'auth/login'
656 payload = {
657 'data': json.dumps({
658 'username': self.proxy.username,
659 'password': self.proxy.password
660 })
661 }
662 content = {'data': 'noauth'}
663 response = self.fake_response(method, path, payload, 200, content)
664 request.return_value = response
665 self.assertRaises(jsonrpc.NefException, instance.auth)
667 @mock.patch('manila.share.drivers.nexenta.ns5.'
668 'jsonrpc.NefRequest.request')
669 def test_failover(self, request):
670 method = 'get'
671 instance = jsonrpc.NefRequest(self.proxy, method)
672 path = self.proxy.root
673 payload = {}
674 content = {'path': path}
675 response = self.fake_response(method, path, payload, 200, content)
676 request.return_value = response
677 result = instance.failover()
678 request.assert_called_once_with(method, path)
679 expected = True
680 self.assertEqual(expected, result)
682 @mock.patch('manila.share.drivers.nexenta.ns5.'
683 'jsonrpc.NefRequest.request')
684 def test_failover_timeout(self, request):
685 method = 'get'
686 instance = jsonrpc.NefRequest(self.proxy, method)
687 path = self.proxy.root
688 payload = {}
689 content = {'path': path}
690 response = self.fake_response(method, path, payload, 200, content)
691 request.side_effect = [requests.exceptions.Timeout, response]
692 result = instance.failover()
693 request.assert_called_once_with(method, path)
694 expected = False
695 self.assertEqual(expected, result)
697 @mock.patch('manila.share.drivers.nexenta.ns5.'
698 'jsonrpc.NefRequest.request')
699 def test_failover_404(self, request):
700 method = 'get'
701 instance = jsonrpc.NefRequest(self.proxy, method)
702 path = self.proxy.root
703 payload = {}
704 content = {}
705 response = self.fake_response(method, path, payload, 404, content)
706 request.side_effect = [response, response]
707 result = instance.failover()
708 request.assert_called_once_with(method, path)
709 expected = False
710 self.assertEqual(expected, result)
712 @mock.patch('manila.share.drivers.nexenta.ns5.'
713 'jsonrpc.NefRequest.request')
714 def test_failover_error(self, request):
715 method = 'get'
716 instance = jsonrpc.NefRequest(self.proxy, method)
717 path = self.proxy.root
718 request.side_effect = [
719 requests.exceptions.Timeout,
720 requests.exceptions.ConnectionError
721 ]
722 result = instance.failover()
723 request.assert_called_with(method, path)
724 expected = False
725 self.assertEqual(expected, result)
727 def test_getpath(self):
728 method = 'get'
729 rel = 'monitor'
730 href = 'jobStatus/jobID'
731 content = {
732 'links': [
733 [1, 2],
734 'bad link',
735 {
736 'rel': 'next',
737 'href': href
738 },
739 {
740 'rel': rel,
741 'href': href
742 }
743 ]
744 }
745 instance = jsonrpc.NefRequest(self.proxy, method)
746 result = instance.getpath(content, rel)
747 expected = href
748 self.assertEqual(expected, result)
750 def test_getpath_no_content(self):
751 method = 'get'
752 rel = 'next'
753 content = None
754 instance = jsonrpc.NefRequest(self.proxy, method)
755 result = instance.getpath(content, rel)
756 self.assertIsNone(result)
758 def test_getpath_no_links(self):
759 method = 'get'
760 rel = 'next'
761 content = {'a': 'b'}
762 instance = jsonrpc.NefRequest(self.proxy, method)
763 result = instance.getpath(content, rel)
764 self.assertIsNone(result)
766 def test_getpath_no_rel(self):
767 method = 'get'
768 rel = 'next'
769 content = {
770 'links': [
771 {
772 'rel': 'monitor',
773 'href': '/jobs/jobID'
774 }
775 ]
776 }
777 instance = jsonrpc.NefRequest(self.proxy, method)
778 result = instance.getpath(content, rel)
779 self.assertIsNone(result)
781 def test_getpath_no_href(self):
782 method = 'get'
783 rel = 'next'
784 content = {
785 'links': [
786 {
787 'rel': rel
788 }
789 ]
790 }
791 instance = jsonrpc.NefRequest(self.proxy, method)
792 result = instance.getpath(content, rel)
793 self.assertIsNone(result)
796class TestNefCollections(test.TestCase):
798 def setUp(self):
799 super(TestNefCollections, self).setUp()
800 self.proxy = mock.Mock()
801 self.instance = jsonrpc.NefCollections(self.proxy)
803 def test_path(self):
804 path = 'path/to/item name + - & # $ = 0'
805 result = self.instance.path(path)
806 quoted_path = urlparse.quote_plus(path)
807 expected = posixpath.join(self.instance.root, quoted_path)
808 self.assertEqual(expected, result)
810 def test_get(self):
811 name = 'parent/child'
812 payload = {'key': 'value'}
813 expected = {'name': 'dataset'}
814 path = self.instance.path(name)
815 self.proxy.get.return_value = expected
816 result = self.instance.get(name, payload)
817 self.proxy.get.assert_called_with(path, payload)
818 self.assertEqual(expected, result)
820 def test_set(self):
821 name = 'parent/child'
822 payload = {'key': 'value'}
823 expected = None
824 path = self.instance.path(name)
825 self.proxy.put.return_value = expected
826 result = self.instance.set(name, payload)
827 self.proxy.put.assert_called_with(path, payload)
828 self.assertIsNone(result)
830 def test_list(self):
831 payload = {'key': 'value'}
832 expected = [{'name': 'dataset'}]
833 self.proxy.get.return_value = expected
834 result = self.instance.list(payload)
835 self.proxy.get.assert_called_with(self.instance.root, payload)
836 self.assertEqual(expected, result)
838 def test_create(self):
839 payload = {'key': 'value'}
840 expected = None
841 self.proxy.post.return_value = expected
842 result = self.instance.create(payload)
843 self.proxy.post.assert_called_with(self.instance.root, payload)
844 self.assertIsNone(result)
846 def test_create_exist(self):
847 payload = {'key': 'value'}
848 self.proxy.post.side_effect = jsonrpc.NefException(code='EEXIST')
849 result = self.instance.create(payload)
850 self.proxy.post.assert_called_with(self.instance.root, payload)
851 self.assertIsNone(result)
853 def test_create_error(self):
854 payload = {'key': 'value'}
855 self.proxy.post.side_effect = jsonrpc.NefException(code='EBUSY')
856 self.assertRaises(jsonrpc.NefException, self.instance.create, payload)
857 self.proxy.post.assert_called_with(self.instance.root, payload)
859 def test_delete(self):
860 name = 'parent/child'
861 payload = {'key': 'value'}
862 expected = None
863 path = self.instance.path(name)
864 self.proxy.delete.return_value = expected
865 result = self.instance.delete(name, payload)
866 self.proxy.delete.assert_called_with(path, payload)
867 self.assertIsNone(result)
869 def test_delete_not_found(self):
870 name = 'parent/child'
871 payload = {'key': 'value'}
872 path = self.instance.path(name)
873 self.proxy.delete.side_effect = jsonrpc.NefException(code='ENOENT')
874 result = self.instance.delete(name, payload)
875 self.proxy.delete.assert_called_with(path, payload)
876 self.assertIsNone(result)
878 def test_delete_error(self):
879 name = 'parent/child'
880 payload = {'key': 'value'}
881 path = self.instance.path(name)
882 self.proxy.delete.side_effect = jsonrpc.NefException(code='EINVAL')
883 self.assertRaises(jsonrpc.NefException, self.instance.delete, name,
884 payload)
885 self.proxy.delete.assert_called_with(path, payload)
888class TestNefSettings(test.TestCase):
890 def setUp(self):
891 super(TestNefSettings, self).setUp()
892 self.proxy = mock.Mock()
893 self.instance = jsonrpc.NefSettings(self.proxy)
895 def test_create(self):
896 payload = {'key': 'value'}
897 result = self.instance.create(payload)
898 expected = NotImplemented
899 self.assertEqual(expected, result)
901 def test_delete(self):
902 name = 'parent/child'
903 payload = {'key': 'value'}
904 result = self.instance.delete(name, payload)
905 expected = NotImplemented
906 self.assertEqual(expected, result)
909class TestNefDatasets(test.TestCase):
911 def setUp(self):
912 super(TestNefDatasets, self).setUp()
913 self.proxy = mock.Mock()
914 self.instance = jsonrpc.NefDatasets(self.proxy)
916 def test_rename(self):
917 name = 'parent/child'
918 payload = {'key': 'value'}
919 expected = None
920 path = self.instance.path(name)
921 path = posixpath.join(path, 'rename')
922 self.proxy.post.return_value = expected
923 result = self.instance.rename(name, payload)
924 self.proxy.post.assert_called_with(path, payload)
925 self.assertIsNone(result)
928class TestNefSnapshots(test.TestCase):
930 def setUp(self):
931 super(TestNefSnapshots, self).setUp()
932 self.proxy = mock.Mock()
933 self.instance = jsonrpc.NefSnapshots(self.proxy)
935 def test_clone(self):
936 name = 'parent/child'
937 payload = {'key': 'value'}
938 expected = None
939 path = self.instance.path(name)
940 path = posixpath.join(path, 'clone')
941 self.proxy.post.return_value = expected
942 result = self.instance.clone(name, payload)
943 self.proxy.post.assert_called_with(path, payload)
944 self.assertIsNone(result)
947class TestNefFilesystems(test.TestCase):
949 def setUp(self):
950 super(TestNefFilesystems, self).setUp()
951 self.proxy = mock.Mock()
952 self.instance = jsonrpc.NefFilesystems(self.proxy)
954 def test_mount(self):
955 name = 'parent/child'
956 payload = {'key': 'value'}
957 expected = None
958 path = self.instance.path(name)
959 path = posixpath.join(path, 'mount')
960 self.proxy.post.return_value = expected
961 result = self.instance.mount(name, payload)
962 self.proxy.post.assert_called_with(path, payload)
963 self.assertIsNone(result)
965 def test_unmount(self):
966 name = 'parent/child'
967 payload = {'key': 'value'}
968 expected = None
969 path = self.instance.path(name)
970 path = posixpath.join(path, 'unmount')
971 self.proxy.post.return_value = expected
972 result = self.instance.unmount(name, payload)
973 self.proxy.post.assert_called_with(path, payload)
974 self.assertIsNone(result)
976 def test_acl(self):
977 name = 'parent/child'
978 payload = {'key': 'value'}
979 expected = None
980 path = self.instance.path(name)
981 path = posixpath.join(path, 'acl')
982 self.proxy.post.return_value = expected
983 result = self.instance.acl(name, payload)
984 self.proxy.post.assert_called_with(path, payload)
985 self.assertIsNone(result)
987 def test_promote(self):
988 name = 'parent/child'
989 payload = {'key': 'value'}
990 expected = None
991 path = self.instance.path(name)
992 path = posixpath.join(path, 'promote')
993 self.proxy.post.return_value = expected
994 result = self.instance.promote(name, payload)
995 self.proxy.post.assert_called_with(path, payload)
996 self.assertIsNone(result)
998 def test_rollback(self):
999 name = 'parent/child'
1000 payload = {'key': 'value'}
1001 expected = None
1002 path = self.instance.path(name)
1003 path = posixpath.join(path, 'rollback')
1004 self.proxy.post.return_value = expected
1005 result = self.instance.rollback(name, payload)
1006 self.proxy.post.assert_called_with(path, payload)
1007 self.assertIsNone(result)
1010class TestNefHpr(test.TestCase):
1012 def setUp(self):
1013 super(TestNefHpr, self).setUp()
1014 self.proxy = mock.Mock()
1015 self.instance = jsonrpc.NefHpr(self.proxy)
1017 def test_activate(self):
1018 payload = {'key': 'value'}
1019 expected = None
1020 path = posixpath.join(self.instance.root, 'activate')
1021 self.proxy.post.return_value = expected
1022 result = self.instance.activate(payload)
1023 self.proxy.post.assert_called_with(path, payload)
1024 self.assertIsNone(result)
1026 def test_start(self):
1027 name = 'parent/child'
1028 payload = {'key': 'value'}
1029 expected = None
1030 path = posixpath.join(self.instance.path(name), 'start')
1031 self.proxy.post.return_value = expected
1032 result = self.instance.start(name, payload)
1033 self.proxy.post.assert_called_with(path, payload)
1034 self.assertIsNone(result)
1037class TestNefProxy(test.TestCase):
1039 def setUp(self):
1040 super(TestNefProxy, self).setUp()
1041 self.cfg = mock.Mock(spec=conf.Configuration)
1042 self.cfg.nexenta_use_https = True
1043 self.cfg.nexenta_ssl_cert_verify = True
1044 self.cfg.nexenta_user = 'user'
1045 self.cfg.nexenta_password = 'pass'
1046 self.cfg.nexenta_rest_addresses = ['1.1.1.1', '2.2.2.2']
1047 self.cfg.nexenta_rest_port = 8443
1048 self.cfg.nexenta_rest_backoff_factor = 1
1049 self.cfg.nexenta_rest_retry_count = 3
1050 self.cfg.nexenta_rest_connect_timeout = 1
1051 self.cfg.nexenta_rest_read_timeout = 1
1052 self.cfg.nexenta_nas_host = '3.3.3.3'
1053 self.cfg.nexenta_folder = 'pool/path/to/share'
1054 self.nef_mock = mock.Mock()
1055 self.mock_object(jsonrpc, 'NefRequest')
1057 self.proto = 'nfs'
1058 self.proxy = jsonrpc.NefProxy(self.proto,
1059 self.cfg.nexenta_folder,
1060 self.cfg)
1062 def test___init___http(self):
1063 proto = 'nfs'
1064 cfg = copy.copy(self.cfg)
1065 cfg.nexenta_use_https = False
1066 result = jsonrpc.NefProxy(proto, cfg.nexenta_folder, cfg)
1067 self.assertIsInstance(result, jsonrpc.NefProxy)
1069 def test___init___no_rest_port_http(self):
1070 proto = 'nfs'
1071 cfg = copy.copy(self.cfg)
1072 cfg.nexenta_rest_port = 0
1073 cfg.nexenta_use_https = False
1074 result = jsonrpc.NefProxy(proto, cfg.nexenta_folder, cfg)
1075 self.assertIsInstance(result, jsonrpc.NefProxy)
1077 def test___init___no_rest_port_https(self):
1078 proto = 'nfs'
1079 cfg = copy.copy(self.cfg)
1080 cfg.nexenta_rest_port = 0
1081 cfg.nexenta_use_https = True
1082 result = jsonrpc.NefProxy(proto, cfg.nexenta_folder, cfg)
1083 self.assertIsInstance(result, jsonrpc.NefProxy)
1085 def test___init___iscsi(self):
1086 proto = 'iscsi'
1087 cfg = copy.copy(self.cfg)
1088 result = jsonrpc.NefProxy(proto, cfg.nexenta_folder, cfg)
1089 self.assertIsInstance(result, jsonrpc.NefProxy)
1091 def test___init___nfs_no_rest_address(self):
1092 proto = 'nfs'
1093 cfg = copy.copy(self.cfg)
1094 cfg.nexenta_rest_addresses = ''
1095 result = jsonrpc.NefProxy(proto, cfg.nexenta_folder, cfg)
1096 self.assertIsInstance(result, jsonrpc.NefProxy)
1098 def test___init___iscsi_no_rest_address(self):
1099 proto = 'iscsi'
1100 cfg = copy.copy(self.cfg)
1101 cfg.nexenta_rest_addresses = ''
1102 cfg.nexenta_nas_host = '4.4.4.4'
1103 result = jsonrpc.NefProxy(proto, cfg.nexenta_folder, cfg)
1104 self.assertIsInstance(result, jsonrpc.NefProxy)
1106 @mock.patch('requests.packages.urllib3.disable_warnings')
1107 def test___init___no_ssl_cert_verify(self, disable_warnings):
1108 proto = 'nfs'
1109 cfg = copy.copy(self.cfg)
1110 cfg.nexenta_ssl_cert_verify = False
1111 disable_warnings.return_value = None
1112 result = jsonrpc.NefProxy(proto, cfg.nexenta_folder, cfg)
1113 disable_warnings.assert_called()
1114 self.assertIsInstance(result, jsonrpc.NefProxy)
1116 def test_delete_bearer(self):
1117 self.assertIsNone(self.proxy.delete_bearer())
1118 self.assertNotIn('Authorization', self.proxy.session.headers)
1119 self.proxy.session.headers['Authorization'] = 'Bearer token'
1120 self.assertIsNone(self.proxy.delete_bearer())
1121 self.assertNotIn('Authorization', self.proxy.session.headers)
1123 def test_update_bearer(self):
1124 token = 'token'
1125 bearer = 'Bearer %s' % token
1126 self.assertNotIn('Authorization', self.proxy.session.headers)
1127 self.assertIsNone(self.proxy.update_bearer(token))
1128 self.assertIn('Authorization', self.proxy.session.headers)
1129 self.assertEqual(self.proxy.session.headers['Authorization'], bearer)
1131 def test_update_token(self):
1132 token = 'token'
1133 bearer = 'Bearer %s' % token
1134 self.assertIsNone(self.proxy.update_token(token))
1135 self.assertEqual(self.proxy.tokens[self.proxy.host], token)
1136 self.assertEqual(self.proxy.session.headers['Authorization'], bearer)
1138 def test_update_host(self):
1139 token = 'token'
1140 bearer = 'Bearer %s' % token
1141 host = self.cfg.nexenta_rest_addresses[0]
1142 self.proxy.tokens[host] = token
1143 self.assertIsNone(self.proxy.update_host(host))
1144 self.assertEqual(self.proxy.session.headers['Authorization'], bearer)
1146 def test_skip_update_host(self):
1147 host = 'nonexistent'
1148 self.assertIsNone(self.proxy.update_host(host))
1150 @mock.patch('manila.share.drivers.nexenta.ns5.'
1151 'jsonrpc.NefSettings.get')
1152 def test_update_lock(self, get_settings):
1153 guid = uuid.uuid4().hex
1154 settings = {'value': guid}
1155 get_settings.return_value = settings
1156 self.assertIsNone(self.proxy.update_lock())
1157 path = '%s:%s' % (guid, self.proxy.path)
1158 if isinstance(path, str): 1158 ↛ 1160line 1158 didn't jump to line 1160 because the condition on line 1158 was always true
1159 path = path.encode('utf-8')
1160 expected = hashlib.md5(path).hexdigest()
1161 self.assertEqual(expected, self.proxy.lock)
1163 def test_url(self):
1164 path = '/path/to/api'
1165 result = self.proxy.url(path)
1166 expected = '%s://%s:%s%s' % (self.proxy.scheme,
1167 self.proxy.host,
1168 self.proxy.port,
1169 path)
1170 self.assertEqual(expected, result)
1172 @mock.patch('time.sleep')
1173 def test_delay(self, sleep):
1174 sleep.return_value = None
1175 for attempt in range(0, 10):
1176 expected = int(self.proxy.backoff_factor * (2 ** (attempt - 1)))
1177 self.assertIsNone(self.proxy.delay(attempt))
1178 sleep.assert_called_with(expected)