From 69b778c922359665a10e0c1f364640f2dd0d0db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Wed, 24 Aug 2022 22:16:47 +0200 Subject: [PATCH] Adding more tests and fixes --- actor/src/actor_config.py | 4 +- actor/src/udsactor/service.py | 1 + server/src/tests/REST/__init__.py | 6 +- server/src/tests/REST/actor/__init__.py | 34 ++++++ .../tests/REST/{ => actor}/test_initialize.py | 32 +++-- .../REST/{ => actor}/test_login_logout.py | 6 +- .../tests/REST/{ => actor}/test_register.py | 4 +- .../src/tests/REST/{ => actor}/test_test.py | 2 +- server/src/tests/core/__init__.py | 8 +- server/src/tests/core/managers/__init__.py | 0 .../src/tests/core/managers/downloadable.txt | 1 + .../src/tests/core/managers/test_downloads.py | 114 ++++++++++++++++++ server/src/tests/core/util/__init__.py | 32 +++++ .../src/tests/core/{ => util}/test_cache.py | 8 +- .../core/{ => util}/test_stats_counters.py | 6 +- server/src/tests/fixtures/calendars.py | 93 ++++++++++++++ server/src/tests/utils/rest/test.py | 2 +- server/src/tests/utils/test.py | 10 +- .../src/tests/web/user/test_login_logout.py | 6 +- server/src/uds/REST/methods/actor_v3.py | 16 ++- server/src/uds/core/auths/auth.py | 4 +- server/src/uds/models/calendar_rule.py | 4 +- 22 files changed, 342 insertions(+), 51 deletions(-) create mode 100644 server/src/tests/REST/actor/__init__.py rename server/src/tests/REST/{ => actor}/test_initialize.py (92%) rename server/src/tests/REST/{ => actor}/test_login_logout.py (97%) rename server/src/tests/REST/{ => actor}/test_register.py (97%) rename server/src/tests/REST/{ => actor}/test_test.py (99%) create mode 100644 server/src/tests/core/managers/__init__.py create mode 100644 server/src/tests/core/managers/downloadable.txt create mode 100644 server/src/tests/core/managers/test_downloads.py create mode 100644 server/src/tests/core/util/__init__.py rename server/src/tests/core/{ => util}/test_cache.py (96%) rename server/src/tests/core/{ => util}/test_stats_counters.py (96%) create mode 100644 server/src/tests/fixtures/calendars.py diff --git a/actor/src/actor_config.py b/actor/src/actor_config.py index bc90205b..c9470dd8 100755 --- a/actor/src/actor_config.py +++ b/actor/src/actor_config.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# Copyright (c) 2020 Virtual Cable S.L. +# Copyright (c) 2020-2022 Virtual Cable S.L.U. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, @@ -35,7 +35,7 @@ import os import logging 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 import udsactor diff --git a/actor/src/udsactor/service.py b/actor/src/udsactor/service.py index 95844078..492caf7e 100644 --- a/actor/src/udsactor/service.py +++ b/actor/src/udsactor/service.py @@ -326,6 +326,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes if self.isManaged() else (initResult.alias_token or self._cfg.master_token) ) + # Replace master token with alias token if present self._cfg = self._cfg._replace( master_token=master_token, own_token=initResult.own_token, diff --git a/server/src/tests/REST/__init__.py b/server/src/tests/REST/__init__.py index 985074d9..06c762b2 100644 --- a/server/src/tests/REST/__init__.py +++ b/server/src/tests/REST/__init__.py @@ -1,4 +1,3 @@ - # -*- coding: utf-8 -*- # # Copyright (c) 2022 Virtual Cable S.L.U. @@ -29,6 +28,5 @@ """ @author: Adolfo Gómez, dkmaster at dkmon dot com """ -from . import test_login_logout -from . import test_register -from . import test_initialize + +from . import actor diff --git a/server/src/tests/REST/actor/__init__.py b/server/src/tests/REST/actor/__init__.py new file mode 100644 index 00000000..985074d9 --- /dev/null +++ b/server/src/tests/REST/actor/__init__.py @@ -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 diff --git a/server/src/tests/REST/test_initialize.py b/server/src/tests/REST/actor/test_initialize.py similarity index 92% rename from server/src/tests/REST/test_initialize.py rename to server/src/tests/REST/actor/test_initialize.py index 8382189b..7c6156cd 100644 --- a/server/src/tests/REST/test_initialize.py +++ b/server/src/tests/REST/actor/test_initialize.py @@ -37,9 +37,8 @@ from django.conf import settings from uds import models from uds.core import VERSION 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__) @@ -153,35 +152,42 @@ class ActorInitializeV3(rest.test.RESTTestCase): success = functools.partial(self.invoke_success, '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( actor_token, mac='00:00:00:00:00:00', ) - alias_token = result['alias_token'] - # Unmanaged host is the response for initialization of unmanaged actor ALWAYS + self.assertIsNone(result['alias_token']) self.assertIsNone(result['own_token']) - self.assertIsInstance(alias_token, str) self.assertIsNone(result['unique_id']) 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 alias = models.ServiceTokenAlias.objects.get(alias=result['alias_token']) 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 # If we call initialize and we get "own-token" means that we have already logged in with this data - result = success( - alias_token, - mac=unique_id - ) + result = success(alias_token, mac=unique_id) self.assertEqual(result['own_token'], user_service.uuid) self.assertEqual(result['alias_token'], alias_token) self.assertEqual(result['unique_id'], unique_id) - - - logger.info('Result: %s', result) \ No newline at end of file + # + failure('invalid token', unique_id, True) diff --git a/server/src/tests/REST/test_login_logout.py b/server/src/tests/REST/actor/test_login_logout.py similarity index 97% rename from server/src/tests/REST/test_login_logout.py rename to server/src/tests/REST/actor/test_login_logout.py index bdb4cfce..8fde7b34 100644 --- a/server/src/tests/REST/test_login_logout.py +++ b/server/src/tests/REST/actor/test_login_logout.py @@ -32,8 +32,8 @@ import random import typing -from .. import fixtures -from ..utils import rest, test +from ... import fixtures +from ...utils import rest, test class RESTLoginLogoutCase(test.UDSTestCase): @@ -41,7 +41,7 @@ class RESTLoginLogoutCase(test.UDSTestCase): Test login and logout """ - def test_login_logout(self): + def test_login_logout(self) -> None: """ Test login and logout """ diff --git a/server/src/tests/REST/test_register.py b/server/src/tests/REST/actor/test_register.py similarity index 97% rename from server/src/tests/REST/test_register.py rename to server/src/tests/REST/actor/test_register.py index 4cb60e46..44497550 100644 --- a/server/src/tests/REST/test_register.py +++ b/server/src/tests/REST/actor/test_register.py @@ -31,12 +31,10 @@ import typing import logging -from django.conf import settings - from uds import models from uds.REST.handlers import AUTH_TOKEN_HEADER -from ..utils import rest, constants +from ...utils import rest, constants logger = logging.getLogger(__name__) diff --git a/server/src/tests/REST/test_test.py b/server/src/tests/REST/actor/test_test.py similarity index 99% rename from server/src/tests/REST/test_test.py rename to server/src/tests/REST/actor/test_test.py index 47d3fdcd..e106d0c6 100644 --- a/server/src/tests/REST/test_test.py +++ b/server/src/tests/REST/actor/test_test.py @@ -34,7 +34,7 @@ import logging from uds.REST.handlers import AUTH_TOKEN_HEADER from uds.REST.methods.actor_v3 import MANAGED, UNMANAGED, ALLOWED_FAILS -from ..utils import rest +from ...utils import rest logger = logging.getLogger(__name__) diff --git a/server/src/tests/core/__init__.py b/server/src/tests/core/__init__.py index 2a4ce0cc..acea4c51 100644 --- a/server/src/tests/core/__init__.py +++ b/server/src/tests/core/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2022 Virtual Cable S.L. +# Copyright (c) 2022 Virtual Cable S.L.U. # All rights reserved. # # 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, # 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 +# * 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. # @@ -28,5 +28,5 @@ """ @author: Adolfo Gómez, dkmaster at dkmon dot com """ -from . import test_cache -from . import test_stats_counters \ No newline at end of file +from . import util +from . import managers \ No newline at end of file diff --git a/server/src/tests/core/managers/__init__.py b/server/src/tests/core/managers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/server/src/tests/core/managers/downloadable.txt b/server/src/tests/core/managers/downloadable.txt new file mode 100644 index 00000000..9c69b0f1 --- /dev/null +++ b/server/src/tests/core/managers/downloadable.txt @@ -0,0 +1 @@ +This file is the downloadable for download manager tests \ No newline at end of file diff --git a/server/src/tests/core/managers/test_downloads.py b/server/src/tests/core/managers/test_downloads.py new file mode 100644 index 00000000..e6b20261 --- /dev/null +++ b/server/src/tests/core/managers/test_downloads.py @@ -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) diff --git a/server/src/tests/core/util/__init__.py b/server/src/tests/core/util/__init__.py new file mode 100644 index 00000000..2a4ce0cc --- /dev/null +++ b/server/src/tests/core/util/__init__.py @@ -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 \ No newline at end of file diff --git a/server/src/tests/core/test_cache.py b/server/src/tests/core/util/test_cache.py similarity index 96% rename from server/src/tests/core/test_cache.py rename to server/src/tests/core/util/test_cache.py index 268f531c..9f8f7a26 100644 --- a/server/src/tests/core/test_cache.py +++ b/server/src/tests/core/util/test_cache.py @@ -32,7 +32,7 @@ @author: Adolfo Gómez, dkmaster at dkmon dot com """ # We use commit/rollback -from django.test import TransactionTestCase as TestCase +from ...utils.test import UDSTransactionTestCase from uds.core.util.cache import Cache import time @@ -41,7 +41,7 @@ UNICODE_CHARS_2 = 'ñöçóá^(€íöè)' VALUE_1 = [u'únîcödè€', b'string', {'a': 1, 'b': 2.0}] -class CacheTests(TestCase): +class CacheTests(UDSTransactionTestCase): def test_cache(self): cache = Cache(UNICODE_CHARS) @@ -60,7 +60,7 @@ class CacheTests(TestCase): # Add new "str" key, with 1 second life, wait 2 seconds and recover 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') # Refresh previous key and will be again available @@ -79,7 +79,7 @@ class CacheTests(TestCase): # Checks cache cleanup (remove expired keys) cache.put('key', 'test', 0) - time.sleep(1) + time.sleep(0.1) Cache.cleanUp() cache.refresh('key') self.assertEqual(cache.get('key'), None, 'Put a key and recover it once it has expired and has been cleaned') diff --git a/server/src/tests/core/test_stats_counters.py b/server/src/tests/core/util/test_stats_counters.py similarity index 96% rename from server/src/tests/core/test_stats_counters.py rename to server/src/tests/core/util/test_stats_counters.py index 29e98e2c..2c00556b 100644 --- a/server/src/tests/core/test_stats_counters.py +++ b/server/src/tests/core/util/test_stats_counters.py @@ -34,10 +34,10 @@ import datetime import typing -from ..fixtures.stats_counters import create_stats_counters +from ...fixtures.stats_counters import create_stats_counters # We use commit/rollback -from django.test import TestCase +from ...utils.test import UDSTransactionTestCase from uds.core.util.stats import counters 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_YEAR = datetime.datetime(2021, 1, 1, 0, 0, 0) -class StatsCountersTests(TestCase): +class StatsCountersTests(UDSTransactionTestCase): def setUp(self) -> None: return super().setUp() diff --git a/server/src/tests/fixtures/calendars.py b/server/src/tests/fixtures/calendars.py new file mode 100644 index 00000000..06c694ba --- /dev/null +++ b/server/src/tests/fixtures/calendars.py @@ -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 \ No newline at end of file diff --git a/server/src/tests/utils/rest/test.py b/server/src/tests/utils/rest/test.py index 40657cf4..29467f50 100644 --- a/server/src/tests/utils/rest/test.py +++ b/server/src/tests/utils/rest/test.py @@ -42,7 +42,7 @@ from uds.REST.handlers import AUTH_TOKEN_HEADER NUMBER_OF_ITEMS_TO_CREATE = 4 -class RESTTestCase(test.UDSTransactionTestCasse): +class RESTTestCase(test.UDSTransactionTestCase): # Authenticators related auth: models.Authenticator groups: typing.List[models.Group] diff --git a/server/src/tests/utils/test.py b/server/src/tests/utils/test.py index 234afa27..137c14b6 100644 --- a/server/src/tests/utils/test.py +++ b/server/src/tests/utils/test.py @@ -33,6 +33,7 @@ import logging from django.test import TestCase, TransactionTestCase from django.test.client import Client +from django.http import HttpResponse from django.conf import settings from uds import models @@ -76,12 +77,19 @@ class UDSClient(Client): 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): client_class: typing.Type = UDSClient client: UDSClient -class UDSTransactionTestCasse(TransactionTestCase): +class UDSTransactionTestCase(TransactionTestCase): client_class: typing.Type = UDSClient client: UDSClient diff --git a/server/src/tests/web/user/test_login_logout.py b/server/src/tests/web/user/test_login_logout.py index 9fe3002c..46ce15da 100644 --- a/server/src/tests/web/user/test_login_logout.py +++ b/server/src/tests/web/user/test_login_logout.py @@ -31,6 +31,8 @@ import random import typing +from django.urls import reverse + from uds.core.util.config import GlobalConfig 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 """ @@ -105,7 +107,7 @@ class WebLoginLogout(test.UDSTransactionTestCasse): # Now invoke logout response = typing.cast('HttpResponse', self.client.get('/uds/page/logout')) 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 # Except for root, that has no user associated on db diff --git a/server/src/uds/REST/methods/actor_v3.py b/server/src/uds/REST/methods/actor_v3.py index 5134686c..50b1eb24 100644 --- a/server/src/uds/REST/methods/actor_v3.py +++ b/server/src/uds/REST/methods/actor_v3.py @@ -302,20 +302,16 @@ class Initialize(ActorV3Action): token = self._params['token'] # First, try to locate an user service providing this token. if self._params['type'] == UNMANAGED: - alias_token = token # Store token as possible alias # First, try to locate on alias table if ServiceTokenAlias.objects.filter(alias=token).exists(): # Retrieve real service from token alias 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 # Not on alias token, try to locate on Service table if not service: 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 # Build the possible ids and make initial filter to match service @@ -355,6 +351,14 @@ class Initialize(ActorV3Action): if osManager: 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( userService.uuid, userService.unique_id, osData, alias_token ) diff --git a/server/src/uds/core/auths/auth.py b/server/src/uds/core/auths/auth.py index 9b00c20e..dd9a4531 100644 --- a/server/src/uds/core/auths/auth.py +++ b/server/src/uds/core/auths/auth.py @@ -454,7 +454,7 @@ def webLogout( username = request.user.name logout = authenticator.logout(request, username) 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: # Log the event if not root user events.addEvent( @@ -472,7 +472,7 @@ def webLogout( request.session.flush() request.authorized = False - response = HttpResponseRedirect(exit_url) # type: ignore + response = HttpResponseRedirect(exit_url) if authenticator: authenticator.webLogoutHook(username, request, response) return response diff --git a/server/src/uds/models/calendar_rule.py b/server/src/uds/models/calendar_rule.py index b9b3a693..d7ea1d37 100644 --- a/server/src/uds/models/calendar_rule.py +++ b/server/src/uds/models/calendar_rule.py @@ -109,12 +109,12 @@ class CalendarRule(UUIDModel): duration = models.IntegerField(default=0) # Duration in minutes 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 ) # "fake" declarations for type checking - objects: 'models.manager.Manager[CalendarRule]' + objects: 'models.manager.Manager["CalendarRule"]' class Meta: """