summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2019-10-09 10:44:14 +0800
committerLi Haoyi <haoyi.sg@gmail.com>2019-10-09 10:47:20 +0800
commit0f0f945abd365c9f6f83b3d315cea30eacb6ed51 (patch)
tree4b812b4f6650a42056aa31c2f712b3d7e4125925
parente21d5ab3526937619c59dd01114b48521eee9d26 (diff)
downloadcask-0f0f945abd365c9f6f83b3d315cea30eacb6ed51.tar.gz
cask-0f0f945abd365c9f6f83b3d315cea30eacb6ed51.tar.bz2
cask-0f0f945abd365c9f6f83b3d315cea30eacb6ed51.zip
Add test to verify `compress` decorator is properly passing through irrelevant results
-rw-r--r--build.sc5
-rw-r--r--cask/src/cask/decorators/compress.scala5
-rw-r--r--cask/src/cask/router/Result.scala6
-rw-r--r--docs/pages/1 - Cask: a Scala HTTP micro-framework.md6
-rw-r--r--example/websockets4/app/src/Websockets4.scala22
-rw-r--r--example/websockets4/app/test/src/ExampleTests.scala51
-rw-r--r--example/websockets4/build.sc17
7 files changed, 106 insertions, 6 deletions
diff --git a/build.sc b/build.sc
index f6ce6ae..dc7f051 100644
--- a/build.sc
+++ b/build.sc
@@ -23,6 +23,7 @@ import $file.example.variableRoutes.build
import $file.example.websockets.build
import $file.example.websockets2.build
import $file.example.websockets3.build
+import $file.example.websockets4.build
trait CaskModule extends ScalaModule with PublishModule{
def scalaVersion = "2.13.0"
@@ -122,7 +123,8 @@ object example extends Module{
object variableRoutes extends $file.example.variableRoutes.build.AppModule with LocalModule
object websockets extends $file.example.websockets.build.AppModule with LocalModule
object websockets2 extends $file.example.websockets2.build.AppModule with LocalModule
- object websockets3 extends $file.example.websockets2.build.AppModule with LocalModule
+ object websockets3 extends $file.example.websockets3.build.AppModule with LocalModule
+ object websockets4 extends $file.example.websockets4.build.AppModule with LocalModule
}
def publishVersion = T.input($file.ci.version.publishVersion)
@@ -167,6 +169,7 @@ def uploadToGithub(authKey: String) = T.command{
$file.example.websockets.build.millSourcePath,
$file.example.websockets2.build.millSourcePath,
$file.example.websockets3.build.millSourcePath,
+ $file.example.websockets4.build.millSourcePath,
)
for(example <- examples){
val f = T.ctx().dest
diff --git a/cask/src/cask/decorators/compress.scala b/cask/src/cask/decorators/compress.scala
index 61d76f6..17931fd 100644
--- a/cask/src/cask/decorators/compress.scala
+++ b/cask/src/cask/decorators/compress.scala
@@ -11,7 +11,8 @@ class compress extends cask.RawDecorator{
.toSeq
.flatMap(_.asScala)
.flatMap(_.split(", "))
- delegate(Map()).transform{ case v: cask.Response[_] =>
+ val r = delegate(Map())
+ val finalResult = r.transform{ case v: cask.Response.Raw =>
val (newData, newHeaders) = if (acceptEncodings.exists(_.toLowerCase == "gzip")) {
new Response.Data {
def write(out: OutputStream): Unit = {
@@ -37,6 +38,6 @@ class compress extends cask.RawDecorator{
v.cookies
)
}
-
+ finalResult
}
}
diff --git a/cask/src/cask/router/Result.scala b/cask/src/cask/router/Result.scala
index e38ee28..3c2f957 100644
--- a/cask/src/cask/router/Result.scala
+++ b/cask/src/cask/router/Result.scala
@@ -9,7 +9,7 @@ package cask.router
*/
sealed trait Result[+T]{
def map[V](f: T => V): Result[V]
- def transform[V](f: PartialFunction[T, V]): Result[V]
+ def transform[V](f: PartialFunction[Any, V]): Result[V]
}
object Result{
@@ -19,7 +19,7 @@ object Result{
*/
case class Success[T](value: T) extends Result[T]{
def map[V](f: T => V) = Success(f(value))
- def transform[V](f: PartialFunction[T, V]) = f.lift(value) match {
+ def transform[V](f: PartialFunction[Any, V]) = f.lift(value) match {
case None => Success(value).asInstanceOf[Result[V]]
case Some(res) => Success(res)
}
@@ -30,7 +30,7 @@ object Result{
*/
sealed trait Error extends Result[Nothing]{
def map[V](f: Nothing => V) = this
- def transform[V](f: PartialFunction[Nothing, V]) = this
+ def transform[V](f: PartialFunction[Any, V]) = this
}
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 aa878c6..8cf80ec 100644
--- a/docs/pages/1 - Cask: a Scala HTTP micro-framework.md
+++ b/docs/pages/1 - Cask: a Scala HTTP micro-framework.md
@@ -378,6 +378,12 @@ interface. While Cask does not model streams, backpressure, iteratees, or
provide any higher level API, it should not be difficult to take the Cask API
and build whatever higher-level abstractions you prefer to use.
+If you are separating your `cask.Routes` from your `cask.Main`, you need to
+inject in a `cask.Logger` to handle errors reported when handling websocket
+requests:
+
+$$$websockets3
+
## TodoMVC Api Server
diff --git a/example/websockets4/app/src/Websockets4.scala b/example/websockets4/app/src/Websockets4.scala
new file mode 100644
index 0000000..f275746
--- /dev/null
+++ b/example/websockets4/app/src/Websockets4.scala
@@ -0,0 +1,22 @@
+package app
+
+case class Websockets4()(implicit val log: cask.Logger) extends cask.Routes{
+ @cask.decorators.compress // make sure compress decorator passes non-requests through correctly
+ @cask.websocket("/connect/:userName")
+ def showUserProfile(userName: String): cask.WebsocketResult = {
+ if (userName != "haoyi") cask.Response("", statusCode = 403)
+ else cask.WsHandler { channel =>
+ cask.WsActor {
+ case cask.Ws.Text("") => channel.send(cask.Ws.Close())
+ case cask.Ws.Text(data) =>
+ channel.send(cask.Ws.Text(userName + " " + data))
+ }
+ }
+ }
+
+ initialize()
+}
+
+object Websockets4Main extends cask.Main{
+ val allRoutes = Seq(Websockets4())
+}
diff --git a/example/websockets4/app/test/src/ExampleTests.scala b/example/websockets4/app/test/src/ExampleTests.scala
new file mode 100644
index 0000000..cd33bb4
--- /dev/null
+++ b/example/websockets4/app/test/src/ExampleTests.scala
@@ -0,0 +1,51 @@
+package app
+
+import java.util.concurrent.atomic.AtomicInteger
+
+import org.asynchttpclient.ws.{WebSocket, WebSocketListener, WebSocketUpgradeHandler}
+import utest._
+import concurrent.ExecutionContext.Implicits.global
+import cask.Logger.Console.globalLogger
+object ExampleTests extends TestSuite{
+
+
+ def withServer[T](example: cask.main.Main)(f: String => T): T = {
+ val server = io.undertow.Undertow.builder
+ .addHttpListener(8080, "localhost")
+ .setHandler(example.defaultHandler)
+ .build
+ server.start()
+ val res =
+ try f("http://localhost:8080")
+ finally server.stop()
+ res
+ }
+
+ val tests = Tests{
+ test("Websockets") - withServer(Websockets4Main){ host =>
+ @volatile var out = List.empty[String]
+ // 4. open websocket
+ val ws = cask.WsClient.connect("ws://localhost:8080/connect/haoyi"){
+ case cask.Ws.Text(s) => out = s :: out
+ }
+
+ try {
+ // 5. send messages
+ ws.send(cask.Ws.Text("hello"))
+ ws.send(cask.Ws.Text("world"))
+ ws.send(cask.Ws.Text(""))
+ Thread.sleep(100)
+ out ==> List("haoyi world", "haoyi hello")
+
+ var error: String = ""
+ val ws2 = cask.WsClient.connect("ws://localhost:8080/connect/nobody") {
+ case cask.Ws.Text(s) => out = s :: out
+ case cask.Ws.Error(t) => error += t.toString
+ case cask.Ws.Close(code, reason) => error += reason
+ }
+
+ assert(error.contains("403"))
+ }finally ws.close()
+ }
+ }
+}
diff --git a/example/websockets4/build.sc b/example/websockets4/build.sc
new file mode 100644
index 0000000..197e285
--- /dev/null
+++ b/example/websockets4/build.sc
@@ -0,0 +1,17 @@
+import mill._, scalalib._
+
+
+trait AppModule extends ScalaModule{
+ def scalaVersion = "2.13.0"
+ def ivyDeps = Agg[Dep](
+ )
+ object test extends Tests{
+ def testFrameworks = Seq("utest.runner.Framework")
+
+ def ivyDeps = Agg(
+ ivy"com.lihaoyi::utest::0.7.1",
+ ivy"com.lihaoyi::requests::0.2.0",
+ ivy"org.asynchttpclient:async-http-client:2.5.2"
+ )
+ }
+} \ No newline at end of file