Skip to content
Snippets Groups Projects
conftest.py 6.50 KiB
from typing import Any, List
from unittest.mock import MagicMock

import pytest
from pyramid.config import Configurator
from pyramid.testing import DummyRequest, setUp, tearDown

from workspaces.capability.enums import CapabilityRequestState, ExecutionState
from workspaces.capability.helpers import Parameter
from workspaces.capability.schema import (
    Capability,
    CapabilityExecution,
    CapabilityRequest,
    CapabilityVersion,
)
from workspaces.capability.schema_interfaces import CapabilityRequestIF
from workspaces.products.schema import FutureProduct


@pytest.fixture(scope="module")
def test_config() -> Configurator:
    """
    Returns a dummy Configurator object for testing purposes with set up and teardown

    :return: Dummy Configurator
    """
    request = DummyRequest()
    config = setUp(request=request)
    config.add_request_method(
        lambda lookup: MagicMock(),
        "capability_info",
        reify=True,
    )
    yield config
    tearDown()


class MockCapabilityInfo(MagicMock):
    capabilities = [
        Capability(
            name="null",
            steps="test",
            max_jobs=2,
            enabled=True,
        ),
        Capability(
            name="error",
            steps="error",
            max_jobs=-1,
            enabled=True,
        ),
    ]
    capability_requests = [
        CapabilityRequest(
            id=0,
            state="Created",
            capability_name="null",
            parameters="-g",
            versions=[],
        )
    ]
    capability_executions = []

    def edit_capability(
        self, name: str, steps: str = None, max_jobs: int = None, enabled: bool = None
    ) -> bool:
        if name == "error":
            # This is here to mimic the case where an update fails to happen
            return False
        for capability in self.capabilities:
            if name == capability.name:
                if steps:
                    capability.steps = steps
                if max_jobs:
                    capability.max_jobs = max_jobs
                if enabled:
                    capability.enabled = enabled
                return True
        return False

    def lookup_capability(self, capability_name: str) -> Capability:
        for capability in self.capabilities:
            if capability_name == capability.name:
                return capability
        return None

    def lookup_capability_request(self, request_id: int) -> CapabilityRequest:
        for capability_request in self.capability_requests:
            if request_id == capability_request.id:
                return capability_request
        return None

    def delete_capability_request(self, request_id: int) -> int:
        for capability_request in self.capability_requests:
            if request_id == capability_request.id:
                if self.can_delete_capability_request(request_id):
                    self.capability_requests.remove(capability_request)
                    return 1
                else:
                    return -1
        return 0

    def can_delete_capability_request(self, request_id) -> bool:
        for execution in self.capability_executions:
            if execution.capability_request_id == request_id:
                print(execution)
                print(execution.capability_request_id)
                return False
        return True

    def save_entity(self, entity: Any):
        if type(entity) is Capability:
            self.capabilities.append(entity)
        elif type(entity) is CapabilityRequest:
            entity.id = len(self.capability_requests)
            self.capability_requests.append(entity)
        elif type(entity) is CapabilityExecution:
            entity.id = len(self.capability_executions)
            self.capability_executions.append(entity)


class MockCapabilityService(MagicMock):
    def __init__(self, capability_info: MockCapabilityInfo):
        super().__init__()
        self.capability_info = capability_info
        self.execution_manager = MockExecutionManager(capability_info)

    def create_request(
        self,
        capability_name: str,
        parameters: List[Parameter] = None,
        products: List[FutureProduct] = None,
    ) -> CapabilityRequestIF:
        """
        Mocked version of the corresponding `CapabilityService.create_request` method

        :param capability_name: Name of capability
        :param parameters: Parameters for request
        :param products: Product that the request will give back
        :return: Newly created request
        """
        capability = self.capability_info.lookup_capability(capability_name)
        request = CapabilityRequest(
            state=CapabilityRequestState.Ready.name,
            capability=capability,
            capability_name=capability_name,
            parameters=str(parameters),
            # a trick here is to ensure that we always have a first version, with the original parameters
            versions=[CapabilityVersion(version_number=1, parameters=str(parameters))],
        )
        self.capability_info.save_entity(request)
        return request

    def run_capability(self, request: CapabilityRequest) -> CapabilityExecution:
        return self.execution_manager.run_capability(request)


class MockExecutionManager:
    def __init__(self, capability_info: MockCapabilityInfo):
        self.capability_info = capability_info

    def run_capability(self, capability_request: CapabilityRequest) -> CapabilityExecution:
        """
        Mock run_capability method

        :param capability_request: Request to make an execution for
        :return: Mocked execution
        """
        execution = CapabilityExecution(
            state=ExecutionState.Ready.name,
            capability_request_id=capability_request.id,
            version=CapabilityVersion(
                capability_request_id=capability_request.id,
                version_number=1,
                parameters=capability_request.parameters,
                request=capability_request,
            ),
            current_step=0,
            steps="test",
        )
        self.capability_info.save_entity(execution)
        return execution


@pytest.fixture(scope="module")
def request_null_capability() -> DummyRequest:
    """
    Returns a dummy request object with a mocked capability_info

    :return: DummyRequest with configured mock CapabilityInfo
    """

    mock_capability_info = MockCapabilityInfo()
    request = DummyRequest(
        capability_info=mock_capability_info,
        capability_service=MockCapabilityService(mock_capability_info),
    )
    return request