Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add e2e test for v2 lists endpoints #3315

Merged
merged 5 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ trait TestStartupUtils extends LazyLogging {
rdfDataObjects: List[RdfDataObject],
): ZIO[TriplestoreService with OntologyCache, Throwable, Unit] =
for {
_ <- ZIO.logInfo("Loading test data started ...")
_ <- ZIO.logInfo(s"Loading test data: ${rdfDataObjects.map(_.name).mkString}")
tss <- ZIO.service[TriplestoreService]
_ <- tss.resetTripleStoreContent(rdfDataObjects).timeout(480.seconds)
_ <- ZIO.logInfo("... loading test data done.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/*
* Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
* SPDX-License-Identifier: Apache-2.0
*/

package org.knora.webapi.slice.lists
import zio.test.*

import org.knora.webapi.E2EZSpec
import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject
import org.knora.webapi.slice.admin.domain.model.ListProperties.ListIri

object ListsV2E2Spec extends E2EZSpec {

private def v2listsListIri(iri: ListIri) = s"/v2/lists/${urlEncode(iri.value)}"
private def v2nodeListIri(iri: ListIri) = s"/v2/node/${urlEncode(iri.value)}"

private val knownRootNode = ListIri.unsafeFrom("http://rdfh.ch/lists/0001/notUsedList")
private val knownSubNode = ListIri.unsafeFrom("http://rdfh.ch/lists/0001/notUsedList01")

override def rdfDataObjects: List[RdfDataObject] =
List(
RdfDataObject(
path = "test_data/project_data/anything-data.ttl",
name = "http://www.knora.org/data/0001/anything",
),
)

override def e2eSpec: Spec[env, Any] = suite("the lists API v2 for")(
suite("/v2/lists/:listIri should")(
test("return 404 for an unknown list") {
for {
response <- sendGetRequest(v2listsListIri(ListIri.unsafeFrom("http://rdfh.ch/lists/0001/unknown")))
} yield assertTrue(response.status.code == 404)
},
test("return 404 for an existing sub node") {
for {
response <- sendGetRequest(v2listsListIri(knownSubNode))
} yield assertTrue(response.status.code == 404)
},
test("return a known list") {
for {
response <- sendGetRequest(v2listsListIri(knownRootNode))
bodyStr <- response.body.asString
} yield {
assertTrue(
response.status.code == 200,
bodyStr == """{
siers marked this conversation as resolved.
Show resolved Hide resolved
| "rdfs:label": "a list that is not used",
| "knora-api:attachedToProject": {
| "@id": "http://rdfh.ch/projects/0001"
| },
| "knora-api:hasSubListNode": [
| {
| "rdfs:label": "node 1",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:hasSubListNode": [
| {
| "rdfs:label": "child of node 1",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 0,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList011"
| },
| {
| "rdfs:label": "List012",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 1,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList012"
| },
| {
| "rdfs:label": "List013",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 2,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList013"
| },
| {
| "rdfs:label": "List014",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:hasSubListNode": [
| {
| "rdfs:label": "first child of node 014",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 0,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList0141"
| },
| {
| "rdfs:label": "second child of node 014",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 0,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList0142"
| }
| ],
| "knora-api:listNodePosition": 3,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList014"
| },
| {
| "rdfs:label": "List015",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 4,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList015"
| }
| ],
| "knora-api:listNodePosition": 0,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList01"
| },
| {
| "rdfs:label": "node 2",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 1,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList02"
| },
| {
| "rdfs:label": "node 3",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:hasSubListNode": {
| "rdfs:label": "child of node 3",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 0,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList031"
| },
| "knora-api:listNodePosition": 2,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList03"
| }
| ],
| "knora-api:isRootNode": true,
| "rdfs:comment": "a list that is not in used in ontology or data",
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList",
| "@context": {
| "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
| "knora-api": "http://api.knora.org/ontology/knora-api/v2#",
| "owl": "http://www.w3.org/2002/07/owl#",
| "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
| "xsd": "http://www.w3.org/2001/XMLSchema#"
| }
|}""".stripMargin,
)
}
},
),
suite("/v2/lists/:listIri should")(
test("return 404 for an unknown list") {
for {
response <- sendGetRequest(v2nodeListIri(ListIri.unsafeFrom("http://rdfh.ch/lists/0001/unknown")))
} yield assertTrue(response.status.code == 404)
},
test("return 404 for an existing root node") {
for {
response <- sendGetRequest(v2nodeListIri(knownRootNode))
} yield assertTrue(response.status.code == 404)
},
test("return 200 for an existing sub node") {
for {
response <- sendGetRequest(v2nodeListIri(knownSubNode))
bodyStr <- response.body.asString
} yield assertTrue(
response.status.code == 200,
bodyStr == """{
| "rdfs:label": "node 1",
| "knora-api:hasRootNode": {
| "@id": "http://rdfh.ch/lists/0001/notUsedList"
| },
| "knora-api:listNodePosition": 0,
| "@type": "knora-api:ListNode",
| "@id": "http://rdfh.ch/lists/0001/notUsedList01",
| "@context": {
| "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
| "knora-api": "http://api.knora.org/ontology/knora-api/v2#",
| "owl": "http://www.w3.org/2002/07/owl#",
| "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
| "xsd": "http://www.w3.org/2001/XMLSchema#"
| }
|}""".stripMargin,
)
},
),
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package org.knora.webapi.slice.lists.api
import sttp.model.MediaType
import zio.*

import dsp.errors.*
import dsp.errors.NotFoundException
import org.knora.webapi.config.AppConfig
import org.knora.webapi.messages.v2.responder.KnoraResponseV2
import org.knora.webapi.slice.admin.domain.model.ListProperties.ListIri
Expand All @@ -27,7 +27,16 @@ final case class ListsEndpointsV2Handler(
private val getV2Lists = SecuredEndpointHandler(
endpoints.getV2Lists,
(user: User) =>
(iri: ListIri, format: FormatOptions) => listsService.getList(iri, user).map(renderResponse(_, format)),
(iri: ListIri, format: FormatOptions) =>
listsService
.getList(iri, user)
.mapBoth(
{
case Some(e) => e
case None => NotFoundException(s"List ${iri.value} not found.")
},
renderResponse(_, format),
),
)

private def renderResponse(resp: KnoraResponseV2, format: FormatOptions): (MediaType, String) = {
Expand All @@ -43,8 +52,11 @@ final case class ListsEndpointsV2Handler(
listsService
.getNode(iri, user)
.mapBoth(
_.fold(NotFoundException(s"Node with IRI ${iri.value} not found"))(identity),
response => renderResponse(response, format),
{
case Some(e) => e
case None => NotFoundException(s"Node ${iri.value} not found.")
},
renderResponse(_, format),
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package org.knora.webapi.slice.lists.domain

import zio.*

import dsp.errors.NotFoundException
import org.knora.webapi.config.AppConfig
import org.knora.webapi.messages.admin.responder.listsmessages.ChildNodeInfoGetResponseADM
import org.knora.webapi.messages.admin.responder.listsmessages.ListGetResponseADM
Expand All @@ -22,33 +23,41 @@ final case class ListsService(private val appConfig: AppConfig, private val list
*
* @param listIri the Iri of the list's root node.
* @param requestingUser the user making the request.
* @return a [[ListGetResponseV2]].
* @return a [[ListGetResponseV2]]. . A [[None]] if the list is not found.
*/
def getList(listIri: ListIri, requestingUser: User): Task[ListGetResponseV2] =
def getList(listIri: ListIri, requestingUser: User): IO[Option[Throwable], ListGetResponseV2] =
listsResponder
.listGetRequestADM(listIri.value)
.mapAttempt(_.asInstanceOf[ListGetResponseADM])
.map(resp => ListGetResponseV2(resp.list, requestingUser.lang, appConfig.fallbackLanguage))
.mapError {
case e: NotFoundException => None
case e => Some(e)
}
.flatMap {
case ListGetResponseADM(list) => ZIO.succeed(list)
case _ => ZIO.fail(None)
}
.map(ListGetResponseV2(_, requestingUser.lang, appConfig.fallbackLanguage))

/**
* Gets a single list node from the triplestore.
*
* @param nodeIri the Iri of the list node.
*
* @param requestingUser the user making the request.
* @return a [[NodeGetResponseV2]].
* @return a [[NodeGetResponseV2]]. A [[None]] if the node is not found.
*/
def getNode(nodeIri: ListIri, requestingUser: User): IO[Option[Throwable], NodeGetResponseV2] =
listsResponder
.listNodeInfoGetRequestADM(nodeIri.value)
.asSomeError
.mapError {
case e: NotFoundException => None
case e => Some(e)
}
.flatMap {
case ChildNodeInfoGetResponseADM(node) =>
ZIO.succeed(
NodeGetResponseV2(node, requestingUser.lang, appConfig.fallbackLanguage),
)
case _ => ZIO.fail(None)
case ChildNodeInfoGetResponseADM(node) => ZIO.succeed(node)
case _ => ZIO.fail(None)
}
.map(NodeGetResponseV2(_, requestingUser.lang, appConfig.fallbackLanguage))
}

object ListsService {
Expand Down
Loading