diff --git a/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsIOValues.scala b/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsIOValues.scala index b28bbbdbfb..f1c5cdcc63 100644 --- a/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsIOValues.scala +++ b/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsIOValues.scala @@ -5,9 +5,17 @@ import org.scalactic.source import org.scalatest.Assertion import org.scalatest.Assertions._ +import scala.concurrent.{ExecutionContext, Future} import scala.reflect.ClassTag -trait CatsIOValues { +trait CatsIOValues extends CatsIOValuesLowPrio { + + implicit def ioToFutureAssertion(io: IO[Assertion]): Future[Assertion] = io.unsafeToFuture() + + implicit def futureListToFutureAssertion(future: Future[List[Assertion]])(implicit + ec: ExecutionContext + ): Future[Assertion] = + future.map(_ => succeed) implicit final class CatsIOValuesOps[A](private val io: IO[A]) { def accepted: A = io.unsafeRunSync() @@ -31,3 +39,8 @@ trait CatsIOValues { } } + +trait CatsIOValuesLowPrio { + implicit def ioListToFutureAssertion(io: IO[List[Assertion]])(implicit ec: ExecutionContext): Future[Assertion] = + io.unsafeToFuture().map(_ => succeed) +} diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/BaseSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/BaseSpec.scala index 324ce31b35..be13ddc138 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/BaseSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/BaseSpec.scala @@ -6,8 +6,12 @@ import akka.http.scaladsl.model._ import akka.http.scaladsl.model.headers._ import akka.http.scaladsl.testkit.ScalatestRouteTest import akka.util.ByteString -import cats.implicits._ +import cats.effect.concurrent.Ref +import cats.effect.{ContextShift, IO} +import cats.syntax.all._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.testkit._ +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues import ch.epfl.bluebrain.nexus.tests.BaseSpec._ import ch.epfl.bluebrain.nexus.tests.HttpClient._ import ch.epfl.bluebrain.nexus.tests.Identity.{allUsers, testClient, testRealm, _} @@ -19,16 +23,14 @@ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.Organizations import ch.epfl.bluebrain.nexus.tests.iam.{AclDsl, PermissionDsl} import ch.epfl.bluebrain.nexus.tests.kg.{ElasticSearchViewsDsl, KgDsl} import com.typesafe.config.ConfigFactory -import com.typesafe.scalalogging.Logger import io.circe.Json -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.scalactic.source.Position import org.scalatest.concurrent.{Eventually, ScalaFutures} import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AsyncWordSpecLike import org.scalatest.{Assertion, BeforeAndAfterAll, OptionValues} +import scala.concurrent.ExecutionContext import scala.concurrent.duration._ trait BaseSpec @@ -42,12 +44,14 @@ trait BaseSpec with TestHelpers with ScalatestRouteTest with Eventually - with IOValues + with CatsIOValues with OptionValues with ScalaFutures with Matchers { - private val logger = Logger[this.type] + implicit val contextShift: ContextShift[IO] = IO.contextShift(ExecutionContext.global) + + private val logger = Logger.cats[this.type] implicit val config: TestsConfig = load[TestsConfig](ConfigFactory.load(), "tests") @@ -67,15 +71,10 @@ trait BaseSpec implicit override def patienceConfig: PatienceConfig = PatienceConfig(config.patience, 300.millis) - def eventually(t: Task[Assertion])(implicit pos: Position): Assertion = - eventually { - t.runSyncUnsafe() - } + def eventually(io: IO[Assertion])(implicit pos: Position): Assertion = + eventually { io.unsafeRunSync() } - def runTask[A](t: Task[A]): Assertion = - t.map { _ => - succeed - }.runSyncUnsafe() + def runIO[A](io: IO[A]): Assertion = io.map { _ => succeed }.unsafeRunSync() override def beforeAll(): Unit = { super.beforeAll() @@ -102,32 +101,28 @@ trait BaseSpec val allTasks = for { isSetupCompleted <- setupCompleted.get - _ <- Task.unless(isSetupCompleted)(setup) + _ <- IO.unlessA(isSetupCompleted)(setup) _ <- setupCompleted.set(true) _ <- aclDsl.cleanAclsAnonymous } yield () - allTasks.runSyncUnsafe() - + allTasks.unsafeRunSync() } override def afterAll(): Unit = - Task.when(config.cleanUp)(elasticsearchDsl.deleteAllIndices().void).runSyncUnsafe() + IO.whenA(config.cleanUp)(elasticsearchDsl.deleteAllIndices().void).unsafeRunSync() protected def toAuthorizationHeader(token: String) = - Authorization( - HttpCredentials.createOAuth2BearerToken(token) - ) - - private[tests] def authenticateUser(user: UserCredentials, client: ClientCredentials): Task[Unit] = { - keycloakDsl.userToken(user, client).map { token => - logger.info(s"Token for user ${user.name} is: $token") - tokensMap.put(user, toAuthorizationHeader(token)) - () - } - } + Authorization(HttpCredentials.createOAuth2BearerToken(token)) - private[tests] def authenticateClient(client: ClientCredentials): Task[Unit] = { + private[tests] def authenticateUser(user: UserCredentials, client: ClientCredentials): IO[Unit] = + for { + token <- keycloakDsl.userToken(user, client) + _ <- logger.info(s"Token for user ${user.name} is: $token") + _ <- IO(tokensMap.put(user, toAuthorizationHeader(token))) + } yield () + + private[tests] def authenticateClient(client: ClientCredentials): IO[Unit] = { keycloakDsl.serviceAccountToken(client).map { token => tokensMap.put(client, toAuthorizationHeader(token)) () @@ -152,35 +147,29 @@ trait BaseSpec identity: Identity, client: ClientCredentials, users: List[UserCredentials] - ): Task[Unit] = { - def createRealmInDelta: Task[Assertion] = + ): IO[Unit] = { + def createRealmInDelta: IO[Assertion] = deltaClient.get[Json](s"/realms/${realm.name}", identity) { (json, response) => - runTask { + runIO { response.status match { case StatusCodes.NotFound => - logger.info(s"Realm ${realm.name} is absent, we create it") val body = jsonContentOf( "/iam/realms/create.json", "realm" -> s"${config.realmSuffix(realm)}" ) for { - _ <- deltaClient.put[Json](s"/realms/${realm.name}", body, identity) { (_, response) => - response.status shouldEqual StatusCodes.Created - } - _ <- deltaClient.get[Json](s"/realms/${realm.name}", Identity.ServiceAccount) { (_, response) => - response.status shouldEqual StatusCodes.OK - } + _ <- logger.info(s"Realm ${realm.name} is absent, we create it") + _ <- deltaClient.put[Json](s"/realms/${realm.name}", body, identity) { expectCreated } + _ <- deltaClient.get[Json](s"/realms/${realm.name}", Identity.ServiceAccount) { expectOk } } yield () case StatusCodes.Forbidden | StatusCodes.OK => - logger.info(s"Realm ${realm.name} has already been created, we got status ${response.status}") - deltaClient.get[Json](s"/realms/${realm.name}", Identity.ServiceAccount) { (_, response) => - response.status shouldEqual StatusCodes.OK - } + for { + _ <- logger.info(s"Realm ${realm.name} has already been created, we got status ${response.status}") + _ <- deltaClient.get[Json](s"/realms/${realm.name}", Identity.ServiceAccount) { expectOk } + } yield () case s => - Task( - fail(s"$s wasn't expected here and we got this response: $json") - ) + IO(fail(s"$s wasn't expected here and we got this response: $json")) } } } @@ -189,12 +178,10 @@ trait BaseSpec // Create the realm in Keycloak _ <- keycloakDsl.importRealm(realm, client, users) // Get the tokens and cache them in the map - _ <- users.parTraverse { user => - authenticateUser(user, client) - } + _ <- users.parTraverse { user => authenticateUser(user, client) } _ <- authenticateClient(client) // Creating the realm in delta - _ <- Task { logger.info(s"Creating realm ${realm.name} in the delta instance") } + _ <- logger.info(s"Creating realm ${realm.name} in the delta instance") _ <- createRealmInDelta } yield () } @@ -202,11 +189,11 @@ trait BaseSpec /** * Create projects and the parent organization for the provided user */ - def createProjects(user: Authenticated, org: String, projects: String*): Task[Unit] = + def createProjects(user: Authenticated, org: String, projects: String*): IO[Unit] = for { _ <- aclDsl.addPermission("/", user, Organizations.Create) _ <- adminDsl.createOrganization(org, org, user, ignoreConflict = true) - _ <- projects.traverse { project => + _ <- projects.toList.traverse { project => val projectRef = s"$org/$project" adminDsl.createProject(org, project, kgDsl.projectJson(name = projectRef), user) } @@ -230,7 +217,7 @@ trait BaseSpec response.header[`Content-Encoding`].value.encodings private[tests] def decodeGzip(input: ByteString): String = - Coders.Gzip.decode(input).map(_.utf8String)(global).futureValue + Coders.Gzip.decode(input).map(_.utf8String).futureValue private[tests] def genId(length: Int = 15): String = genString(length = length, Vector.range('a', 'z') ++ Vector.range('0', '9')) @@ -251,6 +238,6 @@ trait BaseSpec object BaseSpec { - val setupCompleted: IORef[Boolean] = IORef.unsafe(false) + val setupCompleted: Ref[IO, Boolean] = Ref.unsafe(false) } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/BlazegraphDsl.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/BlazegraphDsl.scala index bd8b5235cf..d5786eebf6 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/BlazegraphDsl.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/BlazegraphDsl.scala @@ -6,14 +6,19 @@ import akka.http.scaladsl.model.HttpMethods.GET import akka.http.scaladsl.model.headers.Accept import akka.http.scaladsl.model.{HttpRequest, MediaRange, MediaType} import akka.stream.Materializer +import cats.effect.{ContextShift, IO} import ch.epfl.bluebrain.nexus.testkit.{CirceLiteral, TestHelpers} import io.circe.optics.JsonPath.root -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.scalatest.matchers.should.Matchers -class BlazegraphDsl(implicit as: ActorSystem, materializer: Materializer) - extends TestHelpers +import scala.concurrent.ExecutionContext + +class BlazegraphDsl(implicit + as: ActorSystem, + materializer: Materializer, + contextShift: ContextShift[IO], + ec: ExecutionContext +) extends TestHelpers with CirceLiteral with CirceUnmarshalling with Matchers { @@ -39,17 +44,14 @@ class BlazegraphDsl(implicit as: ActorSystem, materializer: Materializer) all should not contain allElementsOf(namespaces) } - def allNamespaces: Task[List[String]] = { + def allNamespaces: IO[List[String]] = { blazegraphClient( HttpRequest( method = GET, uri = s"$blazegraphUrl/blazegraph/namespace?describe-each-named-graph=false" ).addHeader(Accept(sparqlJsonRange)) ).flatMap { res => - Task - .deferFuture { - jsonUnmarshaller(res.entity)(global, materializer) - } + IO.fromFuture(IO(jsonUnmarshaller(res.entity))) .map { json => root.results.bindings.each.filter(filterNamespaces).`object`.value.string.getAll(json) } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/ElasticsearchDsl.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/ElasticsearchDsl.scala index 3759d04883..90ff6a354e 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/ElasticsearchDsl.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/ElasticsearchDsl.scala @@ -5,49 +5,41 @@ import akka.http.scaladsl.model.HttpMethods.{DELETE, GET, PUT} import akka.http.scaladsl.model.headers.BasicHttpCredentials import akka.http.scaladsl.model.{ContentTypes, HttpEntity, HttpRequest, StatusCode} import akka.stream.Materializer +import cats.effect.{ContextShift, IO} +import cats.syntax.all._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.testkit.{CirceLiteral, TestHelpers} -import com.typesafe.scalalogging.Logger -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.scalatest.matchers.should.Matchers -import scala.concurrent.duration._ +import scala.concurrent.ExecutionContext -class ElasticsearchDsl(implicit as: ActorSystem, materializer: Materializer) - extends TestHelpers +class ElasticsearchDsl(implicit + as: ActorSystem, + materializer: Materializer, + contextShift: ContextShift[IO], + ec: ExecutionContext +) extends TestHelpers with CirceLiteral with CirceUnmarshalling with Matchers { - private val logger = Logger[this.type] + private val logger = Logger.cats[this.type] private val elasticUrl = s"http://${sys.props.getOrElse("elasticsearch-url", "localhost:9200")}" private val elasticClient = HttpClient(elasticUrl) private val credentials = BasicHttpCredentials("elastic", "password") - def createTemplate(): Task[StatusCode] = { - logger.info("Creating template for Elasticsearch indices") - + def createTemplate(): IO[StatusCode] = { val json = jsonContentOf("/elasticsearch/template.json") - elasticClient( - HttpRequest( - method = PUT, - uri = s"$elasticUrl/_index_template/test_template", - entity = HttpEntity(ContentTypes.`application/json`, json.noSpaces) - ).addCredentials(credentials) - ).onErrorRestartLoop((10, 10.seconds)) { (err, state, retry) => - val (maxRetries, delay) = state - if (maxRetries > 0) - retry((maxRetries - 1, delay)).delayExecution(delay) - else - Task.raiseError(err) - }.tapError { t => - Task { logger.error(s"Error while importing elasticsearch template", t) } - }.map { res => - logger.info(s"Importing the elasticsearch template returned ${res.status}") - res.status - } + logger.info("Creating template for Elasticsearch indices") >> + elasticClient( + HttpRequest( + method = PUT, + uri = s"$elasticUrl/_index_template/test_template", + entity = HttpEntity(ContentTypes.`application/json`, json.noSpaces) + ).addCredentials(credentials) + ).map(_.status) } def includes(indices: String*) = @@ -60,32 +52,28 @@ class ElasticsearchDsl(implicit as: ActorSystem, materializer: Materializer) all should not contain allElementsOf(indices) } - def allIndices: Task[List[String]] = { + def allIndices: IO[List[String]] = { elasticClient( HttpRequest( method = GET, uri = s"$elasticUrl/_aliases" ).addCredentials(credentials) ).flatMap { res => - Task - .deferFuture { - jsonUnmarshaller(res.entity)(global, materializer) - } + IO.fromFuture(IO(jsonUnmarshaller(res.entity))) .map(_.asObject.fold(List.empty[String])(_.keys.toList)) } } - def deleteAllIndices(): Task[StatusCode] = + def deleteAllIndices(): IO[StatusCode] = elasticClient( HttpRequest( method = DELETE, uri = s"$elasticUrl/delta_*" ).addCredentials(credentials) - ).tapError { t => - Task { logger.error(s"Error while deleting elasticsearch indices", t) } - }.map { res => - logger.info(s"Deleting elasticsearch indices returned ${res.status}") - res.status + ).onError { t => + logger.error(t)(s"Error while deleting elasticsearch indices") + }.flatMap { res => + logger.info(s"Deleting elasticsearch indices returned ${res.status}").as(res.status) } } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/HttpClient.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/HttpClient.scala index 1b3d009d8e..5b1dbf48ad 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/HttpClient.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/HttpClient.scala @@ -5,55 +5,59 @@ import akka.http.scaladsl.model.HttpCharsets._ import akka.http.scaladsl.model.HttpMethods._ import akka.http.scaladsl.model.Multipart.FormData import akka.http.scaladsl.model.Multipart.FormData.BodyPart -import akka.http.scaladsl.model.headers.{`Accept-Encoding`, Accept, Authorization, HttpEncodings} import akka.http.scaladsl.model._ +import akka.http.scaladsl.model.headers.{`Accept-Encoding`, Accept, Authorization, HttpEncodings} import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller import akka.http.scaladsl.{Http, HttpExt} import akka.stream.Materializer import akka.stream.alpakka.sse.scaladsl.EventSource import akka.stream.scaladsl.Sink -import ch.epfl.bluebrain.nexus.tests.HttpClient.{jsonHeaders, logger, rdfApplicationSqlQuery, tokensMap} +import cats.effect.{ContextShift, IO} +import ch.epfl.bluebrain.nexus.tests.HttpClient.{jsonHeaders, rdfApplicationSqlQuery, tokensMap} import ch.epfl.bluebrain.nexus.tests.Identity.Anonymous -import com.typesafe.scalalogging.Logger import io.circe.Json import io.circe.parser._ import fs2._ -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.scalatest.matchers.should.Matchers import org.scalatest.{AppendedClues, Assertion} import java.nio.file.{Files, Path} import java.util.concurrent.ConcurrentHashMap import scala.collection.immutable.Seq -import scala.concurrent.Future import scala.concurrent.duration._ - -class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSystem, materializer: Materializer) - extends Matchers +import scala.concurrent.{ExecutionContext, Future} + +class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit + as: ActorSystem, + materializer: Materializer, + contextShift: ContextShift[IO], + ec: ExecutionContext +) extends Matchers with AppendedClues { - def apply(req: HttpRequest): Task[HttpResponse] = - Task.deferFuture(httpExt.singleRequest(req)) + private def fromFuture[A](future: => Future[A]) = IO.fromFuture { IO(future) } - def head(url: Uri, identity: Identity)(assertResponse: HttpResponse => Assertion): Task[Assertion] = { + def apply(req: HttpRequest): IO[HttpResponse] = + fromFuture(httpExt.singleRequest(req)) + + def head(url: Uri, identity: Identity)(assertResponse: HttpResponse => Assertion): IO[Assertion] = { val req = HttpRequest(HEAD, s"$baseUrl$url", headers = identityHeader(identity).toList) - Task.deferFuture(httpExt.singleRequest(req)).map(assertResponse) + fromFuture(httpExt.singleRequest(req)).map(assertResponse) } - def run[A](req: HttpRequest)(implicit um: FromEntityUnmarshaller[A]): Task[(A, HttpResponse)] = - Task.deferFuture(httpExt.singleRequest(req)).flatMap { res => - Task.deferFuture(um.apply(res.entity)).map(a => (a, res)) + def run[A](req: HttpRequest)(implicit um: FromEntityUnmarshaller[A]): IO[(A, HttpResponse)] = + fromFuture(httpExt.singleRequest(req)).flatMap { res => + fromFuture(um.apply(res.entity)).map(a => (a, res)) } def post[A](url: String, body: Json, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)( assertResponse: (A, HttpResponse) => Assertion - )(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = + )(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = requestAssert(POST, url, Some(body), identity, extraHeaders)(assertResponse) def put[A](url: String, body: Json, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)( assertResponse: (A, HttpResponse) => Assertion - )(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = + )(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = requestAssert(PUT, url, Some(body), identity, extraHeaders)(assertResponse) def putAttachmentFromPath[A]( @@ -63,9 +67,7 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst fileName: String, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders - )(assertResponse: (A, HttpResponse) => Assertion)(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = { - def onFail(e: Throwable) = - fail(s"Something went wrong while processing the response for $url with identity $identity", e) + )(assertResponse: (A, HttpResponse) => Assertion)(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = { request( PUT, url, @@ -76,7 +78,6 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst FormData(BodyPart.Strict("file", entity, Map("filename" -> fileName))).toEntity() }, assertResponse, - onFail, extraHeaders ) } @@ -88,7 +89,7 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst fileName: String, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders - )(assertResponse: (A, HttpResponse) => Assertion)(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = { + )(assertResponse: (A, HttpResponse) => Assertion)(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = { def buildClue(a: A, response: HttpResponse) = s""" |Endpoint: PUT $url @@ -100,8 +101,6 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst |$a |""".stripMargin - def onFail(e: Throwable) = - fail(s"Something went wrong while processing the response for $url with identity $identity", e) request( PUT, url, @@ -112,38 +111,32 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst FormData(BodyPart.Strict("file", entity, Map("filename" -> fileName))).toEntity() }, (a: A, response: HttpResponse) => assertResponse(a, response) withClue buildClue(a, response), - onFail, extraHeaders ) } def patch[A](url: String, body: Json, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)( assertResponse: (A, HttpResponse) => Assertion - )(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = + )(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = requestAssert(PATCH, url, Some(body), identity, extraHeaders)(assertResponse) def getWithBody[A](url: String, body: Json, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)( assertResponse: (A, HttpResponse) => Assertion - )(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = + )(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = requestAssert(GET, url, Some(body), identity, extraHeaders)(assertResponse) def get[A](url: String, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)( assertResponse: (A, HttpResponse) => Assertion - )(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = + )(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = requestAssert(GET, url, None, identity, extraHeaders)(assertResponse) - def getJson[A](url: String, identity: Identity)(implicit um: FromEntityUnmarshaller[A]): Task[A] = { - def onFail(e: Throwable) = - throw new IllegalStateException( - s"Something went wrong while processing the response for url: $url with identity $identity", - e - ) - requestJson(GET, url, None, identity, (a: A, _: HttpResponse) => a, onFail, jsonHeaders) + def getJson[A](url: String, identity: Identity)(implicit um: FromEntityUnmarshaller[A]): IO[A] = { + requestJson(GET, url, None, identity, (a: A, _: HttpResponse) => a, jsonHeaders) } def delete[A](url: String, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders)( assertResponse: (A, HttpResponse) => Assertion - )(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = + )(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = requestAssert(DELETE, url, None, identity, extraHeaders)(assertResponse) def requestAssert[A]( @@ -152,7 +145,7 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst body: Option[Json], identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders - )(assertResponse: (A, HttpResponse) => Assertion)(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = { + )(assertResponse: (A, HttpResponse) => Assertion)(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = { def buildClue(a: A, response: HttpResponse) = s""" |Endpoint: ${method.value} $url @@ -164,27 +157,19 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst |$a |""".stripMargin - def onFail(e: Throwable) = - fail( - s"Something went wrong while processing the response for url: ${method.value} $url with identity $identity", - e - ) requestJson( method, url, body, identity, (a: A, response: HttpResponse) => assertResponse(a, response) withClue buildClue(a, response), - onFail, extraHeaders ) } def sparqlQuery[A](url: String, query: String, identity: Identity, extraHeaders: Seq[HttpHeader] = Nil)( assertResponse: (A, HttpResponse) => Assertion - )(implicit um: FromEntityUnmarshaller[A]): Task[Assertion] = { - def onFail(e: Throwable): Assertion = - fail(s"Something went wrong while processing the response for url: $url with identity $identity", e) + )(implicit um: FromEntityUnmarshaller[A]): IO[Assertion] = { request( POST, url, @@ -192,7 +177,6 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst identity, (s: String) => HttpEntity(rdfApplicationSqlQuery, s), assertResponse, - onFail, extraHeaders ) } @@ -203,9 +187,8 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst body: Option[Json], identity: Identity, f: (A, HttpResponse) => R, - handleError: Throwable => R, extraHeaders: Seq[HttpHeader] - )(implicit um: FromEntityUnmarshaller[A]): Task[R] = + )(implicit um: FromEntityUnmarshaller[A]): IO[R] = request( method, url, @@ -213,7 +196,6 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst identity, (j: Json) => HttpEntity(ContentTypes.`application/json`, j.noSpaces), f, - handleError, extraHeaders ) @@ -238,9 +220,8 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst identity: Identity, toEntity: B => HttpEntity.Strict, f: (A, HttpResponse) => R, - handleError: Throwable => R, extraHeaders: Seq[HttpHeader] - )(implicit um: FromEntityUnmarshaller[A]): Task[R] = + )(implicit um: FromEntityUnmarshaller[A]): IO[R] = apply( HttpRequest( method = method, @@ -249,22 +230,8 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst entity = body.fold(HttpEntity.Empty)(toEntity) ) ).flatMap { res => - Task - .deferFuture { - um(res.entity)(global, materializer) - } - .map { - f(_, res) - } - .onErrorHandleWith { e => - for { - _ <- Task { - logger.error(s"Status ${res.status} for url $baseUrl$url", e) - } - } yield { - handleError(e) - } - } + fromFuture { um(res.entity) } + .map { f(_, res) } } def stream[A, B]( @@ -273,20 +240,14 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst lens: A => B, identity: Identity, extraHeaders: Seq[HttpHeader] = jsonHeaders - )(implicit um: FromEntityUnmarshaller[A]): Stream[Task, B] = { - def onFail(e: Throwable) = - throw new IllegalStateException( - s"Something went wrong while processing the response for url: $baseUrl$url with identity $identity", - e - ) - Stream.unfoldLoopEval[Task, String, B](url) { currentUrl => + )(implicit um: FromEntityUnmarshaller[A]): Stream[IO, B] = { + Stream.unfoldLoopEval[IO, String, B](url) { currentUrl => requestJson[A, A]( GET, currentUrl, None, identity, (a: A, _: HttpResponse) => a, - onFail, extraHeaders ).map { a => (lens(a), nextUrl(a)) @@ -300,17 +261,16 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst initialLastEventId: Option[String], take: Long = 100L, takeWithin: FiniteDuration = 5.seconds - )(assertResponse: Seq[(Option[String], Option[Json])] => Assertion): Task[Assertion] = { + )(assertResponse: Seq[(Option[String], Option[Json])] => Assertion): IO[Assertion] = { def send(request: HttpRequest): Future[HttpResponse] = - apply(request.addHeader(tokensMap.get(identity))).runToFuture - Task - .deferFuture { - EventSource(s"$baseUrl$url", send, initialLastEventId = initialLastEventId) - //drop resolver, views and storage events - .take(take) - .takeWithin(takeWithin) - .runWith(Sink.seq) - } + apply(request.addHeader(tokensMap.get(identity))).unsafeToFuture() + fromFuture { + EventSource(s"$baseUrl$url", send, initialLastEventId = initialLastEventId) + //drop resolver, views and storage events + .take(take) + .takeWithin(takeWithin) + .runWith(Sink.seq) + } .map { seq => assertResponse( seq.map { s => @@ -324,8 +284,6 @@ class HttpClient private (baseUrl: Uri, httpExt: HttpExt)(implicit as: ActorSyst object HttpClient { - private val logger = Logger[this.type] - val tokensMap: ConcurrentHashMap[Identity, Authorization] = new ConcurrentHashMap[Identity, Authorization] val acceptAll: Seq[Accept] = Seq(Accept(MediaRanges.`*/*`)) @@ -340,6 +298,10 @@ object HttpClient { val gzipHeaders: Seq[HttpHeader] = Seq(Accept(MediaRanges.`*/*`), `Accept-Encoding`(HttpEncodings.gzip)) - def apply(baseUrl: Uri)(implicit as: ActorSystem, materializer: Materializer) = - new HttpClient(baseUrl, Http()) + def apply(baseUrl: Uri)(implicit + as: ActorSystem, + materializer: Materializer, + contextShift: ContextShift[IO], + ec: ExecutionContext + ) = new HttpClient(baseUrl, Http()) } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/KeycloakDsl.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/KeycloakDsl.scala index a0af601df5..54335117f7 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/KeycloakDsl.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/KeycloakDsl.scala @@ -7,20 +7,26 @@ import akka.http.scaladsl.model._ import akka.http.scaladsl.model.headers.Authorization import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller import akka.stream.Materializer +import cats.syntax.all._ +import cats.effect.{ContextShift, IO} +import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.testkit.TestHelpers import ch.epfl.bluebrain.nexus.tests.Identity.{ClientCredentials, UserCredentials} import ch.epfl.bluebrain.nexus.tests.Optics._ -import com.typesafe.scalalogging.Logger import io.circe.Json -import monix.bio.Task -import scala.jdk.CollectionConverters._ -class KeycloakDsl(implicit as: ActorSystem, materializer: Materializer, um: FromEntityUnmarshaller[Json]) - extends TestHelpers { +import scala.concurrent.ExecutionContext +import scala.jdk.CollectionConverters._ - import monix.execution.Scheduler.Implicits.global +class KeycloakDsl(implicit + as: ActorSystem, + materializer: Materializer, + um: FromEntityUnmarshaller[Json], + contextShift: ContextShift[IO], + executionContext: ExecutionContext +) extends TestHelpers { - private val logger = Logger[this.type] + private val logger = Logger.cats[this.type] private val keycloakUrl = Uri(s"http://${sys.props.getOrElse("keycloak-url", "localhost:9090")}") private val keycloakClient = HttpClient(keycloakUrl) @@ -33,8 +39,7 @@ class KeycloakDsl(implicit as: ActorSystem, materializer: Materializer, um: From realm: Realm, clientCredentials: ClientCredentials, userCredentials: List[UserCredentials] - ): Task[StatusCode] = { - logger.info(s"Creating realm $realm in Keycloak...") + ): IO[StatusCode] = { val users = userCredentials.map { u => Map( s"username" -> u.name, @@ -51,28 +56,26 @@ class KeycloakDsl(implicit as: ActorSystem, materializer: Materializer, um: From ) for { + _ <- logger.info(s"Creating realm $realm in Keycloak...") adminToken <- userToken(keycloakAdmin, adminClient) - status <- keycloakClient( + response <- keycloakClient( HttpRequest( method = POST, uri = s"$keycloakUrl/admin/realms/", headers = Authorization(HttpCredentials.createOAuth2BearerToken(adminToken)) :: Nil, entity = HttpEntity(ContentTypes.`application/json`, json.noSpaces) ) - ).tapError { t => - Task { logger.error(s"Error while importing realm: ${realm.name}", t) } - }.map { res => - logger.info(s"${realm.name} has been imported with code: ${res.status}") - res.status + ).onError { t => + logger.error(t)(s"Error while importing realm: ${realm.name}") } - } yield status + _ <- logger.info(s"${realm.name} has been imported with code: ${response.status}") + } yield response.status } private def realmEndpoint(realm: Realm) = Uri(s"$keycloakUrl/realms/${realm.name}/protocol/openid-connect/token") - def userToken(user: UserCredentials, client: ClientCredentials): Task[String] = { - logger.info(s"Getting token for user ${user.name} for ${user.realm.name}") + def userToken(user: UserCredentials, client: ClientCredentials): IO[String] = { val clientFields = if (client.secret == "") { Map("scope" -> "openid", "client_id" -> client.id) } else { @@ -97,53 +100,54 @@ class KeycloakDsl(implicit as: ActorSystem, materializer: Materializer, um: From .toEntity ) - keycloakClient(request) - .flatMap { res => - Task.deferFuture { um(res.entity) } - } - .tapError { t => - Task { logger.error(s"Error while getting user token for realm: ${user.realm.name} and user:$user", t) } - } - .map { response => + logger.info(s"Getting token for user ${user.name} for ${user.realm.name}") >> + keycloakClient(request) + .flatMap { res => + IO.fromFuture { IO(um(res.entity)) } + } + .onError { t => + logger.error(t)(s"Error while getting user token for realm: ${user.realm.name} and user:$user") + } + .map { response => + keycloak.access_token + .getOption(response) + .getOrElse( + throw new IllegalArgumentException( + s"Couldn't get a token for user ${user.name}, we got response: $response" + ) + ) + } + + } + + def serviceAccountToken(client: ClientCredentials): IO[String] = { + logger.info(s"Getting token for client ${client.name} for ${client.realm}") >> + keycloakClient( + HttpRequest( + method = POST, + uri = realmEndpoint(client.realm), + headers = Authorization(HttpCredentials.createBasicHttpCredentials(client.id, client.secret)) :: Nil, + entity = akka.http.scaladsl.model + .FormData( + Map( + "scope" -> "openid", + "grant_type" -> "client_credentials" + ) + ) + .toEntity + ) + ).flatMap { res => + IO.fromFuture { IO(um(res.entity)) } + }.onError { t => + logger.error(t)(s"Error while getting user token for realm: ${client.realm} and client: $client") + }.map { response => keycloak.access_token .getOption(response) .getOrElse( throw new IllegalArgumentException( - s"Couldn't get a token for user ${user.name}, we got response: $response" + s"Couldn't get a token for client ${client.id} for realm ${client.realm.name}, we got response: $response" ) ) } - - } - - def serviceAccountToken(client: ClientCredentials): Task[String] = { - logger.info(s"Getting token for client ${client.name} for ${client.realm}") - keycloakClient( - HttpRequest( - method = POST, - uri = realmEndpoint(client.realm), - headers = Authorization(HttpCredentials.createBasicHttpCredentials(client.id, client.secret)) :: Nil, - entity = akka.http.scaladsl.model - .FormData( - Map( - "scope" -> "openid", - "grant_type" -> "client_credentials" - ) - ) - .toEntity - ) - ).flatMap { res => - Task.deferFuture { um(res.entity) } - }.tapError { t => - Task { logger.error(s"Error while getting user token for realm: ${client.realm} and client: $client", t) } - }.map { response => - keycloak.access_token - .getOption(response) - .getOrElse( - throw new IllegalArgumentException( - s"Couldn't get a token for client ${client.id} for realm ${client.realm.name}, we got response: $response" - ) - ) - } } } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/AdminDsl.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/AdminDsl.scala index 630309ba34..27be4cefc9 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/AdminDsl.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/AdminDsl.scala @@ -1,21 +1,21 @@ package ch.epfl.bluebrain.nexus.tests.admin import akka.http.scaladsl.model.StatusCodes +import cats.effect.IO +import cats.syntax.all._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.testkit.TestHelpers import ch.epfl.bluebrain.nexus.tests.Identity.Authenticated import ch.epfl.bluebrain.nexus.tests.Optics.{filterMetadataKeys, _} import ch.epfl.bluebrain.nexus.tests.config.TestsConfig import ch.epfl.bluebrain.nexus.tests.{CirceUnmarshalling, ExpectedResponse, HttpClient, Identity} -import com.typesafe.scalalogging.Logger import io.circe.Json -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.scalatest.Assertion import org.scalatest.matchers.should.Matchers class AdminDsl(cl: HttpClient, config: TestsConfig) extends TestHelpers with CirceUnmarshalling with Matchers { - private val logger = Logger[this.type] + private val logger = Logger.cats[this.type] def orgPayload(description: String = genString()): Json = jsonContentOf("/admin/orgs/payload.json", "description" -> description) @@ -84,7 +84,7 @@ class AdminDsl(cl: HttpClient, config: TestsConfig) extends TestHelpers with Cir authenticated: Authenticated, expectedResponse: Option[ExpectedResponse] = None, ignoreConflict: Boolean = false - ): Task[Assertion] = + ): IO[Assertion] = updateOrganization(id, description, authenticated, 0, expectedResponse, ignoreConflict) def updateOrganization( @@ -94,7 +94,7 @@ class AdminDsl(cl: HttpClient, config: TestsConfig) extends TestHelpers with Cir rev: Int, expectedResponse: Option[ExpectedResponse] = None, ignoreConflict: Boolean = false - ): Task[Assertion] = { + ): IO[Assertion] = { cl.put[Json](s"/orgs/$id${queryParams(rev)}", orgPayload(description), authenticated) { (json, response) => expectedResponse match { case Some(e) => @@ -122,7 +122,7 @@ class AdminDsl(cl: HttpClient, config: TestsConfig) extends TestHelpers with Cir } } - def deprecateOrganization(id: String, authenticated: Authenticated): Task[Assertion] = + def deprecateOrganization(id: String, authenticated: Authenticated): IO[Assertion] = cl.get[Json](s"/orgs/$id", authenticated) { (json, response) => response.status shouldEqual StatusCodes.OK val rev = admin._rev.getOption(json).value @@ -137,7 +137,7 @@ class AdminDsl(cl: HttpClient, config: TestsConfig) extends TestHelpers with Cir "organizations", deprecated = true ) - }.runSyncUnsafe() + }.unsafeRunSync() } private[tests] val startPool = Vector.range('a', 'z') @@ -168,7 +168,7 @@ class AdminDsl(cl: HttpClient, config: TestsConfig) extends TestHelpers with Cir json: Json, authenticated: Authenticated, expectedResponse: Option[ExpectedResponse] = None - ): Task[Assertion] = + ): IO[Assertion] = updateProject(orgId, projectId, json, authenticated, 0, expectedResponse) def updateProject( @@ -178,30 +178,30 @@ class AdminDsl(cl: HttpClient, config: TestsConfig) extends TestHelpers with Cir authenticated: Authenticated, rev: Int, expectedResponse: Option[ExpectedResponse] = None - ): Task[Assertion] = - cl.put[Json](s"/projects/$orgId/$projectId${queryParams(rev)}", payload, authenticated) { (json, response) => - logger.info(s"Creating/updating project $orgId/$projectId at revision $rev") - expectedResponse match { - case Some(e) => - response.status shouldEqual e.statusCode - json shouldEqual e.json - case None => - if (rev == 0) - response.status shouldEqual StatusCodes.Created - else - response.status shouldEqual StatusCodes.OK - filterProjectMetadataKeys(json) shouldEqual createProjectRespJson( - projectId, - orgId, - rev + 1, - authenticated = authenticated, - schema = "projects" - ) - } + ): IO[Assertion] = + logger.info(s"Creating/updating project $orgId/$projectId at revision $rev") >> + cl.put[Json](s"/projects/$orgId/$projectId${queryParams(rev)}", payload, authenticated) { (json, response) => + expectedResponse match { + case Some(e) => + response.status shouldEqual e.statusCode + json shouldEqual e.json + case None => + if (rev == 0) + response.status shouldEqual StatusCodes.Created + else + response.status shouldEqual StatusCodes.OK + filterProjectMetadataKeys(json) shouldEqual createProjectRespJson( + projectId, + orgId, + rev + 1, + authenticated = authenticated, + schema = "projects" + ) + } - } + } - def getUuids(orgId: String, projectId: String, identity: Identity): Task[(String, String)] = + def getUuids(orgId: String, projectId: String, identity: Identity): IO[(String, String)] = for { orgUuid <- cl.getJson[Json](s"/orgs/$orgId", identity) projectUuid <- cl.getJson[Json](s"/projects/$orgId/$projectId", identity) diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/OrgsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/OrgsSpec.scala index fc3d7c3cc3..806f6529b5 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/OrgsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/OrgsSpec.scala @@ -6,7 +6,6 @@ import ch.epfl.bluebrain.nexus.tests.Identity.orgs.{Fry, Leela} import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.{BaseSpec, ExpectedResponse} import io.circe.Json -import monix.execution.Scheduler.Implicits.global class OrgsSpec extends BaseSpec with EitherValuable { @@ -110,7 +109,7 @@ class OrgsSpec extends BaseSpec with EitherValuable { "fetch organization by UUID" in { deltaClient.get[Json](s"/orgs/$id", Leela) { (jsonById, _) => - runTask { + runIO { val orgUuid = _uuid.getOption(jsonById).value deltaClient.get[Json](s"/orgs/$orgUuid", Leela) { (jsonByUuid, response) => @@ -223,7 +222,7 @@ class OrgsSpec extends BaseSpec with EitherValuable { 2 ) _ <- deltaClient.get[Json](s"/orgs/$id", Leela) { (lastVersion, response) => - runTask { + runIO { response.status shouldEqual StatusCodes.OK admin.validate(lastVersion, "Organization", "orgs", id, updatedName2, 3, id) deltaClient.get[Json](s"/orgs/$id?rev=3", Leela) { (thirdVersion, response) => diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/ProjectsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/ProjectsSpec.scala index b60dbf2a85..3dc991adad 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/ProjectsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/admin/ProjectsSpec.scala @@ -11,7 +11,6 @@ import ch.epfl.bluebrain.nexus.tests.Identity.resources.Rick import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.{BaseSpec, ExpectedResponse, Identity} import io.circe.Json -import monix.execution.Scheduler.Implicits.global class ProjectsSpec extends BaseSpec { @@ -143,10 +142,10 @@ class ProjectsSpec extends BaseSpec { "fetch project by UUID" in { deltaClient.get[Json](s"/orgs/$orgId", Identity.ServiceAccount) { (orgJson, _) => - runTask { + runIO { val orgUuid = _uuid.getOption(orgJson).value deltaClient.get[Json](s"/projects/$id", Bojack) { (projectJson, _) => - runTask { + runIO { val projectUuid = _uuid.getOption(projectJson).value deltaClient.get[Json](s"/projects/$orgUuid/$projectUuid", Bojack) { (json, response) => response.status shouldEqual StatusCodes.OK diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/AclDsl.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/AclDsl.scala index 3b6bcc0c9f..f5ed8c0e0c 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/AclDsl.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/AclDsl.scala @@ -1,27 +1,27 @@ package ch.epfl.bluebrain.nexus.tests.iam import akka.http.scaladsl.model.{HttpResponse, StatusCodes} +import cats.effect.{ContextShift, IO} import cats.implicits._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.testkit.TestHelpers import ch.epfl.bluebrain.nexus.tests.Identity.Authenticated import ch.epfl.bluebrain.nexus.tests.Optics.error import ch.epfl.bluebrain.nexus.tests.iam.types.{AclEntry, AclListing, Anonymous, Permission, User} import ch.epfl.bluebrain.nexus.tests.{CirceUnmarshalling, HttpClient, Identity} -import com.typesafe.scalalogging.Logger import io.circe.Json -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.scalatest.matchers.should.Matchers import org.scalatest.{Assertion, OptionValues} + import scala.jdk.CollectionConverters._ class AclDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling with OptionValues with Matchers { - private val logger = Logger[this.type] + private val logger = Logger.cats[this.type] def fetch(path: String, identity: Identity, self: Boolean = true, ancestors: Boolean = false)( assertAcls: AclListing => Assertion - ): Task[Assertion] = { + ): IO[Assertion] = { path should not startWith "/acls" cl.get[AclListing](s"/acls$path?ancestors=$ancestors&self=$self", identity) { (acls, response) => response.status shouldEqual StatusCodes.OK @@ -29,10 +29,10 @@ class AclDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling with Op } } - def addPermission(path: String, target: Authenticated, permission: Permission): Task[Assertion] = + def addPermission(path: String, target: Authenticated, permission: Permission): IO[Assertion] = addPermissions(path, target, Set(permission)) - def addPermissions(path: String, target: Authenticated, permissions: Set[Permission]): Task[Assertion] = { + def addPermissions(path: String, target: Authenticated, permissions: Set[Permission]): IO[Assertion] = { val json = jsonContentOf( "/iam/add.json", "realm" -> target.realm.name, @@ -43,10 +43,10 @@ class AclDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling with Op addPermissions(path, json, target.name) } - def addPermissionAnonymous(path: String, permission: Permission): Task[Assertion] = + def addPermissionAnonymous(path: String, permission: Permission): IO[Assertion] = addPermissionsAnonymous(path, Set(permission)) - def addPermissionsAnonymous(path: String, permissions: Set[Permission]): Task[Assertion] = { + def addPermissionsAnonymous(path: String, permissions: Set[Permission]): IO[Assertion] = { val json = jsonContentOf( "/iam/add_annon.json", "perms" -> permissions.asJava @@ -55,41 +55,37 @@ class AclDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling with Op addPermissions(path, json, "Anonymous") } - def addPermissions(path: String, payload: Json, targetName: String): Task[Assertion] = { - logger.info(s"Addings permissions to $path for $targetName") + def addPermissions(path: String, payload: Json, targetName: String): IO[Assertion] = { def assertResponse(json: Json, response: HttpResponse) = response.status match { case StatusCodes.Created | StatusCodes.OK => - logger.info(s"Permissions has been successfully added for $targetName on $path") succeed case StatusCodes.BadRequest => val errorType = error.`@type`.getOption(json) - logger.warn( - s"We got a bad request when adding permissions for $targetName on $path with error type $errorType" - ) errorType.value shouldBe "NothingToBeUpdated" case s => fail(s"We were not expecting $s when setting acls on $path for $targetName") } - fetch(path, Identity.ServiceAccount) { acls => - { - val rev = acls._results.headOption - rev match { - case Some(r) => - cl.patch[Json](s"/acls$path?rev=${r._rev}", payload, Identity.ServiceAccount) { - assertResponse - } - case None => - cl.patch[Json](s"/acls$path", payload, Identity.ServiceAccount) { - assertResponse - } - } - }.runSyncUnsafe() - } + logger.info(s"Addings permissions to $path for $targetName") >> + fetch(path, Identity.ServiceAccount) { acls => + { + val rev = acls._results.headOption + rev match { + case Some(r) => + cl.patch[Json](s"/acls$path?rev=${r._rev}", payload, Identity.ServiceAccount) { + assertResponse + } + case None => + cl.patch[Json](s"/acls$path", payload, Identity.ServiceAccount) { + assertResponse + } + } + }.unsafeRunSync() + } } - def cleanAcls(target: Authenticated): Task[Assertion] = + def cleanAcls(target: Authenticated)(implicit contextShift: ContextShift[IO]): IO[Assertion] = fetch(s"/*/*", Identity.ServiceAccount, ancestors = true, self = false) { acls => val permissions = acls._results .map { acls => @@ -114,10 +110,10 @@ class AclDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling with Op } } .map(_ => succeed) - .runSyncUnsafe() + .unsafeRunSync() } - def cleanAclsAnonymous: Task[Assertion] = + def cleanAclsAnonymous(implicit contextShift: ContextShift[IO]): IO[Assertion] = fetch(s"/*/*", Identity.ServiceAccount, ancestors = true, self = false) { acls => val permissions = acls._results .map { acls => @@ -140,23 +136,23 @@ class AclDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling with Op } } .map(_ => succeed) - .runSyncUnsafe() + .unsafeRunSync() } - def deletePermission(path: String, target: Authenticated, permission: Permission): Task[Assertion] = + def deletePermission(path: String, target: Authenticated, permission: Permission): IO[Assertion] = deletePermissions(path, target, Set(permission)) - def deletePermissions(path: String, target: Authenticated, permissions: Set[Permission]): Task[Assertion] = + def deletePermissions(path: String, target: Authenticated, permissions: Set[Permission]): IO[Assertion] = fetch(path, Identity.ServiceAccount) { acls => deletePermissions( path, target, acls._results.head._rev, permissions - ).runSyncUnsafe() + ).unsafeRunSync() } - def deletePermission(path: String, target: Authenticated, rev: Int, permission: Permission): Task[Assertion] = { + def deletePermission(path: String, target: Authenticated, rev: Int, permission: Permission): IO[Assertion] = { deletePermissions(path, target, rev, Set(permission)) } @@ -165,7 +161,7 @@ class AclDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling with Op target: Authenticated, rev: Int, permissions: Set[Permission] - ): Task[Assertion] = { + ): IO[Assertion] = { val body = jsonContentOf( "/iam/subtract-permissions.json", "realm" -> target.realm.name, @@ -177,13 +173,13 @@ class AclDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling with Op } } - def checkAdminAcls(path: String, authenticated: Authenticated): Task[Assertion] = { - logger.info(s"Gettings acls for $path using ${authenticated.name}") - fetch(path, authenticated) { acls => - val acl = acls._results.headOption.value - val entry = acl.acl.headOption.value - entry.permissions shouldEqual Permission.adminPermissions - } + def checkAdminAcls(path: String, authenticated: Authenticated): IO[Assertion] = { + logger.info(s"Gettings acls for $path using ${authenticated.name}") >> + fetch(path, authenticated) { acls => + val acl = acls._results.headOption.value + val entry = acl.acl.headOption.value + entry.permissions shouldEqual Permission.adminPermissions + } } } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/AclsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/AclsSpec.scala index cf449e7010..e3bd124aeb 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/AclsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/AclsSpec.scala @@ -5,7 +5,6 @@ import ch.epfl.bluebrain.nexus.tests.Identity.acls.Marge import ch.epfl.bluebrain.nexus.tests.Identity.testRealm import ch.epfl.bluebrain.nexus.tests.iam.types.{AclEntry, AclListing, Permission, User} import ch.epfl.bluebrain.nexus.tests.{BaseSpec, Identity} -import monix.execution.Scheduler.Implicits.global class AclsSpec extends BaseSpec { diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/PermissionDsl.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/PermissionDsl.scala index 5c78ca3320..4baeb7807d 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/PermissionDsl.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/PermissionDsl.scala @@ -1,12 +1,11 @@ package ch.epfl.bluebrain.nexus.tests.iam import akka.http.scaladsl.model.StatusCodes +import cats.effect.IO import ch.epfl.bluebrain.nexus.testkit.TestHelpers import ch.epfl.bluebrain.nexus.tests.iam.types.{Permission, Permissions} import ch.epfl.bluebrain.nexus.tests.{CirceUnmarshalling, HttpClient, Identity} import io.circe.Json -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.scalatest.Assertion import org.scalatest.matchers.should.Matchers @@ -15,7 +14,7 @@ class PermissionDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling def permissionsRepl(permissions: Iterable[Permission]) = "perms" -> permissions.map { _.value }.mkString("\",\"") - def addPermissions(list: Permission*): Task[Assertion] = + def addPermissions(list: Permission*): IO[Assertion] = cl.get[Permissions]("/permissions", Identity.ServiceAccount) { (permissions, response) => response.status shouldEqual StatusCodes.OK val body = jsonContentOf( @@ -25,7 +24,7 @@ class PermissionDsl(cl: HttpClient) extends TestHelpers with CirceUnmarshalling if (!list.toSet.subsetOf(permissions.permissions)) { cl.patch[Json](s"/permissions?rev=${permissions._rev}", body, Identity.ServiceAccount) { (_, response) => response.status shouldEqual StatusCodes.OK - }.runSyncUnsafe() + }.unsafeRunSync() } else { succeed } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/PermissionsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/PermissionsSpec.scala index 600176aa59..e5f059ddec 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/PermissionsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/PermissionsSpec.scala @@ -1,10 +1,10 @@ package ch.epfl.bluebrain.nexus.tests.iam import akka.http.scaladsl.model.StatusCodes +import cats.effect.IO import ch.epfl.bluebrain.nexus.tests.iam.types.{Permission, Permissions} import ch.epfl.bluebrain.nexus.tests.{BaseSpec, Identity} import io.circe.Json -import monix.bio.Task class PermissionsSpec extends BaseSpec { @@ -14,10 +14,10 @@ class PermissionsSpec extends BaseSpec { "clear permissions" in { deltaClient.get[Permissions]("/permissions", Identity.ServiceAccount) { (permissions, response) => - runTask { + runIO { response.status shouldEqual StatusCodes.OK if (permissions.permissions == Permission.minimalPermissions) - Task(succeed) + IO.pure(succeed) else deltaClient.delete[Json](s"/permissions?rev=${permissions._rev}", Identity.ServiceAccount) { (_, response) => @@ -43,7 +43,7 @@ class PermissionsSpec extends BaseSpec { "subtract permissions" in { deltaClient.get[Permissions]("/permissions", Identity.ServiceAccount) { (permissions, response) => - runTask { + runIO { response.status shouldEqual StatusCodes.OK val body = jsonContentOf( "/iam/permissions/subtract.json", @@ -66,7 +66,7 @@ class PermissionsSpec extends BaseSpec { "replace permissions" in { deltaClient.get[Permissions]("/permissions", Identity.ServiceAccount) { (permissions, response) => - runTask { + runIO { response.status shouldEqual StatusCodes.OK val body = jsonContentOf( @@ -92,7 +92,7 @@ class PermissionsSpec extends BaseSpec { "reject subtracting minimal permission" in { deltaClient.get[Permissions]("/permissions", Identity.ServiceAccount) { (permissions, response) => - runTask { + runIO { response.status shouldEqual StatusCodes.OK val body = jsonContentOf( "/iam/permissions/subtract.json", @@ -110,7 +110,7 @@ class PermissionsSpec extends BaseSpec { "reject replacing minimal permission" in { deltaClient.get[Permissions]("/permissions", Identity.ServiceAccount) { (permissions, response) => - runTask { + runIO { response.status shouldEqual StatusCodes.OK val body = jsonContentOf( "/iam/permissions/replace.json", diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/RealmsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/RealmsSpec.scala index 6ee062e076..2cb8b3d484 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/RealmsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/iam/RealmsSpec.scala @@ -4,7 +4,6 @@ import akka.http.scaladsl.model.StatusCodes import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.{BaseSpec, Identity, Realm} import io.circe.Json -import monix.execution.Scheduler.Implicits.global class RealmsSpec extends BaseSpec { @@ -25,7 +24,7 @@ class RealmsSpec extends BaseSpec { _ <- authenticateClient(testClient) } yield () - setup.runSyncUnsafe() + setup.unsafeRunSync() } "manage realms" should { diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/AggregationsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/AggregationsSpec.scala index da6942532c..bb35a19b34 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/AggregationsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/AggregationsSpec.scala @@ -1,6 +1,7 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.StatusCodes +import cats.syntax.all._ import ch.epfl.bluebrain.nexus.testkit.{CirceEq, EitherValuable} import ch.epfl.bluebrain.nexus.tests.{BaseSpec, SchemaPayload} import ch.epfl.bluebrain.nexus.tests.Identity.Anonymous diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/AutoProjectDeletionSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/AutoProjectDeletionSpec.scala index 21928414d7..c80046e8bb 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/AutoProjectDeletionSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/AutoProjectDeletionSpec.scala @@ -4,7 +4,6 @@ import akka.http.scaladsl.model.StatusCodes import ch.epfl.bluebrain.nexus.tests.BaseSpec import ch.epfl.bluebrain.nexus.tests.Identity.projects.Bojack import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.{Events, Organizations, Projects, Resources} -import monix.execution.Scheduler.Implicits.global import io.circe.Json import scala.concurrent.duration._ @@ -40,7 +39,7 @@ class AutoProjectDeletionSpec extends BaseSpec { _ <- deltaClient.get[Json](s"/projects/$ref1", Bojack)(expect(StatusCodes.OK)) } yield succeed - setup.void.runSyncUnsafe() + setup.void.unsafeRunSync() } "eventually return a not found when attempting to fetch the project" in eventually { diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/CompositeViewsLifeCycleSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/CompositeViewsLifeCycleSpec.scala index ca261dde9a..ce15eef591 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/CompositeViewsLifeCycleSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/CompositeViewsLifeCycleSpec.scala @@ -1,6 +1,7 @@ package ch.epfl.bluebrain.nexus.tests.kg import cats.data.NonEmptyMap +import cats.effect.IO import ch.epfl.bluebrain.nexus.tests.BaseSpec import ch.epfl.bluebrain.nexus.tests.Identity.compositeviews.Jerry import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.{Events, Organizations, Views} @@ -12,8 +13,6 @@ import org.scalactic.source.Position final class CompositeViewsLifeCycleSpec extends BaseSpec { - implicit private val classLoader: ClassLoader = getClass.getClassLoader - private val orgId = genId() private val projId = genId() private val proj2Id = genId() @@ -40,12 +39,14 @@ final class CompositeViewsLifeCycleSpec extends BaseSpec { "proj" -> proj2Id, "query" -> query ) ++ includeCrossProjectOpt ++ includeSparqlProjectionOpt - ioJsonContentOf( - "/kg/views/composite/composite-view-lifecycle.json", - replacements( - Jerry, - values: _* - ): _* + IO( + jsonContentOf( + "/kg/views/composite/composite-view-lifecycle.json", + replacements( + Jerry, + values: _* + ): _* + ) ) } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/CompositeViewsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/CompositeViewsSpec.scala index f40a8305c4..231128c2d2 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/CompositeViewsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/CompositeViewsSpec.scala @@ -2,21 +2,19 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.StatusCodes import cats.implicits._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.tests.BaseSpec import ch.epfl.bluebrain.nexus.tests.HttpClient._ import ch.epfl.bluebrain.nexus.tests.Identity.compositeviews.Jerry import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.{Events, Organizations, Views} import ch.epfl.bluebrain.nexus.tests.kg.CompositeViewsSpec.{albumQuery, bandQuery} -import com.typesafe.scalalogging.Logger import io.circe.Json import io.circe.optics.JsonPath._ -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global class CompositeViewsSpec extends BaseSpec { - private val logger = Logger[this.type] + private val logger = Logger.cats[this.type] case class Stats(totalEvents: Long, remainingEvents: Long) @@ -45,13 +43,11 @@ class CompositeViewsSpec extends BaseSpec { val projectPayload = jsonContentOf("/kg/views/composite/project.json") for { _ <- adminDsl.createOrganization(orgId, orgId, Jerry) - _ <- Task.sequence( - List( - adminDsl.createProject(orgId, bandsProject, projectPayload, Jerry), - adminDsl.createProject(orgId, albumsProject, projectPayload, Jerry), - adminDsl.createProject(orgId, songsProject, projectPayload, Jerry) - ) - ) + _ <- List( + adminDsl.createProject(orgId, bandsProject, projectPayload, Jerry), + adminDsl.createProject(orgId, albumsProject, projectPayload, Jerry), + adminDsl.createProject(orgId, songsProject, projectPayload, Jerry) + ).sequence } yield succeed } @@ -314,32 +310,29 @@ class CompositeViewsSpec extends BaseSpec { private def waitForView(viewId: String = "composite") = { eventually { - deltaClient.get[Json](s"/views/$orgId/bands/$viewId/projections/_/statistics", Jerry) { (json, response) => - val stats = root._results.each.as[Stats].getAll(json) - logger.debug(s"Response: ${response.status} with ${stats.size} stats") - stats.foreach { stat => - logger.debug(s"totalEvents: ${stat.totalEvents}, remainingEvents: ${stat.remainingEvents}") - stat.totalEvents should be > 0L - stat.remainingEvents shouldEqual 0 + logger.info("Waiting for view to be indexed") >> + deltaClient.get[Json](s"/views/$orgId/bands/$viewId/projections/_/statistics", Jerry) { (json, response) => + val stats = root._results.each.as[Stats].getAll(json) + stats.foreach { stat => + stat.totalEvents should be > 0L + stat.remainingEvents shouldEqual 0 + } + response.status shouldEqual StatusCodes.OK } - response.status shouldEqual StatusCodes.OK - } } succeed } - private def resetView(viewId: String) = - deltaClient.delete[Json](s"/views/$orgId/bands/$viewId/projections/_/offset", Jerry) { (_, response) => - logger.info(s"Resetting view responded with ${response.status}") - response.status shouldEqual StatusCodes.OK - } + private def resetView(viewId: String) = { + logger.info("Resetting offsets") >> + deltaClient.delete[Json](s"/views/$orgId/bands/$viewId/projections/_/offset", Jerry) { (_, response) => + response.status shouldEqual StatusCodes.OK + } + } private def resetAndWait(viewId: String = "composite") = { - logger.info("Waiting for view to be indexed") waitForView(viewId) - logger.info("Resetting offsets") - resetView(viewId).runSyncUnsafe() - logger.info("Waiting for view to be indexed again") + resetView(viewId).unsafeRunSync() waitForView(viewId) } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/DiskStorageSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/DiskStorageSpec.scala index 4f8365b39a..bdc4007d7a 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/DiskStorageSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/DiskStorageSpec.scala @@ -1,11 +1,11 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.StatusCodes +import cats.effect.IO import ch.epfl.bluebrain.nexus.tests.Identity.storages.Coyote import ch.epfl.bluebrain.nexus.tests.Optics.filterMetadataKeys import ch.epfl.bluebrain.nexus.tests.iam.types.Permission import io.circe.Json -import monix.bio.Task import org.scalatest.Assertion class DiskStorageSpec extends StorageSpec { @@ -32,7 +32,7 @@ class DiskStorageSpec extends StorageSpec { ): _* ) - override def createStorages: Task[Assertion] = { + override def createStorages: IO[Assertion] = { val payload = jsonContentOf("/kg/storages/disk.json") val payload2 = jsonContentOf("/kg/storages/disk-perms.json") diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ElasticSearchViewsDsl.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ElasticSearchViewsDsl.scala index cca7ed916b..1e0a1e5a0b 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ElasticSearchViewsDsl.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ElasticSearchViewsDsl.scala @@ -1,12 +1,13 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.StatusCodes +import cats.effect.IO import ch.epfl.bluebrain.nexus.testkit.{CirceLiteral, TestHelpers} import ch.epfl.bluebrain.nexus.tests.{CirceUnmarshalling, HttpClient, Identity} import io.circe.Json -import monix.bio.Task import org.scalatest.Assertion import org.scalatest.matchers.should.Matchers + import scala.jdk.CollectionConverters._ final class ElasticSearchViewsDsl(deltaClient: HttpClient) @@ -18,7 +19,7 @@ final class ElasticSearchViewsDsl(deltaClient: HttpClient) /** * Create an aggregate view and expects it to succeed */ - def aggregate(id: String, projectRef: String, identity: Identity, views: (String, String)*): Task[Assertion] = { + def aggregate(id: String, projectRef: String, identity: Identity, views: (String, String)*): IO[Assertion] = { val payload = jsonContentOf( "/kg/views/elasticsearch/aggregate.json", "views" -> views.map { case ((project, view)) => diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ElasticSearchViewsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ElasticSearchViewsSpec.scala index ace536c78e..58a3fdc4b4 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ElasticSearchViewsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ElasticSearchViewsSpec.scala @@ -9,7 +9,6 @@ import ch.epfl.bluebrain.nexus.tests.Identity.views.ScoobyDoo import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.{Organizations, Views} import io.circe.{ACursor, Json} -import monix.execution.Scheduler.Implicits.global class ElasticSearchViewsSpec extends BaseSpec with EitherValuable with CirceEq { @@ -217,7 +216,7 @@ class ElasticSearchViewsSpec extends BaseSpec with EitherValuable with CirceEq { .post[Json](s"/views/$fullId/test-resource:cell-view/_search", matchAll, ScoobyDoo) { (json2, _) => filterKey("took")(json2) shouldEqual filterKey("took")(json) } - .runSyncUnsafe() + .unsafeRunSync() } } @@ -241,7 +240,7 @@ class ElasticSearchViewsSpec extends BaseSpec with EitherValuable with CirceEq { .post[Json](s"/views/$fullId2/test-resource:cell-view/_search", matchAll, ScoobyDoo) { (json2, _) => filterKey("took")(json2) shouldEqual filterKey("took")(json) } - .runSyncUnsafe() + .unsafeRunSync() } } @@ -385,7 +384,7 @@ class ElasticSearchViewsSpec extends BaseSpec with EitherValuable with CirceEq { .post[Json](s"/views/$fullId/test-resource:cell-view/_search", matchAll, ScoobyDoo) { (json2, _) => filterKey("took")(json2) shouldEqual filterKey("took")(json) } - .runSyncUnsafe() + .unsafeRunSync() } } @@ -410,7 +409,7 @@ class ElasticSearchViewsSpec extends BaseSpec with EitherValuable with CirceEq { .post[Json](s"/views/$fullId/test-resource:cell-view/_search", matchAll, ScoobyDoo) { (json2, _) => filterKey("took")(json2) shouldEqual filterKey("took")(json) } - .runSyncUnsafe() + .unsafeRunSync() } } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ErrorsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ErrorsSpec.scala index 415bc7e192..4075956f56 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ErrorsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ErrorsSpec.scala @@ -4,7 +4,6 @@ import akka.http.scaladsl.model.StatusCodes import ch.epfl.bluebrain.nexus.testkit.EitherValuable import ch.epfl.bluebrain.nexus.tests.{BaseSpec, Identity} import io.circe.Json -import monix.execution.Scheduler.Implicits.global class ErrorsSpec extends BaseSpec with EitherValuable { diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/EventsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/EventsSpec.scala index 53c235e41c..2abe0556e7 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/EventsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/EventsSpec.scala @@ -1,14 +1,13 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.{ContentTypes, StatusCodes} +import cats.effect.IO import ch.epfl.bluebrain.nexus.tests.BaseSpec import ch.epfl.bluebrain.nexus.tests.Identity.events.BugsBunny import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.{Events, Organizations, Resources} import ch.epfl.bluebrain.nexus.tests.resources.SimpleResource import io.circe.Json -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.scalatest.Inspectors class EventsSpec extends BaseSpec with Inspectors { @@ -246,43 +245,41 @@ class EventsSpec extends BaseSpec with Inspectors { "fetch global events" in { // TODO: find a way to get the current event sequence in postgres - Task - .when(initialEventId.isDefined) { - for { - uuids <- adminDsl.getUuids(orgId, projId, BugsBunny) - uuids2 <- adminDsl.getUuids(orgId2, projId, BugsBunny) - _ <- deltaClient.sseEvents(s"/resources/events", BugsBunny, initialEventId, take = 21) { seq => - val projectEvents = seq.drop(14) - projectEvents.size shouldEqual 7 - projectEvents.flatMap(_._1) should contain theSameElementsInOrderAs List( - "ResourceCreated", - "ResourceCreated", - "ResourceUpdated", - "ResourceTagAdded", - "ResourceDeprecated", - "FileCreated", - "FileUpdated" - ) - val json = Json.arr(projectEvents.flatMap(_._2.map(events.filterFields)): _*) - json shouldEqual jsonContentOf( - "/kg/events/events-multi-project.json", - replacements( - BugsBunny, - "resources" -> s"${config.deltaUri}/resources/$id", - "organizationUuid" -> uuids._1, - "projectUuid" -> uuids._2, - "organization2Uuid" -> uuids2._1, - "project2Uuid" -> uuids2._2, - "project" -> s"${config.deltaUri}/projects/$orgId/$projId", - "project2" -> s"${config.deltaUri}/projects/$orgId2/$projId", - "schemaProject" -> s"${config.deltaUri}/projects/$orgId/$projId", - "schemaProject2" -> s"${config.deltaUri}/projects/$orgId2/$projId" - ): _* - ) - } - } yield () - } - .as(succeed) + IO.whenA(initialEventId.isDefined) { + for { + uuids <- adminDsl.getUuids(orgId, projId, BugsBunny) + uuids2 <- adminDsl.getUuids(orgId2, projId, BugsBunny) + _ <- deltaClient.sseEvents(s"/resources/events", BugsBunny, initialEventId, take = 21) { seq => + val projectEvents = seq.drop(14) + projectEvents.size shouldEqual 7 + projectEvents.flatMap(_._1) should contain theSameElementsInOrderAs List( + "ResourceCreated", + "ResourceCreated", + "ResourceUpdated", + "ResourceTagAdded", + "ResourceDeprecated", + "FileCreated", + "FileUpdated" + ) + val json = Json.arr(projectEvents.flatMap(_._2.map(events.filterFields)): _*) + json shouldEqual jsonContentOf( + "/kg/events/events-multi-project.json", + replacements( + BugsBunny, + "resources" -> s"${config.deltaUri}/resources/$id", + "organizationUuid" -> uuids._1, + "projectUuid" -> uuids._2, + "organization2Uuid" -> uuids2._1, + "project2Uuid" -> uuids2._2, + "project" -> s"${config.deltaUri}/projects/$orgId/$projId", + "project2" -> s"${config.deltaUri}/projects/$orgId2/$projId", + "schemaProject" -> s"${config.deltaUri}/projects/$orgId/$projId", + "schemaProject2" -> s"${config.deltaUri}/projects/$orgId2/$projId" + ): _* + ) + } + } yield () + }.as(succeed) } } } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/IdResolutionSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/IdResolutionSpec.scala index 9a6028e19b..193d44bec9 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/IdResolutionSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/IdResolutionSpec.scala @@ -4,6 +4,7 @@ import akka.http.scaladsl.model.MediaTypes.`text/html` import akka.http.scaladsl.model.headers.{Accept, Location} import akka.http.scaladsl.model.{HttpResponse, MediaRange, StatusCodes} import akka.http.scaladsl.unmarshalling.PredefinedFromEntityUnmarshallers +import cats.syntax.all._ import ch.epfl.bluebrain.nexus.delta.kernel.utils.UrlUtils import ch.epfl.bluebrain.nexus.tests.BaseSpec import ch.epfl.bluebrain.nexus.tests.Identity.listings.{Alice, Bob} diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/MultiFetchSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/MultiFetchSpec.scala index c6e2e8d134..30993219b8 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/MultiFetchSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/MultiFetchSpec.scala @@ -3,6 +3,7 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.{ContentTypes, HttpResponse, StatusCodes} import ch.epfl.bluebrain.nexus.tests.{BaseSpec, Identity} import ch.epfl.bluebrain.nexus.tests.Identity.listings.{Alice, Bob} +import cats.syntax.all._ import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.Resources import ch.epfl.bluebrain.nexus.tests.resources.SimpleResource diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/RemoteStorageSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/RemoteStorageSpec.scala index cef8374967..4bf6b3ab60 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/RemoteStorageSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/RemoteStorageSpec.scala @@ -2,6 +2,7 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.{ContentTypes, HttpCharsets, MediaTypes, StatusCodes} import akka.util.ByteString +import cats.effect.IO import ch.epfl.bluebrain.nexus.tests.HttpClient._ import ch.epfl.bluebrain.nexus.tests.Identity.storages.Coyote import ch.epfl.bluebrain.nexus.tests.Optics.{filterKey, filterMetadataKeys, projections} @@ -10,7 +11,6 @@ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.Supervision import io.circe.generic.semiauto.deriveDecoder import io.circe.syntax.KeyOps import io.circe.{Decoder, Json} -import monix.bio.Task import org.scalactic.source.Position import org.scalatest.Assertion @@ -60,7 +60,7 @@ class RemoteStorageSpec extends StorageSpec { ): _* ) - override def createStorages: Task[Assertion] = { + override def createStorages: IO[Assertion] = { val payload = jsonContentOf( "/kg/storages/remote-disk.json", "endpoint" -> externalEndpoint, @@ -191,7 +191,7 @@ class RemoteStorageSpec extends StorageSpec { } } - def createFile(filename: String) = Task.delay { + def createFile(filename: String) = IO.delay { val createFile = s"echo 'file content' > /tmp/$remoteFolder/$filename" s"docker exec nexus-storage-service bash -c \"$createFile\"".! } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ResourcesSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ResourcesSpec.scala index bb8af47eb3..575addf0cc 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ResourcesSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/ResourcesSpec.scala @@ -16,7 +16,6 @@ import ch.epfl.bluebrain.nexus.tests.resources.SimpleResource import ch.epfl.bluebrain.nexus.tests.{BaseSpec, Optics, SchemaPayload} import io.circe.Json import io.circe.optics.JsonPath.root -import monix.execution.Scheduler.Implicits.global import monocle.Optional import org.scalatest.matchers.{HavePropertyMatchResult, HavePropertyMatcher} @@ -287,7 +286,7 @@ class ResourcesSpec extends BaseSpec with EitherValuable with CirceEq { for { _ <- deltaClient.get[Json](s"/schemas/$id1/test-schema", Rick) { (json, response1) => response1.status shouldEqual StatusCodes.OK - runTask { + runIO { for { _ <- deltaClient.get[Json](s"/resolvers/$id2/_/test-schema", Rick) { (jsonResolved, response2) => response2.status shouldEqual StatusCodes.OK diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/S3StorageSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/S3StorageSpec.scala index e71cc1d352..cd864ea7f6 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/S3StorageSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/S3StorageSpec.scala @@ -1,12 +1,12 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.StatusCodes +import cats.effect.IO import ch.epfl.bluebrain.nexus.tests.Identity.storages.Coyote import ch.epfl.bluebrain.nexus.tests.Optics.filterMetadataKeys import ch.epfl.bluebrain.nexus.tests.config.S3Config import ch.epfl.bluebrain.nexus.tests.iam.types.Permission import io.circe.Json -import monix.bio.Task import org.scalatest.Assertion import software.amazon.awssdk.auth.credentials.{AnonymousCredentialsProvider, AwsBasicCredentials, StaticCredentialsProvider} import software.amazon.awssdk.regions.Region @@ -82,7 +82,7 @@ class S3StorageSpec extends StorageSpec { ): _* ) - override def createStorages: Task[Assertion] = { + override def createStorages: IO[Assertion] = { val payload = jsonContentOf( "/kg/storages/s3.json", "storageId" -> s"https://bluebrain.github.io/nexus/vocabulary/$storageId", diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SchemasSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SchemasSpec.scala index 571ccde29b..0f2d7edd34 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SchemasSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SchemasSpec.scala @@ -8,7 +8,6 @@ import ch.epfl.bluebrain.nexus.tests.Identity.resources.Rick import ch.epfl.bluebrain.nexus.tests.builders.SchemaPayloads._ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.Organizations import io.circe.Json -import monix.execution.Scheduler.Implicits.global import org.scalatest.BeforeAndAfterAll import org.scalatest.LoneElement._ diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SearchConfigSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SearchConfigSpec.scala index 89ddd7bfba..831bb5a61d 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SearchConfigSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SearchConfigSpec.scala @@ -1,12 +1,12 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.StatusCodes +import cats.effect.IO import cats.implicits._ import ch.epfl.bluebrain.nexus.tests.BaseSpec import ch.epfl.bluebrain.nexus.tests.Identity.resources.Rick import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.{Organizations, Resources} import io.circe.Json -import monix.bio.Task import org.scalatest.Assertion import java.time.Instant @@ -794,7 +794,7 @@ class SearchConfigSpec extends BaseSpec { jsonContentOf("/kg/search/id-query.json", "id" -> id, "field" -> field) /** Post a resource across all defined projects in the suite */ - private def postResource(resourcePath: String): Task[List[Assertion]] = { + private def postResource(resourcePath: String): IO[List[Assertion]] = { val json = jsonContentOf(resourcePath) projects.parTraverse { project => for { @@ -809,7 +809,7 @@ class SearchConfigSpec extends BaseSpec { * Queries ES using the provided query. Asserts that there is only on result in _source. Runs the provided assertion * on the _source. */ - private def assertOneSource(query: Json)(assertion: Json => Assertion): Task[Assertion] = + private def assertOneSource(query: Json)(assertion: Json => Assertion): IO[Assertion] = eventually { deltaClient.post[Json]("/search/query", query, Rick) { (body, response) => response.status shouldEqual StatusCodes.OK @@ -822,7 +822,7 @@ class SearchConfigSpec extends BaseSpec { } } - private def assertEmpty(query: Json): Task[Assertion] = + private def assertEmpty(query: Json): IO[Assertion] = assertOneSource(query)(j => assert(j == json"""{ }""")) /** Check that a given field in the json can be parsed as [[Instant]] */ diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SparqlViewsSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SparqlViewsSpec.scala index 7136cc572b..9585bceaa5 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SparqlViewsSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SparqlViewsSpec.scala @@ -9,7 +9,6 @@ import ch.epfl.bluebrain.nexus.tests.Identity.views.ScoobyDoo import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.{Organizations, Views} import io.circe.Json -import monix.execution.Scheduler.Implicits.global class SparqlViewsSpec extends BaseSpec with EitherValuable with CirceEq { diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/StorageSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/StorageSpec.scala index 656ebdb761..5d72bb42e8 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/StorageSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/StorageSpec.scala @@ -3,6 +3,7 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.headers.{ContentDispositionTypes, HttpEncodings} import akka.http.scaladsl.model._ import akka.util.ByteString +import cats.effect.IO import ch.epfl.bluebrain.nexus.testkit.CirceEq import ch.epfl.bluebrain.nexus.tests.BaseSpec import ch.epfl.bluebrain.nexus.tests.HttpClient._ @@ -14,8 +15,6 @@ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission import com.typesafe.config.ConfigFactory import io.circe.Json import io.circe.optics.JsonPath.root -import monix.bio.Task -import monix.execution.Scheduler.Implicits.global import org.apache.commons.codec.Charsets import org.scalatest.Assertion @@ -41,7 +40,7 @@ abstract class StorageSpec extends BaseSpec with CirceEq { def locationPrefix: Option[String] - def createStorages: Task[Assertion] + def createStorages: IO[Assertion] protected def fileSelf(project: String, id: String): String = { val uri = Uri(s"${config.deltaUri}/files/$project") @@ -226,7 +225,7 @@ abstract class StorageSpec extends BaseSpec with CirceEq { val textFileContent = "text file" - def uploadStorageWithCustomPermissions: ((Json, HttpResponse) => Assertion) => Task[Assertion] = + def uploadStorageWithCustomPermissions: ((Json, HttpResponse) => Assertion) => IO[Assertion] = deltaClient.uploadFile[Json]( s"/files/$projectRef/attachment3?storage=nxv:${storageId}2", textFileContent, @@ -348,7 +347,7 @@ abstract class StorageSpec extends BaseSpec with CirceEq { "Upload files with the .custom extension" should { val fileContent = "file content" - def uploadCustomFile(id: String, contentType: ContentType): ((Json, HttpResponse) => Assertion) => Task[Assertion] = + def uploadCustomFile(id: String, contentType: ContentType): ((Json, HttpResponse) => Assertion) => IO[Assertion] = deltaClient.uploadFile[Json]( s"/files/$projectRef/$id?storage=nxv:$storageId", fileContent, diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SupervisionSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SupervisionSpec.scala index de7773b5ea..af45c5b7f3 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SupervisionSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/SupervisionSpec.scala @@ -1,14 +1,14 @@ package ch.epfl.bluebrain.nexus.tests.kg import akka.http.scaladsl.model.StatusCodes -import ch.epfl.bluebrain.nexus.testkit.{CirceLiteral, EitherValuable, IOValues} +import ch.epfl.bluebrain.nexus.testkit.{CirceLiteral, EitherValuable} import ch.epfl.bluebrain.nexus.tests.BaseSpec import ch.epfl.bluebrain.nexus.tests.Identity.supervision.Mickey import ch.epfl.bluebrain.nexus.tests.Optics.{filterKeys, projections} import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.{Events, Organizations, Supervision} import io.circe._ -class SupervisionSpec extends BaseSpec with EitherValuable with CirceLiteral with IOValues { +class SupervisionSpec extends BaseSpec with EitherValuable with CirceLiteral { "The supervision endpoint" should { s"reject calls without ${Supervision.Read.value} permission" in { diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/VersionSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/VersionSpec.scala index bf62fe9b04..98ec2c081e 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/VersionSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/VersionSpec.scala @@ -7,7 +7,6 @@ import ch.epfl.bluebrain.nexus.tests.kg.VersionSpec.VersionBundle import ch.epfl.bluebrain.nexus.tests.{BaseSpec, Identity} import io.circe.generic.semiauto.deriveDecoder import io.circe.{Decoder, Json} -import monix.execution.Scheduler.Implicits.global class VersionSpec extends BaseSpec with EitherValuable { @@ -19,7 +18,7 @@ class VersionSpec extends BaseSpec with EitherValuable { } "return the dependencies and plugin versions" in { - aclDsl.addPermissionAnonymous("/", Permission.Version.Read).runSyncUnsafe() + aclDsl.addPermissionAnonymous("/", Permission.Version.Read).unsafeRunSync() deltaClient.get[Json]("/version", Identity.Anonymous) { (json, response) => response.status shouldEqual StatusCodes.OK