Skip to content

Commit 29dd147

Browse files
authored
Saimon/refactor ut (#288)
1 parent d93c3cb commit 29dd147

File tree

121 files changed

+862
-276
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+862
-276
lines changed

cterasdk/asynchronous/core/notifications.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ async def get(self, cloudfolders=None, cursor=None, max_results=None):
3232
param.max_results = max_results if max_results is not None else 2000
3333
logging.getLogger('cterasdk.metadata.connector').debug('Listing updates.')
3434
response = await self._core.v2.api.post('/metadata/list', param)
35+
print(response)
3536
if response is not None:
3637
return CursorResponse(response)
3738
logging.getLogger('cterasdk.metadata.connector').error('An error occurred while trying to retrieve notifications.')
@@ -197,13 +198,13 @@ async def persist_cursor(save_cursor, cursor):
197198
:param callback save_cursor: Asynchronous callback function to persist the cursor.
198199
:param str cursor: Cursor
199200
"""
200-
logging.getLogger('cterasdk.metadata.connector').debug("Persisting Cursor. Calling function: '%s'", save_cursor.__name__)
201+
logging.getLogger('cterasdk.metadata.connector').debug("Persisting Cursor. Calling function: '%s'", save_cursor)
201202
try:
202203
await save_cursor(cursor)
203204
logging.getLogger('cterasdk.metadata.connector').debug("Called Persist Cursor Function.")
204205
except Exception: # pylint: disable=broad-exception-caught
205206
logging.getLogger('cterasdk.metadata.connector').error("An error occurred while trying to persist cursor. Function: '%s'",
206-
save_cursor.__name__)
207+
save_cursor)
207208

208209

209210
async def on_connection_error(error):

docs/source/UserGuides/Portal/Administration.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1573,7 +1573,7 @@ Timezone
15731573
15741574
.. code:: python
15751575
1576-
admin.settings.global_settings.set_timzeone('(GMT-05:00) Eastern Time (US , Canada)')
1576+
admin.settings.global_settings.set_timezone('(GMT-05:00) Eastern Time (US , Canada)')
15771577
15781578
15791579
Virtual Portal Settings

tests/ut/aio/__init__.py

Whitespace-only changes.

tests/ut/aio/base.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import unittest
2+
from ..common import utilities
3+
4+
5+
class BaseAsyncTest(unittest.IsolatedAsyncioTestCase):
6+
"""Base Async Test"""
7+
8+
def patch_call(self, module_path, **patch_kwargs):
9+
return utilities.patch_call(self, module_path, **patch_kwargs)
10+
11+
def patch_property(self, module_path, **patch_kwargs):
12+
return utilities.patch_property(self, module_path, **patch_kwargs)
13+
14+
def assert_equal_objects(self, actual_param, expected_param):
15+
return utilities.assert_equal_objects(self, actual_param, expected_param)

tests/ut/aio/base_core.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from unittest import mock
2+
3+
from cterasdk.objects import AsyncGlobalAdmin
4+
from tests.ut.aio import base
5+
6+
7+
class BaseAsyncCoreTest(base.BaseAsyncTest):
8+
9+
def setUp(self):
10+
super().setUp()
11+
self._global_admin = AsyncGlobalAdmin("")
12+
13+
def _init_global_admin(self, get_multi_response=None, form_data_response=None, post_response=None):
14+
self._global_admin.v1.api.get_multi = mock.AsyncMock(return_value=get_multi_response)
15+
self._global_admin.v1.api.form_data = mock.AsyncMock(return_value=form_data_response)
16+
self._global_admin.v2.api.post = mock.AsyncMock(return_value=post_response)

tests/ut/aio/direct/__init__.py

Whitespace-only changes.

tests/ut/aio/direct/base.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from unittest import mock
2+
from cterasdk import ctera_direct
3+
from .. import base
4+
5+
6+
class BaseAsyncDirect(base.BaseAsyncTest):
7+
8+
def setUp(self, access=None, secret=None):
9+
super().setUp()
10+
self._direct = ctera_direct.client.DirectIO('', access, secret)
11+
self._direct._client._api.get = mock.AsyncMock() # pylint: disable=protected-access
12+
self._direct._client._client.get = mock.AsyncMock() # pylint: disable=protected-access
13+
self._authorization_header = {'Authorization': f'Bearer {access}'}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import asyncio
2+
import errno
3+
from unittest import mock
4+
import munch
5+
from cterasdk import ctera_direct
6+
from cterasdk import exceptions, Object
7+
from . import base
8+
9+
10+
class BaseDirectMetadata(base.BaseAsyncDirect):
11+
12+
def setUp(self): # pylint: disable=arguments-differ
13+
super().setUp()
14+
self._retries = 3
15+
self._file_id = 12345
16+
17+
async def test_retries_on_error(self):
18+
self._direct._client._api.get.return_value = munch.Munch({'chunks': None}) # pylint: disable=protected-access
19+
with mock.patch('asyncio.sleep'):
20+
with self.assertRaises(ctera_direct.exceptions.BlocksNotFoundError):
21+
await self._direct.metadata(self._file_id)
22+
self._direct._client._api.get.assert_has_calls( # pylint: disable=protected-access
23+
self._retries * [
24+
mock.call(f'{self._file_id}', headers=self._authorization_header),
25+
]
26+
)
27+
28+
async def test_get_file_metadata_not_found(self):
29+
self._direct._client._api.get.return_value = munch.Munch({'chunks': None}) # pylint: disable=protected-access
30+
with mock.patch('asyncio.sleep'):
31+
with self.assertRaises(ctera_direct.exceptions.BlocksNotFoundError) as error:
32+
await self._direct.metadata(self._file_id)
33+
self.assertEqual(error.exception.errno, errno.ENODATA)
34+
self.assertEqual(error.exception.strerror, 'Blocks not found')
35+
self.assertEqual(error.exception.filename, self._file_id)
36+
37+
async def test_get_file_metadata_error_400(self):
38+
self._direct._client._api.get.side_effect = exceptions.ClientResponseException( # pylint: disable=protected-access
39+
BaseDirectMetadata._create_error_object(400)
40+
)
41+
with mock.patch('asyncio.sleep'):
42+
with self.assertRaises(ctera_direct.exceptions.NotFoundError) as error:
43+
await self._direct.metadata(self._file_id)
44+
self.assertEqual(error.exception.errno, errno.EBADF)
45+
self.assertEqual(error.exception.strerror, 'File not found')
46+
self.assertEqual(error.exception.filename, self._file_id)
47+
48+
async def test_get_file_metadata_error_401(self):
49+
self._direct._client._api.get.side_effect = exceptions.ClientResponseException( # pylint: disable=protected-access
50+
BaseDirectMetadata._create_error_object(401)
51+
)
52+
with mock.patch('asyncio.sleep'):
53+
with self.assertRaises(ctera_direct.exceptions.UnAuthorized) as error:
54+
await self._direct.metadata(self._file_id)
55+
self.assertEqual(error.exception.errno, errno.EACCES)
56+
self.assertEqual(error.exception.strerror, 'Unauthorized: You do not have the necessary permissions to access this resource')
57+
self.assertEqual(error.exception.filename, self._file_id)
58+
59+
async def test_get_file_metadata_error_422(self):
60+
self._direct._client._api.get.side_effect = exceptions.ClientResponseException( # pylint: disable=protected-access
61+
BaseDirectMetadata._create_error_object(422)
62+
)
63+
with mock.patch('asyncio.sleep'):
64+
with self.assertRaises(ctera_direct.exceptions.UnprocessableContent) as error:
65+
await self._direct.metadata(self._file_id)
66+
self.assertEqual(error.exception.errno, errno.ENOTSUP)
67+
self.assertEqual(error.exception.strerror, 'Not all blocks of the requested file are stored on a storage node set to Direct Mode')
68+
self.assertEqual(error.exception.filename, self._file_id)
69+
70+
async def test_get_file_metadata_unknown_error(self):
71+
self._direct._client._api.get.side_effect = exceptions.ClientResponseException( # pylint: disable=protected-access
72+
BaseDirectMetadata._create_error_object(500)
73+
)
74+
with mock.patch('asyncio.sleep'):
75+
with self.assertRaises(exceptions.ClientResponseException) as error:
76+
await self._direct.metadata(self._file_id)
77+
self.assertEqual(error.exception.message, 'An error occurred while processing the HTTP request.')
78+
79+
async def test_get_file_metadata_connection_error(self):
80+
self._direct._client._api.get.side_effect = ConnectionError # pylint: disable=protected-access
81+
with mock.patch('asyncio.sleep'):
82+
with self.assertRaises(ctera_direct.exceptions.BlockListConnectionError) as error:
83+
await self._direct.metadata(self._file_id)
84+
self.assertEqual(error.exception.errno, errno.ENETRESET)
85+
self.assertEqual(error.exception.strerror, 'Failed to list blocks. Connection error')
86+
self.assertEqual(error.exception.filename, self._file_id)
87+
88+
async def test_get_file_metadata_timeout(self):
89+
self._direct._client._api.get.side_effect = asyncio.TimeoutError # pylint: disable=protected-access
90+
with mock.patch('asyncio.sleep'):
91+
with self.assertRaises(ctera_direct.exceptions.BlockListTimeout) as error:
92+
await self._direct.metadata(self._file_id)
93+
self.assertEqual(error.exception.errno, errno.ETIMEDOUT)
94+
self.assertEqual(error.exception.strerror, 'Failed to list blocks. Timed out')
95+
self.assertEqual(error.exception.filename, self._file_id)
96+
97+
@staticmethod
98+
def _create_error_object(status):
99+
param = Object()
100+
param.response = Object()
101+
param.response.status = status
102+
return param
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import asyncio
2+
import errno
3+
from unittest import mock
4+
import munch
5+
from cterasdk.direct.lib import get_object
6+
from cterasdk import exceptions, ctera_direct, Object
7+
from . import base
8+
9+
10+
class BaseDirectMetadata(base.BaseAsyncDirect):
11+
12+
def setUp(self): # pylint: disable=arguments-differ
13+
super().setUp()
14+
self._retries = 3
15+
self._file_id = 12345
16+
17+
async def test_get_object_connection_error(self):
18+
chunk = BaseDirectMetadata._create_chunk()
19+
self._direct._client._client.get.side_effect = ConnectionError # pylint: disable=protected-access
20+
with mock.patch('asyncio.sleep'):
21+
with self.assertRaises(ctera_direct.exceptions.DownloadConnectionError) as error:
22+
await get_object(self._direct._client._client, self._file_id, chunk) # pylint: disable=protected-access
23+
self.assertEqual(error.exception.errno, errno.ENETRESET)
24+
self.assertEqual(error.exception.strerror, 'Failed to download block. Connection error')
25+
self.assertEqual(error.exception.filename, self._file_id)
26+
self.assert_equal_objects(error.exception.block, BaseDirectMetadata._create_block_info(self._file_id, chunk))
27+
28+
async def test_get_object_timeout(self):
29+
chunk = BaseDirectMetadata._create_chunk()
30+
self._direct._client._client.get.side_effect = asyncio.TimeoutError # pylint: disable=protected-access
31+
with mock.patch('asyncio.sleep'):
32+
with self.assertRaises(ctera_direct.exceptions.DownloadTimeout) as error:
33+
await get_object(self._direct._client._client, self._file_id, chunk) # pylint: disable=protected-access
34+
self.assertEqual(error.exception.errno, errno.ETIMEDOUT)
35+
self.assertEqual(error.exception.strerror, 'Failed to download block. Timed out')
36+
self.assertEqual(error.exception.filename, self._file_id)
37+
self.assert_equal_objects(error.exception.block, BaseDirectMetadata._create_block_info(self._file_id, chunk))
38+
39+
async def test_response_read_io_error(self):
40+
message = 'Error reading block.'
41+
chunk = BaseDirectMetadata._create_chunk()
42+
43+
async def stream_reader():
44+
raise IOError(message)
45+
46+
self._direct._client._client.get.return_value = munch.Munch({'read': stream_reader}) # pylint: disable=protected-access
47+
with mock.patch('asyncio.sleep'):
48+
with self.assertRaises(ctera_direct.exceptions.DownloadError) as error:
49+
await get_object(self._direct._client._client, self._file_id, chunk) # pylint: disable=protected-access
50+
self.assertEqual(error.exception.errno, errno.EIO)
51+
self.assertEqual(str(error.exception.strerror), message)
52+
self.assertEqual(error.exception.filename, self._file_id)
53+
self.assert_equal_objects(error.exception.block, BaseDirectMetadata._create_block_info(self._file_id, chunk))
54+
55+
async def test_get_client_error(self):
56+
chunk = BaseDirectMetadata._create_chunk()
57+
self._direct._client._client.get.side_effect = exceptions.ClientResponseException( # pylint: disable=protected-access
58+
self._create_error_object(500)
59+
)
60+
with mock.patch('asyncio.sleep'):
61+
with self.assertRaises(ctera_direct.exceptions.DownloadError) as error:
62+
await get_object(self._direct._client._client, self._file_id, chunk) # pylint: disable=protected-access
63+
self.assertEqual(error.exception.errno, errno.EIO)
64+
self.assertEqual(error.exception.strerror.status, 500)
65+
self.assertEqual(error.exception.filename, self._file_id)
66+
self.assert_equal_objects(error.exception.block, BaseDirectMetadata._create_block_info(self._file_id, chunk))
67+
68+
@staticmethod
69+
def _create_error_object(status):
70+
param = Object()
71+
param.response = Object()
72+
param.response.status = status
73+
return param
74+
75+
@staticmethod
76+
def _create_block_info(file_id, chunk):
77+
return munch.Munch({
78+
'file_id': file_id,
79+
'number': chunk.index,
80+
'offset': chunk.offset,
81+
'length': chunk.length
82+
})
83+
84+
@staticmethod
85+
def _create_chunk():
86+
return munch.Munch({
87+
'url': 'https://s3.amazonaws.com/test',
88+
'index': 1,
89+
'offset': 0,
90+
'length': 4096
91+
})

tests/ut/aio/test_cloudfs_drives.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from unittest import mock
2+
import munch
3+
from cterasdk.asynchronous.core import cloudfs
4+
from cterasdk.core.query import QueryParamBuilder, FilterBuilder
5+
from tests.ut.aio import base_core
6+
7+
8+
class TestAsyncCoreUsers(base_core.BaseAsyncCoreTest):
9+
10+
def setUp(self):
11+
super().setUp()
12+
self._user_id = 56
13+
self._name = 'My Files'
14+
self._owner = 'owner'
15+
16+
async def test_find(self):
17+
self._global_admin.users.get = mock.AsyncMock(return_value=munch.Munch({'uid': self._user_id}))
18+
builder = QueryParamBuilder().include(cloudfs.CloudDrives.default).ownedBy(self._user_id)
19+
builder.addFilter(FilterBuilder('name').eq(self._name))
20+
expected_param = builder.build()
21+
with mock.patch("cterasdk.asynchronous.core.cloudfs.query.iterator") as query_iterator_mock:
22+
await cloudfs.CloudDrives(self._global_admin).find(self._name, self._owner)
23+
self._global_admin.users.get.assert_called_once_with(self._owner, ['uid'])
24+
query_iterator_mock.assert_called_once_with(self._global_admin, '/cloudDrives', mock.ANY)
25+
self.assert_equal_objects(query_iterator_mock.call_args[0][2], expected_param)

tests/ut/aio/test_login.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from unittest import mock
2+
from cterasdk.common import Object
3+
from cterasdk import exceptions
4+
from tests.ut.aio import base_core
5+
6+
7+
class TestAsyncCoreLogin(base_core.BaseAsyncCoreTest):
8+
9+
_tenant = 'ctera'
10+
_username = 'username'
11+
_password = 'password'
12+
_version = '7.5.182.16'
13+
14+
def setUp(self):
15+
super().setUp()
16+
self._tenant = TestAsyncCoreLogin._tenant
17+
self._username = TestAsyncCoreLogin._username
18+
self._password = TestAsyncCoreLogin._password
19+
self._version = TestAsyncCoreLogin._version
20+
21+
async def test_login_success(self):
22+
self._init_global_admin()
23+
self._global_admin.v1.api.get = mock.AsyncMock(side_effect=TestAsyncCoreLogin._obtain_session_info)
24+
await self._global_admin.login(self._username, self._password)
25+
self._global_admin.v1.api.form_data.assert_called_once_with('/login', {'j_username': self._username, 'j_password': self._password})
26+
27+
async def test_login_failure(self):
28+
self._init_global_admin()
29+
self._global_admin.v1.api.form_data = mock.AsyncMock(side_effect=exceptions.ClientResponseException(Object()))
30+
with self.assertRaises(exceptions.CTERAException):
31+
await self._global_admin.login(self._username, self._password)
32+
33+
async def test_logout_success_after_login(self):
34+
self._init_global_admin()
35+
self._global_admin.v1.api.get = mock.AsyncMock(side_effect=TestAsyncCoreLogin._obtain_session_info)
36+
await self._global_admin.login(self._username, self._password)
37+
await self._global_admin.logout()
38+
self._global_admin.v1.api.form_data.assert_has_calls(
39+
[
40+
mock.call('/login', {'j_username': self._username, 'j_password': self._password}),
41+
mock.call('/logout', {})
42+
]
43+
)
44+
45+
@staticmethod
46+
def _obtain_session_info(path):
47+
if path == '/currentPortal':
48+
return TestAsyncCoreLogin._tenant
49+
if path == '/version':
50+
return TestAsyncCoreLogin._version
51+
if path == '/currentSession':
52+
current_session = Object()
53+
current_session.username = TestAsyncCoreLogin._username
54+
current_session.role = TestAsyncCoreLogin._password
55+
current_session.domain = None
56+
return current_session
57+
return ''

0 commit comments

Comments
 (0)