Skip to content

Commit

Permalink
Merge a687e38 into 69040f8
Browse files Browse the repository at this point in the history
  • Loading branch information
UnDarkle committed Aug 12, 2019
2 parents 69040f8 + a687e38 commit 295b08d
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 12 deletions.
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -3,7 +3,7 @@
from setuptools import setup, find_packages


__version__ = "7.9.2"
__version__ = "7.10.0"

result_handlers = [
"db = rotest.core.result.handlers.db_handler:DBHandler",
Expand Down
5 changes: 4 additions & 1 deletion src/rotest/management/__init__.py
Expand Up @@ -7,12 +7,15 @@ class ManagementConfig(AppConfig):
def ready(self):
from .models import ResourceData
from .client.manager import ClientResourceManager
from .base_resource import BaseResource, ResourceRequest
from .base_resource import (BaseResource,
ResourceAdapter,
ResourceRequest)

import rotest
rotest.management.ResourceData = ResourceData
rotest.management.ClientResourceManager = ClientResourceManager
rotest.management.BaseResource = BaseResource
rotest.management.ResourceAdapter = ResourceAdapter
rotest.management.ResourceRequest = ResourceRequest


Expand Down
46 changes: 39 additions & 7 deletions src/rotest/management/base_resource.py
Expand Up @@ -4,7 +4,7 @@
responsible for the resource static & dynamic information.
"""
# pylint: disable=too-many-instance-attributes,no-self-use,broad-except
# pylint: disable=protected-access
# pylint: disable=protected-access,unused-argument
from __future__ import absolute_import

import sys
Expand Down Expand Up @@ -55,12 +55,44 @@ def __eq__(self, oth):

def __repr__(self):
"""Return a string representing the request."""
return "Request %r of type %r (kwargs=%r)" % (self.name, self.type,
self.kwargs)
return "%s %r of type %r (kwargs=%r)" % (self.__class__.__name__,
self.name,
self.type,
self.kwargs)

def clone(self):
"""Create a copy of the request."""
return ResourceRequest(self.name, self.type, **self.kwargs)
def get_type(self, config):
"""Get the requested resource class.
Args:
config (dict): the configuration file being used.
"""
return self.type


class ResourceAdapter(ResourceRequest):

"""Holds the data for a resource request.
Attributes:
resource_name (str): attribute name to be assigned.
resource_class (type): resource type.
force_initialize (bool): a flag to determine if the resources will be
initialized even if their validation succeeds.
kwargs (dict): requested resource arguments.
"""

def __init__(self, config_key, resource_classes, **kwargs):
"""Initialize the required parameters of resource request."""
super(ResourceAdapter, self).__init__(None, resource_classes, **kwargs)
self.config_key = config_key

def get_type(self, config):
"""Get the requested resource class.
Args:
config (dict): the configuration file being used.
"""
return self.type[config.get(self.config_key)]


class ExceptionCatchingThread(Thread):
Expand Down Expand Up @@ -158,7 +190,7 @@ class fields, where the 'data' attribute in the declaration points
sub_resources = []
for sub_name, sub_request in get_class_fields(self.__class__,
ResourceRequest):
sub_class = sub_request.type
sub_class = sub_request.get_type(self.config)
actual_kwargs = sub_request.kwargs.copy()
actual_kwargs['config'] = self.config
actual_kwargs['base_work_dir'] = self.work_dir
Expand Down
3 changes: 2 additions & 1 deletion src/rotest/management/client/manager.py
Expand Up @@ -384,7 +384,8 @@ def request_resources(self, requests,
ServerError. resource manager failed to lock resources.
"""
requests = list(requests)
descriptors = [ResourceDescriptor(request.type, **request.kwargs)
descriptors = [ResourceDescriptor(request.get_type(config),
**request.kwargs)
for request in requests]

initialized_resources = AttrDict()
Expand Down
22 changes: 21 additions & 1 deletion src/rotest/management/models/ut_resources.py
Expand Up @@ -5,7 +5,7 @@
import os
import shutil

from rotest.management.base_resource import BaseResource
from rotest.management.base_resource import BaseResource, ResourceAdapter
from .ut_models import ResourceData, DemoResourceData, DemoComplexResourceData


Expand Down Expand Up @@ -158,3 +158,23 @@ def initialize(self):
class DemoService(BaseResource):
"""Fake service class, used in resource manager tests."""
DATA_CLASS = None


class DemoResource2(DemoResource):
"""A demo resource class similar to DemoResource."""


class DemoAdaptiveComplexResource(BaseResource):
"""Fake complex resource class, used in resource manager tests.
Attributes:
sub_res1 (DemoResource): sub resource pointer.
sub_res2 (DemoResource / DemoResource2): sub resource pointer.
"""
DATA_CLASS = DemoComplexResourceData

sub_res1 = DemoResource2.request(data=DATA_CLASS.demo1)
sub_res2 = ResourceAdapter(config_key='field1',
resource_classes={True: DemoResource,
False: DemoResource2},
data=DATA_CLASS.demo2)
118 changes: 117 additions & 1 deletion tests/core/test_case.py
@@ -1,6 +1,7 @@
"""Test Rotest's TestCase class behavior."""
# pylint: disable=missing-docstring,unused-argument,protected-access
# pylint: disable=no-member,no-self-use,too-many-public-methods,invalid-name
# pylint: disable=too-many-lines
from __future__ import absolute_import

import os
Expand All @@ -11,10 +12,14 @@
from future.utils import iteritems

from rotest.core.case import request
from rotest.management.base_resource import ResourceAdapter
from rotest.core.models.case_data import TestOutcome, CaseData
from rotest.management.models.ut_models import DemoResourceData
from rotest.management.models.ut_resources import (DemoResource,
NonExistingResource)
DemoResource2,
NonExistingResource,
DemoComplexResource,
DemoAdaptiveComplexResource)

from tests.core.utils import (ErrorInSetupCase, SuccessCase, FailureCase,
ErrorCase, StoreMultipleFailuresCase,
Expand Down Expand Up @@ -49,6 +54,35 @@ class TempComplexRequestCase(SuccessCase):
res2 = DemoResource.request(name='available_resource2')


class TempComplexAdaptiveResourceCase(SuccessCase):
"""Inherit class and override resources requests."""
__test__ = False

resources = (request('res1', DemoAdaptiveComplexResource),)


class TempAdaptiveRequestPositiveCase(SuccessCase):
"""Inherit class and override resources requests."""
__test__ = False

resources = ()
res = ResourceAdapter(config_key='field1',
resource_classes={False: DemoResource,
True: DemoComplexResource},
name='available_resource1')


class TempAdaptiveRequestNegativeCase(SuccessCase):
"""Inherit class and override resources requests."""
__test__ = False

resources = ()
res = ResourceAdapter(config_key='field1',
resource_classes={True: DemoResource,
False: DemoComplexResource},
name='available_resource1')


class TempInheritRequestCase(TempComplexRequestCase):
"""Inherit one resource requests from the parent class."""
__test__ = False
Expand Down Expand Up @@ -261,6 +295,29 @@ def test_complex_resource_request(self):
self.assertIn('available_resource2', locked_names,
"Resource request using class field ignored kwargs")

def test_complex_adaptive_resource_request(self):
"""Test a TestCase that requests a complex adaptive resources."""
case = self._run_case(TempComplexAdaptiveResourceCase,
config={'field1': False})

self.assertTrue(self.result.wasSuccessful(),
'Case failed when it should have succeeded')

# === Validate case data object ===
self.assertTrue(case.data.success)

test_resources = case.all_resources

self.assertEqual(len(test_resources), 1,
"Unexpected number of resources, expected %r got %r" %
(1, len(test_resources)))

resource, = list(test_resources.values())
self.assertTrue(isinstance(resource.sub_res1, DemoResource2),
"Got wrong resource %r for sub_res1" % resource)
self.assertTrue(isinstance(resource.sub_res2, DemoResource2),
"Got wrong resource %r for sub_res2" % resource)

def test_inherit_resource_request(self):
"""Test a TestCase that inherits its resource request."""
case = self._run_case(TempInheritRequestCase)
Expand All @@ -284,6 +341,65 @@ def test_inherit_resource_request(self):
"Test doesn't contain field named %s" %
request_name)

def test_adaptive_request_positive(self):
"""Test a positive TestCase with a resource adapter.
* Using the kwargs, ask for an existing resource.
"""
case = self._run_case(TempAdaptiveRequestPositiveCase,
config={'field1': False})

self.assertTrue(self.result.wasSuccessful(),
'Case failed when it should have succeeded')

# === Validate case data object ===
self.assertTrue(case.data.success)

test_resources = case.all_resources
locked_names = []
for resource in six.itervalues(test_resources):
self.assertTrue(isinstance(resource, DemoResource),
"Got wrong resource %r for the request" % resource)

test_resource = DemoResourceData.objects.get(name=resource.name)
self.validate_resource(test_resource)
locked_names.append(resource.name)

self.assertEqual(len(test_resources), 1,
"Unexpected number of resources, expected %r got %r" %
(1, len(test_resources)))

request_name = 'res'
self.assertTrue(request_name in test_resources,
"Test didn't request a resource for %s" %
request_name)

self.assertTrue(request_name in case.__dict__,
"Test doesn't contain field named %s" %
request_name)

self.assertIn('available_resource1', locked_names,
"Resource request using 'resources' ignored kwargs")

def test_adaptive_request_negative(self):
"""Test a negative TestCase with a resource adapter.
* Using the kwargs, ask for a non existing resource.
"""
case = self._run_case(TempAdaptiveRequestNegativeCase,
config={'field1': False})

self.assertFalse(self.result.wasSuccessful(),
'Case failed when it should have succeeded')

# === Validate case data object ===
self.assertFalse(case.data.success)

test_resources = case.all_resources
self.assertEqual(len(test_resources), 0,
"Unexpected number of resources, expected %r got %r" %
(0, len(test_resources)))

def test_dynamic_resources_locking(self):
"""Test that cases can dynamically lock resources.
Expand Down

0 comments on commit 295b08d

Please sign in to comment.