forked from shaba/openuds
Adding more tests and fixes
This commit is contained in:
parent
5f12c2e7b3
commit
69b778c922
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2020 Virtual Cable S.L.
|
# Copyright (c) 2020-2022 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -35,7 +35,7 @@ import os
|
|||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import PyQt5 # pylint: disable=unused-import
|
import PyQt5 # Ensures PyQt is included in the package
|
||||||
from PyQt5.QtWidgets import QApplication, QDialog, QFileDialog, QMessageBox
|
from PyQt5.QtWidgets import QApplication, QDialog, QFileDialog, QMessageBox
|
||||||
|
|
||||||
import udsactor
|
import udsactor
|
||||||
|
@ -326,6 +326,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
if self.isManaged()
|
if self.isManaged()
|
||||||
else (initResult.alias_token or self._cfg.master_token)
|
else (initResult.alias_token or self._cfg.master_token)
|
||||||
)
|
)
|
||||||
|
# Replace master token with alias token if present
|
||||||
self._cfg = self._cfg._replace(
|
self._cfg = self._cfg._replace(
|
||||||
master_token=master_token,
|
master_token=master_token,
|
||||||
own_token=initResult.own_token,
|
own_token=initResult.own_token,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2022 Virtual Cable S.L.U.
|
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||||
@ -29,6 +28,5 @@
|
|||||||
"""
|
"""
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
"""
|
"""
|
||||||
from . import test_login_logout
|
|
||||||
from . import test_register
|
from . import actor
|
||||||
from . import test_initialize
|
|
||||||
|
34
server/src/tests/REST/actor/__init__.py
Normal file
34
server/src/tests/REST/actor/__init__.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
"""
|
||||||
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
|
"""
|
||||||
|
from . import test_login_logout
|
||||||
|
from . import test_register
|
||||||
|
from . import test_initialize
|
@ -37,9 +37,8 @@ from django.conf import settings
|
|||||||
from uds import models
|
from uds import models
|
||||||
from uds.core import VERSION
|
from uds.core import VERSION
|
||||||
from uds.REST.handlers import AUTH_TOKEN_HEADER
|
from uds.REST.handlers import AUTH_TOKEN_HEADER
|
||||||
from uds.models import user_service
|
|
||||||
|
|
||||||
from ..utils import rest, constants
|
from ...utils import rest
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -153,35 +152,42 @@ class ActorInitializeV3(rest.test.RESTTestCase):
|
|||||||
success = functools.partial(self.invoke_success, 'unmanaged')
|
success = functools.partial(self.invoke_success, 'unmanaged')
|
||||||
failure = functools.partial(self.invoke_failure, 'unmanaged')
|
failure = functools.partial(self.invoke_failure, 'unmanaged')
|
||||||
|
|
||||||
# This will succeed, but only alias token is provided
|
# This will succeed, but only alias token is returned because MAC is not registered by UDS
|
||||||
result = success(
|
result = success(
|
||||||
actor_token,
|
actor_token,
|
||||||
mac='00:00:00:00:00:00',
|
mac='00:00:00:00:00:00',
|
||||||
)
|
)
|
||||||
|
|
||||||
alias_token = result['alias_token']
|
|
||||||
|
|
||||||
# Unmanaged host is the response for initialization of unmanaged actor ALWAYS
|
# Unmanaged host is the response for initialization of unmanaged actor ALWAYS
|
||||||
|
self.assertIsNone(result['alias_token'])
|
||||||
self.assertIsNone(result['own_token'])
|
self.assertIsNone(result['own_token'])
|
||||||
self.assertIsInstance(alias_token, str)
|
|
||||||
self.assertIsNone(result['unique_id'])
|
self.assertIsNone(result['unique_id'])
|
||||||
self.assertIsNone(result['os'])
|
self.assertIsNone(result['os'])
|
||||||
|
|
||||||
|
# Now, invoke a "nice" initialize
|
||||||
|
result = success(
|
||||||
|
actor_token,
|
||||||
|
mac=unique_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
alias_token = result['alias_token']
|
||||||
|
|
||||||
|
self.assertIsInstance(alias_token, str)
|
||||||
|
self.assertEqual(result['own_token'], user_service.uuid)
|
||||||
|
self.assertEqual(result['alias_token'], alias_token)
|
||||||
|
self.assertEqual(result['unique_id'], unique_id)
|
||||||
|
|
||||||
# Ensure that the alias returned is on alias db, and it points to the same service as the one we belong to
|
# Ensure that the alias returned is on alias db, and it points to the same service as the one we belong to
|
||||||
alias = models.ServiceTokenAlias.objects.get(alias=result['alias_token'])
|
alias = models.ServiceTokenAlias.objects.get(alias=result['alias_token'])
|
||||||
self.assertEqual(alias.service, user_service.deployed_service.service)
|
self.assertEqual(alias.service, user_service.deployed_service.service)
|
||||||
|
|
||||||
# Now, we should be able to "initialize" with valid mac and with original and alias tokens
|
# Now, we should be able to "initialize" with valid mac and with original and alias tokens
|
||||||
# If we call initialize and we get "own-token" means that we have already logged in with this data
|
# If we call initialize and we get "own-token" means that we have already logged in with this data
|
||||||
result = success(
|
result = success(alias_token, mac=unique_id)
|
||||||
alias_token,
|
|
||||||
mac=unique_id
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(result['own_token'], user_service.uuid)
|
self.assertEqual(result['own_token'], user_service.uuid)
|
||||||
self.assertEqual(result['alias_token'], alias_token)
|
self.assertEqual(result['alias_token'], alias_token)
|
||||||
self.assertEqual(result['unique_id'], unique_id)
|
self.assertEqual(result['unique_id'], unique_id)
|
||||||
|
|
||||||
|
#
|
||||||
|
failure('invalid token', unique_id, True)
|
||||||
logger.info('Result: %s', result)
|
|
@ -32,8 +32,8 @@ import random
|
|||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
|
||||||
from .. import fixtures
|
from ... import fixtures
|
||||||
from ..utils import rest, test
|
from ...utils import rest, test
|
||||||
|
|
||||||
|
|
||||||
class RESTLoginLogoutCase(test.UDSTestCase):
|
class RESTLoginLogoutCase(test.UDSTestCase):
|
||||||
@ -41,7 +41,7 @@ class RESTLoginLogoutCase(test.UDSTestCase):
|
|||||||
Test login and logout
|
Test login and logout
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_login_logout(self):
|
def test_login_logout(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test login and logout
|
Test login and logout
|
||||||
"""
|
"""
|
@ -31,12 +31,10 @@
|
|||||||
import typing
|
import typing
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from uds import models
|
from uds import models
|
||||||
from uds.REST.handlers import AUTH_TOKEN_HEADER
|
from uds.REST.handlers import AUTH_TOKEN_HEADER
|
||||||
|
|
||||||
from ..utils import rest, constants
|
from ...utils import rest, constants
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
@ -34,7 +34,7 @@ import logging
|
|||||||
from uds.REST.handlers import AUTH_TOKEN_HEADER
|
from uds.REST.handlers import AUTH_TOKEN_HEADER
|
||||||
from uds.REST.methods.actor_v3 import MANAGED, UNMANAGED, ALLOWED_FAILS
|
from uds.REST.methods.actor_v3 import MANAGED, UNMANAGED, ALLOWED_FAILS
|
||||||
|
|
||||||
from ..utils import rest
|
from ...utils import rest
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2022 Virtual Cable S.L.
|
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -11,7 +11,7 @@
|
|||||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
# and/or other materials provided with the distribution.
|
# and/or other materials provided with the distribution.
|
||||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||||
# may be used to endorse or promote products derived from this software
|
# may be used to endorse or promote products derived from this software
|
||||||
# without specific prior written permission.
|
# without specific prior written permission.
|
||||||
#
|
#
|
||||||
@ -28,5 +28,5 @@
|
|||||||
"""
|
"""
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
"""
|
"""
|
||||||
from . import test_cache
|
from . import util
|
||||||
from . import test_stats_counters
|
from . import managers
|
0
server/src/tests/core/managers/__init__.py
Normal file
0
server/src/tests/core/managers/__init__.py
Normal file
1
server/src/tests/core/managers/downloadable.txt
Normal file
1
server/src/tests/core/managers/downloadable.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
This file is the downloadable for download manager tests
|
114
server/src/tests/core/managers/test_downloads.py
Normal file
114
server/src/tests/core/managers/test_downloads.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
"""
|
||||||
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
|
"""
|
||||||
|
import typing
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# We use commit/rollback
|
||||||
|
from ...utils.test import UDSTransactionTestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
from uds.core.managers.downloads import DownloadsManager
|
||||||
|
|
||||||
|
from uds.core.util.config import GlobalConfig
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
class DownloadsManagerTests(UDSTransactionTestCase):
|
||||||
|
filePath: str = ''
|
||||||
|
manager: DownloadsManager
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
from uds.core.managers import downloadsManager
|
||||||
|
|
||||||
|
super(DownloadsManagerTests, cls).setUpClass()
|
||||||
|
|
||||||
|
cls.filePath = os.path.join(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)), 'downloadable.txt'
|
||||||
|
)
|
||||||
|
cls.manager = downloadsManager()
|
||||||
|
|
||||||
|
def test_downloads(self):
|
||||||
|
for v in (
|
||||||
|
('test.txt', 'text/plain', '1f47ec0a-1ad4-5d63-b41c-5d2befadab8d'),
|
||||||
|
(
|
||||||
|
'test.bin',
|
||||||
|
'application/octet-stream',
|
||||||
|
'6454d619-cc62-5bd4-aa9a-c9e2458d44da',
|
||||||
|
),
|
||||||
|
):
|
||||||
|
fileName, mimeType, knownUuid = v
|
||||||
|
self.manager.registerDownloadable(
|
||||||
|
fileName,
|
||||||
|
'This is the test file {}'.format(fileName),
|
||||||
|
self.filePath,
|
||||||
|
mimeType,
|
||||||
|
)
|
||||||
|
|
||||||
|
downloadables = self.manager.getDownloadables()
|
||||||
|
|
||||||
|
self.assertIn(
|
||||||
|
knownUuid,
|
||||||
|
downloadables,
|
||||||
|
'The File {} was not found in downloadables!'.format(fileName),
|
||||||
|
)
|
||||||
|
|
||||||
|
# This will fail, no user has logged in
|
||||||
|
self.client.get(
|
||||||
|
reverse('utility.downloader', kwargs={'idDownload': knownUuid})
|
||||||
|
)
|
||||||
|
# Remove last '/' for redirect check. URL redirection will not contain it
|
||||||
|
# Commented because i don't know why when executed in batch returns the last '/', and alone don't
|
||||||
|
# self.assertRedirects(response, reverse('uds.web.views.login'), fetch_redirect_response=False)
|
||||||
|
|
||||||
|
# And try to download again
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('utility.downloader', kwargs={'idDownload': knownUuid})
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
response.get('Content-Type'),
|
||||||
|
mimeType,
|
||||||
|
'Mime type of {} is not {} as expected (it is {})'.format(
|
||||||
|
fileName, mimeType, response.get('Content-Type')
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.assertContains(
|
||||||
|
response,
|
||||||
|
'This file is the downloadable for download manager tests',
|
||||||
|
msg_prefix='File does not seems to be fine',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Now do logout
|
||||||
|
# response = client.get(reverse('uds.web.views.logout'))
|
||||||
|
# self.assertRedirects(response, reverse('uds.web.views.login')[:-1], fetch_redirect_response=False)
|
32
server/src/tests/core/util/__init__.py
Normal file
32
server/src/tests/core/util/__init__.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Virtual Cable S.L.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
"""
|
||||||
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
|
"""
|
||||||
|
from . import test_cache
|
||||||
|
from . import test_stats_counters
|
@ -32,7 +32,7 @@
|
|||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
"""
|
"""
|
||||||
# We use commit/rollback
|
# We use commit/rollback
|
||||||
from django.test import TransactionTestCase as TestCase
|
from ...utils.test import UDSTransactionTestCase
|
||||||
from uds.core.util.cache import Cache
|
from uds.core.util.cache import Cache
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ UNICODE_CHARS_2 = 'ñöçóá^(€íöè)'
|
|||||||
VALUE_1 = [u'únîcödè€', b'string', {'a': 1, 'b': 2.0}]
|
VALUE_1 = [u'únîcödè€', b'string', {'a': 1, 'b': 2.0}]
|
||||||
|
|
||||||
|
|
||||||
class CacheTests(TestCase):
|
class CacheTests(UDSTransactionTestCase):
|
||||||
|
|
||||||
def test_cache(self):
|
def test_cache(self):
|
||||||
cache = Cache(UNICODE_CHARS)
|
cache = Cache(UNICODE_CHARS)
|
||||||
@ -60,7 +60,7 @@ class CacheTests(TestCase):
|
|||||||
|
|
||||||
# Add new "str" key, with 1 second life, wait 2 seconds and recover
|
# Add new "str" key, with 1 second life, wait 2 seconds and recover
|
||||||
cache.put(b'key', VALUE_1, 1)
|
cache.put(b'key', VALUE_1, 1)
|
||||||
time.sleep(2)
|
time.sleep(1.1)
|
||||||
self.assertEqual(cache.get(b'key'), None, 'Put an "str" key and recover it once it has expired')
|
self.assertEqual(cache.get(b'key'), None, 'Put an "str" key and recover it once it has expired')
|
||||||
|
|
||||||
# Refresh previous key and will be again available
|
# Refresh previous key and will be again available
|
||||||
@ -79,7 +79,7 @@ class CacheTests(TestCase):
|
|||||||
|
|
||||||
# Checks cache cleanup (remove expired keys)
|
# Checks cache cleanup (remove expired keys)
|
||||||
cache.put('key', 'test', 0)
|
cache.put('key', 'test', 0)
|
||||||
time.sleep(1)
|
time.sleep(0.1)
|
||||||
Cache.cleanUp()
|
Cache.cleanUp()
|
||||||
cache.refresh('key')
|
cache.refresh('key')
|
||||||
self.assertEqual(cache.get('key'), None, 'Put a key and recover it once it has expired and has been cleaned')
|
self.assertEqual(cache.get('key'), None, 'Put a key and recover it once it has expired and has been cleaned')
|
@ -34,10 +34,10 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from ..fixtures.stats_counters import create_stats_counters
|
from ...fixtures.stats_counters import create_stats_counters
|
||||||
|
|
||||||
# We use commit/rollback
|
# We use commit/rollback
|
||||||
from django.test import TestCase
|
from ...utils.test import UDSTransactionTestCase
|
||||||
|
|
||||||
from uds.core.util.stats import counters
|
from uds.core.util.stats import counters
|
||||||
from uds import models
|
from uds import models
|
||||||
@ -47,7 +47,7 @@ END_DATE_DAY = datetime.datetime(2020, 1, 2, 0, 0, 0)
|
|||||||
END_DATE_MONTH = datetime.datetime(2020, 2, 1, 0, 0, 0)
|
END_DATE_MONTH = datetime.datetime(2020, 2, 1, 0, 0, 0)
|
||||||
END_DATE_YEAR = datetime.datetime(2021, 1, 1, 0, 0, 0)
|
END_DATE_YEAR = datetime.datetime(2021, 1, 1, 0, 0, 0)
|
||||||
|
|
||||||
class StatsCountersTests(TestCase):
|
class StatsCountersTests(UDSTransactionTestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
return super().setUp()
|
return super().setUp()
|
||||||
|
|
93
server/src/tests/fixtures/calendars.py
vendored
Normal file
93
server/src/tests/fixtures/calendars.py
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
"""
|
||||||
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
|
"""
|
||||||
|
import typing
|
||||||
|
import datetime
|
||||||
|
import random
|
||||||
|
|
||||||
|
from uds import models
|
||||||
|
from uds.models.calendar_rule import freqs, dunits
|
||||||
|
|
||||||
|
# Counters so we can reinvoke the same method and generate new data
|
||||||
|
glob = {
|
||||||
|
'calendar_id': 1,
|
||||||
|
'calendar_rule_id': 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
def createCalendars(number: int) -> typing.List[models.Calendar]:
|
||||||
|
"""
|
||||||
|
Creates some testing calendars
|
||||||
|
"""
|
||||||
|
calendars: typing.List[models.Calendar] = []
|
||||||
|
for i in range(number):
|
||||||
|
calendar = models.Calendar.objects.create(
|
||||||
|
name='Calendar {}'.format(glob['calendar_id']),
|
||||||
|
comments='Calendar {} comments'.format(glob['calendar_id']),
|
||||||
|
)
|
||||||
|
calendars.append(calendar)
|
||||||
|
glob['calendar_id'] += 1
|
||||||
|
return calendars
|
||||||
|
|
||||||
|
|
||||||
|
def createRules(number: int, calendar: models.Calendar) -> typing.List[models.CalendarRule]:
|
||||||
|
"""
|
||||||
|
Creates some testing rules associated to a calendar
|
||||||
|
"""
|
||||||
|
rules: typing.List[models.CalendarRule] = []
|
||||||
|
rnd = random.Random() # nosec: testing purposes
|
||||||
|
for i in range(number):
|
||||||
|
# All rules will start now
|
||||||
|
# Rules duration will be a random between 1 and 10 days
|
||||||
|
# freqs a random value from freqs
|
||||||
|
# interval is a random value between 1 and 10
|
||||||
|
# duration is a random value between 0 and 24
|
||||||
|
# duration_unit is a random from dunits
|
||||||
|
start = datetime.datetime.now()
|
||||||
|
end = start + datetime.timedelta(days=rnd.randint(1, 10))
|
||||||
|
freq = rnd.choice(freqs)
|
||||||
|
interval = rnd.randint(1, 10)
|
||||||
|
duration = rnd.randint(0, 24)
|
||||||
|
duration_unit = rnd.choice(dunits)
|
||||||
|
|
||||||
|
rule = models.CalendarRule.objects.create(
|
||||||
|
calendar=calendar,
|
||||||
|
name='Rule {}'.format(glob['calendar_rule_id']),
|
||||||
|
comments='Rule {} comments'.format(glob['calendar_rule_id']),
|
||||||
|
start=start,
|
||||||
|
end=end,
|
||||||
|
freq=freq,
|
||||||
|
interval=interval,
|
||||||
|
duration=duration,
|
||||||
|
duration_unit=duration_unit,
|
||||||
|
)
|
||||||
|
rules.append(rule)
|
||||||
|
glob['calendar_rule_id'] += 1
|
||||||
|
|
||||||
|
return rules
|
@ -42,7 +42,7 @@ from uds.REST.handlers import AUTH_TOKEN_HEADER
|
|||||||
NUMBER_OF_ITEMS_TO_CREATE = 4
|
NUMBER_OF_ITEMS_TO_CREATE = 4
|
||||||
|
|
||||||
|
|
||||||
class RESTTestCase(test.UDSTransactionTestCasse):
|
class RESTTestCase(test.UDSTransactionTestCase):
|
||||||
# Authenticators related
|
# Authenticators related
|
||||||
auth: models.Authenticator
|
auth: models.Authenticator
|
||||||
groups: typing.List[models.Group]
|
groups: typing.List[models.Group]
|
||||||
|
@ -33,6 +33,7 @@ import logging
|
|||||||
|
|
||||||
from django.test import TestCase, TransactionTestCase
|
from django.test import TestCase, TransactionTestCase
|
||||||
from django.test.client import Client
|
from django.test.client import Client
|
||||||
|
from django.http import HttpResponse
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from uds import models
|
from uds import models
|
||||||
@ -76,12 +77,19 @@ class UDSClient(Client):
|
|||||||
return super().request(**request)
|
return super().request(**request)
|
||||||
|
|
||||||
|
|
||||||
|
def get(self, *args, **kwargs) -> 'HttpResponse':
|
||||||
|
return typing.cast('HttpResponse', super().get(*args, **kwargs))
|
||||||
|
|
||||||
|
def post(self, *args, **kwargs) -> 'HttpResponse':
|
||||||
|
return typing.cast('HttpResponse', super().post(*args, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
class UDSTestCase(TestCase):
|
class UDSTestCase(TestCase):
|
||||||
client_class: typing.Type = UDSClient
|
client_class: typing.Type = UDSClient
|
||||||
|
|
||||||
client: UDSClient
|
client: UDSClient
|
||||||
|
|
||||||
class UDSTransactionTestCasse(TransactionTestCase):
|
class UDSTransactionTestCase(TransactionTestCase):
|
||||||
client_class: typing.Type = UDSClient
|
client_class: typing.Type = UDSClient
|
||||||
|
|
||||||
client: UDSClient
|
client: UDSClient
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
import random
|
import random
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from uds.core.util.config import GlobalConfig
|
from uds.core.util.config import GlobalConfig
|
||||||
|
|
||||||
from ...utils import test
|
from ...utils import test
|
||||||
@ -43,7 +45,7 @@ from uds import models
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebLoginLogout(test.UDSTransactionTestCasse):
|
class WebLoginLogout(test.UDSTransactionTestCase):
|
||||||
"""
|
"""
|
||||||
Test WEB login and logout
|
Test WEB login and logout
|
||||||
"""
|
"""
|
||||||
@ -105,7 +107,7 @@ class WebLoginLogout(test.UDSTransactionTestCasse):
|
|||||||
# Now invoke logout
|
# Now invoke logout
|
||||||
response = typing.cast('HttpResponse', self.client.get('/uds/page/logout'))
|
response = typing.cast('HttpResponse', self.client.get('/uds/page/logout'))
|
||||||
self.assertRedirects(
|
self.assertRedirects(
|
||||||
response, 'http://testserver/uds/page/login', status_code=302
|
response, reverse('page.login'), status_code=302
|
||||||
)
|
)
|
||||||
# Ensures a couple of logs are created for every operation
|
# Ensures a couple of logs are created for every operation
|
||||||
# Except for root, that has no user associated on db
|
# Except for root, that has no user associated on db
|
||||||
|
@ -302,20 +302,16 @@ class Initialize(ActorV3Action):
|
|||||||
token = self._params['token']
|
token = self._params['token']
|
||||||
# First, try to locate an user service providing this token.
|
# First, try to locate an user service providing this token.
|
||||||
if self._params['type'] == UNMANAGED:
|
if self._params['type'] == UNMANAGED:
|
||||||
alias_token = token # Store token as possible alias
|
|
||||||
# First, try to locate on alias table
|
# First, try to locate on alias table
|
||||||
if ServiceTokenAlias.objects.filter(alias=token).exists():
|
if ServiceTokenAlias.objects.filter(alias=token).exists():
|
||||||
# Retrieve real service from token alias
|
# Retrieve real service from token alias
|
||||||
service = ServiceTokenAlias.objects.get(alias=token).service
|
service = ServiceTokenAlias.objects.get(alias=token).service
|
||||||
|
alias_token = token # Store token as possible alias
|
||||||
|
|
||||||
# If not found an alias, try to locate on service table
|
# If not found an alias, try to locate on service table
|
||||||
# Not on alias token, try to locate on Service table
|
# Not on alias token, try to locate on Service table
|
||||||
if not service:
|
if not service:
|
||||||
service = typing.cast('Service', Service.objects.get(token=token))
|
service = typing.cast('Service', Service.objects.get(token=token))
|
||||||
# And create a new alias for it, and save
|
|
||||||
alias_token = (
|
|
||||||
cryptoManager().randomString(40)
|
|
||||||
) # fix alias with new token
|
|
||||||
service.aliases.create(alias=alias_token)
|
|
||||||
|
|
||||||
# Locate an userService that belongs to this service and which
|
# Locate an userService that belongs to this service and which
|
||||||
# Build the possible ids and make initial filter to match service
|
# Build the possible ids and make initial filter to match service
|
||||||
@ -355,6 +351,14 @@ class Initialize(ActorV3Action):
|
|||||||
if osManager:
|
if osManager:
|
||||||
osData = osManager.actorData(userService)
|
osData = osManager.actorData(userService)
|
||||||
|
|
||||||
|
if service and not alias_token: # Is a service managed by UDS
|
||||||
|
# Create a new alias for it, and save
|
||||||
|
alias_token = (
|
||||||
|
cryptoManager().randomString(40)
|
||||||
|
) # fix alias with new token
|
||||||
|
service.aliases.create(alias=alias_token)
|
||||||
|
|
||||||
|
|
||||||
return initialization_result(
|
return initialization_result(
|
||||||
userService.uuid, userService.unique_id, osData, alias_token
|
userService.uuid, userService.unique_id, osData, alias_token
|
||||||
)
|
)
|
||||||
|
@ -454,7 +454,7 @@ def webLogout(
|
|||||||
username = request.user.name
|
username = request.user.name
|
||||||
logout = authenticator.logout(request, username)
|
logout = authenticator.logout(request, username)
|
||||||
if logout and logout.success == auths.AuthenticationSuccess.REDIRECT:
|
if logout and logout.success == auths.AuthenticationSuccess.REDIRECT:
|
||||||
exit_url = logout.url
|
exit_url = logout.url or exit_url
|
||||||
if request.user.id != ROOT_ID:
|
if request.user.id != ROOT_ID:
|
||||||
# Log the event if not root user
|
# Log the event if not root user
|
||||||
events.addEvent(
|
events.addEvent(
|
||||||
@ -472,7 +472,7 @@ def webLogout(
|
|||||||
request.session.flush()
|
request.session.flush()
|
||||||
request.authorized = False
|
request.authorized = False
|
||||||
|
|
||||||
response = HttpResponseRedirect(exit_url) # type: ignore
|
response = HttpResponseRedirect(exit_url)
|
||||||
if authenticator:
|
if authenticator:
|
||||||
authenticator.webLogoutHook(username, request, response)
|
authenticator.webLogoutHook(username, request, response)
|
||||||
return response
|
return response
|
||||||
|
@ -109,12 +109,12 @@ class CalendarRule(UUIDModel):
|
|||||||
duration = models.IntegerField(default=0) # Duration in minutes
|
duration = models.IntegerField(default=0) # Duration in minutes
|
||||||
duration_unit = models.CharField(choices=dunits, default='MINUTES', max_length=32)
|
duration_unit = models.CharField(choices=dunits, default='MINUTES', max_length=32)
|
||||||
|
|
||||||
calendar: 'models.ForeignKey[CalendarRule, Calendar]' = models.ForeignKey(
|
calendar: 'models.ForeignKey["CalendarRule", Calendar]' = models.ForeignKey(
|
||||||
Calendar, related_name='rules', on_delete=models.CASCADE
|
Calendar, related_name='rules', on_delete=models.CASCADE
|
||||||
)
|
)
|
||||||
|
|
||||||
# "fake" declarations for type checking
|
# "fake" declarations for type checking
|
||||||
objects: 'models.manager.Manager[CalendarRule]'
|
objects: 'models.manager.Manager["CalendarRule"]'
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user