mirror of
https://github.com/dkmstr/openuds.git
synced 2025-08-25 13:49:59 +03:00
Adding more tests and fixes
This commit is contained in:
@ -85,19 +85,24 @@ class UniqueIdTests(UDSTestCase):
|
||||
self.assertEqual(self.uidGen.get(), 0)
|
||||
|
||||
def test_release_older_unique_id(self):
|
||||
self.uidGen.get() # 0
|
||||
|
||||
self.assertEqual(self.uidGen.get(), 1)
|
||||
NUM = 100
|
||||
for i in range(NUM):
|
||||
self.assertEqual(self.uidGen.get(), i)
|
||||
|
||||
stamp = getSqlDatetimeAsUnix() + 1
|
||||
time.sleep(2)
|
||||
|
||||
self.uidGen.get() # 2
|
||||
for i in range(NUM):
|
||||
self.assertEqual(self.uidGen.get(), i + NUM)
|
||||
|
||||
self.uidGen.releaseOlderThan(getSqlDatetimeAsUnix() - 1) # Clear ups older than 1 seconds ago
|
||||
self.uidGen.releaseOlderThan(stamp) # Clear ups older than 0 seconds ago
|
||||
|
||||
self.assertEqual(self.uidGen.get(), 0)
|
||||
self.assertEqual(self.uidGen.get(), 1)
|
||||
self.assertEqual(self.uidGen.get(), 3)
|
||||
for i in range(NUM):
|
||||
self.assertEqual(self.uidGen.get(), i)
|
||||
|
||||
# from NUM to NUM*2-1 (both included) are still there, so we should get 200
|
||||
self.assertEqual(self.uidGen.get(), NUM*2)
|
||||
self.assertEqual(self.uidGen.get(), NUM*2+1)
|
||||
|
||||
def test_gid(self):
|
||||
for x in range(100):
|
||||
|
0
server/src/tests/core/workers/__init__.py
Normal file
0
server/src/tests/core/workers/__init__.py
Normal file
69
server/src/tests/core/workers/test_assigned_unused.py
Normal file
69
server/src/tests/core/workers/test_assigned_unused.py
Normal file
@ -0,0 +1,69 @@
|
||||
# -*- 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
|
||||
|
||||
from uds import models
|
||||
from uds.core.environment import Environment
|
||||
from uds.core.util import config
|
||||
from uds.core.util.state import State
|
||||
from uds.core.workers.assigned_unused import AssignedAndUnused
|
||||
|
||||
from ...utils.test import UDSTransactionTestCase
|
||||
from ...fixtures import services as fixtures_services
|
||||
|
||||
|
||||
class AssignedAndUnusedTests(UDSTransactionTestCase):
|
||||
userServices: typing.List[models.UserService]
|
||||
|
||||
def setUp(self):
|
||||
config.GlobalConfig.CHECK_UNUSED_TIME.set('600')
|
||||
AssignedAndUnused.setup()
|
||||
# All created user services has "in_use" to False, os_state and state to USABLE
|
||||
self.userServices = fixtures_services.newUserServiceForTesting(count=32)
|
||||
|
||||
def test_assigned_unused(self):
|
||||
for us in self.userServices: # Update state date to now
|
||||
us.setState(State.USABLE)
|
||||
# Set now, should not be removed
|
||||
count = models.UserService.objects.filter(state=State.REMOVABLE).count()
|
||||
cleaner = AssignedAndUnused(Environment.getTempEnv())
|
||||
# since_state = getSqlDatetime() - datetime.timedelta(seconds=cleaner.frecuency)
|
||||
cleaner.run()
|
||||
self.assertEqual(models.UserService.objects.filter(state=State.REMOVABLE).count(), count)
|
||||
# Set half the userServices to a long-ago state, should be removed
|
||||
for i, us in enumerate(self.userServices):
|
||||
if i%2 == 0:
|
||||
us.state_date = models.getSqlDatetime() - datetime.timedelta(seconds=602)
|
||||
us.save(update_fields=['state_date'])
|
||||
cleaner.run()
|
||||
self.assertEqual(models.UserService.objects.filter(state=State.REMOVABLE).count(), count + len(self.userServices)//2)
|
@ -0,0 +1,96 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012 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
|
||||
"""
|
||||
import datetime
|
||||
import typing
|
||||
|
||||
from uds import models
|
||||
from uds.core.environment import Environment
|
||||
from uds.core.util import config
|
||||
from uds.core.util.state import State
|
||||
from uds.core.workers.hanged_userservice_cleaner import HangedCleaner
|
||||
|
||||
from ...utils.test import UDSTransactionTestCase
|
||||
from ...fixtures import services as fixtures_services
|
||||
|
||||
MAX_INIT = 300
|
||||
TEST_SERVICES = 5 * 5 # Ensure multiple of 5 for testing
|
||||
|
||||
|
||||
class HangedCleanerTests(UDSTransactionTestCase):
|
||||
userServices: typing.List[models.UserService]
|
||||
|
||||
def setUp(self):
|
||||
config.GlobalConfig.MAX_INITIALIZING_TIME.set(MAX_INIT)
|
||||
config.GlobalConfig.MAX_REMOVAL_TIME.set(MAX_INIT)
|
||||
HangedCleaner.setup()
|
||||
# All created user services has "in_use" to False, os_state and state to USABLE
|
||||
self.userServices = fixtures_services.newUserServiceForTesting(
|
||||
count=TEST_SERVICES
|
||||
)
|
||||
|
||||
# Setup a few user services as hanged
|
||||
for i, us in enumerate(self.userServices):
|
||||
if i % 5 == 0:
|
||||
us.state = (
|
||||
State.PREPARING
|
||||
) # These will convert in "CANCELED" (first CANCELING but TestDeployment Cancels inmediately, so it will be CANCELED)
|
||||
elif i % 5 == 1:
|
||||
us.state = State.USABLE
|
||||
us.os_state = State.PREPARING # THese in "REMOVABLE"
|
||||
elif i % 5 == 2:
|
||||
us.state = State.REMOVING # These will be set "REMOVABLE" to retry
|
||||
elif i % 5 == 3:
|
||||
us.state = State.CANCELING # These will be set "REMOVABLE" to retry
|
||||
else:
|
||||
# Just for setting defaults, that already are defaults :)
|
||||
us.state = State.USABLE
|
||||
us.os_state = State.USABLE
|
||||
|
||||
us.state_date = models.getSqlDatetime() - datetime.timedelta(
|
||||
seconds=MAX_INIT + 1
|
||||
)
|
||||
us.save(update_fields=['state', 'os_state', 'state_date'])
|
||||
|
||||
def test_hanged_cleaner(self):
|
||||
# At start, there is no "removable" user services
|
||||
cleaner = HangedCleaner(Environment.getTempEnv())
|
||||
cleaner.run()
|
||||
one_fith = TEST_SERVICES // 5
|
||||
self.assertEqual(
|
||||
models.UserService.objects.filter(state=State.CANCELED).count(), one_fith
|
||||
)
|
||||
self.assertEqual(
|
||||
models.UserService.objects.filter(state=State.REMOVABLE).count(), 3*one_fith
|
||||
)
|
||||
self.assertEqual(
|
||||
models.UserService.objects.filter(state=State.USABLE).count(), one_fith
|
||||
)
|
21
server/src/tests/fixtures/services.py
vendored
21
server/src/tests/fixtures/services.py
vendored
@ -153,3 +153,24 @@ def createSingleTestingUserServiceStructure(
|
||||
)
|
||||
|
||||
return user_service
|
||||
|
||||
|
||||
def newUserServiceForTesting(
|
||||
count: int = 1,
|
||||
type_: typing.Union[
|
||||
typing.Literal['managed'], typing.Literal['unmanaged']
|
||||
] = 'managed',
|
||||
) -> typing.List[models.UserService]:
|
||||
from . import authenticators
|
||||
|
||||
auth = authenticators.createAuthenticator()
|
||||
user_services: typing.List[models.UserService] = []
|
||||
for _ in range(count):
|
||||
groups = authenticators.createGroups(auth, 3)
|
||||
user = authenticators.createUsers(auth, 1, groups=groups)[0]
|
||||
user_services.append(
|
||||
createSingleTestingUserServiceStructure(
|
||||
createProvider(), user, groups, type_
|
||||
)
|
||||
)
|
||||
return user_services
|
||||
|
@ -36,9 +36,8 @@ from django.test.client import Client
|
||||
from django.http.response import HttpResponse
|
||||
from django.conf import settings
|
||||
|
||||
from uds import models
|
||||
from uds.REST.handlers import AUTH_TOKEN_HEADER
|
||||
from uds.core.managers.crypto import CryptoManager
|
||||
from uds.core.util.config import GlobalConfig
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -104,14 +103,26 @@ class UDSClient(Client):
|
||||
def post(self, *args, **kwargs) -> 'UDSHttpResponse':
|
||||
return typing.cast('UDSHttpResponse', super().post(*args, **kwargs))
|
||||
|
||||
|
||||
class UDSTestCase(TestCase):
|
||||
client_class: typing.Type = UDSClient
|
||||
|
||||
client: UDSClient
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
super().setUpClass()
|
||||
setupClass(cls)
|
||||
|
||||
class UDSTransactionTestCase(TransactionTestCase):
|
||||
client_class: typing.Type = UDSClient
|
||||
|
||||
client: UDSClient
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
super().setUpClass()
|
||||
setupClass(cls)
|
||||
|
||||
def setupClass(cls: typing.Union[typing.Type[UDSTestCase], typing.Type[UDSTransactionTestCase]]) -> None:
|
||||
# Nothing right now
|
||||
pass
|
||||
|
@ -31,7 +31,7 @@
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import base64
|
||||
import pickle
|
||||
import pickle # nosec: Safe pickle usage
|
||||
import gzip
|
||||
import typing
|
||||
|
||||
@ -92,7 +92,7 @@ class Serializable:
|
||||
to unmarshal that data variable
|
||||
"""
|
||||
if hasattr(self, 'data') and hasattr(getattr(self, 'data'), '__dict__'):
|
||||
setattr(self, 'data', pickle.loads(data))
|
||||
setattr(self, 'data', pickle.loads(data)) # nosec: Safe pickle load
|
||||
return
|
||||
|
||||
raise NotImplementedError('You must override the unmarshal method or provide a data member')
|
||||
|
@ -86,7 +86,7 @@ class Config:
|
||||
|
||||
|
||||
class Value:
|
||||
_section: 'Config.Section'
|
||||
_section: 'Config.Section' # type: ignore # mypy bug?
|
||||
_type: int
|
||||
_key: str
|
||||
_crypt: bool
|
||||
@ -211,7 +211,7 @@ class Config:
|
||||
def getHelp(self) -> str:
|
||||
return gettext(self._help)
|
||||
|
||||
def set(self, value: typing.Union[str, bool]) -> None:
|
||||
def set(self, value: typing.Union[str, bool, int]) -> None:
|
||||
if GlobalConfig.isInitialized() is False:
|
||||
_saveLater.append((self, value))
|
||||
return
|
||||
@ -219,6 +219,9 @@ class Config:
|
||||
if isinstance(value, bool):
|
||||
value = ['0', '1'][value]
|
||||
|
||||
if isinstance(value, int):
|
||||
value = str(value)
|
||||
|
||||
if self._crypt:
|
||||
value = cryptoManager().encrypt(value)
|
||||
|
||||
@ -249,6 +252,8 @@ class Config:
|
||||
self._section.name(),
|
||||
self._key,
|
||||
)
|
||||
finally:
|
||||
self._data = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
return '{}.{}'.format(self._section.name(), self._key)
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 20122 Virtual Cable S.L.U.
|
||||
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -64,7 +64,11 @@ class TestUserDeployment(services.UserDeployment):
|
||||
ip: str = ''
|
||||
mac: str = ''
|
||||
|
||||
data: Data = dataclasses.field(default_factory=Data)
|
||||
data: Data
|
||||
|
||||
def initialize(self) -> None:
|
||||
super().initialize()
|
||||
self.data = TestUserDeployment.Data()
|
||||
|
||||
# : Recheck every five seconds by default (for task methods)
|
||||
suggestedTime = 5
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 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,
|
||||
@ -12,7 +12,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,8 +28,6 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
Created on Jun 22, 2012
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import logging
|
||||
@ -92,11 +90,13 @@ class TestProvider(services.ServiceProvider):
|
||||
name: str = ''
|
||||
integer: int = 0
|
||||
|
||||
data: Data = dataclasses.field(default_factory=Data)
|
||||
data: Data
|
||||
|
||||
def initialize(self, values: 'module.Module.ValuesType') -> None:
|
||||
self.data = TestProvider.Data()
|
||||
if values:
|
||||
name = random.SystemRandom().choices(string.ascii_letters, k=10)
|
||||
self.data.name = ''.join(random.SystemRandom().choices(string.ascii_letters, k=10))
|
||||
self.data.integer = random.randint(0, 100)
|
||||
return super().initialize(values)
|
||||
|
||||
@staticmethod
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 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,
|
||||
@ -12,7 +12,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.
|
||||
#
|
||||
@ -51,9 +51,7 @@ logger = logging.getLogger(__name__)
|
||||
class ServiceTestNoCache(services.Service):
|
||||
"""
|
||||
Basic testing service without cache and no publication OFC
|
||||
|
||||
"""
|
||||
|
||||
# : Name to show the administrator. This string will be translated BEFORE
|
||||
# : sending it to administration interface, so don't forget to
|
||||
# : mark it as _ (using gettext_noop)
|
||||
|
Reference in New Issue
Block a user