Permalink
Browse files

[reactivemongo] Driver specification

  • Loading branch information...
cchantep
cchantep committed Sep 18, 2014
1 parent 23517d9 commit 11832214f443bb84a54d4397aee4a68818737da5
View
@@ -16,13 +16,13 @@ Then any connection created will be managed by your Acolyte (query & writer) han
```scala
import reactivemongo.api.MongoDriver
import acolyte.reactivemongo.AcolyteDSL.{ driver, handleStatement }
import acolyte.reactivemongo.AcolyteDSL.{ driver, handle }
val mongoDriver: MongoDriver = driver {
??? // dispatch query and write request as you want using pattern matching
}
val noOpDriver = driver { handleStatement/* ConnectionHandler.empty */}
val noOpDriver = driver { handle/* ConnectionHandler.empty */}
```
### Request patterns
@@ -25,5 +25,5 @@ object AcolyteDSL {
* connection { handleStatement }
* }}}
*/
def handleStatement: ConnectionHandler = ConnectionHandler.empty
def handle: ConnectionHandler = ConnectionHandler.empty
}
@@ -83,14 +83,12 @@ private[reactivemongo] class Actor(
}
})
exp.promise.success(resp)
resp.error.fold(exp.promise.success(resp))(exp.promise.failure(_))
case close @ Close /* Do nothing: next forward close */
case msg
/*
println(s"message = $msg")
next forward msg
*/
//println(s"message = $msg")
//next forward msg
()
}
@@ -0,0 +1,116 @@
package acolyte.reactivemongo
import scala.util.Try
import scala.concurrent.{ Await, Future }
import scala.concurrent.duration.Duration
import reactivemongo.api.{ MongoDriver, MongoConnection, DefaultDB }
import reactivemongo.api.collections.default.BSONCollection
import reactivemongo.bson.{
BSONBoolean,
BSONDocument,
BSONDouble,
BSONInteger,
BSONString
}
import reactivemongo.core.errors.DetailedDatabaseException
import reactivemongo.core.commands.LastError
object DriverSpec extends org.specs2.mutable.Specification
with QueryHandlerFixtures with WriteHandlerFixtures
with ConnectionHandlerFixtures with ResponseMatchers {
"Acolyte Mongo driver" title
"Acolyte driver" should {
"successfully create connection" in {
connect().acquireAndGet(identity).
aka("connection") must not(throwA[Throwable])
}
"successfully select database" in {
db("any-mockup-name").acquireAndGet(identity).
aka("database") must not(throwA[Throwable])
}
"successfully select DB collection" in {
collection("mock-collection").acquireAndGet(identity).
aka("collection") must not(throwA[Throwable])
}
"return expected query result" >> {
"when is successful #1" in withCol(query1.collection) { col
await(col.find(query1.body).cursor[BSONDocument].toList()).
aka("query result") must beSuccessfulTry[List[BSONDocument]].like {
case ValueDocument(("b", BSONInteger(3)) :: Nil) :: Nil ok
}
}
"when is successful #2" in withCol(query2.collection) { col
await(col.find(query2.body).cursor[BSONDocument].toList()).
aka("query result") must beSuccessfulTry[List[BSONDocument]].like {
case ValueDocument(("d", BSONDouble(4.56d)) :: Nil) ::
ValueDocument(("ef", BSONString("ghi")) :: Nil) :: Nil ok
}
}
"as error when query handler returns no query result" in withCol(
query3.collection) { col
await(col.find(query3.body).cursor[BSONDocument].toList()).
aka("query result") must beFailedTry.
withThrowable[DetailedDatabaseException](".*No response: .*")
}
"as error when connection handler is empty" in {
false must beTrue
}
}
"return expected write result" >> {
"when error is raised without code" in withCol(write1._2.collection) {
col
await(col.remove(write1._2.body)) aka "write result" must beFailedTry.
withThrowable[LastError](".*Error #2.*code = -1.*")
}
"when successful" in withCol(write2._2.collection) { col
await(col.insert(write2._2.body)).
aka("result") must beSuccessfulTry.like {
case lastError
lastError.elements.toList aka "body" must beLike {
case ("ok", BSONInteger(1)) ::
("updatedExisting", BSONBoolean(false)) ::
("n", BSONInteger(0)) :: Nil ok
} and (lastError.ok aka "ok" must beTrue) and (
lastError.n aka "updated" must_== 0) and (
lastError.inError aka "in-error" must beFalse) and (
lastError.err aka "err" must beNone) and (
lastError.errMsg aka "errmsg" must beNone)
}
}
"when no write result" in withCol(write3._2.collection) { col
await(col.update(BSONDocument("name" -> "x"), write3._2.body)).
aka("result") must beFailedTry.withThrowable[LastError](
".*No response: .*")
}
}
}
// ---
import resource.{ ManagedResource, managed }
val driver: ManagedResource[MongoDriver] =
managed(AcolyteDSL driver chandler1)
def connect(d: ManagedResource[MongoDriver] = driver): ManagedResource[MongoConnection] = driver.flatMap(d managed(d.connection(List("localhost"))))
def db(n: String, con: ManagedResource[MongoConnection] = connect()): ManagedResource[DefaultDB] = con.map(_(n))
def collection(n: String, d: ManagedResource[DefaultDB] = db("test-db")): ManagedResource[BSONCollection] = d.map(_(n))
def withCol[T](n: String, col: String ManagedResource[BSONCollection] = collection(_))(f: BSONCollection T): T = col(n).acquireAndGet(f)
def await[T](f: Future[T], tmout: Duration = Duration(5, "seconds")): Try[T] = Try[T](Await.result(f, tmout))
}
@@ -5,8 +5,15 @@ import scala.util.Try
import org.specs2.mutable.Specification
import org.specs2.matcher.{ Expectable, Matcher, MatchResult }
import reactivemongo.bson.{ BSONBoolean, BSONDocument, BSONInteger, BSONString }
import reactivemongo.bson.{
BSONBoolean,
BSONDocument,
BSONInteger,
BSONString,
BSONValue
}
import reactivemongo.core.protocol.Response
import reactivemongo.core.errors.DatabaseException
trait ResponseMatchers { specs: Specification
def beResponse(f: List[BSONDocument] MatchResult[_]) =
@@ -25,16 +32,17 @@ trait ResponseMatchers { specs: Specification ⇒
def beQueryError(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(("$err", BSONString(m)) :: others) :: Nil
m aka "error message" must_== msg and ((code, others).
aka("extra properties") must beLike {
case (None, _) ok
case (Some(a), ("code", BSONInteger(b)) :: Nil)
a aka "code" must_== b
})
}
e.value aka "prepared" must beSuccessfulTry.which { r
r.reply.inError aka "in-error" must beTrue and (
Response.parse(r).toList aka "response" must beLike {
case ValueDocument(("$err", BSONString(m)) :: others) :: Nil
m aka "error message" must_== msg and ((code, others).
aka("extra properties") must beLike {
case (None, _) ok
case (Some(a), ("code", BSONInteger(b)) :: Nil)
a aka "code" must_== b
})
})
}
}
@@ -55,4 +63,16 @@ trait ResponseMatchers { specs: Specification ⇒
}
}
}
def beWriteSuccess(count: Int, updatedExisting: Boolean) =
new Matcher[List[BSONDocument]] {
val C = count
val U = updatedExisting
def apply[L <: List[BSONDocument]](e: Expectable[L]) =
e.value aka "body" must beLike {
case ValueDocument(("ok", BSONInteger(1)) ::
("updatedExisting", BSONBoolean(U)) ::
("n", BSONInteger(C)) :: Nil) :: Nil ok
}
}
}
@@ -13,11 +13,8 @@ object WriteHandlerSpec extends org.specs2.mutable.Specification
(_: WriteOp, _: Request) WriteResponse(1 -> true)
}) aka "write handler" must beLike {
case h h(1, write1._1, write1._2) must beSome.which(
_ aka "response" must beResponse {
case ValueDocument(("ok", BSONInteger(k)) ::
("updatedExisting", BSONBoolean(up)) ::
("n", BSONInteger(1)) :: Nil) :: Nil
k aka "ok" must_== 1 and (up aka "updated existing" must beTrue)
_ aka "result" must beResponse {
_ aka "response" must beWriteSuccess(1, true)
})
}
}
@@ -27,11 +24,8 @@ object WriteHandlerSpec extends org.specs2.mutable.Specification
(_: WriteOp, _: Request) WriteResponse(0 -> false)
}) aka "write handler" must beLike {
case h h(1, write1._1, write1._2) must beSome.which(
_ aka "response" must beResponse {
case ValueDocument(("ok", BSONInteger(k)) ::
("updatedExisting", BSONBoolean(up)) ::
("n", BSONInteger(0)) :: Nil) :: Nil
k aka "ok" must_== 1 and (up aka "updated existing" must beFalse)
_ aka "result" must beResponse {
_ aka "response" must beWriteSuccess(0, false)
})
}
}
@@ -41,11 +35,8 @@ object WriteHandlerSpec extends org.specs2.mutable.Specification
(_: WriteOp, _: Request) WriteResponse()
}) aka "write handler" must beLike {
case h h(1, write1._1, write1._2) must beSome.which(
_ aka "response" must beResponse {
case ValueDocument(("ok", BSONInteger(k)) ::
("updatedExisting", BSONBoolean(up)) ::
("n", BSONInteger(0)) :: Nil) :: Nil
k aka "ok" must_== 1 and (up aka "updated existing" must beFalse)
_ aka "result" must beResponse {
_ aka "response" must beWriteSuccess(0, false)
})
}
}
@@ -46,43 +46,35 @@ object WriteResponseSpec
"with a boolean updatedExisting flag" in {
WriteResponse(1 -> true) aka "prepared" must beLike {
case prepared prepared(3) aka "applied" must beSome.which(
_ aka "write response" must beResponse {
case ValueDocument(("ok", BSONInteger(1)) ::
("updatedExisting", BSONBoolean(true)) ::
("n", BSONInteger(1)) :: Nil) :: Nil ok
_ aka "result" must beResponse {
_ aka "response" must beWriteSuccess(1, true)
})
}
}
"with a boolean updatedExisting flag using named factory" in {
WriteResponse.successful(0, false) aka "prepared" must beLike {
case prepared prepared(3) aka "applied" must beSome.which(
_ aka "write response" must beResponse {
case ValueDocument(("ok", BSONInteger(1)) ::
("updatedExisting", BSONBoolean(false)) ::
("n", BSONInteger(0)) :: Nil) :: Nil ok
_ aka "result" must beResponse {
_ aka "response" must beWriteSuccess(0, false)
})
}
}
"with a unit (effect)" in {
WriteResponse() aka "prepared" must beLike {
case prepared prepared(4) aka "applied" must beSome.which(
_ aka "write response" must beResponse {
case ValueDocument(("ok", BSONInteger(1)) ::
("updatedExisting", BSONBoolean(false)) ::
("n", BSONInteger(0)) :: Nil) :: Nil ok
_ aka "result" must beResponse {
_ aka "response" must beWriteSuccess(0, false)
})
}
}
"with a unit (effect) using named factory" in {
WriteResponse.successful() aka "prepared" must beLike {
case prepared prepared(4) aka "applied" must beSome.which(
_ aka "write response" must beResponse {
case ValueDocument(("ok", BSONInteger(1)) ::
("updatedExisting", BSONBoolean(false)) ::
("n", BSONInteger(0)) :: Nil) :: Nil ok
_ aka "result" must beResponse {
_ aka "response" must beWriteSuccess(0, false)
})
}
}

0 comments on commit 1183221

Please sign in to comment.