From 9ede5afbe62911199ee3adbe734c24255e6ee2e8 Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Tue, 7 Jan 2025 15:08:47 +0100 Subject: [PATCH] add error handling to checkout endpoint --- .../exceptions/backend_errors.py | 15 ++++++++++++++ .../services_rpc/wb_api_server.py | 20 +++++++++++++++++++ .../tests/unit/test_licensed_items.py | 11 ++++++++++ .../licenses/_rpc.py | 13 +++++++++++- 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/services/api-server/src/simcore_service_api_server/exceptions/backend_errors.py b/services/api-server/src/simcore_service_api_server/exceptions/backend_errors.py index 0a23d0400f7..11c3e65a28e 100644 --- a/services/api-server/src/simcore_service_api_server/exceptions/backend_errors.py +++ b/services/api-server/src/simcore_service_api_server/exceptions/backend_errors.py @@ -105,3 +105,18 @@ class PricingPlanNotFoundError(BaseBackEndError): class ProjectAlreadyStartedError(BaseBackEndError): msg_template = "Project already started" status_code = status.HTTP_200_OK + + +class InsufficientNumberOfSeatsError(BaseBackEndError): + msg_template = "Not enough available seats. Current available seats {num_of_seats} for license item {licensed_item_id}" + status_code = status.HTTP_409_CONFLICT + + +class CanNotCheckoutServiceIsNotRunningError(BaseBackEndError): + msg_template = "Can not checkout license item {licensed_item_id} as dynamic service is not running. Current service id: {service_run_id}" + status_code = status.HTTP_422_UNPROCESSABLE_ENTITY + + +class LicensedItemCheckoutNotFoundError(BaseBackEndError): + msg_template = "Licensed item checkout {licensed_item_checkout_id} not found." + status_code = status.HTTP_404_NOT_FOUND diff --git a/services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py b/services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py index 8f1d5241ed9..413c4e509db 100644 --- a/services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py +++ b/services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py @@ -13,6 +13,15 @@ from models_library.users import UserID from models_library.wallets import WalletID from servicelib.rabbitmq._client_rpc import RabbitMQRPCClient +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( + CanNotCheckoutNotEnoughAvailableSeatsError, +) +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( + CanNotCheckoutServiceIsNotRunningError as _CanNotCheckoutServiceIsNotRunningError, +) +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( + NotEnoughAvailableSeatsError, +) from servicelib.rabbitmq.rpc_interfaces.webserver.licenses.licensed_items import ( checkout_licensed_item_for_wallet as _checkout_licensed_item_for_wallet, ) @@ -26,6 +35,10 @@ release_licensed_item_for_wallet as _release_licensed_item_for_wallet, ) +from ..exceptions.backend_errors import ( + CanNotCheckoutServiceIsNotRunningError, + InsufficientNumberOfSeatsError, +) from ..exceptions.service_errors_utils import service_exception_mapper from ..models.pagination import PaginationParams from ..models.schemas.model_adapter import LicensedItemCheckoutGet, LicensedItemGet @@ -94,6 +107,13 @@ async def get_available_licensed_items_for_wallet( licensed_items_page=licensed_items_page, page_params=page_params ) + @_exception_mapper( + rpc_exception_map={ + NotEnoughAvailableSeatsError: InsufficientNumberOfSeatsError, + CanNotCheckoutNotEnoughAvailableSeatsError: InsufficientNumberOfSeatsError, + _CanNotCheckoutServiceIsNotRunningError: CanNotCheckoutServiceIsNotRunningError, + } + ) async def checkout_licensed_item_for_wallet( self, *, diff --git a/services/api-server/tests/unit/test_licensed_items.py b/services/api-server/tests/unit/test_licensed_items.py index 4b156c545d9..e3e3a351ffe 100644 --- a/services/api-server/tests/unit/test_licensed_items.py +++ b/services/api-server/tests/unit/test_licensed_items.py @@ -26,6 +26,11 @@ from pytest_mock import MockerFixture from servicelib.rabbitmq._client_rpc import RabbitMQRPCClient from servicelib.rabbitmq._errors import RemoteMethodNotRegisteredError +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( + CanNotCheckoutNotEnoughAvailableSeatsError, + CanNotCheckoutServiceIsNotRunningError, + NotEnoughAvailableSeatsError, +) from simcore_service_api_server._meta import API_VTAG from simcore_service_api_server.api.dependencies.webserver_rpc import ( get_wb_api_rpc_client, @@ -159,6 +164,12 @@ async def side_effect( "exception_to_raise,expected_api_server_status_code", [ (None, status.HTTP_200_OK), + (NotEnoughAvailableSeatsError(), status.HTTP_409_CONFLICT), + (CanNotCheckoutNotEnoughAvailableSeatsError(), status.HTTP_409_CONFLICT), + ( + CanNotCheckoutServiceIsNotRunningError(), + status.HTTP_422_UNPROCESSABLE_ENTITY, + ), ], ) async def test_get_licensed_items_checkout( diff --git a/services/web/server/src/simcore_service_webserver/licenses/_rpc.py b/services/web/server/src/simcore_service_webserver/licenses/_rpc.py index 261eb51c3aa..8784806b788 100644 --- a/services/web/server/src/simcore_service_webserver/licenses/_rpc.py +++ b/services/web/server/src/simcore_service_webserver/licenses/_rpc.py @@ -17,6 +17,11 @@ from servicelib.rabbitmq import RPCRouter from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( LICENSES_ERRORS, + CanNotCheckoutNotEnoughAvailableSeatsError, + NotEnoughAvailableSeatsError, +) +from simcore_service_api_server.exceptions.backend_errors import ( + CanNotCheckoutServiceIsNotRunningError, ) from ..rabbitmq import get_rabbitmq_rpc_server @@ -58,7 +63,13 @@ async def get_available_licensed_items_for_wallet( raise NotImplementedError -@router.expose(reraise_if_error_type=LICENSES_ERRORS) +@router.expose( + reraise_if_error_type=( + NotEnoughAvailableSeatsError, + CanNotCheckoutNotEnoughAvailableSeatsError, + CanNotCheckoutServiceIsNotRunningError, + ) +) async def checkout_licensed_item_for_wallet( app: web.Application, *,