From 4f10982c451284f04c94b2d8f9076641b25f9798 Mon Sep 17 00:00:00 2001 From: Vladimir Kostyukov Date: Thu, 15 Jun 2017 14:33:12 -0700 Subject: [PATCH] Fix Bootstrap.copy() bug --- core/src/main/scala/io/finch/Bootstrap.scala | 19 ++++++++--- core/src/main/scala/io/finch/ToService.scala | 4 +-- ...oServiceSpec.scala => BootstrapSpec.scala} | 34 ++++++++++++++----- .../finch/{internal => }/ToResponseSpec.scala | 3 +- 4 files changed, 42 insertions(+), 18 deletions(-) rename core/src/test/scala/io/finch/{internal/ToServiceSpec.scala => BootstrapSpec.scala} (60%) rename core/src/test/scala/io/finch/{internal => }/ToResponseSpec.scala (92%) diff --git a/core/src/main/scala/io/finch/Bootstrap.scala b/core/src/main/scala/io/finch/Bootstrap.scala index 21c78dc97..aa7adb3b7 100644 --- a/core/src/main/scala/io/finch/Bootstrap.scala +++ b/core/src/main/scala/io/finch/Bootstrap.scala @@ -16,20 +16,29 @@ import shapeless._ * * @note This API is experimental/unstable. Use with caution. */ -case class Bootstrap[ES <: HList, CTS <: HList]( - endpoints: ES, - includeDateHeader: Boolean = true, - includeServerHeader: Boolean = true) { self => +class Bootstrap[ES <: HList, CTS <: HList]( + val endpoints: ES, + val includeDateHeader: Boolean = true, + val includeServerHeader: Boolean = true) { self => class Serve[CT <: String] { def apply[E](e: Endpoint[E]): Bootstrap[Endpoint[E] :: ES, CT :: CTS] = - self.copy(e :: self.endpoints) + new Bootstrap[Endpoint[E] :: ES, CT :: CTS]( + e :: self.endpoints, includeDateHeader, includeServerHeader + ) } + def configure( + includeDateHeader: Boolean = self.includeDateHeader, + includeServerHeader: Boolean = self.includeServerHeader + ): Bootstrap[ES, CTS] = new Bootstrap[ES, CTS](endpoints, includeDateHeader, includeServerHeader) + def serve[CT <: String]: Serve[CT] = new Serve[CT] def toService(implicit ts: ToService[ES, CTS]): Service[Request, Response] = ts(endpoints, includeDateHeader, includeServerHeader) + + final override def toString: String = s"Bootstrap($endpoints)" } object Bootstrap extends Bootstrap[HNil, HNil]( diff --git a/core/src/main/scala/io/finch/ToService.scala b/core/src/main/scala/io/finch/ToService.scala index c7cf37277..dda4162b1 100644 --- a/core/src/main/scala/io/finch/ToService.scala +++ b/core/src/main/scala/io/finch/ToService.scala @@ -16,8 +16,8 @@ import shapeless._ * - copy requests's HTTP version onto a response * - respond with 404 when en endpoint is not matched - * - include the date header on each response (if enabled) - * - include the server header on each reponse (if enabled) + * - include the date header on each response (unless disabled) + * - include the server header on each response (unless disabled) */ @implicitNotFound( """An Endpoint you're trying to convert into a Finagle service is missing one or more encoders. diff --git a/core/src/test/scala/io/finch/internal/ToServiceSpec.scala b/core/src/test/scala/io/finch/BootstrapSpec.scala similarity index 60% rename from core/src/test/scala/io/finch/internal/ToServiceSpec.scala rename to core/src/test/scala/io/finch/BootstrapSpec.scala index 95968f27b..027967ebd 100644 --- a/core/src/test/scala/io/finch/internal/ToServiceSpec.scala +++ b/core/src/test/scala/io/finch/BootstrapSpec.scala @@ -1,15 +1,14 @@ -package io.finch.internal +package io.finch import com.twitter.finagle.http.{Request, Status} import com.twitter.util.{Await, Future} -import io.finch._ +import io.finch.internal.currentTime +import java.time.{ZonedDateTime, ZoneOffset} import java.time.format.DateTimeFormatter -import java.time.ZonedDateTime -import java.time.ZoneOffset -class ToServiceSpec extends FinchSpec { +class BootstrapSpec extends FinchSpec { - behavior of "ToService" + behavior of "Bootstrap" it should "handle both Error and Errors" in { check { e: Either[Error, Errors] => @@ -43,12 +42,29 @@ class ToServiceSpec extends FinchSpec { val formatter = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC) def parseDate(s: String): Long = ZonedDateTime.parse(s, formatter).toEpochSecond - check { req: Request => - val s = Endpoint.const(()).toServiceAs[Text.Plain] + check { (req: Request, include: Boolean) => + val s = Bootstrap.configure(includeDateHeader = include) + .serve[Text.Plain](Endpoint.const(())) + .toService + val rep = Await.result(s(req)) val now = parseDate(currentTime()) - rep.date.nonEmpty && (parseDate(rep.date.get) - now).abs <= 1 + (include && (parseDate(rep.date.get) - now).abs <= 1) || + (!include && rep.date.isEmpty) + } + } + + it should "include Server header" in { + check { (req: Request, include: Boolean) => + val s = Bootstrap.configure(includeServerHeader = include) + .serve[Text.Plain](Endpoint.const(())) + .toService + + val rep = Await.result(s(req)) + + (include && rep.server === Some("Finch")) || + (!include && rep.server.isEmpty) } } } diff --git a/core/src/test/scala/io/finch/internal/ToResponseSpec.scala b/core/src/test/scala/io/finch/ToResponseSpec.scala similarity index 92% rename from core/src/test/scala/io/finch/internal/ToResponseSpec.scala rename to core/src/test/scala/io/finch/ToResponseSpec.scala index b8e7b43dc..e631f528e 100644 --- a/core/src/test/scala/io/finch/internal/ToResponseSpec.scala +++ b/core/src/test/scala/io/finch/ToResponseSpec.scala @@ -1,9 +1,8 @@ -package io.finch.internal +package io.finch import com.twitter.concurrent.AsyncStream import com.twitter.io.Buf import com.twitter.util.Await -import io.finch._ import java.nio.charset.StandardCharsets class ToResponseSpec extends FinchSpec {