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

test: Set up plumbing for ZIO Test based E2E-Tests #3148

Merged
merged 12 commits into from
Mar 26, 2024
83 changes: 83 additions & 0 deletions integration/src/test/scala/org/knora/webapi/E2EZSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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

import zio._
import zio.http._
import zio.json._
import zio.test._

import org.knora.webapi.core.AppServer
import org.knora.webapi.core.LayersTest
import org.knora.webapi.core.TestStartupUtils
import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject

abstract class E2EZSpec extends ZIOSpecDefault with TestStartupUtils {

private lazy val testLayers = util.Logger.text() >>> core.LayersTest.integrationTestsWithFusekiTestcontainers()

def rdfDataObjects: List[RdfDataObject] = List.empty[RdfDataObject]

type env = LayersTest.DefaultTestEnvironmentWithoutSipi with Client with Scope

private def prepare: ZIO[AppServer.AppServerEnvironment, Throwable, AppServer] = for {
appServer <- AppServer.init()
_ <- appServer.start(requiresAdditionalRepositoryChecks = false, requiresIIIFService = false).orDie
_ <- prepareRepository(rdfDataObjects)
} yield appServer

def withResettedTriplestore =
TestAspect.before(prepareRepository(rdfDataObjects))

def e2eSpec: Spec[env, Any]

override def spec = (
e2eSpec
@@ TestAspect.beforeAll(prepare)
@@ TestAspect.sequential
).provideShared(testLayers, Client.default, Scope.default)

def sendGetRequestString(url: String): ZIO[env, String, String] =
for {
client <- ZIO.service[Client]
urlStr = s"http://localhost:3333$url"
urlFull <- ZIO.fromEither(URL.decode(urlStr)).mapError(_.getMessage)
response <- client.url(urlFull).get("/").mapError(_.getMessage)
data <- response.body.asString.mapError(_.getMessage)
} yield data

def sendGetRequest[B](url: String)(implicit dec: JsonDecoder[B]): ZIO[env, String, B] =
for {
response <- sendGetRequestString(url)
result <- ZIO.fromEither(response.fromJson[B])
} yield result

def sendPostRequestString(url: String, data: String): ZIO[env, String, String] =
for {
client <- ZIO.service[Client]
urlStr = s"http://localhost:3333$url"
urlFull <- ZIO.fromEither(URL.decode(urlStr)).mapError(_.getMessage)
body = Body.fromString(data)
header = Header.ContentType(MediaType.application.json)
response <- client.url(urlFull).addHeader(header).post("")(body).mapError(_.getMessage)
data <- response.body.asString.mapError(_.getMessage)
} yield data

def getToken(email: String, password: String): ZIO[env, String, String] =
for {
response <-
sendPostRequestString(
"/v2/authentication",
s"""|{
| "email": "$email",
| "password": "$password"
|}""".stripMargin,
)
result <- ZIO.fromEither(response.fromJson[Map[String, String]])
token <- ZIO.fromOption(result.get("token")).orElseFail("No token in response")
} yield token

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.e2e

import zio.json._
import zio.test._

import org.knora.webapi.E2EZSpec
import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject

object SampleE2ESpec extends E2EZSpec {

// add something to this list, if particular test data should be loaded
override def rdfDataObjects: List[RdfDataObject] = List.empty

case class VersionResponse(
buildCommit: String,
buildTime: String,
fuseki: String,
name: String,
pekkoHttp: String,
scala: String,
sipi: String,
webapi: String,
)
object VersionResponse {
implicit val decoder: JsonDecoder[VersionResponse] = DeriveJsonDecoder.gen[VersionResponse]
}

case class HealthResponse(name: String, severity: String, status: Boolean, message: String)
object HealthResponse {
implicit val decoder: JsonDecoder[HealthResponse] = DeriveJsonDecoder.gen[HealthResponse]
}

override def e2eSpec = suite("SampleE2ESpec")(
versionTest,
healthTest,
getTokenTest @@ withResettedTriplestore, // this is not actually needed, it just shows how to use it
)

val versionTest = test("check version endpoint") {
for {
response <- sendGetRequest[VersionResponse]("/version")
} yield assertTrue(
response.name == "version",
response.webapi.startsWith("v"),
response.scala.startsWith("2.13."),
)
}

val healthTest = test("check health endpoint") {
for {
response <- sendGetRequest[HealthResponse]("/health")
expected = HealthResponse("AppState", "non fatal", true, "Application is healthy")
} yield assertTrue(response == expected)
}

val getTokenTest = test("foo") {
for {
token <- getToken("root@example.com", "test")
} yield assertTrue(token.nonEmpty)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ final case class AppServer(

object AppServer {

private type AppServerEnvironment =
type AppServerEnvironment =
State & TriplestoreService & RepositoryUpdater & actor.ActorSystem & OntologyCache & SipiService & HttpServer & AppConfig

/**
Expand Down