Permalink
Browse files

[reactivemongo] Write response & handler specs

  • Loading branch information...
cchantep
cchantep committed Sep 15, 2014
1 parent 357c676 commit 66cc12f36f0127598f72c2c9c2cc59d01d1ba9d2
View
@@ -19,8 +19,10 @@ import reactivemongo.api.MongoDriver
import acolyte.reactivemongo.AcolyteDSL.{ driver, handleStatement }
val mongoDriver: MongoDriver = driver {
- handleStatement
+ ??? // dispatch query and write request as you want using pattern matching
}
+
+val noOpDriver = driver { handleStatement/* ConnectionHandler.empty */}
```
### Request patterns
@@ -159,10 +161,12 @@ import acolyte.reactivemongo.WriteResponse
val error1: Option[Try[Response]] = WriteResponse.failed("Error #1")
val error2 = WriteResponse("Error #1") // equivalent
-val error3 = WriteResponse("Error #2" -> Some(1)/* code */)
+val error3 = WriteResponse.failed("Error #2", 1/* code */)
+val error4 = WriteResponse("Error #2" -> 1/* code */) // equivalent
val success1 = WriteResponse(true/* updatedExisting */)
val success2 = WriteResponse.successful(true) // equivalent
+val success3 = WriteResponse() // = WriteResponse.successful(false)
```
When a handler supports some write cases, but not other, it can return an undefined response, to let the chance other handlers would manage it.
@@ -25,5 +25,5 @@ object AcolyteDSL {
* connection { handleStatement }
* }}}
*/
- def handleStatement: ConnectionHandler = ???
+ def handleStatement: ConnectionHandler = ConnectionHandler.empty
}
@@ -50,9 +50,6 @@ private[reactivemongo] class Actor(
val req = Request(op.fullCollectionName, doc.merged)
val exp = new ExpectingResponse(msg)
val cid = r()._1.channelIdHint getOrElse 1
-
- println(s"chan = $cid, ${req.body.elements.toList}")
-
val resp = MongoDB.WriteOp(op).fold({
MongoDB.WriteError(cid, s"No write operator: $msg") match {
case Success(err) err
@@ -70,32 +67,6 @@ private[reactivemongo] class Actor(
})
}
- /*
- val xxp = scala.concurrent.Promise[Response]() completeWith {
- exp.promise.future.transform({ resp ⇒
- println(s"Suc: $resp ${resp.getClass}")
- println(s"--> ${resp.reply.flags}") // 8
- resp
- }, { err ⇒
- err.printStackTrace()
- err
- //new RuntimeException("Yipee")
- })
-
- Future.successful[Response](MongoDB.Success(chan, List(
- reactivemongo.bson.BSONDocument("ok" -> 0, "err" -> "Err_1",
- "code" -> 7, "errmsg" -> "Err_Msg", "n" -> 0,
- "updatedExisting" -> false)
- )).get)
- }
- */
-
- // Success:
- //exp.promise.success(MongoDB.WriteSuccess(chan).get)
-
- // Error:
- //exp.promise.success(MongoDB.WriteError(chan, "Err_1").get)
- //exp.promise.success(NoWriteResponse(chanId, msg.toString))
exp.promise.success(resp)
case msg @ RequestMakerExpectingResponse(RequestMaker(
@@ -16,9 +16,16 @@ object WriteResponse {
* Named factory for error response.
*
* @param message Error message
- * @param code Optional error code
*/
- def failed(message: String, code: Option[Int] = None) = apply(message -> code)
+ def failed(message: String) = apply(message)
+
+ /**
+ * Named factory for error response.
+ *
+ * @param message Error message
+ * @param code Error code
+ */
+ def failed(message: String, code: Int) = apply(message -> code)
/**
* Factory for successful response.
@@ -30,19 +30,45 @@ object WriteResponseMaker {
override def apply(channelId: Int, updatedExisting: Boolean): Option[Try[Response]] = Some(MongoDB.WriteSuccess(channelId, updatedExisting))
}
+ /**
+ * {{{
+ * import acolyte.reactivemongo.WriteResponseMaker
+ *
+ * val maker = implicitly[WriteResponseMaker[Unit]]
+ * }}}
+ */
+ implicit def UnitWriteResponseMaker = new WriteResponseMaker[Unit] {
+ override def apply(channelId: Int, effect: Unit): Option[Try[Response]] = Some(MongoDB.WriteSuccess(channelId, false))
+ }
+
/**
* Provides response maker for an error.
*
* {{{
* import acolyte.reactivemongo.WriteResponseMaker
*
- * val maker = implicitly[WriteResponseMaker[(String, Option[Int])]]
+ * val maker = implicitly[WriteResponseMaker[String]]
* }}}
*/
- implicit def ErrorWriteResponseMaker = new WriteResponseMaker[(String, Option[Int])] {
- override def apply(channelId: Int, error: (String, Option[Int])): Option[Try[Response]] = Some(MongoDB.WriteError(channelId, error._1, error._2))
+ implicit def ErrorWriteResponseMaker = new WriteResponseMaker[String] {
+ override def apply(channelId: Int, error: String): Option[Try[Response]] =
+ Some(MongoDB.WriteError(channelId, error, None))
}
+ /**
+ * Provides response maker for an error.
+ *
+ * {{{
+ * import acolyte.reactivemongo.WriteResponseMaker
+ *
+ * val maker = implicitly[WriteResponseMaker[(String, Int)]]
+ * }}}
+ */
+ implicit def ErrorCodeWriteResponseMaker =
+ new WriteResponseMaker[(String, Int)] {
+ override def apply(channelId: Int, error: (String, Int)): Option[Try[Response]] = Some(MongoDB.WriteError(channelId, error._1, Some(error._2)))
+ }
+
/**
* Provides response maker for handler not supporting
* specific write operation.
@@ -1,15 +1,18 @@
package acolyte.reactivemongo
-object ConnectionHandlerSpec
- extends org.specs2.mutable.Specification with QueryHandlerFixtures {
+object ConnectionHandlerSpec extends org.specs2.mutable.Specification
+ with QueryHandlerFixtures with WriteHandlerFixtures {
"Connection handler" title
"Empty handler" should {
"not respond to any query" in {
ConnectionHandler.empty aka "connection handler" must beLike {
- case h h.queryHandler(1, query1) must beNone
+ case h
+ h.queryHandler(1, query1) aka "query result" must beNone and (
+ h.writeHandler(2, write1._1, write1._2).
+ aka("write result") must beNone)
}
- }
+ }
}
}
@@ -13,7 +13,7 @@ object QueryHandlerSpec extends org.specs2.mutable.Specification
_: Request QueryResponse(Seq(BSONDocument("prop" -> "A")))
}) aka "query handler" must beLike {
case h h(1, query1) must beSome.which(
- _ aka "response" must beSuccessResponse {
+ _ aka "response" must beResponse {
case ValueDocument(("prop", BSONString("A")) :: Nil) :: Nil ok
})
}
@@ -24,7 +24,7 @@ object QueryHandlerSpec extends org.specs2.mutable.Specification
_: Request QueryResponse.successful(BSONDocument("prop" -> "A"))
}) aka "query handler" must beLike {
case h h(1, query1) must beSome.which(
- _ aka "response" must beSuccessResponse {
+ _ aka "response" must beResponse {
case ValueDocument(("prop", BSONString("A")) :: Nil) :: Nil ok
})
}
@@ -34,7 +34,7 @@ object QueryHandlerSpec extends org.specs2.mutable.Specification
implicitly[QueryHandler]({ _: Request
QueryResponse("Error message") }) aka "query handler" must beLike {
case h h(1, query1) must beSome.which(
- _ aka "response" must beErrorResponse("Error message"))
+ _ aka "response" must beQueryError("Error message"))
}
}
@@ -77,14 +77,14 @@ object QueryHandlerSpec extends org.specs2.mutable.Specification
"return an error response" in {
handler aka "mixed handler" must beLike {
case h h(2, query2) aka "prepared" must beSome.which(
- _ aka "query response" must beErrorResponse("Error #2"))
+ _ aka "query response" must beQueryError("Error #2"))
}
}
"return an success response with many documents" in {
handler aka "mixed handler" must beLike {
case h h(3, query3) aka "prepared" must beSome.which(
- _ aka "query response" must beSuccessResponse {
+ _ aka "query response" must beResponse {
case ValueDocument(("prop", BSONString("A")) :: Nil) ::
ValueDocument(("a", BSONInteger(1)) :: Nil) :: Nil ok
})
@@ -12,14 +12,14 @@ object QueryResponseSpec
"using generic factory" in {
QueryResponse("error message #1") aka "prepared" must beLike {
case prepared prepared(1) aka "applied" must beSome.which(
- _ aka "query response" must beErrorResponse("error message #1"))
+ _ aka "query response" must beQueryError("error message #1"))
}
}
"using named factory" in {
QueryResponse.failed("error message #2") aka "prepared" must beLike {
case prepared prepared(2) aka "applied" must beSome.which(
- _ aka "query response" must beErrorResponse("error message #2"))
+ _ aka "query response" must beQueryError("error message #2"))
}
}
}
@@ -30,7 +30,7 @@ object QueryResponseSpec
"with a single document using named factory" in {
QueryResponse.successful(Doc1) aka "prepared" must beLike {
case prepared prepared(3) aka "applied" must beSome.which(
- _ aka "query response" must beSuccessResponse {
+ _ aka "query response" must beResponse {
case ValueDocument(("a", BSONString("b")) :: Nil) :: Nil ok
})
}
@@ -40,7 +40,7 @@ object QueryResponseSpec
QueryResponse(Seq(Doc1, BSONDocument("b" -> 2))).
aka("prepared") must beLike {
case prepared prepared(3) aka "applied" must beSome.which(
- _ aka "response" must beSuccessResponse {
+ _ aka "response" must beResponse {
case Doc1 :: ValueDocument(
("b", BSONInteger(2)) :: Nil) :: Nil ok
})
@@ -51,7 +51,7 @@ object QueryResponseSpec
QueryResponse.successful(Doc1, BSONDocument("b" -> 3)).
aka("prepared") must beLike {
case prepared prepared(3) aka "applied" must beSome.which(
- _ aka "response" must beSuccessResponse {
+ _ aka "response" must beResponse {
case Doc1 :: ValueDocument(
("b", BSONInteger(3)) :: Nil) :: Nil ok
})
@@ -35,7 +35,7 @@ object ResponseMakerSpec
}
"Write response maker" should {
- "be working for boolean (updatedExisting)" in {
+ "be a successful one for boolean (updatedExisting)" in {
val makr = implicitly[WriteResponseMaker[Boolean]]
makr(4, true) aka "response" must beSome.which { prepared
@@ -46,10 +46,21 @@ object ResponseMakerSpec
}
}
- "be working for an error (String, None)" in {
- val makr = implicitly[WriteResponseMaker[(String, Option[Int])]]
+ "be a successful one for Unit (updatedExisting = false)" in {
+ val makr = implicitly[WriteResponseMaker[Unit]]
- makr(5, "Custom error #1" -> None) aka "response" must beSome.
+ makr(4, ()) aka "response" must beSome.which { prepared
+ zip(prepared, MongoDB.WriteSuccess(4, false)).
+ aka("maker") must beSuccessfulTry.like {
+ case (a, b) a.documents aka "response" must_== b.documents
+ }
+ }
+ }
+
+ "be working for an error message (String)" in {
+ val makr = implicitly[WriteResponseMaker[String]]
+
+ makr(5, "Custom error #1") aka "response" must beSome.
which { prepared
zip(prepared, MongoDB.WriteError(5, "Custom error #1", None)).
aka("maker") must beSuccessfulTry.like {
@@ -58,10 +69,10 @@ object ResponseMakerSpec
}
}
- "be working for an error (String, Some(Int))" in {
- val makr = implicitly[WriteResponseMaker[(String, Option[Int])]]
+ "be working for an error with code (String, Int)" in {
+ val makr = implicitly[WriteResponseMaker[(String, Int)]]
- makr(5, "Custom error #2" -> Some(7)) aka "response" must beSome.
+ makr(5, "Custom error #2" -> 7) aka "response" must beSome.
which { prepared
zip(prepared, MongoDB.WriteError(5, "Custom error #2", Some(7))).
aka("maker") must beSuccessfulTry.like {
@@ -5,21 +5,11 @@ import scala.util.Try
import org.specs2.mutable.Specification
import org.specs2.matcher.{ Expectable, Matcher, MatchResult }
-import reactivemongo.bson.{ BSONDocument, BSONString }
+import reactivemongo.bson.{ BSONDocument, BSONInteger, BSONString }
import reactivemongo.core.protocol.Response
trait ResponseMatchers { specs: Specification
- def beErrorResponse(msg: String) = new Matcher[Try[Response]] {
- def apply[R <: Try[Response]](e: Expectable[R]) =
- e.value aka "prepared" must beSuccessfulTry.which {
- Response.parse(_).toList aka "response" must beLike {
- case ValueDocument(("$err", BSONString(m)) :: Nil) :: Nil
- m aka "error message" must_== msg
- }
- }
- }
-
- def beSuccessResponse(f: List[BSONDocument] MatchResult[_]) =
+ def beResponse(f: List[BSONDocument] MatchResult[_]) =
new Matcher[Try[Response]] {
def apply[R <: Try[Response]](e: Expectable[R]) = {
e.value aka "prepared" must beSuccessfulTry.which { resp
@@ -32,4 +22,28 @@ trait ResponseMatchers { specs: Specification ⇒
}
}
+ def beQueryError(msg: String) = new Matcher[Try[Response]] {
+ def apply[R <: Try[Response]](e: Expectable[R]) =
+ e.value aka "prepared" must beSuccessfulTry.which {
+ Response.parse(_).toList aka "response" must beLike {
+ case ValueDocument(("$err", BSONString(m)) :: Nil) :: Nil
+ m aka "error message" must_== msg
+ }
+ }
+ }
+
+ def beWriteError(msg: String, code: Option[Int] = None) =
+ new Matcher[Try[Response]] {
+ def apply[R <: Try[Response]](e: Expectable[R]) =
+ e.value aka "prepared" must beSuccessfulTry.which {
+ Response.parse(_).toList aka "response" must beLike {
+ case ValueDocument(("ok", BSONInteger(0)) ::
+ ("err", BSONString(err)) :: ("errmsg", BSONString(errmsg)) ::
+ ("code", BSONInteger(c)) :: Nil) :: Nil
+ err aka "error message (err)" must_== msg and (
+ errmsg aka "error message (errmsg)" must_== msg) and (
+ c aka "error code" must_== code.getOrElse(-1))
+ }
+ }
+ }
}
Oops, something went wrong.

0 comments on commit 66cc12f

Please sign in to comment.