Skip to content

Commit

Permalink
Add tests for transfer of resolvers (#4817)
Browse files Browse the repository at this point in the history
  • Loading branch information
shinyhappydan authored Apr 3, 2024
1 parent f1108a1 commit 7e5f9a0
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.resources.Resources
import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors
import ch.epfl.bluebrain.nexus.delta.sourcing.model.EntityType
import ch.epfl.bluebrain.nexus.delta.sourcing.offset.Offset
import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.Doobie.{PostgresPassword, PostgresUser, transactors}
import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.Doobie.{transactors, PostgresPassword, PostgresUser}
import ch.epfl.bluebrain.nexus.ship.ImportReport.Count
import ch.epfl.bluebrain.nexus.ship.RunShipSuite.clearDB
import ch.epfl.bluebrain.nexus.testkit.config.SystemPropertyOverride
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.nxv
import ch.epfl.bluebrain.nexus.delta.sourcing.exporter.ExportEventQuery
import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ProjectRef}
import ch.epfl.bluebrain.nexus.delta.sourcing.offset.Offset
import ch.epfl.bluebrain.nexus.tests.BaseIntegrationSpec
import ch.epfl.bluebrain.nexus.tests.Identity.writer
import ch.epfl.bluebrain.nexus.tests.admin.ProjectPayload
import ch.epfl.bluebrain.nexus.tests.iam.types.Permission
import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.Export
import ch.epfl.bluebrain.nexus.tests.{BaseIntegrationSpec, Optics}
import io.circe.Json
import io.circe.syntax.EncoderOps
import org.scalatest.Assertion
Expand Down Expand Up @@ -65,7 +65,7 @@ class ShipIntegrationSpec extends BaseIntegrationSpec {
"transfer the default resolver" in {
val (project, _, _) = thereIsAProject()
val defaultInProjectResolver = nxv + "defaultInProject"
val (_, resolverJson) = thereIsAResolver(defaultInProjectResolver, project)
val (_, resolverJson) = thereIsADefaultResolver(defaultInProjectResolver, project)

whenTheExportIsRunOnProject(project)
theOldProjectIsDeleted(project)
Expand All @@ -76,6 +76,17 @@ class ShipIntegrationSpec extends BaseIntegrationSpec {
thereShouldBeAResolver(project, defaultInProjectResolver, resolverJson)
}

"transfer all events from a resolver" in {
val (project, id, revisionsAndStates) = thereAreManyRevisionsOfAResolver()

whenTheExportIsRunOnProject(project)
theOldProjectIsDeleted(project)
weRunTheImporter(project)
weFixThePermissions(project)

thereShouldBeAResolverThatMatchesExpectations(project, id, revisionsAndStates)
}

"transfer a generic resource" in {
val (project, _, _) = thereIsAProject()
val (resource, resourceJson) = thereIsAResource(project)
Expand Down Expand Up @@ -243,6 +254,24 @@ class ShipIntegrationSpec extends BaseIntegrationSpec {
)
}

def thereAreManyRevisionsOfAResolver(): (ProjectRef, String, Map[Int, Json]) = {
val (project, _, _) = thereIsAProject()
val (id, payload, json) = thereIsAResolver(project)
val updatedPayload =
payload.hcursor.downField("priority").set(3.asJson).top.getOrElse(fail("could not update payload"))
val updatedJson = resolverIsUpdated(project, id, updatedPayload, 1)
val deprecatedJson = resolverIsDeprecated(project, id, 2)
(
project,
id,
Map(
1 -> json,
2 -> updatedJson,
3 -> deprecatedJson
)
)
}

def thereIsAProject(): (ProjectRef, ProjectPayload, Json) = {
val orgName = genString()
val projName = genString()
Expand Down Expand Up @@ -342,18 +371,49 @@ class ShipIntegrationSpec extends BaseIntegrationSpec {
succeed
}

def thereShouldBeAResolverThatMatchesExpectations(
project: ProjectRef,
id: String,
expectations: Map[Int, Json]
): Assertion = {
expectations.foreach { case (rev, expectedJson) =>
thereShouldBeAResolverRevision(project, id, rev, expectedJson)
}
succeed
}

def weFixThePermissions(project: ProjectRef) =
aclDsl.addPermissions(s"/$project", writer, Permission.minimalPermissions).accepted

def thereIsAResolver(resolver: Iri, project: ProjectRef): (Iri, Json) = {
val encodedResolver = UrlUtils.encode(resolver.toString)
def thereIsADefaultResolver(id: Iri, project: ProjectRef): (Iri, Json) = {
val encodedResolver = UrlUtils.encode(id.toString)
val (resolverJson, status) = deltaClient
.getJsonAndStatus(s"/resolvers/${project.organization}/${project.project}/$encodedResolver", writer)
.accepted
status shouldEqual StatusCodes.OK
resolver -> resolverJson
id -> resolverJson
}

def thereIsAResolver(project: ProjectRef): (String, Json, Json) = {
val payload = json"""{"@type": "InProject", "priority": 2}"""
val response = deltaClient
.postAndReturn[Json](s"/resolvers/${project.organization}/${project.project}", payload, writer) {
case (_, response) => response.status shouldBe StatusCodes.Created
}
.accepted

val id = Optics.`@id`.getOption(response).getOrElse(fail("resolver creation response did not contain an @id"))

val (resolverJson, status) = deltaClient
.getJsonAndStatus(resolverUrl(project, id), writer)
.accepted
status shouldEqual StatusCodes.OK
(id, payload, resolverJson)
}

def resolverUrl(project: ProjectRef, id: String): String =
s"/resolvers/${project.organization}/${project.project}/${UrlUtils.encode(id)}"

def thereShouldBeAResolver(project: ProjectRef, resolver: Iri, originalJson: Json): Assertion = {
val encodedResolver = UrlUtils.encode(resolver.toString)
deltaClient
Expand All @@ -367,6 +427,15 @@ class ShipIntegrationSpec extends BaseIntegrationSpec {
.accepted
}

def fetchResolver(project: ProjectRef, id: String): Json = {
val (json, status) = deltaClient
.getJsonAndStatus(s"/resolvers/${project.organization}/${project.project}/${UrlUtils.encode(id)}", writer)
.accepted

status shouldEqual StatusCodes.OK
json
}

def thereIsAResource(project: ProjectRef): (Iri, Json) = {
val resource = nxv + genString()
val encodedResource = UrlUtils.encode(resource.toString)
Expand Down Expand Up @@ -438,6 +507,38 @@ class ShipIntegrationSpec extends BaseIntegrationSpec {
.accepted
}

}
def thereShouldBeAResolverRevision(
project: ProjectRef,
id: String,
rev: Int,
expectedProjectJson: Json
): Assertion = {
deltaClient
.get[Json](s"${resolverUrl(project, id)}?rev=$rev", writer) { (json, response) =>
response.status shouldEqual StatusCodes.OK
json shouldEqual expectedProjectJson
}
.accepted
}

def resolverIsUpdated(project: ProjectRef, id: String, updatedPayload: Json, rev: Int): Json = {
deltaClient
.put[Json](s"${resolverUrl(project, id)}?rev=$rev", updatedPayload, writer) { case (_, response) =>
response.status shouldBe StatusCodes.OK
}
.accepted

fetchResolver(project, id)
}

def resolverIsDeprecated(project: ProjectRef, id: String, rev: Int): Json = {
deltaClient
.delete[Json](s"${resolverUrl(project, id)}?rev=$rev", writer) { case (_, response) =>
response.status shouldBe StatusCodes.OK
}
.accepted

fetchResolver(project, id)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit
)(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] =
requestAssert(POST, url, Some(body), identity, extraHeaders)(assertResponse)

def postJson(url: String, body: Json, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)(
assertResponse: (Json, HttpResponse) => Assertion
)(implicit um: FromEntityUnmarshaller[Json]): IO[Assertion] =
requestAssert(POST, url, Some(body), identity, extraHeaders)(assertResponse)

def postIO[A](url: String, body: IO[Json], identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)(
assertResponse: (A, HttpResponse) => Assertion
)(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = {
Expand All @@ -76,7 +81,7 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit
requestAssert(PUT, url, Some(body), identity, extraHeaders)(assertResponse)

def postAndReturn[A](url: String, body: Json, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)(
assertResponse: (A, HttpResponse) => (A, Assertion)
assertResponse: (A, HttpResponse) => Assertion
)(implicit um: FromEntityUnmarshaller[A]): IO[A] =
requestAssertAndReturn(POST, url, Some(body), identity, extraHeaders)(assertResponse).map(_._1)

Expand Down Expand Up @@ -229,7 +234,7 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit
body: Option[Json],
identity: Identity,
extraHeaders: Seq[HttpHeader] = jsonHeaders
)(assertResponse: (A, HttpResponse) => (A, Assertion))(implicit um: FromEntityUnmarshaller[A]): IO[(A, Assertion)] = {
)(assertResponse: (A, HttpResponse) => Assertion)(implicit um: FromEntityUnmarshaller[A]): IO[(A, Assertion)] = {
def buildClue(a: A, response: HttpResponse) =
s"""
|Endpoint: ${method.value} $url
Expand All @@ -248,7 +253,7 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit
identity,
(a: A, response: HttpResponse) => {
assertDeltaNodeHeader(response)
assertResponse(a, response) withClue buildClue(a, response)
a -> assertResponse(a, response) withClue buildClue(a, response)
},
extraHeaders
)
Expand All @@ -262,7 +267,7 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit
extraHeaders: Seq[HttpHeader] = jsonHeaders
)(assertResponse: (A, HttpResponse) => Assertion)(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] =
requestAssertAndReturn[A](method, url, body, identity, extraHeaders) { (a, resp) =>
(a, assertResponse(a, resp))
assertResponse(a, resp)
}.map(_._2)

def sparqlQuery[A](url: String, query: String, identity: Identity, extraHeaders: Seq[HttpHeader] = Nil)(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class BatchCopySpec extends BaseIntegrationSpec {

for {
response <- deltaClient.postAndReturn[Response](uri, payload, Coyote) { (json, response) =>
(json, expectCreated(json, response))
expectCreated(json, response)
}
ids = response.ids
_ <- checkFileResourcesExist(destProjRef, ids)
Expand Down

0 comments on commit 7e5f9a0

Please sign in to comment.