Skip to content

Commit

Permalink
added some tests for resource API
Browse files Browse the repository at this point in the history
  • Loading branch information
mwigham committed Jan 15, 2024
1 parent bc5827e commit 9a5b09f
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 97 deletions.
4 changes: 2 additions & 2 deletions src/apis/dataset/dataset_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def get(self, number=None):
current_app.config.get("URI_NISV_ORGANISATION"),
)
if html_page:
return make_response(html_page, 200)
return APIUtil.toSuccessResponse(html_page)
else:
logger.error(f"Could not generate the HTML page for {dataset_uri}.")
return APIUtil.toErrorResponse(
Expand Down Expand Up @@ -193,7 +193,7 @@ def get(self, number=None):
current_app.config.get("URI_NISV_ORGANISATION"),
)
if html_page:
return make_response(html_page, 200)
return APIUtil.toSuccessResponse(html_page)
else:
logger.error(
f"Could not generate proper HTML page for data catalog: {data_catalog_uri}."
Expand Down
105 changes: 105 additions & 0 deletions src/apis/resource/ResourceHandler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import logging
from flask import Response, render_template

import util.ld_util as ld_util

from models.ResourceURILevel import ResourceURILevel
from util.APIUtil import APIUtil
from util.mime_type_util import MimeType

logger = logging.getLogger()

class ResourceHandler():
@staticmethod
def get_lod_for_resource_in_type(mime_type: MimeType, identifier: str, data_domain: str, sparql_endpoint: str, nisv_organisation: str, cat_type="program"):
lod_url = None
try:
lod_url = ld_util.generate_lod_resource_uri(
ResourceURILevel(cat_type),
identifier,
data_domain,
)
except ValueError:
logger.error(
"Could not generate LOD resource URI. Invalid resource level supplied."
)
return APIUtil.toErrorResponse(
"bad_request", "Invalid resource level supplied"
)

if mime_type is MimeType.HTML:
# note that data for HTML is requested from the RDF store, so no need to do is_public_resource
logger.info(f"Generating HTML page for {lod_url}.")
html_page = ResourceHandler._get_lod_view_resource(
lod_url,
sparql_endpoint,
nisv_organisation,
)
if html_page:
return APIUtil.toSuccessResponse(html_page)
else:
logger.error(
f"Could not generate an HTML view for {lod_url}.",
)
return APIUtil.toErrorResponse(
"internal_server_error",
"Could not generate an HTML view for this resource.",
)

if mime_type:
# note we need to use empty params for the UI
logger.info(
f"Getting the RDF in the proper serialization format for {lod_url}."
)
rdf_graph = ld_util.get_lod_resource_from_rdf_store(
lod_url,
sparql_endpoint,
nisv_organisation
)
if rdf_graph is not None:
serialised_graph = rdf_graph.serialize(format=mime_type)
if serialised_graph:
return APIUtil.toSuccessResponse(serialised_graph)
else:
return Response("Error: serialisation failed")
else:
return Response("Error: no graph created")
logger.error("Error: no mime type was given.")
return APIUtil.toErrorResponse("bad_request", "No mime type detected...")

@staticmethod
def _get_lod_view_resource(
resource_url: str, sparql_endpoint: str, nisv_organisation_uri: str
):
"""Handler that, given a URI, gets RDF from the SPARQL endpoint and generates an HTML page.
:param resource_url: The URI for the resource.
:param sparql_endpoint - the SPARQL endpoint to get the resource from
:param nisv_organisation_uri - the URI identifying the NISV organisation, for provenance
"""
logger.info(
f"Getting the graph from the triple store for resource {resource_url}."
)
rdf_graph = ld_util.get_lod_resource_from_rdf_store(
resource_url, sparql_endpoint, nisv_organisation_uri
)
if rdf_graph:
logger.info(
f"A valid graph ({len(rdf_graph)} triples) was retrieved from the RDF store. "
"Returning a rendered HTML template 'resource.html'."
)
return render_template(
"resource.html",
resource_uri=resource_url,
structured_data=ld_util.json_ld_structured_data_for_resource(
rdf_graph, resource_url
),
json_header=ld_util.json_header_from_rdf_graph(rdf_graph, resource_url),
json_iri_iri=ld_util.json_iri_iri_from_rdf_graph(rdf_graph, resource_url),
json_iri_lit=ld_util.json_iri_lit_from_rdf_graph(rdf_graph, resource_url),
json_iri_bnode=ld_util.json_iri_bnode_from_rdf_graph(rdf_graph, resource_url),
nisv_sparql_endpoint=sparql_endpoint,
)
logger.error(
f"Triple data for lod view could not be retrieved from the triple store for {resource_url}."
)
return None
107 changes: 12 additions & 95 deletions src/apis/resource/resource_api.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
import logging

from flask import current_app, request, Response, render_template, make_response
from flask import current_app, request
from flask_restx import Namespace, Resource

from apis.resource.ResourceHandler import ResourceHandler
from util.mime_type_util import MimeType
from models.ResourceURILevel import ResourceURILevel
from util.APIUtil import APIUtil
from util.ld_util import (
generate_lod_resource_uri,
get_lod_resource_from_rdf_store,
json_ld_structured_data_for_resource,
json_header_from_rdf_graph,
json_iri_iri_from_rdf_graph,
json_iri_lit_from_rdf_graph,
json_iri_bnode_from_rdf_graph,
)


logger = logging.getLogger()

Expand All @@ -24,12 +16,12 @@
)



