Skip to content

Commit

Permalink
chore: Add e2e test for v2 lists endpoints (#3315)
Browse files Browse the repository at this point in the history
  • Loading branch information
seakayone authored Jul 11, 2024
1 parent 9c1a2c5 commit 17d7441
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 16 deletions.
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 == """{
| "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

0 comments on commit 17d7441

Please sign in to comment.