1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-03-11 00:58:39 +03:00

Adding testing mechaniccs

This commit is contained in:
Adolfo Gómez García 2024-02-18 16:48:20 +01:00
parent 9614323a1b
commit 57be9c80b6
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
11 changed files with 187 additions and 21 deletions

View File

@ -153,13 +153,23 @@ class Environment:
return Environment(name, id_generators)
@staticmethod
def environment_for_type(type_) -> 'Environment':
def type_environment(type_: typing.Type) -> 'Environment':
"""
Obtains an environment associated with a type instead of a record
@param type_: Type
@return Associated Environment
"""
return Environment('type-' + str(type_))
@staticmethod
def private_environment(owner: typing.Any) -> 'Environment':
"""
Obtains an environment with an unique identifier
@return: An environment with an unique identifier
"""
return Environment(
'#_#' + str(id(owner)) + '#^#'
)
@staticmethod
def temporary_environment() -> 'Environment':
@ -187,7 +197,7 @@ class Environment:
return env
@staticmethod
def ommon_environment() -> 'Environment':
def common_environment() -> 'Environment':
"""
Provides global environment
"""

View File

@ -50,7 +50,7 @@ class DelayedTask(Environmentable):
"""
Remember to invoke parent init in derived clases using super(myClass,self).__init__() to let this initialize its own variables
"""
super().__init__(environment or Environment.environment_for_type(self.__class__))
super().__init__(environment or Environment.type_environment(self.__class__))
def execute(self) -> None:
"""

View File

@ -28,8 +28,8 @@
"""
@author: Adolfo Gómez, dkmaster at dkmon dot com
"""
import base64
import time
import codecs
import pickle # nosec: pickle is safe here
import threading
from socket import gethostname
@ -71,6 +71,7 @@ class DelayedTaskThread(threading.Thread):
except Exception as e:
logger.exception("Exception in thread %s: %s", e.__class__, e)
finally:
# This is run on a different thread, so we ensure the connection is closed
connections['default'].close()
@ -120,9 +121,9 @@ class DelayedTaskRunner(metaclass=singleton.Singleton):
) # @UndefinedVariable
if task.insert_date > now + timedelta(seconds=30):
logger.warning('Executed %s due to insert_date being in the future!', task.type)
taskInstanceDump = codecs.decode(task.instance.encode(), 'base64')
task_instance_dump = base64.b64decode(task.instance.encode())
task.delete()
taskInstance = pickle.loads(taskInstanceDump) # nosec: controlled pickle
task_instance = pickle.loads(task_instance_dump) # nosec: controlled pickle
except IndexError:
return # No problem, there is no waiting delayed task
except OperationalError:
@ -134,11 +135,11 @@ class DelayedTaskRunner(metaclass=singleton.Singleton):
logger.exception('Obtainint one task for execution')
return
if taskInstance:
if task_instance:
logger.debug('Executing delayedTask:>%s<', task)
# Re-create environment data
taskInstance.env = Environment.environment_for_type(taskInstance.__class__)
DelayedTaskThread(taskInstance).start()
task_instance.env = Environment.type_environment(task_instance.__class__)
DelayedTaskThread(task_instance).start()
def _insert(self, instance: DelayedTask, delay: int, tag: str) -> None:
now = sql_datetime()
@ -148,7 +149,7 @@ class DelayedTaskRunner(metaclass=singleton.Singleton):
# Save "env" from delayed task, set it to None and restore it after save
env = instance.env
instance.env = None # type: ignore # clean env before saving pickle, save space (the env will be created again when executing)
instance_dump = codecs.encode(pickle.dumps(instance), 'base64').decode()
instance_dump = base64.b64encode(pickle.dumps(instance)).decode()
instance.env = env
type_name = str(cls.__module__ + '.' + cls.__name__)

View File

@ -47,7 +47,7 @@ from uds.core import types, consts
if typing.TYPE_CHECKING:
from .user_service import UserService
from .publication import Publication
from uds.core import services
from uds.core import services, environment
from uds.core.util.unique_name_generator import UniqueNameGenerator
from uds.core.util.unique_mac_generator import UniqueMacGenerator
from uds.core.util.unique_gid_generator import UniqueGIDGenerator
@ -211,7 +211,7 @@ class Service(Module):
def __init__(
self,
environment,
environment: 'environment.Environment',
parent: 'services.ServiceProvider',
values: Module.ValuesType = None,
uuid: typing.Optional[str] = None,

View File

@ -83,7 +83,7 @@ class TestEnvironment(UDSTransactionTestCase):
self.assertEqual(env.cache.get('test'), None)
def test_global_environment(self) -> None:
env = environment.Environment.ommon_environment()
env = environment.Environment.common_environment()
self._check_environment(env, environment.COMMON_ENV, True)
def test_temporary_environment(self) -> None:
@ -99,8 +99,8 @@ class TestEnvironment(UDSTransactionTestCase):
self._check_environment(env, 't-test_table-123', True)
def test_environment_for_type(self) -> None:
env = environment.Environment.environment_for_type('test_type')
self._check_environment(env, 'type-test_type', True)
env = environment.Environment.type_environment(TestEnvironment)
self._check_environment(env, 'type-' + str(TestEnvironment), True)
def test_exclusive_temporary_environment(self) -> None:
unique_key: str = ''

View File

@ -96,7 +96,7 @@ class PhysicalMachinesMultiSerializationTest(UDSTestCase):
environment: Environment
def setUp(self) -> None:
self.environment = Environment.environment_for_type('test')
self.environment = Environment.temporary_environment()
self.environment.storage.save_to_db('ips', pickle.dumps(STORED_IPS))
def check(self, version: str, instance: 'service_multi.IPMachinesService') -> None:

View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2024 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 collections.abc
from unittest import mock
from ...utils.autospec import autospec, AutoSpecMethodInfo
from uds.services.Proxmox import provider, client
METHODS_INFO: typing.Final[list[AutoSpecMethodInfo]] = [
AutoSpecMethodInfo('test', method=mock.Mock(return_value=True)),
]
class TestProxmovProvider:
def test_provider(self) -> None:
"""
Test the provider
"""
client = autospec(provider.ProxmoxProvider, METHODS_INFO)
assert client.test() is True

View File

@ -35,9 +35,8 @@ import typing
# We use storage, so we need transactional tests
from tests.utils.test import UDSTransactionTestCase
from uds.core.util import autoserializable
from uds.core.services import service
from uds.core.environment import Environment
from uds.services import Proxmox
from uds.services.Proxmox.deployment import Operation as Operation, ProxmoxDeployment as Deployment
@ -95,7 +94,7 @@ class ProxmoxDeploymentSerializationTest(UDSTransactionTestCase):
environment = Environment.testing_environment()
def _create_instance(unmarshal_data: 'bytes|None' = None) -> Deployment:
instance = Deployment(environment=environment, service=None)
instance = Deployment(environment=environment, service=service.Service(Environment.testing_environment(), )
if unmarshal_data:
instance.unmarshal(unmarshal_data)
return instance

View File

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2024 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 collections.abc
import typing
import dataclasses
from unittest import mock
@dataclasses.dataclass
class AutoSpecMethodInfo:
name: str
return_value: typing.Any = None
method: 'typing.Callable|None' = None
def autospec(cls: typing.Type, metods_info: collections.abc.Iterable, **kwargs: typing.Any) -> typing.Any:
"""
This is a helper function that will create a mock object with the same methods as the class passed as parameter.
This is useful for testing purposes, where you want to mock a class and still have the same methods available.
"""
obj = mock.create_autospec(cls, **kwargs)
for method_info in metods_info:
setattr(obj, method_info.name, method_info.method or mock.Mock(return_value=method_info.return_value))
return obj

View File

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2024 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 random
import uuid
import typing
import collections.abc
from uds.core import services, environment
def fake_service_provider() -> services.ServiceProvider:
uuid_ = str(uuid.uuid4())
return services.ServiceProvider(
environment=environment.Environment.private_environment(uuid_),
uuid=uuid_,
)
def fake_service() -> services.Service:
uuid_ = str(uuid.uuid4())
return services.Service(
environment=environment.Environment.private_environment(uuid_),
parent=fake_service_provider(),
uuid=uuid_,
)

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2022 Virtual Cable S.L.
# Copyright (c) 2022-2024 Virtual Cable S.L.U.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@ -26,7 +26,7 @@
# 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
Author: Adolfo Gómez, dkmaster at dkmon dot com
"""
import random