@api.doc(
responses={
200: "Success",
400: "Bad request.",
404: "Resource does not exist.",
500: "Server error"
}
)
@api.route(
Expand All @@ -41,21 +33,7 @@ class ResourceAPI(Resource):

@api.produces([mt.value for mt in MimeType])
def get(self, identifier, cat_type="program"):
lod_url = None
try:
lod_url = generate_lod_resource_uri(
ResourceURILevel(cat_type),
identifier,
current_app.config.get("BENG_DATA_DOMAIN"),
)
except ValueError:
logger.error(
"Could not generate LOD resource URI. Invalid resource level supplied."
)
return APIUtil.toErrorResponse(
"bad request", "Invalid resource level supplied"
)

resource_handler = ResourceHandler
lod_server_supported_mime_types = [mt.value for mt in MimeType]
best_match = request.accept_mimetypes.best_match(
lod_server_supported_mime_types
Expand All @@ -64,70 +42,9 @@ def get(self, identifier, cat_type="program"):
if best_match is not None:
mime_type = MimeType(best_match)

if mime_type is MimeType.HTML:
# note that data for HTML is requested from the RDF store, so no need to do is_public_resource
logger.info(f"Generating HTML page for {lod_url}.")
html_page = self._get_lod_view_resource(
lod_url,
current_app.config.get("SPARQL_ENDPOINT"),
current_app.config.get("URI_NISV_ORGANISATION"),
)
if html_page:
return make_response(html_page, 200)
else:
logger.error(
f"Could not generate an HTML view for {lod_url}.",
)
return APIUtil.toErrorResponse(
"internal_server_error",
"Could not generate an HTML view for this resource.",
)

if mime_type:
# note we need to use empty params for the UI
logger.info(
f"Getting the RDF in the proper serialization format for {lod_url}."
)
return get_lod_resource_from_rdf_store(
lod_url,
current_app.config.get("SPARQL_ENDPOINT"),
current_app.config.get("URI_NISV_ORGANISATION"),
)
logger.error("Error: no mime type was given.")
return Response("Error: No mime type detected...")

def _get_lod_view_resource(
self, resource_url: str, sparql_endpoint: str, nisv_organisation_uri: str
):
"""Handler that, given a URI, gets RDF from the SPARQL endpoint and generates an HTML page.
:param resource_url: The URI for the resource.
:param sparql_endpoint - the SPARQL endpoint to get the resource from
:param nisv_organisation_uri - the URI identifying the NISV organisation, for provenance
"""
logger.info(
f"Getting the graph from the triple store for resource {resource_url}."
)
rdf_graph = get_lod_resource_from_rdf_store(
resource_url, sparql_endpoint, nisv_organisation_uri
)
if rdf_graph:
logger.info(
f"A valid graph ({len(rdf_graph)} triples) was retrieved from the RDF store. "
"Returning a rendered HTML template 'resource.html'."
)
return render_template(
"resource.html",
resource_uri=resource_url,
structured_data=json_ld_structured_data_for_resource(
rdf_graph, resource_url
),
json_header=json_header_from_rdf_graph(rdf_graph, resource_url),
json_iri_iri=json_iri_iri_from_rdf_graph(rdf_graph, resource_url),
json_iri_lit=json_iri_lit_from_rdf_graph(rdf_graph, resource_url),
json_iri_bnode=json_iri_bnode_from_rdf_graph(rdf_graph, resource_url),
nisv_sparql_endpoint=sparql_endpoint,
)
logger.error(
f"Triple data for lod view could not be retrieved from the triple store for {resource_url}."
)
return None
return resource_handler.get_lod_for_resource_in_type(mime_type,
identifier,
current_app.config.get("BENG_DATA_DOMAIN"),
current_app.config.get("SPARQL_ENDPOINT"),
current_app.config.get("URI_NISV_ORGANISATION"),
cat_type)
1 change: 1 addition & 0 deletions src/tests/unit_tests/apis/resource/resource_api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
def test_init():
resource_api = ResourceAPI()
assert isinstance(resource_api, ResourceAPI)

71 changes: 71 additions & 0 deletions src/tests/unit_tests/apis/resource/resource_handler_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import pytest

from mockito import when, unstub, verify, ANY
from rdflib import Graph

import util.ld_util

from apis.resource.ResourceHandler import ResourceHandler
from models.ResourceURILevel import ResourceURILevel
from util.mime_type_util import MimeType

@pytest.mark.parametrize('mime_type',[
MimeType.JSON_LD,
MimeType.HTML
])
def test_get_200(mime_type):
DUMMY_IDENTIFIER = "dummy-identifier"
DUMMY_URL = f"https://{DUMMY_IDENTIFIER}"
DUMMY_PAGE = "just something pretending to be an HTML page"
DUMMY_GRAPH = Graph()
DUMMY_DOMAIN = "dummy domain"
DUMMY_ENDPOINT = "https://dummy"
DUMMY_NISV_ORGANISATION = "nisv"
DUMMY_SERIALISED_GRAPH = "just something pretending to be a serialisation of a graph"
CAT_TYPE = "program"
resource_handler = ResourceHandler

try:
when(util.ld_util).generate_lod_resource_uri(ResourceURILevel(CAT_TYPE), DUMMY_IDENTIFIER, DUMMY_DOMAIN).thenReturn(DUMMY_URL)
if mime_type is MimeType.HTML:
when(resource_handler)._get_lod_view_resource(DUMMY_URL, DUMMY_ENDPOINT, DUMMY_NISV_ORGANISATION).thenReturn(DUMMY_PAGE)
else:
when(util.ld_util).get_lod_resource_from_rdf_store(DUMMY_URL, DUMMY_ENDPOINT, DUMMY_NISV_ORGANISATION).thenReturn(DUMMY_GRAPH)
when(DUMMY_GRAPH).serialize(format=mime_type).thenReturn(DUMMY_SERIALISED_GRAPH)

resource_handler.get_lod_for_resource_in_type(mime_type, DUMMY_IDENTIFIER, DUMMY_DOMAIN, DUMMY_ENDPOINT, DUMMY_NISV_ORGANISATION, CAT_TYPE)

verify(util.ld_util, times=1).generate_lod_resource_uri(ResourceURILevel(CAT_TYPE), DUMMY_IDENTIFIER, DUMMY_DOMAIN)
if mime_type is MimeType.HTML:
verify(resource_handler, times=1)._get_lod_view_resource(DUMMY_URL, DUMMY_ENDPOINT, DUMMY_NISV_ORGANISATION)
else:
verify(util.ld_util, times=1).get_lod_resource_from_rdf_store(DUMMY_URL, DUMMY_ENDPOINT, DUMMY_NISV_ORGANISATION)
verify(DUMMY_GRAPH, times=1).serialize(format=mime_type)
finally:
unstub()

@pytest.mark.parametrize("cause", [
"no_mime_type",
"generate_uri_failed"
])
def test_get_400(cause):
DUMMY_IDENTIFIER = "dummy-identifier"
DUMMY_DOMAIN = "dummy domain"
DUMMY_ENDPOINT = "https://dummy"
DUMMY_NISV_ORGANISATION = "nisv"
CAT_TYPE = "program"
resource_handler = ResourceHandler

if cause == "no_mime_type":
BAD_MIME_TYPE = None
msg, code, explaination = resource_handler.get_lod_for_resource_in_type(BAD_MIME_TYPE, DUMMY_IDENTIFIER, DUMMY_DOMAIN, DUMMY_ENDPOINT, DUMMY_NISV_ORGANISATION, CAT_TYPE)
assert code == 400

elif cause == "generate_uri_failed":
DUMMY_MIME_TYPE = "dummy mime type"
with when(util.ld_util).generate_lod_resource_uri(ResourceURILevel(CAT_TYPE), DUMMY_IDENTIFIER, DUMMY_DOMAIN).thenRaise(ValueError):
msg, code, explaination = resource_handler.get_lod_for_resource_in_type(DUMMY_MIME_TYPE, DUMMY_IDENTIFIER, DUMMY_DOMAIN, DUMMY_ENDPOINT, DUMMY_NISV_ORGANISATION, CAT_TYPE)
assert code == 400
else:
raise ValueError("Bad test variable")

0 comments on commit 9a5b09f

Please sign in to comment.