All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.iterators.stir.testkit.RouteTestResultComponent.scala Maven / Gradle / Ivy

The newest version!
package pl.iterators.stir.testkit

import cats.effect.IO
import cats.effect.unsafe.IORuntime
import fs2.Stream
import org.http4s.{ EntityBody, Response }
import pl.iterators.stir.server.{ Rejection, RejectionHandler, RouteResult }

trait RouteTestResultComponent {

  def failTest(msg: String): Nothing

  /**
   * A receptacle for the response or rejections created by a route.
   */
  class RouteTestResult() {
    private[this] var result: Option[Either[Seq[Rejection], Response[IO]]] = None
//    private[this] val latch = new CountDownLatch(1)

    def handled: Boolean = synchronized { result.isDefined && result.get.isRight }

    def rejections: Seq[Rejection] = synchronized {
      result match {
        case Some(Left(rejections)) => rejections
        case Some(Right(response))  => failTest("Request was not rejected, response was " + response)
        case None                   => failNeitherCompletedNorRejected()
      }
    }

    def response(implicit runtime: IORuntime): Response[IO] = rawResponse.withEntity(entity)

    /** Returns a "fresh" entity with a "fresh" unconsumed byte- or chunk stream (if not strict) */
    def entity(implicit runtime: IORuntime): EntityBody[IO] = entityRecreator(runtime)

//    def chunks: Seq[ChunkStreamPart] =
//      entity match {
//        case HttpEntity.Chunked(_, chunks) => awaitAllElements[ChunkStreamPart](chunks)
//        case _                             => Nil
//      }
//
//    def chunksStream: Source[ChunkStreamPart, Any] =
//      rawResponse.entity match {
//        case HttpEntity.Chunked(_, data) => data
//        case _                           => Source.empty
//      }

    def ~>[T](f: RouteTestResult => T): T = f(this)

    private[testkit] def rawResponse: Response[IO] = synchronized {
      result match {
        case Some(Right(response))        => response
        case Some(Left(Nil))              => failTest("Request was rejected")
        case Some(Left(rejection :: Nil)) => failTest("Request was rejected with rejection " + rejection)
        case Some(Left(rejections))       => failTest("Request was rejected with rejections " + rejections)
        case None                         => failNeitherCompletedNorRejected()
      }
    }

    private[testkit] def handleResult(rr: RouteResult): Unit =
      synchronized {
        if (result.isEmpty) {
          result = rr match {
            case RouteResult.Complete(response)   => Some(Right(response))
            case RouteResult.Rejected(rejections) => Some(Left(RejectionHandler.applyTransformations(rejections)))
          }
//          latch.countDown()
        } else failTest("Route completed/rejected more than once")
      }

    private[testkit] def handleResponse(r: Response[IO]): Unit =
      synchronized {
        if (result.isEmpty) {
          result = Some(Right(r))
//          latch.countDown()
        } else failTest("Route completed/rejected more than once")
      }

//    private[testkit] def awaitResult: this.type = scala.concurrent.blocking {
////      latch.await(timeout.toMillis, MILLISECONDS)
//      this
//    }

    private[this] lazy val entityRecreator: IORuntime => EntityBody[IO] = implicit runtime =>
      rawResponse.body.compile.toVector.map { bytes =>
        Stream.emits(bytes): Stream[IO, Byte]
      }.unsafeRunSync()

    private def failNeitherCompletedNorRejected(): Nothing =
      failTest("Request was neither completed nor rejected" /*within " + timeout */ )
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy