Skip to content
Snippets Groups Projects
Commit f978f3b7 authored by Nathan Hertz's avatar Nathan Hertz Committed by Nathan Hertz
Browse files

Implemented view_capability_request and create_capability_request

Pyramid views
parent d62fae77
No related branches found
No related tags found
1 merge request!89WS-31: Viewing and creating capability requests
Pipeline #601 passed
This commit is part of merge request !89. Comments created here will be created in the context of that merge request.
...@@ -59,18 +59,15 @@ def capability_request_routes(config: Configurator): ...@@ -59,18 +59,15 @@ def capability_request_routes(config: Configurator):
# GET # GET
config.add_route("view_capability_request", f"{request_url}", request_method="GET") config.add_route("view_capability_request", f"{request_url}", request_method="GET")
# POST # POST
# TODO: Make it so {capability_name} in URL can be passed to capability request
config.add_route( config.add_route(
"create_capability_request", "create_capability_request",
"capability/{capability_name}/request/create", "capability/{capability_name}/request/create",
request_method="POST", request_method="POST",
request_param=["parameters", "versions"],
) )
config.add_route( config.add_route(
"edit_capability_request", "edit_capability_request",
f"{request_url}/edit", f"{request_url}/edit",
request_method="POST", request_method="POST",
request_param=["parameters", "versions"],
) )
config.add_route("submit_capability_request", f"{request_url}/submit", request_method="POST") config.add_route("submit_capability_request", f"{request_url}/submit", request_method="POST")
config.add_route("cancel_capability_request", f"{request_url}/cancel", request_method="POST") config.add_route("cancel_capability_request", f"{request_url}/cancel", request_method="POST")
......
...@@ -26,7 +26,8 @@ def view_capability(request: Request) -> Response: ...@@ -26,7 +26,8 @@ def view_capability(request: Request) -> Response:
URL: capability/{capability_name} URL: capability/{capability_name}
:param request: GET request :param request: GET request
:return: Response with JSON-formatted capability info if found or 404 response (HTTPNotFound) :return: Response with JSON-formatted capability info if found
or 404 response (HTTPNotFound)
""" """
capability = request.capability_info.lookup_capability(request.matchdict["capability_name"]) capability = request.capability_info.lookup_capability(request.matchdict["capability_name"])
if capability: if capability:
...@@ -44,8 +45,8 @@ def create_capability(request: Request) -> Response: ...@@ -44,8 +45,8 @@ def create_capability(request: Request) -> Response:
:param request: POST request, expecting JSON parameters ["capability_name", "steps", "max_jobs"] :param request: POST request, expecting JSON parameters ["capability_name", "steps", "max_jobs"]
optionally, accepts a boolean "enabled" parameter optionally, accepts a boolean "enabled" parameter
:return: Response with JSON-formatted capability info of newly created capability :return: Response with JSON-formatted capability info of newly created capability
or 400 response (HTTPBadRequest) if expected parameters not given or 400 response (HTTPBadRequest) if expected parameters not given
or 412 response (HTTPPreconditionFailed) if capability with given name already exists or 412 response (HTTPPreconditionFailed) if capability with given name already exists
""" """
expected_params = ["capability_name", "steps", "max_jobs"] expected_params = ["capability_name", "steps", "max_jobs"]
params = request.json_body params = request.json_body
...@@ -82,8 +83,9 @@ def edit_capability(request: Request) -> Response: ...@@ -82,8 +83,9 @@ def edit_capability(request: Request) -> Response:
:param request: POST request, expecting JSON parameters ["capability_name", "steps", "max_jobs"] :param request: POST request, expecting JSON parameters ["capability_name", "steps", "max_jobs"]
:return: Response with JSON-formatted capability info of newly created capability :return: Response with JSON-formatted capability info of newly created capability
or 400 response (HTTPBadRequest) if expected parameters not given or 400 response (HTTPBadRequest) if expected parameters not given
or 412 response (HTTPPreconditionFailed) if capability with given name does not exist or 412 response (HTTPPreconditionFailed) if capability with given name does not exist
or 417 response (HTTPExpectationFailed) if the capability was unable to be edited
TODO: In the future, we should check if there are any active requests for the capability being edited and TODO: In the future, we should check if there are any active requests for the capability being edited and
disallow its editing until they are finished disallow its editing until they are finished
...@@ -117,6 +119,14 @@ def edit_capability(request: Request) -> Response: ...@@ -117,6 +119,14 @@ def edit_capability(request: Request) -> Response:
@view_config(route_name="enable_capability", renderer="json") @view_config(route_name="enable_capability", renderer="json")
def enable_capability(request: Request) -> Response: def enable_capability(request: Request) -> Response:
"""
Pyramid view that enables a capability
:param request: POST request
:return: HTTP 200 response
or 412 response (HTTPPreconditionFailed) if capability with given name does not exist
or 417 response (HTTPExpectationFailed) if the capability was unable to be enabled
"""
capability_name = request.matchdict["capability_name"] capability_name = request.matchdict["capability_name"]
if not request.capability_info.lookup_capability(capability_name): if not request.capability_info.lookup_capability(capability_name):
...@@ -133,6 +143,14 @@ def enable_capability(request: Request) -> Response: ...@@ -133,6 +143,14 @@ def enable_capability(request: Request) -> Response:
@view_config(route_name="disable_capability", renderer="json") @view_config(route_name="disable_capability", renderer="json")
def disable_capability(request: Request) -> Response: def disable_capability(request: Request) -> Response:
"""
Pyramid view that disables a capability
:param request: POST request
:return: HTTP 200 response
or 412 response (HTTPPreconditionFailed) if capability with given name does not exist
or 417 response (HTTPExpectationFailed) if the capability was unable to be disabled
"""
capability_name = request.matchdict["capability_name"] capability_name = request.matchdict["capability_name"]
if not request.capability_info.lookup_capability(capability_name): if not request.capability_info.lookup_capability(capability_name):
......
"""
.. codeauthor:: Nathan Hertz <nhertz@nrao.edu>
File containing definitions for the other half of the capability side of the Workspaces REST API,
concerning capability requests
"""
from pyramid.httpexceptions import (
HTTPBadRequest,
HTTPExpectationFailed,
HTTPNotFound,
HTTPPreconditionFailed,
)
from pyramid.request import Request
from pyramid.response import Response
from pyramid.view import view_config
from workspaces.capability.schema import CapabilityRequest
@view_config(route_name="view_capability_request", renderer="json")
def view_capability_request(request: Request) -> Response:
"""
Pyramid view that accepts a request to view a capability request and responds with the request's info, if it exists
URL: capability/{capability_name}/request/{request_id}
:param request: GET request
:return: Response with JSON-formatted capability request info if found
or 404 response (HTTPNotFound)
"""
capability_request = request.capability_info.lookup_capability_request(
request.matchdict["request_id"]
)
if capability_request:
return Response(json_body=capability_request.__json__())
else:
not_found_msg = (
f"Capability request for capability {request.matchdict['capability_name']}",
f"with ID {request.matchdict['request_id']} not found.",
)
return HTTPNotFound(detail=not_found_msg)
@view_config(route_name="create_capability_request", renderer="json")
def create_capability_request(request: Request) -> Response:
"""
Pyramid view that accepts a request to create a capability request
URL: capability/{capability_name}/request/create
:param request: POST request, expecting JSON parameters ["parameters", "versions"]
:return: Response with JSON-formatted info of newly created capability request
or 400 response (HTTPBadRequest) if expected parameters not given
or 412 response (HTTPPreconditionFailed) if capability with given name does not exist and thus cannot be
requested
"""
expected_params = ["parameters", "versions"]
# TODO: What is the versions parameter going to look like?
# We can error check for a well-formatted param once we decide
capability_name = request.matchdict["capability_name"]
params = request.json_body
if not all([expected in params for expected in expected_params]):
# JSON params do not contain all expected params
params_not_given_msg = (
f"Expected JSON parameters {expected_params}. Received only {params}."
)
return HTTPBadRequest(detail=params_not_given_msg)
elif not request.capability_info.lookup_capability(capability_name):
# Capability with given name does not exist; can't create a request for it
does_not_exist_msg = (
f"Capability {capability_name} does not exist. Cannot create request.",
)
return HTTPPreconditionFailed(detail=does_not_exist_msg)
else:
new_capability_request = CapabilityRequest(
parameters=params["parameters"],
versions=params["versions"],
capability_name=capability_name,
state="Created",
)
request.capability_info.save_entity(new_capability_request)
return Response(json_body=new_capability_request.__json__())
@view_config(route_name="edit_capability_request", renderer="json")
def edit_capability_request(request: Request) -> Response:
"""
Pyramid view that accepts a request to edit a capability request
URL: capability/{capability_name}/request/{request_id}/edit
TODO: Implement once CapabilityVersions are supported
"""
return HTTPBadRequest()
from typing import Any
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest import pytest
from pyramid.config import Configurator from pyramid.config import Configurator
from pyramid.testing import DummyRequest, setUp, tearDown from pyramid.testing import DummyRequest, setUp, tearDown
from workspaces.capability.schema import Capability from workspaces.capability.schema import Capability, CapabilityRequest
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
...@@ -46,6 +47,15 @@ def request_null_capability() -> DummyRequest: ...@@ -46,6 +47,15 @@ def request_null_capability() -> DummyRequest:
max_jobs=-1, max_jobs=-1,
), ),
] ]
capability_requests = [
CapabilityRequest(
id=0,
state="Created",
capability_name="null",
parameters="-g",
versions=[],
)
]
def edit_capability( def edit_capability(
self, name: str, steps: str = None, max_jobs: int = None, enabled: bool = None self, name: str, steps: str = None, max_jobs: int = None, enabled: bool = None
...@@ -64,14 +74,24 @@ def request_null_capability() -> DummyRequest: ...@@ -64,14 +74,24 @@ def request_null_capability() -> DummyRequest:
return True return True
return False return False
def lookup_capability(self, capability_name: str): def lookup_capability(self, capability_name: str) -> Capability:
for capability in self.capabilities: for capability in self.capabilities:
if capability_name == capability.name: if capability_name == capability.name:
return capability return capability
return None return None
def save_entity(self, capability: Capability): def lookup_capability_request(self, request_id: int) -> CapabilityRequest:
self.capabilities.append(capability) for capability_request in self.capability_requests:
if request_id == capability_request.id:
return capability_request
return None
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)
request = DummyRequest(capability_info=MockCapabilityInfo()) request = DummyRequest(capability_info=MockCapabilityInfo())
return request return request
"""
Tests that test the view functionality of our capability REST API.
The logic can be found in `capability/views/capability.py`.
"""
from pyramid.config import Configurator from pyramid.config import Configurator
from pyramid.httpexceptions import ( from pyramid.httpexceptions import (
HTTPBadRequest, HTTPBadRequest,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment