summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2019-09-14 20:44:03 +0800
committerGitHub <noreply@github.com>2019-09-14 20:44:03 +0800
commitdedeed376e1e906ec2eb1574a73f08c24aba47c8 (patch)
tree337f0528e9284759800228e46f649cbc01f5edfe
parent90b6806e5fb91b207f9d8e2da2a58c25928badea (diff)
parentedd1f62ce364f8b559431249e2350c2bb75fccec (diff)
downloadcask-dedeed376e1e906ec2eb1574a73f08c24aba47c8.tar.gz
cask-dedeed376e1e906ec2eb1574a73f08c24aba47c8.tar.bz2
cask-dedeed376e1e906ec2eb1574a73f08c24aba47c8.zip
Merge pull request #13 from lihaoyi-databricks/wip0.2.3
Upstream some fixes
-rw-r--r--build.sc2
-rw-r--r--cask/src/cask/decorators/compress.scala2
-rw-r--r--cask/src/cask/endpoints/FormEndpoint.scala14
-rw-r--r--cask/src/cask/endpoints/JsonEndpoint.scala52
-rw-r--r--cask/src/cask/endpoints/StaticEndpoints.scala19
-rw-r--r--cask/src/cask/endpoints/WebEndpoints.scala18
-rw-r--r--cask/src/cask/endpoints/WebSocketEndpoint.scala22
-rw-r--r--cask/src/cask/internal/Conversion.scala9
-rw-r--r--cask/src/cask/internal/Util.scala7
-rw-r--r--cask/src/cask/main/Decorators.scala74
-rw-r--r--cask/src/cask/main/Main.scala41
-rw-r--r--cask/src/cask/main/Routes.scala15
-rw-r--r--cask/src/cask/model/Response.scala55
-rw-r--r--cask/src/cask/package.scala7
-rw-r--r--cask/test/src/test/cask/FailureTests.scala4
-rw-r--r--docs/pages/1 - Cask: a Scala HTTP micro-framework.md14
-rw-r--r--example/compress/app/test/src/ExampleTests.scala4
-rw-r--r--example/compress/build.sc2
-rw-r--r--example/compress2/app/test/src/ExampleTests.scala4
-rw-r--r--example/compress2/build.sc2
-rw-r--r--example/compress3/app/test/src/ExampleTests.scala4
-rw-r--r--example/compress3/build.sc2
-rw-r--r--example/cookies/app/test/src/ExampleTests.scala4
-rw-r--r--example/cookies/build.sc2
-rw-r--r--example/decorated/app/src/Decorated.scala8
-rw-r--r--example/decorated/app/test/src/ExampleTests.scala4
-rw-r--r--example/decorated/build.sc2
-rw-r--r--example/decorated2/app/src/Decorated2.scala8
-rw-r--r--example/decorated2/app/test/src/ExampleTests.scala4
-rw-r--r--example/decorated2/build.sc2
-rw-r--r--example/endpoints/app/src/Endpoints.scala7
-rw-r--r--example/endpoints/app/test/src/ExampleTests.scala4
-rw-r--r--example/endpoints/build.sc2
-rw-r--r--example/formJsonPost/app/src/FormJsonPost.scala2
-rw-r--r--example/formJsonPost/app/test/src/ExampleTests.scala18
-rw-r--r--example/formJsonPost/build.sc2
-rw-r--r--example/httpMethods/app/test/src/ExampleTests.scala4
-rw-r--r--example/httpMethods/build.sc2
-rw-r--r--example/minimalApplication/app/test/src/ExampleTests.scala4
-rw-r--r--example/minimalApplication/build.sc2
-rw-r--r--example/minimalApplication2/app/test/src/ExampleTests.scala4
-rw-r--r--example/minimalApplication2/build.sc2
-rw-r--r--example/redirectAbort/app/test/src/ExampleTests.scala4
-rw-r--r--example/redirectAbort/build.sc2
-rw-r--r--example/scalatags/app/test/src/ExampleTests.scala4
-rw-r--r--example/scalatags/build.sc2
-rw-r--r--example/staticFiles/app/test/src/ExampleTests.scala4
-rw-r--r--example/staticFiles/build.sc2
-rw-r--r--example/todo/app/src/TodoServer.scala2
-rw-r--r--example/todo/app/test/src/ExampleTests.scala4
-rw-r--r--example/todo/build.sc2
-rw-r--r--example/todoApi/app/test/src/ExampleTests.scala4
-rw-r--r--example/todoApi/build.sc2
-rw-r--r--example/todoDb/app/src/TodoMvcDb.scala2
-rw-r--r--example/todoDb/app/test/src/ExampleTests.scala4
-rw-r--r--example/todoDb/build.sc2
-rw-r--r--example/twirl/app/test/src/ExampleTests.scala4
-rw-r--r--example/twirl/build.sc2
-rw-r--r--example/variableRoutes/app/test/src/ExampleTests.scala4
-rw-r--r--example/variableRoutes/build.sc2
-rw-r--r--example/websockets/app/test/src/ExampleTests.scala6
-rw-r--r--example/websockets/build.sc2
62 files changed, 302 insertions, 218 deletions
diff --git a/build.sc b/build.sc
index e767276..f6050e3 100644
--- a/build.sc
+++ b/build.sc
@@ -50,7 +50,7 @@ object cask extends ScalaModule with PublishModule {
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
// ivy"org.xerial:sqlite-jdbc:3.18.0",
// ivy"io.getquill::quill-jdbc:2.6.0"
diff --git a/cask/src/cask/decorators/compress.scala b/cask/src/cask/decorators/compress.scala
index 75e2bed..7a7eefb 100644
--- a/cask/src/cask/decorators/compress.scala
+++ b/cask/src/cask/decorators/compress.scala
@@ -6,7 +6,7 @@ import cask.internal.Router
import cask.model.{Request, Response}
import collection.JavaConverters._
-class compress extends cask.Decorator{
+class compress extends cask.RawDecorator{
def wrapFunction(ctx: Request, delegate: Delegate) = {
val acceptEncodings = ctx.exchange.getRequestHeaders.get("Accept-Encoding").asScala.flatMap(_.split(", "))
delegate(Map()).map{ v =>
diff --git a/cask/src/cask/endpoints/FormEndpoint.scala b/cask/src/cask/endpoints/FormEndpoint.scala
index 471c5e5..6f65786 100644
--- a/cask/src/cask/endpoints/FormEndpoint.scala
+++ b/cask/src/cask/endpoints/FormEndpoint.scala
@@ -1,7 +1,7 @@
package cask.endpoints
import cask.internal.{Router, Util}
-import cask.main.Endpoint
+import cask.main.HttpEndpoint
import cask.model._
import io.undertow.server.handlers.form.FormParserFactory
@@ -43,14 +43,13 @@ object FormReader{
def read(ctx: Request, label: String, input: Seq[FormEntry]) = input.map(_.asInstanceOf[FormFile])
}
}
-class postForm(val path: String, override val subpath: Boolean = false) extends Endpoint {
- type Output = Response
+class postForm(val path: String, override val subpath: Boolean = false)
+ extends HttpEndpoint[Response.Raw, Seq[FormEntry]] {
val methods = Seq("post")
- type Input = Seq[FormEntry]
type InputParser[T] = FormReader[T]
def wrapFunction(ctx: Request,
- delegate: Map[String, Input] => Router.Result[Output]): Router.Result[Response] = {
+ delegate: Delegate): Router.Result[Response.Raw] = {
try {
val formData = FormParserFactory.builder().build().createParser(ctx.exchange).parseBlocking()
delegate(
@@ -62,11 +61,12 @@ class postForm(val path: String, override val subpath: Boolean = false) extends
)
} catch{case e: Exception =>
Router.Result.Success(cask.model.Response(
- "Unable to parse form data: " + e + "\n" + Util.stackTraceString(e)
+ "Unable to parse form data: " + e + "\n" + Util.stackTraceString(e),
+ statusCode = 400
))
}
}
- def wrapPathSegment(s: String): Input = Seq(FormValue(s, new io.undertow.util.HeaderMap))
+ def wrapPathSegment(s: String): Seq[FormEntry] = Seq(FormValue(s, new io.undertow.util.HeaderMap))
}
diff --git a/cask/src/cask/endpoints/JsonEndpoint.scala b/cask/src/cask/endpoints/JsonEndpoint.scala
index e0d1257..6d3db82 100644
--- a/cask/src/cask/endpoints/JsonEndpoint.scala
+++ b/cask/src/cask/endpoints/JsonEndpoint.scala
@@ -1,11 +1,13 @@
package cask.endpoints
-import java.io.ByteArrayOutputStream
+import java.io.{ByteArrayOutputStream, InputStream, OutputStream, OutputStreamWriter}
import cask.internal.{Router, Util}
-import cask.main.Endpoint
+import cask.main.HttpEndpoint
+import cask.model.Response.DataCompanion
import cask.model.{Request, Response}
+import collection.JavaConverters._
sealed trait JsReader[T] extends Router.ArgReader[ujson.Value, T, cask.model.Request]
object JsReader{
@@ -26,13 +28,24 @@ object JsReader{
}
}
}
-class postJson(val path: String, override val subpath: Boolean = false) extends Endpoint{
- type Output = Response
+trait JsonData extends Response.Data
+object JsonData extends DataCompanion[JsonData]{
+ implicit class JsonDataImpl[T: upickle.default.Writer](t: T) extends JsonData{
+ def write(out: OutputStream) = {
+ val writer = new OutputStreamWriter(out)
+ implicitly[upickle.default.Writer[T]].write(new ujson.BaseRenderer(writer), t)
+ writer.flush()
+ }
+ }
+}
+
+class postJson(val path: String, override val subpath: Boolean = false)
+ extends HttpEndpoint[Response[JsonData], ujson.Value]{
val methods = Seq("post")
- type Input = ujson.Js.Value
type InputParser[T] = JsReader[T]
+ override type OuterReturned = Router.Result[Response.Raw]
def wrapFunction(ctx: Request,
- delegate: Map[String, Input] => Router.Result[Output]): Router.Result[Response] = {
+ delegate: Delegate): Router.Result[Response.Raw] = {
val obj = for{
str <-
try {
@@ -41,21 +54,38 @@ class postJson(val path: String, override val subpath: Boolean = false) extends
Right(new String(boas.toByteArray))
}
catch{case e: Throwable => Left(cask.model.Response(
- "Unable to deserialize input JSON text: " + e + "\n" + Util.stackTraceString(e)
+ "Unable to deserialize input JSON text: " + e + "\n" + Util.stackTraceString(e),
+ statusCode = 400
))}
json <-
try Right(ujson.read(str))
catch{case e: Throwable => Left(cask.model.Response(
- "Input text is invalid JSON: " + e + "\n" + Util.stackTraceString(e)
+ "Input text is invalid JSON: " + e + "\n" + Util.stackTraceString(e),
+ statusCode = 400
))}
obj <-
try Right(json.obj)
- catch {case e: Throwable => Left(cask.model.Response("Input JSON must be a dictionary"))}
+ catch {case e: Throwable => Left(cask.model.Response(
+ "Input JSON must be a dictionary",
+ statusCode = 400
+ ))}
} yield obj.toMap
obj match{
- case Left(r) => Router.Result.Success(r)
+ case Left(r) => Router.Result.Success(r.map(Response.Data.StringData))
case Right(params) => delegate(params)
}
}
- def wrapPathSegment(s: String): Input = ujson.Js.Str(s)
+ def wrapPathSegment(s: String): ujson.Value = ujson.Str(s)
}
+
+class getJson(val path: String, override val subpath: Boolean = false)
+ extends HttpEndpoint[Response[JsonData], Seq[String]]{
+ val methods = Seq("get")
+ type InputParser[T] = QueryParamReader[T]
+ override type OuterReturned = Router.Result[Response.Raw]
+ def wrapFunction(ctx: Request, delegate: Delegate): Router.Result[Response.Raw] = {
+
+ delegate(WebEndpoint.buildMapFromQueryParams(ctx))
+ }
+ def wrapPathSegment(s: String) = Seq(s)
+} \ No newline at end of file
diff --git a/cask/src/cask/endpoints/StaticEndpoints.scala b/cask/src/cask/endpoints/StaticEndpoints.scala
index fd194ca..0abfcf5 100644
--- a/cask/src/cask/endpoints/StaticEndpoints.scala
+++ b/cask/src/cask/endpoints/StaticEndpoints.scala
@@ -1,15 +1,13 @@
package cask.endpoints
-import cask.main.Endpoint
+import cask.main.HttpEndpoint
import cask.model.Request
-class staticFiles(val path: String) extends Endpoint{
- type Output = String
+class staticFiles(val path: String) extends HttpEndpoint[String, Seq[String]]{
val methods = Seq("get")
- type Input = Seq[String]
type InputParser[T] = QueryParamReader[T]
override def subpath = true
- def wrapFunction(ctx: Request, delegate: Delegate): Returned = {
+ def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = {
delegate(Map()).map(t =>
cask.model.StaticFile(
(cask.internal.Util.splitPath(t) ++ ctx.remainingPathSegments)
@@ -19,16 +17,15 @@ class staticFiles(val path: String) extends Endpoint{
)
}
- def wrapPathSegment(s: String): Input = Seq(s)
+ def wrapPathSegment(s: String): Seq[String] = Seq(s)
}
-class staticResources(val path: String, resourceRoot: ClassLoader = getClass.getClassLoader) extends Endpoint{
- type Output = String
+class staticResources(val path: String, resourceRoot: ClassLoader = getClass.getClassLoader)
+ extends HttpEndpoint[String, Seq[String]]{
val methods = Seq("get")
- type Input = Seq[String]
type InputParser[T] = QueryParamReader[T]
override def subpath = true
- def wrapFunction(ctx: Request, delegate: Delegate): Returned = {
+ def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = {
delegate(Map()).map(t =>
cask.model.StaticResource(
(cask.internal.Util.splitPath(t) ++ ctx.remainingPathSegments)
@@ -39,5 +36,5 @@ class staticResources(val path: String, resourceRoot: ClassLoader = getClass.get
)
}
- def wrapPathSegment(s: String): Input = Seq(s)
+ def wrapPathSegment(s: String): Seq[String] = Seq(s)
}
diff --git a/cask/src/cask/endpoints/WebEndpoints.scala b/cask/src/cask/endpoints/WebEndpoints.scala
index ab3b480..8bb3bae 100644
--- a/cask/src/cask/endpoints/WebEndpoints.scala
+++ b/cask/src/cask/endpoints/WebEndpoints.scala
@@ -1,19 +1,22 @@
package cask.endpoints
import cask.internal.Router
-import cask.main.Endpoint
+import cask.main.HttpEndpoint
import cask.model.{Request, Response}
import collection.JavaConverters._
-trait WebEndpoint extends Endpoint{
- type Output = Response
- type Input = Seq[String]
+trait WebEndpoint extends HttpEndpoint[Response.Raw, Seq[String]]{
type InputParser[T] = QueryParamReader[T]
def wrapFunction(ctx: Request,
- delegate: Map[String, Input] => Router.Result[Output]): Router.Result[Response] = {
-
+ delegate: Delegate): Router.Result[Response.Raw] = {
+ delegate(WebEndpoint.buildMapFromQueryParams(ctx))
+ }
+ def wrapPathSegment(s: String) = Seq(s)
+}
+object WebEndpoint{
+ def buildMapFromQueryParams(ctx: Request) = {
val b = Map.newBuilder[String, Seq[String]]
val queryParams = ctx.exchange.getQueryParameters
for(k <- queryParams.keySet().iterator().asScala){
@@ -22,9 +25,8 @@ trait WebEndpoint extends Endpoint{
deque.toArray(arr)
b += (k -> (arr: Seq[String]))
}
- delegate(b.result())
+ b.result()
}
- def wrapPathSegment(s: String) = Seq(s)
}
class get(val path: String, override val subpath: Boolean = false) extends WebEndpoint{
val methods = Seq("get")
diff --git a/cask/src/cask/endpoints/WebSocketEndpoint.scala b/cask/src/cask/endpoints/WebSocketEndpoint.scala
index f747341..842d508 100644
--- a/cask/src/cask/endpoints/WebSocketEndpoint.scala
+++ b/cask/src/cask/endpoints/WebSocketEndpoint.scala
@@ -3,22 +3,24 @@ package cask.endpoints
import cask.internal.Router
import cask.model.Request
import io.undertow.websockets.WebSocketConnectionCallback
-
+import collection.JavaConverters._
sealed trait WebsocketResult
object WebsocketResult{
- implicit class Response(val value: cask.model.Response) extends WebsocketResult
+ implicit class Response[T](value0: cask.model.Response[T])
+ (implicit f: T => cask.model.Response.Data) extends WebsocketResult{
+ def value = value0.map(f)
+ }
implicit class Listener(val value: WebSocketConnectionCallback) extends WebsocketResult
}
-class websocket(val path: String, override val subpath: Boolean = false) extends cask.main.BaseEndpoint{
- type Output = WebsocketResult
+class websocket(val path: String, override val subpath: Boolean = false)
+ extends cask.main.Endpoint[WebsocketResult, Seq[String]]{
val methods = Seq("websocket")
- type Input = Seq[String]
type InputParser[T] = QueryParamReader[T]
- type Returned = Router.Result[WebsocketResult]
- def wrapFunction(ctx: Request, delegate: Delegate): Returned = delegate(Map())
-
- def wrapPathSegment(s: String): Input = Seq(s)
-
+ type OuterReturned = Router.Result[WebsocketResult]
+ def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = {
+ delegate(WebEndpoint.buildMapFromQueryParams(ctx))
+ }
+ def wrapPathSegment(s: String): Seq[String] = Seq(s)
}
diff --git a/cask/src/cask/internal/Conversion.scala b/cask/src/cask/internal/Conversion.scala
new file mode 100644
index 0000000..8d8ee3a
--- /dev/null
+++ b/cask/src/cask/internal/Conversion.scala
@@ -0,0 +1,9 @@
+package cask.internal
+
+import scala.annotation.implicitNotFound
+
+@implicitNotFound("Cannot return ${T} as a ${V}")
+class Conversion[T, V](val f: T => V)
+object Conversion{
+ implicit def create[T, V](implicit f: T => V) = new Conversion(f)
+}
diff --git a/cask/src/cask/internal/Util.scala b/cask/src/cask/internal/Util.scala
index 3f7ab61..87e2a15 100644
--- a/cask/src/cask/internal/Util.scala
+++ b/cask/src/cask/internal/Util.scala
@@ -7,9 +7,14 @@ import scala.collection.mutable
import java.io.OutputStream
import scala.annotation.switch
+import scala.concurrent.{ExecutionContext, Future, Promise}
object Util {
-
+ def firstFutureOf[T](futures: Seq[Future[T]])(implicit ec: ExecutionContext) = {
+ val p = Promise[T]
+ futures.foreach(_.foreach(p.trySuccess))
+ p.future
+ }
/**
* Convert a string to a C&P-able literal. Basically
* copied verbatim from the uPickle source code.
diff --git a/cask/src/cask/main/Decorators.scala b/cask/src/cask/main/Decorators.scala
index 7aa361f..573c139 100644
--- a/cask/src/cask/main/Decorators.scala
+++ b/cask/src/cask/main/Decorators.scala
@@ -1,18 +1,44 @@
package cask.main
-import cask.internal.Router
+import cask.internal.{Conversion, Router}
import cask.internal.Router.ArgReader
import cask.model.{Request, Response}
+/**
+ * A [[Decorator]] allows you to annotate a function to wrap it, via
+ * `wrapFunction`. You can use this to perform additional validation before or
+ * after the function runs, provide an additional parameter list of params,
+ * open/commit/rollback database transactions before/after the function runs,
+ * or even retrying the wrapped function if it fails.
+ *
+ * Calls to the wrapped function are done on the `delegate` parameter passed
+ * to `wrapFunction`, which takes a `Map` representing any additional argument
+ * lists (if any).
+ */
+trait Decorator[InnerReturned, Input]{
+ final type InputTypeAlias = Input
+ type InputParser[T] <: ArgReader[Input, T, Request]
+ final type Delegate = Map[String, Input] => Router.Result[InnerReturned]
+ type OuterReturned <: Router.Result[Any]
+ def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned
+ def getParamParser[T](implicit p: InputParser[T]) = p
+}
-trait Endpoint extends BaseEndpoint {
- type Returned = Router.Result[Response]
+/**
+ * A [[RawDecorator]] is a decorator that operates on the raw request and
+ * response stream, before and after the primary [[Endpoint]] does it's job.
+ */
+trait RawDecorator extends Decorator[Response.Raw, Any]{
+ type OuterReturned = Router.Result[Response.Raw]
+ type InputParser[T] = NoOpParser[Any, T]
}
+
+
/**
- * Used to annotate a single Cask endpoint function; similar to a [[Decorator]]
- * but with additional metadata and capabilities.
+ * An [[HttpEndpoint]] that may return something else than a HTTP response, e.g.
+ * a websocket endpoint which may instead return a websocket event handler
*/
-trait BaseEndpoint extends BaseDecorator{
+trait Endpoint[InnerReturned, Input] extends Decorator[InnerReturned, Input]{
/**
* What is the path that this particular endpoint matches?
*/
@@ -31,10 +57,13 @@ trait BaseEndpoint extends BaseDecorator{
*/
def subpath: Boolean = false
- def convertToResultType(t: Output): Output = t
+ def convertToResultType[T](t: T)
+ (implicit f: Conversion[T, InnerReturned]): InnerReturned = {
+ f.f(t)
+ }
/**
- * [[Endpoint]]s are unique among decorators in that they alone can bind
+ * [[HttpEndpoint]]s are unique among decorators in that they alone can bind
* path segments to parameters, e.g. binding `/hello/:world` to `(world: Int)`.
* In order to do so, we need to box up the path segment strings into an
* [[Input]] so they can later be parsed by [[getParamParser]] into an
@@ -44,34 +73,15 @@ trait BaseEndpoint extends BaseDecorator{
}
-trait BaseDecorator{
- type Input
- type InputParser[T] <: ArgReader[Input, T, Request]
- type Output
- type Delegate = Map[String, Input] => Router.Result[Output]
- type Returned <: Router.Result[Any]
- def wrapFunction(ctx: Request, delegate: Delegate): Returned
- def getParamParser[T](implicit p: InputParser[T]) = p
-}
-
/**
- * A decorator allows you to annotate a function to wrap it, via
- * `wrapFunction`. You can use this to perform additional validation before or
- * after the function runs, provide an additional parameter list of params,
- * open/commit/rollback database transactions before/after the function runs,
- * or even retrying the wrapped function if it fails.
- *
- * Calls to the wrapped function are done on the `delegate` parameter passed
- * to `wrapFunction`, which takes a `Map` representing any additional argument
- * lists (if any).
+ * Annotates a Cask endpoint that returns a HTTP [[Response]]; similar to a
+ * [[RawDecorator]] but with additional metadata and capabilities.
*/
-trait Decorator extends BaseDecorator{
- type Returned = Router.Result[Response]
- type Input = Any
- type Output = Response
- type InputParser[T] = NoOpParser[Input, T]
+trait HttpEndpoint[InnerReturned, Input] extends Endpoint[InnerReturned, Input] {
+ type OuterReturned = Router.Result[Response.Raw]
}
+
class NoOpParser[Input, T] extends ArgReader[Input, T, Request] {
def arity = 1
diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala
index 88d7a61..32e6517 100644
--- a/cask/src/cask/main/Main.scala
+++ b/cask/src/cask/main/Main.scala
@@ -28,7 +28,7 @@ class Main(servers0: Routes*) extends BaseMain{
def allRoutes = servers0.toSeq
}
abstract class BaseMain{
- def mainDecorators = Seq.empty[cask.main.Decorator]
+ def mainDecorators = Seq.empty[cask.main.RawDecorator]
def allRoutes: Seq[Routes]
def port: Int = 8080
def host: String = "localhost"
@@ -48,7 +48,7 @@ abstract class BaseMain{
)
}.toMap
- def writeResponse(exchange: HttpServerExchange, response: Response) = {
+ def writeResponse(exchange: HttpServerExchange, response: Response.Raw) = {
response.headers.foreach{case (k, v) =>
exchange.getResponseHeaders.put(new HttpString(k), v)
}
@@ -58,7 +58,7 @@ abstract class BaseMain{
response.data.write(exchange.getOutputStream)
}
- def handleNotFound(): Response = {
+ def handleNotFound(): Response.Raw = {
Response(
s"Error 404: ${Status.codesToStatus(404).reason}",
statusCode = 404
@@ -68,36 +68,38 @@ abstract class BaseMain{
def defaultHandler = new BlockingHandler(
new HttpHandler() {
- def handleRequest(exchange: HttpServerExchange): Unit = {
+ def handleRequest(exchange: HttpServerExchange): Unit = try {
+// println("Handling Request: " + exchange.getRequestPath)
val (effectiveMethod, runner) = if (exchange.getRequestHeaders.getFirst("Upgrade") == "websocket") {
"websocket" -> ((r: Any) =>
r.asInstanceOf[WebsocketResult] match{
case l: WebsocketResult.Listener =>
io.undertow.Handlers.websocket(l.value).handleRequest(exchange)
- case r: WebsocketResult.Response =>
+ case r: WebsocketResult.Response[_] =>
writeResponseHandler(r).handleRequest(exchange)
}
- )
+ )
} else (
exchange.getRequestMethod.toString.toLowerCase(),
- (r: Any) => writeResponse(exchange, r.asInstanceOf[Response])
+ (r: Any) => writeResponse(exchange, r.asInstanceOf[Response.Raw])
)
routeTries(effectiveMethod).lookup(Util.splitPath(exchange.getRequestPath).toList, Map()) match {
case None => writeResponse(exchange, handleNotFound())
case Some(((routes, metadata), routeBindings, remaining)) =>
val ctx = Request(exchange, remaining)
- def rec(remaining: List[Decorator],
+ def rec(remaining: List[RawDecorator],
bindings: List[Map[String, Any]]): Router.Result[Any] = try {
remaining match {
case head :: rest =>
head.wrapFunction(
ctx,
- args => rec(rest, args :: bindings).asInstanceOf[Router.Result[head.Output]]
+ args => rec(rest, args :: bindings)
+ .asInstanceOf[cask.internal.Router.Result[cask.model.Response.Raw]]
)
case Nil =>
- metadata.endpoint.wrapFunction(ctx, endpointBindings =>
+ metadata.endpoint.wrapFunction(ctx, (endpointBindings: Map[String, Any]) =>
metadata.entryPoint
.asInstanceOf[EntryPoint[cask.main.Routes, cask.model.Request]]
.invoke(
@@ -116,16 +118,21 @@ abstract class BaseMain{
rec((metadata.decorators ++ routes.decorators ++ mainDecorators).toList, Nil)match{
case Router.Result.Success(res) => runner(res)
case e: Router.Result.Error =>
- writeResponse(exchange, handleEndpointError(exchange, routes, metadata, e))
+ writeResponse(
+ exchange,
+ handleEndpointError(exchange, routes, metadata, e).map(Response.Data.StringData)
+ )
None
}
}
-
+// println("Completed Request: " + exchange.getRequestPath)
+ }catch{case e: Throwable =>
+ e.printStackTrace()
}
}
)
- def writeResponseHandler(r: WebsocketResult.Response) = new BlockingHandler(
+ def writeResponseHandler(r: WebsocketResult.Response[_]) = new BlockingHandler(
new HttpHandler {
def handleRequest(exchange: HttpServerExchange): Unit = {
writeResponse(exchange, r.value)
@@ -142,15 +149,15 @@ abstract class BaseMain{
case _: Router.Result.Error.InvalidArguments => 400
case _: Router.Result.Error.MismatchedArguments => 400
}
- Response(
+ val str =
if (!debugMode) s"Error $statusCode: ${Status.codesToStatus(statusCode).reason}"
else ErrorMsgs.formatInvokeError(
routes,
metadata.entryPoint.asInstanceOf[EntryPoint[cask.main.Routes, _]],
e
- ),
- statusCode = statusCode
- )
+ )
+ println(str)
+ Response(str, statusCode = statusCode)
}
diff --git a/cask/src/cask/main/Routes.scala b/cask/src/cask/main/Routes.scala
index a4660a9..f133fdb 100644
--- a/cask/src/cask/main/Routes.scala
+++ b/cask/src/cask/main/Routes.scala
@@ -7,8 +7,8 @@ import scala.reflect.macros.blackbox.Context
import language.experimental.macros
object Routes{
- case class EndpointMetadata[T](decorators: Seq[Decorator],
- endpoint: BaseEndpoint,
+ case class EndpointMetadata[T](decorators: Seq[RawDecorator],
+ endpoint: Endpoint[_, _],
entryPoint: EntryPoint[T, _])
case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*)
object RoutesEndpointsMetadata{
@@ -19,15 +19,15 @@ object Routes{
val routeParts = for{
m <- c.weakTypeOf[T].members
- val annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[BaseDecorator]).reverse
+ val annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator[_, _]]).reverse
if annotations.nonEmpty
} yield {
- if(!(annotations.head.tree.tpe <:< weakTypeOf[BaseEndpoint])) c.abort(
+ if(!(annotations.head.tree.tpe <:< weakTypeOf[Endpoint[_, _]])) c.abort(
annotations.head.tree.pos,
s"Last annotation applied to a function must be an instance of Endpoint, " +
s"not ${annotations.head.tree.tpe}"
)
- val allEndpoints = annotations.filter(_.tree.tpe <:< weakTypeOf[BaseEndpoint])
+ val allEndpoints = annotations.filter(_.tree.tpe <:< weakTypeOf[Endpoint[_, _]])
if(allEndpoints.length > 1) c.abort(
annotations.head.tree.pos,
s"You can only apply one Endpoint annotation to a function, not " +
@@ -45,8 +45,7 @@ object Routes{
q"${annotObjectSyms.head}.convertToResultType",
tq"cask.Request",
annotObjectSyms.map(annotObjectSym => q"$annotObjectSym.getParamParser"),
- annotObjectSyms.map(annotObjectSym => tq"$annotObjectSym.Input")
-
+ annotObjectSyms.map(annotObjectSym => tq"$annotObjectSym.InputTypeAlias")
)
val declarations =
@@ -71,7 +70,7 @@ object Routes{
trait Routes{
- def decorators = Seq.empty[cask.main.Decorator]
+ def decorators = Seq.empty[cask.main.RawDecorator]
private[this] var metadata0: Routes.RoutesEndpointsMetadata[this.type] = null
def caskMetadata =
if (metadata0 != null) metadata0
diff --git a/cask/src/cask/model/Response.scala b/cask/src/cask/model/Response.scala
index 59b44c9..e9ca672 100644
--- a/cask/src/cask/model/Response.scala
+++ b/cask/src/cask/model/Response.scala
@@ -4,6 +4,7 @@ import java.io.{InputStream, OutputStream, OutputStreamWriter}
import cask.internal.Util
+
/**
* The basic response returned by a HTTP endpoint.
*
@@ -11,40 +12,62 @@ import cask.internal.Util
* bytes, uPickle JSON-convertable types or arbitrary input streams. You can
* also construct your own implementations of `Response.Data`.
*/
-case class Response(
- data: Response.Data,
+case class Response[+T](
+ data: T,
statusCode: Int,
headers: Seq[(String, String)],
cookies: Seq[Cookie]
-)
-object Response{
- def apply(data: Data,
- statusCode: Int = 200,
- headers: Seq[(String, String)] = Nil,
- cookies: Seq[Cookie] = Nil) = new Response(data, statusCode, headers, cookies)
+){
+ def map[V](f: T => V) = new Response(f(data), statusCode, headers, cookies)
+}
- implicit def dataResponse[T](t: T)(implicit c: T => Data) = Response(t)
+object Response {
+ type Raw = Response[Data]
+ def apply[T](data: T,
+ statusCode: Int = 200,
+ headers: Seq[(String, String)] = Nil,
+ cookies: Seq[Cookie] = Nil) = new Response(data, statusCode, headers, cookies)
trait Data{
def write(out: OutputStream): Unit
}
- object Data{
+ trait DataCompanion[V]{
+ // Put the implicit constructors for Response[Data] into the `Data` companion
+ // object and all subclasses of `Data`, because for some reason putting them in
+ // the `Response` companion object doesn't work properly. For the same unknown
+ // reasons, we cannot have `dataResponse` and `dataResponse2` take two type
+ // params T and V, and instead have to embed the implicit target type as a
+ // parameter of the enclosing trait
+
+ implicit def dataResponse[T](t: T)(implicit c: T => V): Response[V] = {
+ Response(c(t))
+ }
+
+ implicit def dataResponse2[T](t: Response[T])(implicit c: T => V): Response[V] = {
+ t.map(c(_))
+ }
+ }
+ object Data extends DataCompanion[Data]{
+ implicit class UnitData(s: Unit) extends Data{
+ def write(out: OutputStream) = ()
+ }
implicit class StringData(s: String) extends Data{
def write(out: OutputStream) = out.write(s.getBytes)
}
+ implicit class NumericData[T: Numeric](s: T) extends Data{
+ def write(out: OutputStream) = out.write(s.toString.getBytes)
+ }
+ implicit class BooleanData(s: Boolean) extends Data{
+ def write(out: OutputStream) = out.write(s.toString.getBytes)
+ }
implicit class BytesData(b: Array[Byte]) extends Data{
def write(out: OutputStream) = out.write(b)
}
implicit class StreamData(b: InputStream) extends Data{
def write(out: OutputStream) = Util.transferTo(b, out)
}
- implicit def JsonResponse[T: upickle.default.Writer](t: T) = new Data{
- def write(out: OutputStream) = implicitly[upickle.default.Writer[T]].write(
- new ujson.BaseRenderer(new OutputStreamWriter(out)),
- t
- )
- }
}
}
+
object Redirect{
def apply(url: String) = Response("", 301, Seq("Location" -> url), Nil)
}
diff --git a/cask/src/cask/package.scala b/cask/src/cask/package.scala
index 405bab7..d17cfe6 100644
--- a/cask/src/cask/package.scala
+++ b/cask/src/cask/package.scala
@@ -1,6 +1,6 @@
package object cask {
// model
- type Response = model.Response
+ type Response[T] = model.Response[T]
val Response = model.Response
val Abort = model.Abort
val Redirect = model.Redirect
@@ -29,6 +29,7 @@ package object cask {
type staticFiles = endpoints.staticFiles
type staticResources = endpoints.staticResources
type postJson = endpoints.postJson
+ type getJson = endpoints.getJson
type postForm = endpoints.postForm
// main
@@ -36,7 +37,7 @@ package object cask {
type Routes = main.Routes
val Routes = main.Routes
type Main = main.Main
- type Decorator = main.Decorator
- type Endpoint = main.Endpoint
+ type RawDecorator = main.RawDecorator
+ type HttpEndpoint[InnerReturned, Input] = main.HttpEndpoint[InnerReturned, Input]
}
diff --git a/cask/test/src/test/cask/FailureTests.scala b/cask/test/src/test/cask/FailureTests.scala
index d24d52c..6b01ec1 100644
--- a/cask/test/src/test/cask/FailureTests.scala
+++ b/cask/test/src/test/cask/FailureTests.scala
@@ -4,8 +4,8 @@ import cask.model.Request
import utest._
object FailureTests extends TestSuite {
- class myDecorator extends cask.Decorator {
- def wrapFunction(ctx: Request, delegate: Delegate): Returned = {
+ class myDecorator extends cask.RawDecorator {
+ def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = {
delegate(Map("extra" -> 31337))
}
}
diff --git a/docs/pages/1 - Cask: a Scala HTTP micro-framework.md b/docs/pages/1 - Cask: a Scala HTTP micro-framework.md
index 093c8c3..52653d2 100644
--- a/docs/pages/1 - Cask: a Scala HTTP micro-framework.md
+++ b/docs/pages/1 - Cask: a Scala HTTP micro-framework.md
@@ -162,13 +162,13 @@ what to do in each case. You can use the `@cask.route` annotation to do so
$$$formJsonPost
If you need to handle a JSON-encoded POST request, you can use the
-`@cask.postJson` decorator. This assumes the posted request body is a JSON dict,
-and uses its keys to populate the endpoint's parameters, either as raw
-`ujson.Js.Value`s or deserialized into `Seq[Int]`s or other things.
-Deserialization is handled using the
-[uPickle](https://github.com/lihaoyi/upickle) JSON library, though you could
-write your own version of `postJson` to work with any other JSON library of your
-choice.
+`@cask.postJson` decorator. This assumes the posted request body is a
+JSON dict, and uses its keys to populate the endpoint's parameters,
+either as raw `ujson.Value`s or deserialized into `Seq[Int]`s or other
+things. Deserialization is handled using the
+[uPickle](https://github.com/lihaoyi/upickle) JSON library, though you
+could write your own version of `postJson` to work with any other JSON
+library of your choice.
Similarly, you can mark endpoints as `@cask.postForm`, in which case the
endpoints params will be taken from the form-encoded POST body either raw (as
diff --git a/example/compress/app/test/src/ExampleTests.scala b/example/compress/app/test/src/ExampleTests.scala
index 5a4a5bf..cd4d8d0 100644
--- a/example/compress/app/test/src/ExampleTests.scala
+++ b/example/compress/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'Compress - test(Compress){ host =>
+ test("Compress") - withServer(Compress){ host =>
val expected = "Hello World! Hello World! Hello World!"
requests.get(s"$host").text() ==> expected
assert(
diff --git a/example/compress/build.sc b/example/compress/build.sc
index ac96e15..5e00fc0 100644
--- a/example/compress/build.sc
+++ b/example/compress/build.sc
@@ -10,7 +10,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/compress2/app/test/src/ExampleTests.scala b/example/compress2/app/test/src/ExampleTests.scala
index cbe3301..9f9b4b3 100644
--- a/example/compress2/app/test/src/ExampleTests.scala
+++ b/example/compress2/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'Compress2Main - test(Compress2Main) { host =>
+ test("Compress2Main") - withServer(Compress2Main) { host =>
val expected = "Hello World! Hello World! Hello World!"
requests.get(s"$host").text() ==> expected
assert(
diff --git a/example/compress2/build.sc b/example/compress2/build.sc
index c0e75a7..e4c2108 100644
--- a/example/compress2/build.sc
+++ b/example/compress2/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/compress3/app/test/src/ExampleTests.scala b/example/compress3/app/test/src/ExampleTests.scala
index 3b013f8..88e1cbf 100644
--- a/example/compress3/app/test/src/ExampleTests.scala
+++ b/example/compress3/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'Compress3Main - test(Compress3Main){ host =>
+ test("Compress3Main") - withServer(Compress3Main){ host =>
val expected = "Hello World! Hello World! Hello World!"
requests.get(s"$host").text() ==> expected
assert(
diff --git a/example/compress3/build.sc b/example/compress3/build.sc
index c0e75a7..e4c2108 100644
--- a/example/compress3/build.sc
+++ b/example/compress3/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/cookies/app/test/src/ExampleTests.scala b/example/cookies/app/test/src/ExampleTests.scala
index 951728b..150f59a 100644
--- a/example/cookies/app/test/src/ExampleTests.scala
+++ b/example/cookies/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'Cookies - test(Cookies){ host =>
+ test("Cookies") - withServer(Cookies){ host =>
val sess = requests.Session()
sess.get(s"$host/read-cookie").statusCode ==> 400
sess.get(s"$host/store-cookie")
diff --git a/example/cookies/build.sc b/example/cookies/build.sc
index c0e75a7..e4c2108 100644
--- a/example/cookies/build.sc
+++ b/example/cookies/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/decorated/app/src/Decorated.scala b/example/decorated/app/src/Decorated.scala
index f037c6a..a88bd2e 100644
--- a/example/decorated/app/src/Decorated.scala
+++ b/example/decorated/app/src/Decorated.scala
@@ -3,13 +3,13 @@ object Decorated extends cask.MainRoutes{
class User{
override def toString = "[haoyi]"
}
- class loggedIn extends cask.Decorator {
- def wrapFunction(ctx: cask.Request, delegate: Delegate): Returned = {
+ class loggedIn extends cask.RawDecorator {
+ def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = {
delegate(Map("user" -> new User()))
}
}
- class withExtra extends cask.Decorator {
- def wrapFunction(ctx: cask.Request, delegate: Delegate): Returned = {
+ class withExtra extends cask.RawDecorator {
+ def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = {
delegate(Map("extra" -> 31337))
}
}
diff --git a/example/decorated/app/test/src/ExampleTests.scala b/example/decorated/app/test/src/ExampleTests.scala
index 9aea3bc..c2c19a6 100644
--- a/example/decorated/app/test/src/ExampleTests.scala
+++ b/example/decorated/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'Decorated - test(Decorated){ host =>
+ test("Decorated") - withServer(Decorated){ host =>
requests.get(s"$host/hello/woo").text() ==> "woo31337"
requests.get(s"$host/internal/boo").text() ==> "boo[haoyi]"
requests.get(s"$host/internal-extra/goo").text() ==> "goo[haoyi]31337"
diff --git a/example/decorated/build.sc b/example/decorated/build.sc
index c0e75a7..e4c2108 100644
--- a/example/decorated/build.sc
+++ b/example/decorated/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/decorated2/app/src/Decorated2.scala b/example/decorated2/app/src/Decorated2.scala
index 20526b7..305281a 100644
--- a/example/decorated2/app/src/Decorated2.scala
+++ b/example/decorated2/app/src/Decorated2.scala
@@ -3,13 +3,13 @@ object Decorated2 extends cask.MainRoutes{
class User{
override def toString = "[haoyi]"
}
- class loggedIn extends cask.Decorator {
- def wrapFunction(ctx: cask.Request, delegate: Delegate): Returned = {
+ class loggedIn extends cask.RawDecorator {
+ def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = {
delegate(Map("user" -> new User()))
}
}
- class withExtra extends cask.Decorator {
- def wrapFunction(ctx: cask.Request, delegate: Delegate): Returned = {
+ class withExtra extends cask.RawDecorator {
+ def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = {
delegate(Map("extra" -> 31337))
}
}
diff --git a/example/decorated2/app/test/src/ExampleTests.scala b/example/decorated2/app/test/src/ExampleTests.scala
index 7fec82a..4343097 100644
--- a/example/decorated2/app/test/src/ExampleTests.scala
+++ b/example/decorated2/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'Decorated2 - test(Decorated2){ host =>
+ test("Decorated2") - withServer(Decorated2){ host =>
requests.get(s"$host/hello/woo").text() ==> "woo31337"
requests.get(s"$host/internal-extra/goo").text() ==> "goo[haoyi]31337"
requests.get(s"$host/ignore-extra/boo").text() ==> "boo[haoyi]"
diff --git a/example/decorated2/build.sc b/example/decorated2/build.sc
index c0e75a7..e4c2108 100644
--- a/example/decorated2/build.sc
+++ b/example/decorated2/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/endpoints/app/src/Endpoints.scala b/example/endpoints/app/src/Endpoints.scala
index b478c80..9722673 100644
--- a/example/endpoints/app/src/Endpoints.scala
+++ b/example/endpoints/app/src/Endpoints.scala
@@ -1,8 +1,8 @@
package app
-class custom(val path: String, val methods: Seq[String]) extends cask.Endpoint{
- type Output = Int
- def wrapFunction(ctx: cask.Request, delegate: Delegate): Returned = {
+class custom(val path: String, val methods: Seq[String])
+ extends cask.HttpEndpoint[Int, Seq[String]]{
+ def wrapFunction(ctx: cask.Request, delegate: Delegate): OuterReturned = {
delegate(Map()).map{num =>
cask.Response("Echo " + num, statusCode = num)
}
@@ -10,7 +10,6 @@ class custom(val path: String, val methods: Seq[String]) extends cask.Endpoint{
def wrapPathSegment(s: String) = Seq(s)
- type Input = Seq[String]
type InputParser[T] = cask.endpoints.QueryParamReader[T]
}
diff --git a/example/endpoints/app/test/src/ExampleTests.scala b/example/endpoints/app/test/src/ExampleTests.scala
index 1302d85..3314f24 100644
--- a/example/endpoints/app/test/src/ExampleTests.scala
+++ b/example/endpoints/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'Endpoints - test(Endpoints){ host =>
+ test("Endpoints") - withServer(Endpoints){ host =>
requests.get(s"$host/echo/200").text() ==> "Echo 200"
requests.get(s"$host/echo/200").statusCode ==> 200
requests.get(s"$host/echo/400").text() ==> "Echo 400"
diff --git a/example/endpoints/build.sc b/example/endpoints/build.sc
index c0e75a7..e4c2108 100644
--- a/example/endpoints/build.sc
+++ b/example/endpoints/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/formJsonPost/app/src/FormJsonPost.scala b/example/formJsonPost/app/src/FormJsonPost.scala
index 3714f39..b994ac1 100644
--- a/example/formJsonPost/app/src/FormJsonPost.scala
+++ b/example/formJsonPost/app/src/FormJsonPost.scala
@@ -1,7 +1,7 @@
package app
object FormJsonPost extends cask.MainRoutes{
@cask.postJson("/json")
- def jsonEndpoint(value1: ujson.Js.Value, value2: Seq[Int]) = {
+ def jsonEndpoint(value1: ujson.Value, value2: Seq[Int]) = {
"OK " + value1 + " " + value2
}
diff --git a/example/formJsonPost/app/test/src/ExampleTests.scala b/example/formJsonPost/app/test/src/ExampleTests.scala
index 148ebfd..4178497 100644
--- a/example/formJsonPost/app/test/src/ExampleTests.scala
+++ b/example/formJsonPost/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,23 +17,23 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'FormJsonPost - test(FormJsonPost){ host =>
- requests.post(s"$host/json", data = """{"value1": true, "value2": [3]}""").text() ==>
- "OK true List(3)"
+ test("FormJsonPost") - withServer(FormJsonPost){ host =>
+ val response1 = requests.post(s"$host/json", data = """{"value1": true, "value2": [3]}""")
+ ujson.read(response1.text()) ==> ujson.Str("OK true List(3)")
- requests.post(
+ val response2 = requests.post(
s"$host/form",
data = Seq("value1" -> "hello", "value2" -> "1", "value2" -> "2")
- ).text() ==>
- "OK FormValue(hello,null) List(1, 2)"
+ )
+ response2.text() ==> "OK FormValue(hello,null) List(1, 2)"
- val resp = requests.post(
+ val response3 = requests.post(
s"$host/upload",
data = requests.MultiPart(
requests.MultiItem("image", "...", "my-best-image.txt")
)
)
- resp.text() ==> "my-best-image.txt"
+ response3.text() ==> "my-best-image.txt"
}
}
}
diff --git a/example/formJsonPost/build.sc b/example/formJsonPost/build.sc
index c0e75a7..e4c2108 100644
--- a/example/formJsonPost/build.sc
+++ b/example/formJsonPost/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/httpMethods/app/test/src/ExampleTests.scala b/example/httpMethods/app/test/src/ExampleTests.scala
index e14bcf5..30fa87f 100644
--- a/example/httpMethods/app/test/src/ExampleTests.scala
+++ b/example/httpMethods/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'HttpMethods - test(HttpMethods){ host =>
+ test("HttpMethods") - withServer(HttpMethods){ host =>
requests.post(s"$host/login").text() ==> "do_the_login"
requests.get(s"$host/login").text() ==> "show_the_login_form"
}
diff --git a/example/httpMethods/build.sc b/example/httpMethods/build.sc
index c0e75a7..e4c2108 100644
--- a/example/httpMethods/build.sc
+++ b/example/httpMethods/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/minimalApplication/app/test/src/ExampleTests.scala b/example/minimalApplication/app/test/src/ExampleTests.scala
index 8c8ecb2..1cda7a6 100644
--- a/example/minimalApplication/app/test/src/ExampleTests.scala
+++ b/example/minimalApplication/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests {
- 'MinimalApplication - test(MinimalApplication) { host =>
+ test("MinimalApplication") - withServer(MinimalApplication) { host =>
val success = requests.get(host)
success.text() ==> "Hello World!"
diff --git a/example/minimalApplication/build.sc b/example/minimalApplication/build.sc
index c0e75a7..e4c2108 100644
--- a/example/minimalApplication/build.sc
+++ b/example/minimalApplication/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/minimalApplication2/app/test/src/ExampleTests.scala b/example/minimalApplication2/app/test/src/ExampleTests.scala
index 0d8f1bc..4e5621c 100644
--- a/example/minimalApplication2/app/test/src/ExampleTests.scala
+++ b/example/minimalApplication2/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'MinimalApplication2 - test(MinimalMain){ host =>
+ test("MinimalApplication2") - withServer(MinimalMain){ host =>
val success = requests.get(host)
success.text() ==> "Hello World!"
diff --git a/example/minimalApplication2/build.sc b/example/minimalApplication2/build.sc
index c0e75a7..e4c2108 100644
--- a/example/minimalApplication2/build.sc
+++ b/example/minimalApplication2/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/redirectAbort/app/test/src/ExampleTests.scala b/example/redirectAbort/app/test/src/ExampleTests.scala
index f095517..a4d149f 100644
--- a/example/redirectAbort/app/test/src/ExampleTests.scala
+++ b/example/redirectAbort/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -18,7 +18,7 @@ object ExampleTests extends TestSuite{
val tests = Tests{
- 'RedirectAbort - test(RedirectAbort){ host =>
+ test("RedirectAbort") - withServer(RedirectAbort){ host =>
val resp = requests.get(s"$host/")
resp.statusCode ==> 401
resp.history.get.statusCode ==> 301
diff --git a/example/redirectAbort/build.sc b/example/redirectAbort/build.sc
index c0e75a7..e4c2108 100644
--- a/example/redirectAbort/build.sc
+++ b/example/redirectAbort/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/scalatags/app/test/src/ExampleTests.scala b/example/scalatags/app/test/src/ExampleTests.scala
index 8eccecf..53bc1ea 100644
--- a/example/scalatags/app/test/src/ExampleTests.scala
+++ b/example/scalatags/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests {
- 'Scalatags - test(Scalatags) { host =>
+ test("Scalatags") - withServer(Scalatags) { host =>
val body = requests.get(host).text()
assert(
diff --git a/example/scalatags/build.sc b/example/scalatags/build.sc
index 3971d88..e95569a 100644
--- a/example/scalatags/build.sc
+++ b/example/scalatags/build.sc
@@ -11,7 +11,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/staticFiles/app/test/src/ExampleTests.scala b/example/staticFiles/app/test/src/ExampleTests.scala
index ab67bcf..ebda8a0 100644
--- a/example/staticFiles/app/test/src/ExampleTests.scala
+++ b/example/staticFiles/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -18,7 +18,7 @@ object ExampleTests extends TestSuite{
val tests = Tests{
- 'StaticFiles - test(StaticFiles){ host =>
+ test("StaticFiles") - withServer(StaticFiles){ host =>
requests.get(s"$host/static/file/example.txt").text() ==>
"the quick brown fox jumps over the lazy dog"
diff --git a/example/staticFiles/build.sc b/example/staticFiles/build.sc
index d45045d..e0f8519 100644
--- a/example/staticFiles/build.sc
+++ b/example/staticFiles/build.sc
@@ -11,7 +11,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
diff --git a/example/todo/app/src/TodoServer.scala b/example/todo/app/src/TodoServer.scala
index 4adb55c..1a58d09 100644
--- a/example/todo/app/src/TodoServer.scala
+++ b/example/todo/app/src/TodoServer.scala
@@ -17,7 +17,7 @@ object TodoServer extends cask.MainRoutes{
class transactional extends cask.Decorator{
class TransactionFailed(val value: Router.Result.Error) extends Exception
- def wrapFunction(pctx: cask.Request, delegate: Delegate): Returned = {
+ def wrapFunction(pctx: cask.Request, delegate: Delegate): OuterReturned = {
try ctx.transaction(
delegate(Map()) match{
case Router.Result.Success(t) => Router.Result.Success(t)
diff --git a/example/todo/app/test/src/ExampleTests.scala b/example/todo/app/test/src/ExampleTests.scala
index e8ca7eb..e1be23c 100644
--- a/example/todo/app/test/src/ExampleTests.scala
+++ b/example/todo/app/test/src/ExampleTests.scala
@@ -1,7 +1,7 @@
package app
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = io.undertow.Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -13,7 +13,7 @@ object ExampleTests extends TestSuite{
res
}
val tests = Tests{
- 'TodoServer - test(TodoServer){ host =>
+ test("TodoServer") - withServer(TodoServer){ host =>
val page = requests.get(host).text()
assert(page.contains("What needs to be done?"))
}
diff --git a/example/todo/build.sc b/example/todo/build.sc
index beeb947..c5d5610 100644
--- a/example/todo/build.sc
+++ b/example/todo/build.sc
@@ -13,7 +13,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/todoApi/app/test/src/ExampleTests.scala b/example/todoApi/app/test/src/ExampleTests.scala
index 5e9e11a..4e85a8e 100644
--- a/example/todoApi/app/test/src/ExampleTests.scala
+++ b/example/todoApi/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'TodoMvcApi - test(TodoMvcApi){ host =>
+ test("TodoMvcApi") - withServer(TodoMvcApi){ host =>
requests.get(s"$host/list/all").text() ==>
"""[{"checked":true,"text":"Get started with Cask"},{"checked":false,"text":"Profit!"}]"""
requests.get(s"$host/list/active").text() ==>
diff --git a/example/todoApi/build.sc b/example/todoApi/build.sc
index c0e75a7..e4c2108 100644
--- a/example/todoApi/build.sc
+++ b/example/todoApi/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/todoDb/app/src/TodoMvcDb.scala b/example/todoDb/app/src/TodoMvcDb.scala
index 7ce3c50..669b2b8 100644
--- a/example/todoDb/app/src/TodoMvcDb.scala
+++ b/example/todoDb/app/src/TodoMvcDb.scala
@@ -16,7 +16,7 @@ object TodoMvcDb extends cask.MainRoutes{
class transactional extends cask.Decorator{
class TransactionFailed(val value: Router.Result.Error) extends Exception
- def wrapFunction(pctx: cask.Request, delegate: Delegate): Returned = {
+ def wrapFunction(pctx: cask.Request, delegate: Delegate): OuterReturned = {
try ctx.transaction(
delegate(Map()) match{
case Router.Result.Success(t) => Router.Result.Success(t)
diff --git a/example/todoDb/app/test/src/ExampleTests.scala b/example/todoDb/app/test/src/ExampleTests.scala
index eccd913..77cbbb3 100644
--- a/example/todoDb/app/test/src/ExampleTests.scala
+++ b/example/todoDb/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'TodoMvcDb - test(TodoMvcDb){ host =>
+ test("TodoMvcDb") - withServer(TodoMvcDb){ host =>
requests.get(s"$host/list/all").text() ==>
"""[{"id":1,"checked":true,"text":"Get started with Cask"},{"id":2,"checked":false,"text":"Profit!"}]"""
requests.get(s"$host/list/active").text() ==>
diff --git a/example/todoDb/build.sc b/example/todoDb/build.sc
index e2afdfc..589af39 100644
--- a/example/todoDb/build.sc
+++ b/example/todoDb/build.sc
@@ -12,7 +12,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/twirl/app/test/src/ExampleTests.scala b/example/twirl/app/test/src/ExampleTests.scala
index 815f656..2c445fb 100644
--- a/example/twirl/app/test/src/ExampleTests.scala
+++ b/example/twirl/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests {
- 'Twirl - test(Twirl) { host =>
+ test("Twirl") - withServer(Twirl) { host =>
val body = requests.get(host).text()
assert(
diff --git a/example/twirl/build.sc b/example/twirl/build.sc
index 6a59f0d..de9fc20 100644
--- a/example/twirl/build.sc
+++ b/example/twirl/build.sc
@@ -15,7 +15,7 @@ trait AppModule extends ScalaModule with mill.twirllib.TwirlModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/variableRoutes/app/test/src/ExampleTests.scala b/example/variableRoutes/app/test/src/ExampleTests.scala
index 48455fa..1755dea 100644
--- a/example/variableRoutes/app/test/src/ExampleTests.scala
+++ b/example/variableRoutes/app/test/src/ExampleTests.scala
@@ -4,7 +4,7 @@ import io.undertow.Undertow
import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -17,7 +17,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'VariableRoutes - test(VariableRoutes){ host =>
+ test("VariableRoutes") - withServer(VariableRoutes){ host =>
val noIndexPage = requests.get(host)
noIndexPage.statusCode ==> 404
diff --git a/example/variableRoutes/build.sc b/example/variableRoutes/build.sc
index c0e75a7..e4c2108 100644
--- a/example/variableRoutes/build.sc
+++ b/example/variableRoutes/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
)
}
diff --git a/example/websockets/app/test/src/ExampleTests.scala b/example/websockets/app/test/src/ExampleTests.scala
index 896c051..a463824 100644
--- a/example/websockets/app/test/src/ExampleTests.scala
+++ b/example/websockets/app/test/src/ExampleTests.scala
@@ -8,7 +8,7 @@ import utest._
object ExampleTests extends TestSuite{
- def test[T](example: cask.main.BaseMain)(f: String => T): T = {
+ def withServer[T](example: cask.main.BaseMain)(f: String => T): T = {
val server = io.undertow.Undertow.builder
.addHttpListener(8080, "localhost")
.setHandler(example.defaultHandler)
@@ -21,7 +21,7 @@ object ExampleTests extends TestSuite{
}
val tests = Tests{
- 'Websockets - test(Websockets){ host =>
+ test("Websockets") - withServer(Websockets){ host =>
@volatile var out = List.empty[String]
val client = org.asynchttpclient.Dsl.asyncHttpClient();
try{
@@ -72,7 +72,7 @@ object ExampleTests extends TestSuite{
}
}
- 'Websockets2000 - test(Websockets){ host =>
+ test("Websockets2000") - withServer(Websockets){ host =>
@volatile var out = List.empty[String]
val closed = new AtomicInteger(0)
val client = org.asynchttpclient.Dsl.asyncHttpClient();
diff --git a/example/websockets/build.sc b/example/websockets/build.sc
index c788216..197e285 100644
--- a/example/websockets/build.sc
+++ b/example/websockets/build.sc
@@ -9,7 +9,7 @@ trait AppModule extends ScalaModule{
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(
- ivy"com.lihaoyi::utest::0.6.9",
+ ivy"com.lihaoyi::utest::0.7.1",
ivy"com.lihaoyi::requests::0.2.0",
ivy"org.asynchttpclient:async-http-client:2.5.2"
)