diff --git a/akka-persistence/akka-persistence-mongo/src/main/scala/MongoStorage.scala b/akka-persistence/akka-persistence-mongo/src/main/scala/MongoStorage.scala
index 98776253a5..79cacfeb07 100644
--- a/akka-persistence/akka-persistence-mongo/src/main/scala/MongoStorage.scala
+++ b/akka-persistence/akka-persistence-mongo/src/main/scala/MongoStorage.scala
@@ -9,7 +9,7 @@ import se.scalablesolutions.akka.persistence.common._
import se.scalablesolutions.akka.util.UUID
object MongoStorage extends Storage {
- type ElementType = AnyRef
+ type ElementType = Array[Byte]
def newMap: PersistentMap[ElementType, ElementType] = newMap(UUID.newUuid.toString)
def newVector: PersistentVector[ElementType] = newVector(UUID.newUuid.toString)
@@ -29,7 +29,7 @@ object MongoStorage extends Storage {
*
* @author Debasish Ghosh
*/
-class MongoPersistentMap(id: String) extends PersistentMap[AnyRef, AnyRef] {
+class MongoPersistentMap(id: String) extends PersistentMap[Array[Byte], Array[Byte]] {
val uuid = id
val storage = MongoStorageBackend
}
@@ -40,12 +40,12 @@ class MongoPersistentMap(id: String) extends PersistentMap[AnyRef, AnyRef] {
*
* @author Debaissh Ghosh
*/
-class MongoPersistentVector(id: String) extends PersistentVector[AnyRef] {
+class MongoPersistentVector(id: String) extends PersistentVector[Array[Byte]] {
val uuid = id
val storage = MongoStorageBackend
}
-class MongoPersistentRef(id: String) extends PersistentRef[AnyRef] {
+class MongoPersistentRef(id: String) extends PersistentRef[Array[Byte]] {
val uuid = id
val storage = MongoStorageBackend
}
diff --git a/akka-persistence/akka-persistence-mongo/src/main/scala/MongoStorageBackend.scala b/akka-persistence/akka-persistence-mongo/src/main/scala/MongoStorageBackend.scala
index 950165567d..847c226630 100644
--- a/akka-persistence/akka-persistence-mongo/src/main/scala/MongoStorageBackend.scala
+++ b/akka-persistence/akka-persistence-mongo/src/main/scala/MongoStorageBackend.scala
@@ -9,13 +9,8 @@ import se.scalablesolutions.akka.persistence.common._
import se.scalablesolutions.akka.util.Logging
import se.scalablesolutions.akka.config.Config.config
-import sjson.json.Serializer._
-
import java.util.NoSuchElementException
-
-import com.mongodb._
-
-import java.util.{Map=>JMap, List=>JList, ArrayList=>JArrayList}
+import com.novus.casbah.mongodb.Imports._
/**
* A module for supporting MongoDB based persistence.
@@ -28,294 +23,189 @@ import java.util.{Map=>JMap, List=>JList, ArrayList=>JArrayList}
* @author Debasish Ghosh
*/
private[akka] object MongoStorageBackend extends
- MapStorageBackend[AnyRef, AnyRef] with
- VectorStorageBackend[AnyRef] with
- RefStorageBackend[AnyRef] with
+ MapStorageBackend[Array[Byte], Array[Byte]] with
+ VectorStorageBackend[Array[Byte]] with
+ RefStorageBackend[Array[Byte]] with
Logging {
- // enrich with null safe findOne
- class RichDBCollection(value: DBCollection) {
- def findOneNS(o: DBObject): Option[DBObject] = {
- value.findOne(o) match {
- case null => None
- case x => Some(x)
- }
- }
- }
-
- implicit def enrichDBCollection(c: DBCollection) = new RichDBCollection(c)
-
- val KEY = "key"
- val VALUE = "value"
+ val KEY = "__key"
+ val REF = "__ref"
val COLLECTION = "akka_coll"
- val MONGODB_SERVER_HOSTNAME = config.getString("akka.storage.mongodb.hostname", "127.0.0.1")
- val MONGODB_SERVER_DBNAME = config.getString("akka.storage.mongodb.dbname", "testdb")
- val MONGODB_SERVER_PORT = config.getInt("akka.storage.mongodb.port", 27017)
+ val HOSTNAME = config.getString("akka.storage.mongodb.hostname", "127.0.0.1")
+ val DBNAME = config.getString("akka.storage.mongodb.dbname", "testdb")
+ val PORT = config.getInt("akka.storage.mongodb.port", 27017)
- val db = new Mongo(MONGODB_SERVER_HOSTNAME, MONGODB_SERVER_PORT)
- val coll = db.getDB(MONGODB_SERVER_DBNAME).getCollection(COLLECTION)
+ val db: MongoDB = MongoConnection(HOSTNAME, PORT)(DBNAME)
+ val coll: MongoCollection = db(COLLECTION)
- private[this] val serializer = SJSON
+ def drop() { db.dropDatabase() }
- def insertMapStorageEntryFor(name: String, key: AnyRef, value: AnyRef) {
+ def insertMapStorageEntryFor(name: String, key: Array[Byte], value: Array[Byte]) {
insertMapStorageEntriesFor(name, List((key, value)))
}
- def insertMapStorageEntriesFor(name: String, entries: List[Tuple2[AnyRef, AnyRef]]) {
- import java.util.{Map, HashMap}
-
- val m: Map[AnyRef, AnyRef] = new HashMap
- for ((k, v) <- entries) {
- m.put(k, serializer.out(v))
- }
-
- nullSafeFindOne(name) match {
- case None =>
- coll.insert(new BasicDBObject().append(KEY, name).append(VALUE, m))
- case Some(dbo) => {
- // collate the maps
- val o = dbo.get(VALUE).asInstanceOf[Map[AnyRef, AnyRef]]
- o.putAll(m)
-
- val newdbo = new BasicDBObject().append(KEY, name).append(VALUE, o)
- coll.update(new BasicDBObject().append(KEY, name), newdbo, true, false)
- }
+ def insertMapStorageEntriesFor(name: String, entries: List[(Array[Byte], Array[Byte])]) {
+ val q: DBObject = MongoDBObject(KEY -> name)
+ coll.findOne(q) match {
+ case Some(dbo) =>
+ entries.foreach { case (k, v) => dbo += new String(k) -> v }
+ coll.update(q, dbo, true, false)
+ case None =>
+ val builder = MongoDBObject.newBuilder
+ builder += KEY -> name
+ entries.foreach { case (k, v) => builder += new String(k) -> v }
+ coll += builder.result.asDBObject
}
}
def removeMapStorageFor(name: String): Unit = {
- val q = new BasicDBObject
- q.put(KEY, name)
+ val q: DBObject = MongoDBObject(KEY -> name)
coll.remove(q)
}
- def removeMapStorageFor(name: String, key: AnyRef): Unit = {
- nullSafeFindOne(name) match {
- case None =>
- case Some(dbo) => {
- val orig = dbo.get(VALUE).asInstanceOf[DBObject].toMap
- if (key.isInstanceOf[List[_]]) {
- val keys = key.asInstanceOf[List[_]]
- keys.foreach(k => orig.remove(k.asInstanceOf[String]))
- } else {
- orig.remove(key.asInstanceOf[String])
- }
-
- // remove existing reference
- removeMapStorageFor(name)
- // and insert
- coll.insert(new BasicDBObject().append(KEY, name).append(VALUE, orig))
- }
- }
+ private def queryFor[T](name: String)(body: (MongoDBObject, MongoDBObject) => T): T = {
+ val q: DBObject = MongoDBObject(KEY -> name)
+ val dbo = coll.findOne(q).getOrElse { throw new NoSuchElementException(name + " not present") }
+ body(q, dbo)
}
- def getMapStorageEntryFor(name: String, key: AnyRef): Option[AnyRef] =
- getValueForKey(name, key.asInstanceOf[String])
-
- def getMapStorageSizeFor(name: String): Int = {
- nullSafeFindOne(name) match {
- case None => 0
- case Some(dbo) =>
- dbo.get(VALUE).asInstanceOf[JMap[String, AnyRef]].keySet.size
- }
+ def removeMapStorageFor(name: String, key: Array[Byte]): Unit = queryFor(name) { (q, dbo) =>
+ dbo -= new String(key)
+ coll.update(q, dbo, true, false)
}
- def getMapStorageFor(name: String): List[Tuple2[AnyRef, AnyRef]] = {
- val m =
- nullSafeFindOne(name) match {
- case None =>
- throw new NoSuchElementException(name + " not present")
- case Some(dbo) =>
- dbo.get(VALUE).asInstanceOf[JMap[String, AnyRef]]
- }
- val n =
- List(m.keySet.toArray: _*).asInstanceOf[List[String]]
- val vals =
- for(s <- n)
- yield (s, serializer.in[AnyRef](m.get(s).asInstanceOf[Array[Byte]]))
- vals.asInstanceOf[List[Tuple2[String, AnyRef]]]
+ def getMapStorageEntryFor(name: String, key: Array[Byte]): Option[Array[Byte]] = queryFor(name) { (q, dbo) =>
+ dbo.get(new String(key)).asInstanceOf[Option[Array[Byte]]]
}
- def getMapStorageRangeFor(name: String, start: Option[AnyRef],
- finish: Option[AnyRef],
- count: Int): List[Tuple2[AnyRef, AnyRef]] = {
- val m =
- nullSafeFindOne(name) match {
- case None =>
- throw new NoSuchElementException(name + " not present")
- case Some(dbo) =>
- dbo.get(VALUE).asInstanceOf[JMap[String, AnyRef]]
- }
-
- /**
- * count is the max number of results to return. Start with
- * start or 0 (if start is not defined) and go until
- * you hit finish or count.
- */
- val s = if (start.isDefined) start.get.asInstanceOf[Int] else 0
- val cnt =
- if (finish.isDefined) {
- val f = finish.get.asInstanceOf[Int]
- if (f >= s) math.min(count, (f - s)) else count
- }
- else count
-
- val n =
- List(m.keySet.toArray: _*).asInstanceOf[List[String]].sortWith((e1, e2) => (e1 compareTo e2) < 0).slice(s, s + cnt)
- val vals =
- for(s <- n)
- yield (s, serializer.in[AnyRef](m.get(s).asInstanceOf[Array[Byte]]))
- vals.asInstanceOf[List[Tuple2[String, AnyRef]]]
+ def getMapStorageSizeFor(name: String): Int = queryFor(name) { (q, dbo) =>
+ dbo.size - 2 // need to exclude object id and our KEY
}
- private def getValueForKey(name: String, key: String): Option[AnyRef] = {
- try {
- nullSafeFindOne(name) match {
- case None => None
- case Some(dbo) =>
- Some(serializer.in[AnyRef](
- dbo.get(VALUE)
- .asInstanceOf[JMap[String, AnyRef]]
- .get(key).asInstanceOf[Array[Byte]]))
- }
- } catch {
- case e =>
- throw new NoSuchElementException(e.getMessage)
- }
+ def getMapStorageFor(name: String): List[(Array[Byte], Array[Byte])] = queryFor(name) { (q, dbo) =>
+ for {
+ (k, v) <- dbo.toList
+ if k != "_id" && k != KEY
+ } yield (k.getBytes, v.asInstanceOf[Array[Byte]])
}
- def insertVectorStorageEntriesFor(name: String, elements: List[AnyRef]) = {
- val q = new BasicDBObject
- q.put(KEY, name)
+ def getMapStorageRangeFor(name: String, start: Option[Array[Byte]],
+ finish: Option[Array[Byte]],
+ count: Int): List[(Array[Byte], Array[Byte])] = queryFor(name) { (q, dbo) =>
+ // get all keys except the special ones
+ val keys =
+ dbo.keySet
+ .toList
+ .filter(k => k != "_id" && k != KEY)
+ .sortWith(_ < _)
- val currentList =
- coll.findOneNS(q) match {
- case None =>
- new JArrayList[AnyRef]
- case Some(dbo) =>
- dbo.get(VALUE).asInstanceOf[JArrayList[AnyRef]]
- }
- if (!currentList.isEmpty) {
- // record exists
- // remove before adding
- coll.remove(q)
- }
+ // if the supplied start is not defined, get the head of keys
+ val s = start.map(new String(_)).getOrElse(keys.head)
- // add to the current list
- elements.map(serializer.out(_)).foreach(currentList.add(_))
+ // if the supplied finish is not defined, get the last element of keys
+ val f = finish.map(new String(_)).getOrElse(keys.last)
- coll.insert(
- new BasicDBObject()
- .append(KEY, name)
- .append(VALUE, currentList)
- )
+ // slice from keys: both ends inclusive
+ val ks = keys.slice(keys.indexOf(s), scala.math.min(count, keys.indexOf(f) + 1))
+ ks.map(k => (k.getBytes, dbo.get(k).get.asInstanceOf[Array[Byte]]))
}
- def insertVectorStorageEntryFor(name: String, element: AnyRef) = {
+ def insertVectorStorageEntryFor(name: String, element: Array[Byte]) = {
insertVectorStorageEntriesFor(name, List(element))
}
- def getVectorStorageEntryFor(name: String, index: Int): AnyRef = {
- try {
- val o =
- nullSafeFindOne(name) match {
- case None =>
- throw new NoSuchElementException(name + " not present")
+ def insertVectorStorageEntriesFor(name: String, elements: List[Array[Byte]]) = {
+ // lookup with name
+ val q: DBObject = MongoDBObject(KEY -> name)
- case Some(dbo) =>
- dbo.get(VALUE).asInstanceOf[JList[AnyRef]]
+ coll.findOne(q) match {
+ // exists : need to update
+ case Some(dbo) =>
+ dbo -= KEY
+ dbo -= "_id"
+ val listBuilder = MongoDBList.newBuilder
+
+ // expensive!
+ listBuilder ++= (elements ++ dbo.toSeq.sortWith((e1, e2) => (e1._1.toInt < e2._1.toInt)).map(_._2))
+
+ val builder = MongoDBObject.newBuilder
+ builder += KEY -> name
+ builder ++= listBuilder.result
+ coll.update(q, builder.result.asDBObject, true, false)
+
+ // new : just add
+ case None =>
+ val listBuilder = MongoDBList.newBuilder
+ listBuilder ++= elements
+
+ val builder = MongoDBObject.newBuilder
+ builder += KEY -> name
+ builder ++= listBuilder.result
+ coll += builder.result.asDBObject
+ }
+ }
+
+ def updateVectorStorageEntryFor(name: String, index: Int, elem: Array[Byte]) = queryFor(name) { (q, dbo) =>
+ dbo += ((index.toString, elem))
+ coll.update(q, dbo, true, false)
+ }
+
+ def getVectorStorageEntryFor(name: String, index: Int): Array[Byte] = queryFor(name) { (q, dbo) =>
+ dbo(index.toString).asInstanceOf[Array[Byte]]
+ }
+
+ /**
+ * if start and finish both are defined, ignore count and
+ * report the range [start, finish)
+ * if start is not defined, assume start = 0
+ * if start == 0 and finish == 0, return an empty collection
+ */
+ def getVectorStorageRangeFor(name: String, start: Option[Int], finish: Option[Int], count: Int): List[Array[Byte]] = queryFor(name) { (q, dbo) =>
+ val ls = dbo.filter { case (k, v) => k != KEY && k != "_id" }
+ .toSeq
+ .sortWith((e1, e2) => (e1._1.toInt < e2._1.toInt))
+ .map(_._2)
+
+ val st = start.getOrElse(0)
+ val cnt =
+ if (finish.isDefined) {
+ val f = finish.get
+ if (f >= st) (f - st) else count
}
- serializer.in[AnyRef](
- o.get(index).asInstanceOf[Array[Byte]])
- } catch {
- case e =>
- throw new NoSuchElementException(e.getMessage)
+ else count
+ if (st == 0 && cnt == 0) List()
+ ls.slice(st, st + cnt).asInstanceOf[List[Array[Byte]]]
+ }
+
+ def getVectorStorageSizeFor(name: String): Int = queryFor(name) { (q, dbo) =>
+ dbo.size - 2
+ }
+
+ def insertRefStorageFor(name: String, element: Array[Byte]) = {
+ // lookup with name
+ val q: DBObject = MongoDBObject(KEY -> name)
+
+ coll.findOne(q) match {
+ // exists : need to update
+ case Some(dbo) =>
+ dbo += ((REF, element))
+ coll.update(q, dbo, true, false)
+
+ // not found : make one
+ case None =>
+ val builder = MongoDBObject.newBuilder
+ builder += KEY -> name
+ builder += REF -> element
+ coll += builder.result.asDBObject
}
}
- def getVectorStorageRangeFor(name: String,
- start: Option[Int], finish: Option[Int], count: Int): List[AnyRef] = {
- try {
- val o =
- nullSafeFindOne(name) match {
- case None =>
- throw new NoSuchElementException(name + " not present")
-
- case Some(dbo) =>
- dbo.get(VALUE).asInstanceOf[JList[AnyRef]]
- }
-
- val s = if (start.isDefined) start.get else 0
- val cnt =
- if (finish.isDefined) {
- val f = finish.get
- if (f >= s) (f - s) else count
- }
- else count
-
- // pick the subrange and make a Scala list
- val l =
- List(o.subList(s, s + cnt).toArray: _*)
-
- for(e <- l)
- yield serializer.in[AnyRef](e.asInstanceOf[Array[Byte]])
- } catch {
- case e =>
- throw new NoSuchElementException(e.getMessage)
- }
- }
-
- def updateVectorStorageEntryFor(name: String, index: Int, elem: AnyRef) = {
- val q = new BasicDBObject
- q.put(KEY, name)
-
- val dbobj =
- coll.findOneNS(q) match {
- case None =>
- throw new NoSuchElementException(name + " not present")
- case Some(dbo) => dbo
- }
- val currentList = dbobj.get(VALUE).asInstanceOf[JArrayList[AnyRef]]
- currentList.set(index, serializer.out(elem))
- coll.update(q,
- new BasicDBObject().append(KEY, name).append(VALUE, currentList))
- }
-
- def getVectorStorageSizeFor(name: String): Int = {
- nullSafeFindOne(name) match {
- case None => 0
- case Some(dbo) =>
- dbo.get(VALUE).asInstanceOf[JList[AnyRef]].size
- }
- }
-
- private def nullSafeFindOne(name: String): Option[DBObject] = {
- val o = new BasicDBObject
- o.put(KEY, name)
- coll.findOneNS(o)
- }
-
- def insertRefStorageFor(name: String, element: AnyRef) = {
- nullSafeFindOne(name) match {
- case None =>
- case Some(dbo) => {
- val q = new BasicDBObject
- q.put(KEY, name)
- coll.remove(q)
- }
- }
- coll.insert(
- new BasicDBObject()
- .append(KEY, name)
- .append(VALUE, serializer.out(element)))
- }
-
- def getRefStorageFor(name: String): Option[AnyRef] = {
- nullSafeFindOne(name) match {
- case None => None
- case Some(dbo) =>
- Some(serializer.in[AnyRef](dbo.get(VALUE).asInstanceOf[Array[Byte]]))
+ def getRefStorageFor(name: String): Option[Array[Byte]] = try {
+ queryFor(name) { (q, dbo) =>
+ dbo.get(REF).asInstanceOf[Option[Array[Byte]]]
}
+ } catch {
+ case e: java.util.NoSuchElementException => None
}
}
diff --git a/akka-persistence/akka-persistence-mongo/src/test/scala/MongoPersistentActorSpec.scala b/akka-persistence/akka-persistence-mongo/src/test/scala/MongoPersistentActorSpec.scala
index 1acc9ee97d..01f735b254 100644
--- a/akka-persistence/akka-persistence-mongo/src/test/scala/MongoPersistentActorSpec.scala
+++ b/akka-persistence/akka-persistence-mongo/src/test/scala/MongoPersistentActorSpec.scala
@@ -1,32 +1,19 @@
package se.scalablesolutions.akka.persistence.mongo
-import org.junit.{Test, Before}
-import org.junit.Assert._
-import org.scalatest.junit.JUnitSuite
-
-import _root_.dispatch.json.{JsNumber, JsValue}
-import _root_.dispatch.json.Js._
+import org.scalatest.Spec
+import org.scalatest.matchers.ShouldMatchers
+import org.scalatest.BeforeAndAfterEach
+import org.scalatest.junit.JUnitRunner
+import org.junit.runner.RunWith
import se.scalablesolutions.akka.actor.{Transactor, Actor, ActorRef}
import Actor._
-/**
- * A persistent actor based on MongoDB storage.
- *
- * Demonstrates a bank account operation consisting of messages that:
- * checks balance Balance
- * debits amountDebit
- * debits multiple amountsMultiDebit
- * credits amountCredit
- *
- * Needs a running Mongo server.
- * @author Debasish Ghosh
- */
case class Balance(accountNo: String)
-case class Debit(accountNo: String, amount: BigInt, failer: ActorRef)
-case class MultiDebit(accountNo: String, amounts: List[BigInt], failer: ActorRef)
-case class Credit(accountNo: String, amount: BigInt)
+case class Debit(accountNo: String, amount: Int, failer: ActorRef)
+case class MultiDebit(accountNo: String, amounts: List[Int], failer: ActorRef)
+case class Credit(accountNo: String, amount: Int)
case class Log(start: Int, finish: Int)
case object LogSize
@@ -35,63 +22,65 @@ class BankAccountActor extends Transactor {
private lazy val accountState = MongoStorage.newMap
private lazy val txnLog = MongoStorage.newVector
+ import sjson.json.DefaultProtocol._
+ import sjson.json.JsonSerialization._
+
def receive: Receive = {
// check balance
case Balance(accountNo) =>
- txnLog.add("Balance:" + accountNo)
- self.reply(accountState.get(accountNo).get)
+ txnLog.add(("Balance:" + accountNo).getBytes)
+ self.reply(
+ accountState.get(accountNo.getBytes)
+ .map(frombinary[Int](_))
+ .getOrElse(0))
// debit amount: can fail
case Debit(accountNo, amount, failer) =>
- txnLog.add("Debit:" + accountNo + " " + amount)
+ txnLog.add(("Debit:" + accountNo + " " + amount).getBytes)
+ val m = accountState.get(accountNo.getBytes)
+ .map(frombinary[Int](_))
+ .getOrElse(0)
+
+ accountState.put(accountNo.getBytes, tobinary(m - amount))
+ if (amount > m) failer !! "Failure"
- val m: BigInt =
- accountState.get(accountNo) match {
- case Some(JsNumber(n)) =>
- BigInt(n.asInstanceOf[BigDecimal].intValue)
- case None => 0
- }
- accountState.put(accountNo, (m - amount))
- if (amount > m)
- failer !! "Failure"
self.reply(m - amount)
// many debits: can fail
// demonstrates true rollback even if multiple puts have been done
case MultiDebit(accountNo, amounts, failer) =>
- txnLog.add("MultiDebit:" + accountNo + " " + amounts.map(_.intValue).foldLeft(0)(_ + _))
+ val sum = amounts.foldRight(0)(_ + _)
+ txnLog.add(("MultiDebit:" + accountNo + " " + sum).getBytes)
- val m: BigInt =
- accountState.get(accountNo) match {
- case Some(JsNumber(n)) => BigInt(n.toString)
- case None => 0
+ val m = accountState.get(accountNo.getBytes)
+ .map(frombinary[Int](_))
+ .getOrElse(0)
+
+ var cbal = m
+ amounts.foreach { amount =>
+ accountState.put(accountNo.getBytes, tobinary(m - amount))
+ cbal = cbal - amount
+ if (cbal < 0) failer !! "Failure"
}
- var bal: BigInt = 0
- amounts.foreach {amount =>
- bal = bal + amount
- accountState.put(accountNo, (m - bal))
- }
- if (bal > m) failer !! "Failure"
- self.reply(m - bal)
+
+ self.reply(m - sum)
// credit amount
case Credit(accountNo, amount) =>
- txnLog.add("Credit:" + accountNo + " " + amount)
+ txnLog.add(("Credit:" + accountNo + " " + amount).getBytes)
+ val m = accountState.get(accountNo.getBytes)
+ .map(frombinary[Int](_))
+ .getOrElse(0)
+
+ accountState.put(accountNo.getBytes, tobinary(m + amount))
- val m: BigInt =
- accountState.get(accountNo) match {
- case Some(JsNumber(n)) =>
- BigInt(n.asInstanceOf[BigDecimal].intValue)
- case None => 0
- }
- accountState.put(accountNo, (m + amount))
self.reply(m + amount)
case LogSize =>
- self.reply(txnLog.length.asInstanceOf[AnyRef])
+ self.reply(txnLog.length)
case Log(start, finish) =>
- self.reply(txnLog.slice(start, finish))
+ self.reply(txnLog.slice(start, finish).map(new String(_)))
}
}
@@ -102,82 +91,71 @@ class BankAccountActor extends Transactor {
}
}
-class MongoPersistentActorSpec extends JUnitSuite {
- @Test
- def testSuccessfulDebit = {
- val bactor = actorOf[BankAccountActor]
- bactor.start
- val failer = actorOf[PersistentFailerActor]
- failer.start
- bactor !! Credit("a-123", 5000)
- bactor !! Debit("a-123", 3000, failer)
+@RunWith(classOf[JUnitRunner])
+class MongoPersistentActorSpec extends
+ Spec with
+ ShouldMatchers with
+ BeforeAndAfterEach {
- val JsNumber(b) = (bactor !! Balance("a-123")).get.asInstanceOf[JsValue]
- assertEquals(BigInt(2000), BigInt(b.intValue))
-
- bactor !! Credit("a-123", 7000)
-
- val JsNumber(b1) = (bactor !! Balance("a-123")).get.asInstanceOf[JsValue]
- assertEquals(BigInt(9000), BigInt(b1.intValue))
-
- bactor !! Debit("a-123", 8000, failer)
-
- val JsNumber(b2) = (bactor !! Balance("a-123")).get.asInstanceOf[JsValue]
- assertEquals(BigInt(1000), BigInt(b2.intValue))
-
- assert(7 == (bactor !! LogSize).get.asInstanceOf[Int])
-
- import scala.collection.mutable.ArrayBuffer
- assert((bactor !! Log(0, 7)).get.asInstanceOf[ArrayBuffer[String]].size == 7)
- assert((bactor !! Log(0, 0)).get.asInstanceOf[ArrayBuffer[String]].size == 0)
- assert((bactor !! Log(1, 2)).get.asInstanceOf[ArrayBuffer[String]].size == 1)
- assert((bactor !! Log(6, 7)).get.asInstanceOf[ArrayBuffer[String]].size == 1)
- assert((bactor !! Log(0, 1)).get.asInstanceOf[ArrayBuffer[String]].size == 1)
+ override def beforeEach {
+ MongoStorageBackend.drop
}
- @Test
- def testUnsuccessfulDebit = {
- val bactor = actorOf[BankAccountActor]
- bactor.start
- bactor !! Credit("a-123", 5000)
-
- val JsNumber(b) = (bactor !! Balance("a-123")).get.asInstanceOf[JsValue]
- assertEquals(BigInt(5000), BigInt(b.intValue))
-
- val failer = actorOf[PersistentFailerActor]
- failer.start
- try {
- bactor !! Debit("a-123", 7000, failer)
- fail("should throw exception")
- } catch { case e: RuntimeException => {}}
-
- val JsNumber(b1) = (bactor !! Balance("a-123")).get.asInstanceOf[JsValue]
- assertEquals(BigInt(5000), BigInt(b1.intValue))
-
- // should not count the failed one
- assert(3 == (bactor !! LogSize).get.asInstanceOf[Int])
+ override def afterEach {
+ MongoStorageBackend.drop
}
- @Test
- def testUnsuccessfulMultiDebit = {
- val bactor = actorOf[BankAccountActor]
- bactor.start
- bactor !! Credit("a-123", 5000)
+ describe("successful debit") {
+ it("should debit successfully") {
+ val bactor = actorOf[BankAccountActor]
+ bactor.start
+ val failer = actorOf[PersistentFailerActor]
+ failer.start
+ bactor !! Credit("a-123", 5000)
+ bactor !! Debit("a-123", 3000, failer)
- val JsNumber(b) = (bactor !! Balance("a-123")).get.asInstanceOf[JsValue]
- assertEquals(BigInt(5000), BigInt(b.intValue))
+ (bactor !! Balance("a-123")).get.asInstanceOf[Int] should equal(2000)
- val failer = actorOf[PersistentFailerActor]
- failer.start
- try {
- bactor !! MultiDebit("a-123", List(500, 2000, 1000, 3000), failer)
- fail("should throw exception")
- } catch { case e: RuntimeException => {}}
+ bactor !! Credit("a-123", 7000)
+ (bactor !! Balance("a-123")).get.asInstanceOf[Int] should equal(9000)
- val JsNumber(b1) = (bactor !! Balance("a-123")).get.asInstanceOf[JsValue]
- assertEquals(BigInt(5000), BigInt(b1.intValue))
+ bactor !! Debit("a-123", 8000, failer)
+ (bactor !! Balance("a-123")).get.asInstanceOf[Int] should equal(1000)
- // should not count the failed one
- assert(3 == (bactor !! LogSize).get.asInstanceOf[Int])
+ (bactor !! LogSize).get.asInstanceOf[Int] should equal(7)
+ (bactor !! Log(0, 7)).get.asInstanceOf[Iterable[String]].size should equal(7)
+ }
+ }
+
+ describe("unsuccessful debit") {
+ it("debit should fail") {
+ val bactor = actorOf[BankAccountActor]
+ bactor.start
+ val failer = actorOf[PersistentFailerActor]
+ failer.start
+ bactor !! Credit("a-123", 5000)
+ (bactor !! Balance("a-123")).get.asInstanceOf[Int] should equal(5000)
+ evaluating {
+ bactor !! Debit("a-123", 7000, failer)
+ } should produce [Exception]
+ (bactor !! Balance("a-123")).get.asInstanceOf[Int] should equal(5000)
+ (bactor !! LogSize).get.asInstanceOf[Int] should equal(3)
+ }
+ }
+
+ describe("unsuccessful multidebit") {
+ it("multidebit should fail") {
+ val bactor = actorOf[BankAccountActor]
+ bactor.start
+ val failer = actorOf[PersistentFailerActor]
+ failer.start
+ bactor !! Credit("a-123", 5000)
+ (bactor !! Balance("a-123")).get.asInstanceOf[Int] should equal(5000)
+ evaluating {
+ bactor !! MultiDebit("a-123", List(1000, 2000, 4000), failer)
+ } should produce [Exception]
+ (bactor !! Balance("a-123")).get.asInstanceOf[Int] should equal(5000)
+ (bactor !! LogSize).get.asInstanceOf[Int] should equal(3)
+ }
}
}
diff --git a/akka-persistence/akka-persistence-mongo/src/test/scala/MongoStorageSpec.scala b/akka-persistence/akka-persistence-mongo/src/test/scala/MongoStorageSpec.scala
index e518b28d66..fb2034b6c1 100644
--- a/akka-persistence/akka-persistence-mongo/src/test/scala/MongoStorageSpec.scala
+++ b/akka-persistence/akka-persistence-mongo/src/test/scala/MongoStorageSpec.scala
@@ -1,364 +1,158 @@
package se.scalablesolutions.akka.persistence.mongo
-import org.junit.{Test, Before}
-import org.junit.Assert._
-import org.scalatest.junit.JUnitSuite
-import _root_.dispatch.json._
-import _root_.dispatch.json.Js._
+import org.scalatest.Spec
+import org.scalatest.matchers.ShouldMatchers
+import org.scalatest.BeforeAndAfterEach
+import org.scalatest.junit.JUnitRunner
+import org.junit.runner.RunWith
import java.util.NoSuchElementException
-@scala.reflect.BeanInfo case class Foo(no: Int, name: String)
-class MongoStorageSpec extends JUnitSuite {
+@RunWith(classOf[JUnitRunner])
+class MongoStorageSpec extends
+ Spec with
+ ShouldMatchers with
+ BeforeAndAfterEach {
- val changeSetV = new scala.collection.mutable.ArrayBuffer[AnyRef]
- val changeSetM = new scala.collection.mutable.HashMap[AnyRef, AnyRef]
-
- @Before def initialize() = {
- MongoStorageBackend.coll.drop
+ override def beforeEach {
+ MongoStorageBackend.drop
}
- @Test
- def testVectorInsertForTransactionId = {
- changeSetV += "debasish" // string
- changeSetV += List(1, 2, 3) // Scala List
- changeSetV += List(100, 200)
- MongoStorageBackend.insertVectorStorageEntriesFor("U-A1", changeSetV.toList)
- assertEquals(
- 3,
- MongoStorageBackend.getVectorStorageSizeFor("U-A1"))
- changeSetV.clear
-
- // changeSetV should be reinitialized
- changeSetV += List(12, 23, 45)
- changeSetV += "maulindu"
- MongoStorageBackend.insertVectorStorageEntriesFor("U-A1", changeSetV.toList)
- assertEquals(
- 5,
- MongoStorageBackend.getVectorStorageSizeFor("U-A1"))
-
- // add more to the same changeSetV
- changeSetV += "ramanendu"
- changeSetV += Map(1 -> "dg", 2 -> "mc")
-
- // add for a diff transaction
- MongoStorageBackend.insertVectorStorageEntriesFor("U-A2", changeSetV.toList)
- assertEquals(
- 4,
- MongoStorageBackend.getVectorStorageSizeFor("U-A2"))
-
- // previous transaction change set should remain same
- assertEquals(
- 5,
- MongoStorageBackend.getVectorStorageSizeFor("U-A1"))
-
- // test single element entry
- MongoStorageBackend.insertVectorStorageEntryFor("U-A1", Map(1->1, 2->4, 3->9))
- assertEquals(
- 6,
- MongoStorageBackend.getVectorStorageSizeFor("U-A1"))
+ override def afterEach {
+ MongoStorageBackend.drop
}
- @Test
- def testVectorFetchForKeys = {
+ describe("persistent maps") {
+ it("should insert with single key and value") {
+ import MongoStorageBackend._
- // initially everything 0
- assertEquals(
- 0,
- MongoStorageBackend.getVectorStorageSizeFor("U-A2"))
-
- assertEquals(
- 0,
- MongoStorageBackend.getVectorStorageSizeFor("U-A1"))
-
- // get some stuff
- changeSetV += "debasish"
- changeSetV += List(BigDecimal(12), BigDecimal(13), BigDecimal(14))
- MongoStorageBackend.insertVectorStorageEntriesFor("U-A1", changeSetV.toList)
-
- assertEquals(
- 2,
- MongoStorageBackend.getVectorStorageSizeFor("U-A1"))
-
- val JsString(str) = MongoStorageBackend.getVectorStorageEntryFor("U-A1", 0).asInstanceOf[JsString]
- assertEquals("debasish", str)
-
- val l = MongoStorageBackend.getVectorStorageEntryFor("U-A1", 1).asInstanceOf[JsValue]
- val num_list = list ! num
- val num_list(l0) = l
- assertEquals(List(12, 13, 14), l0)
-
- changeSetV.clear
- changeSetV += Map(1->1, 2->4, 3->9)
- changeSetV += BigInt(2310)
- changeSetV += List(100, 200, 300)
- MongoStorageBackend.insertVectorStorageEntriesFor("U-A1", changeSetV.toList)
-
- assertEquals(
- 5,
- MongoStorageBackend.getVectorStorageSizeFor("U-A1"))
-
- val r =
- MongoStorageBackend.getVectorStorageRangeFor("U-A1", Some(1), None, 3)
-
- assertEquals(3, r.size)
- val lr = r(0).asInstanceOf[JsValue]
- val num_list(l1) = lr
- assertEquals(List(12, 13, 14), l1)
- }
-
- @Test
- def testVectorFetchForNonExistentKeys = {
- try {
- MongoStorageBackend.getVectorStorageEntryFor("U-A1", 1)
- fail("should throw an exception")
- } catch {case e: NoSuchElementException => {}}
-
- try {
- MongoStorageBackend.getVectorStorageRangeFor("U-A1", Some(2), None, 12)
- fail("should throw an exception")
- } catch {case e: NoSuchElementException => {}}
- }
-
- @Test
- def testVectorUpdateForTransactionId = {
- import MongoStorageBackend._
-
- changeSetV += "debasish" // string
- changeSetV += List(1, 2, 3) // Scala List
- changeSetV += List(100, 200)
-
- insertVectorStorageEntriesFor("U-A1", changeSetV.toList)
- assertEquals(3, getVectorStorageSizeFor("U-A1"))
- updateVectorStorageEntryFor("U-A1", 0, "maulindu")
- val JsString(str) = getVectorStorageEntryFor("U-A1", 0).asInstanceOf[JsString]
- assertEquals("maulindu", str)
-
- updateVectorStorageEntryFor("U-A1", 1, Map("1"->"dg", "2"->"mc"))
- val JsObject(m) = getVectorStorageEntryFor("U-A1", 1).asInstanceOf[JsObject]
- assertEquals(m.keySet.size, 2)
- }
-
- @Test
- def testMapInsertForTransactionId = {
- fillMap
-
- // add some more to changeSet
- changeSetM += "5" -> Foo(12, "dg")
- changeSetM += "6" -> java.util.Calendar.getInstance.getTime
-
- // insert all into Mongo
- MongoStorageBackend.insertMapStorageEntriesFor("U-M1", changeSetM.toList)
- assertEquals(
- 6,
- MongoStorageBackend.getMapStorageSizeFor("U-M1"))
-
- // individual insert api
- MongoStorageBackend.insertMapStorageEntryFor("U-M1", "7", "akka")
- MongoStorageBackend.insertMapStorageEntryFor("U-M1", "8", List(23, 25))
- assertEquals(
- 8,
- MongoStorageBackend.getMapStorageSizeFor("U-M1"))
-
- // add the same changeSet for another transaction
- MongoStorageBackend.insertMapStorageEntriesFor("U-M2", changeSetM.toList)
- assertEquals(
- 6,
- MongoStorageBackend.getMapStorageSizeFor("U-M2"))
-
- // the first transaction should remain the same
- assertEquals(
- 8,
- MongoStorageBackend.getMapStorageSizeFor("U-M1"))
- changeSetM.clear
- }
-
- @Test
- def testMapContents = {
- fillMap
- MongoStorageBackend.insertMapStorageEntriesFor("U-M1", changeSetM.toList)
- MongoStorageBackend.getMapStorageEntryFor("U-M1", "2") match {
- case Some(x) => {
- val JsString(str) = x.asInstanceOf[JsValue]
- assertEquals("peter", str)
- }
- case None => fail("should fetch peter")
- }
- MongoStorageBackend.getMapStorageEntryFor("U-M1", "4") match {
- case Some(x) => {
- val num_list = list ! num
- val num_list(l0) = x.asInstanceOf[JsValue]
- assertEquals(3, l0.size)
- }
- case None => fail("should fetch list")
- }
- MongoStorageBackend.getMapStorageEntryFor("U-M1", "3") match {
- case Some(x) => {
- val num_list = list ! num
- val num_list(l0) = x.asInstanceOf[JsValue]
- assertEquals(2, l0.size)
- }
- case None => fail("should fetch list")
+ insertMapStorageEntryFor("t1", "odersky".getBytes, "scala".getBytes)
+ insertMapStorageEntryFor("t1", "gosling".getBytes, "java".getBytes)
+ insertMapStorageEntryFor("t1", "stroustrup".getBytes, "c++".getBytes)
+ getMapStorageSizeFor("t1") should equal(3)
+ new String(getMapStorageEntryFor("t1", "odersky".getBytes).get) should equal("scala")
+ new String(getMapStorageEntryFor("t1", "gosling".getBytes).get) should equal("java")
+ new String(getMapStorageEntryFor("t1", "stroustrup".getBytes).get) should equal("c++")
+ getMapStorageEntryFor("t1", "torvalds".getBytes) should equal(None)
}
- // get the entire map
- val l: List[Tuple2[AnyRef, AnyRef]] =
- MongoStorageBackend.getMapStorageFor("U-M1")
+ it("should insert with multiple keys and values") {
+ import MongoStorageBackend._
- assertEquals(4, l.size)
- assertTrue(l.map(_._1).contains("1"))
- assertTrue(l.map(_._1).contains("2"))
- assertTrue(l.map(_._1).contains("3"))
- assertTrue(l.map(_._1).contains("4"))
+ val l = List(("stroustrup", "c++"), ("odersky", "scala"), ("gosling", "java"))
+ insertMapStorageEntriesFor("t1", l.map { case (k, v) => (k.getBytes, v.getBytes) })
+ getMapStorageSizeFor("t1") should equal(3)
+ new String(getMapStorageEntryFor("t1", "stroustrup".getBytes).get) should equal("c++")
+ new String(getMapStorageEntryFor("t1", "gosling".getBytes).get) should equal("java")
+ new String(getMapStorageEntryFor("t1", "odersky".getBytes).get) should equal("scala")
+ getMapStorageEntryFor("t1", "torvalds".getBytes) should equal(None)
- val JsString(str) = l.filter(_._1 == "2").head._2
- assertEquals(str, "peter")
+ evaluating { getMapStorageEntryFor("t2", "torvalds".getBytes) } should produce [NoSuchElementException]
- // trying to fetch for a non-existent transaction will throw
- try {
- MongoStorageBackend.getMapStorageFor("U-M2")
- fail("should throw an exception")
- } catch {case e: NoSuchElementException => {}}
+ getMapStorageFor("t1").map { case (k, v) => (new String(k), new String(v)) } should equal (l)
- changeSetM.clear
- }
+ removeMapStorageFor("t1", "gosling".getBytes)
+ getMapStorageSizeFor("t1") should equal(2)
- @Test
- def testMapContentsByRange = {
- fillMap
- changeSetM += "5" -> Map(1 -> "dg", 2 -> "mc")
- MongoStorageBackend.insertMapStorageEntriesFor("U-M1", changeSetM.toList)
-
- // specify start and count
- val l: List[Tuple2[AnyRef, AnyRef]] =
- MongoStorageBackend.getMapStorageRangeFor(
- "U-M1", Some(Integer.valueOf(2)), None, 3)
-
- assertEquals(3, l.size)
- assertEquals("3", l(0)._1.asInstanceOf[String])
- val lst = l(0)._2.asInstanceOf[JsValue]
- val num_list = list ! num
- val num_list(l0) = lst
- assertEquals(List(100, 200), l0)
- assertEquals("4", l(1)._1.asInstanceOf[String])
- val ls = l(1)._2.asInstanceOf[JsValue]
- val num_list(l1) = ls
- assertEquals(List(10, 20, 30), l1)
-
- // specify start, finish and count where finish - start == count
- assertEquals(3,
- MongoStorageBackend.getMapStorageRangeFor(
- "U-M1", Some(Integer.valueOf(2)), Some(Integer.valueOf(5)), 3).size)
-
- // specify start, finish and count where finish - start > count
- assertEquals(3,
- MongoStorageBackend.getMapStorageRangeFor(
- "U-M1", Some(Integer.valueOf(2)), Some(Integer.valueOf(9)), 3).size)
-
- // do not specify start or finish
- assertEquals(3,
- MongoStorageBackend.getMapStorageRangeFor(
- "U-M1", None, None, 3).size)
-
- // specify finish and count
- assertEquals(3,
- MongoStorageBackend.getMapStorageRangeFor(
- "U-M1", None, Some(Integer.valueOf(3)), 3).size)
-
- // specify start, finish and count where finish < start
- assertEquals(3,
- MongoStorageBackend.getMapStorageRangeFor(
- "U-M1", Some(Integer.valueOf(2)), Some(Integer.valueOf(1)), 3).size)
-
- changeSetM.clear
- }
-
- @Test
- def testMapStorageRemove = {
- fillMap
- changeSetM += "5" -> Map(1 -> "dg", 2 -> "mc")
-
- MongoStorageBackend.insertMapStorageEntriesFor("U-M1", changeSetM.toList)
- assertEquals(5,
- MongoStorageBackend.getMapStorageSizeFor("U-M1"))
-
- // remove key "3"
- MongoStorageBackend.removeMapStorageFor("U-M1", "3")
- assertEquals(4,
- MongoStorageBackend.getMapStorageSizeFor("U-M1"))
-
- try {
- MongoStorageBackend.getMapStorageEntryFor("U-M1", "3")
- fail("should throw exception")
- } catch { case e => {}}
-
- // remove key "4"
- MongoStorageBackend.removeMapStorageFor("U-M1", "4")
- assertEquals(3,
- MongoStorageBackend.getMapStorageSizeFor("U-M1"))
-
- // remove key "2"
- MongoStorageBackend.removeMapStorageFor("U-M1", "2")
- assertEquals(2,
- MongoStorageBackend.getMapStorageSizeFor("U-M1"))
-
- // remove the whole stuff
- MongoStorageBackend.removeMapStorageFor("U-M1")
-
- try {
- MongoStorageBackend.getMapStorageFor("U-M1")
- fail("should throw exception")
- } catch { case e: NoSuchElementException => {}}
-
- changeSetM.clear
- }
-
- private def fillMap = {
- changeSetM += "1" -> "john"
- changeSetM += "2" -> "peter"
- changeSetM += "3" -> List(100, 200)
- changeSetM += "4" -> List(10, 20, 30)
- changeSetM
- }
-
- @Test
- def testRefStorage = {
- MongoStorageBackend.getRefStorageFor("U-R1") match {
- case None =>
- case Some(o) => fail("should be None")
+ removeMapStorageFor("t1")
+ evaluating { getMapStorageSizeFor("t1") } should produce [NoSuchElementException]
}
- val m = Map("1"->1, "2"->4, "3"->9)
- MongoStorageBackend.insertRefStorageFor("U-R1", m)
- MongoStorageBackend.getRefStorageFor("U-R1") match {
- case None => fail("should not be empty")
- case Some(r) => {
- val a = r.asInstanceOf[JsValue]
- val m1 = Symbol("1") ? num
- val m2 = Symbol("2") ? num
- val m3 = Symbol("3") ? num
+ it("should do proper range queries") {
+ import MongoStorageBackend._
+ val l = List(
+ ("bjarne stroustrup", "c++"),
+ ("martin odersky", "scala"),
+ ("james gosling", "java"),
+ ("yukihiro matsumoto", "ruby"),
+ ("slava pestov", "factor"),
+ ("rich hickey", "clojure"),
+ ("ola bini", "ioke"),
+ ("dennis ritchie", "c"),
+ ("larry wall", "perl"),
+ ("guido van rossum", "python"),
+ ("james strachan", "groovy"))
+ insertMapStorageEntriesFor("t1", l.map { case (k, v) => (k.getBytes, v.getBytes) })
+ getMapStorageSizeFor("t1") should equal(l.size)
+ getMapStorageRangeFor("t1", None, None, 100).map { case (k, v) => (new String(k), new String(v)) } should equal(l.sortWith(_._1 < _._1))
+ getMapStorageRangeFor("t1", None, None, 5).map { case (k, v) => (new String(k), new String(v)) }.size should equal(5)
+ }
+ }
- val m1(n1) = a
- val m2(n2) = a
- val m3(n3) = a
+ describe("persistent vectors") {
+ it("should insert a single value") {
+ import MongoStorageBackend._
- assertEquals(n1, 1)
- assertEquals(n2, 4)
- assertEquals(n3, 9)
- }
+ insertVectorStorageEntryFor("t1", "martin odersky".getBytes)
+ insertVectorStorageEntryFor("t1", "james gosling".getBytes)
+ new String(getVectorStorageEntryFor("t1", 0)) should equal("james gosling")
+ new String(getVectorStorageEntryFor("t1", 1)) should equal("martin odersky")
}
- // insert another one
- // the previous one should be replaced
- val b = List("100", "jonas")
- MongoStorageBackend.insertRefStorageFor("U-R1", b)
- MongoStorageBackend.getRefStorageFor("U-R1") match {
- case None => fail("should not be empty")
- case Some(r) => {
- val a = r.asInstanceOf[JsValue]
- val str_lst = list ! str
- val str_lst(l) = a
- assertEquals(b, l)
- }
+ it("should insert multiple values") {
+ import MongoStorageBackend._
+
+ insertVectorStorageEntryFor("t1", "martin odersky".getBytes)
+ insertVectorStorageEntryFor("t1", "james gosling".getBytes)
+ insertVectorStorageEntriesFor("t1", List("ola bini".getBytes, "james strachan".getBytes, "dennis ritchie".getBytes))
+ new String(getVectorStorageEntryFor("t1", 0)) should equal("ola bini")
+ new String(getVectorStorageEntryFor("t1", 1)) should equal("james strachan")
+ new String(getVectorStorageEntryFor("t1", 2)) should equal("dennis ritchie")
+ new String(getVectorStorageEntryFor("t1", 3)) should equal("james gosling")
+ new String(getVectorStorageEntryFor("t1", 4)) should equal("martin odersky")
+ }
+
+ it("should fetch a range of values") {
+ import MongoStorageBackend._
+
+ insertVectorStorageEntryFor("t1", "martin odersky".getBytes)
+ insertVectorStorageEntryFor("t1", "james gosling".getBytes)
+ getVectorStorageSizeFor("t1") should equal(2)
+ insertVectorStorageEntriesFor("t1", List("ola bini".getBytes, "james strachan".getBytes, "dennis ritchie".getBytes))
+ getVectorStorageRangeFor("t1", None, None, 100).map(new String(_)) should equal(List("ola bini", "james strachan", "dennis ritchie", "james gosling", "martin odersky"))
+ getVectorStorageRangeFor("t1", Some(0), Some(5), 100).map(new String(_)) should equal(List("ola bini", "james strachan", "dennis ritchie", "james gosling", "martin odersky"))
+ getVectorStorageRangeFor("t1", Some(2), Some(5), 100).map(new String(_)) should equal(List("dennis ritchie", "james gosling", "martin odersky"))
+
+ getVectorStorageSizeFor("t1") should equal(5)
+ }
+
+ it("should insert and query complex structures") {
+ import MongoStorageBackend._
+ import sjson.json.DefaultProtocol._
+ import sjson.json.JsonSerialization._
+
+ // a list[AnyRef] should be added successfully
+ val l = List("ola bini".getBytes, tobinary(List(100, 200, 300)), tobinary(List(1, 2, 3)))
+
+ // for id = t1
+ insertVectorStorageEntriesFor("t1", l)
+ new String(getVectorStorageEntryFor("t1", 0)) should equal("ola bini")
+ frombinary[List[Int]](getVectorStorageEntryFor("t1", 1)) should equal(List(100, 200, 300))
+ frombinary[List[Int]](getVectorStorageEntryFor("t1", 2)) should equal(List(1, 2, 3))
+
+ getVectorStorageSizeFor("t1") should equal(3)
+
+ // some more for id = t1
+ val m = List(tobinary(Map(1 -> "dg", 2 -> "mc", 3 -> "nd")), tobinary(List("martin odersky", "james gosling")))
+ insertVectorStorageEntriesFor("t1", m)
+
+ // size should add up
+ getVectorStorageSizeFor("t1") should equal(5)
+
+ // now for a diff id
+ insertVectorStorageEntriesFor("t2", l)
+ getVectorStorageSizeFor("t2") should equal(3)
+ }
+ }
+
+ describe("persistent refs") {
+ it("should insert a ref") {
+ import MongoStorageBackend._
+
+ insertRefStorageFor("t1", "martin odersky".getBytes)
+ new String(getRefStorageFor("t1").get) should equal("martin odersky")
+ insertRefStorageFor("t1", "james gosling".getBytes)
+ new String(getRefStorageFor("t1").get) should equal("james gosling")
+ getRefStorageFor("t2") should equal(None)
}
}
}
diff --git a/embedded-repo/org/scala-tools/time/2.8.0-0.2-SNAPSHOT/time-2.8.0-0.2-SNAPSHOT.jar b/embedded-repo/org/scala-tools/time/2.8.0-0.2-SNAPSHOT/time-2.8.0-0.2-SNAPSHOT.jar
new file mode 100644
index 0000000000..038768fe14
Binary files /dev/null and b/embedded-repo/org/scala-tools/time/2.8.0-0.2-SNAPSHOT/time-2.8.0-0.2-SNAPSHOT.jar differ
diff --git a/embedded-repo/sjson/json/sjson/0.8-SNAPSHOT-2.8.0/sjson-0.8-SNAPSHOT-2.8.0.jar b/embedded-repo/sjson/json/sjson/0.8-SNAPSHOT-2.8.0/sjson-0.8-SNAPSHOT-2.8.0.jar
new file mode 100644
index 0000000000..1542632a82
Binary files /dev/null and b/embedded-repo/sjson/json/sjson/0.8-SNAPSHOT-2.8.0/sjson-0.8-SNAPSHOT-2.8.0.jar differ
diff --git a/project/build/AkkaProject.scala b/project/build/AkkaProject.scala
index 393b531dd6..0eb289a290 100644
--- a/project/build/AkkaProject.scala
+++ b/project/build/AkkaProject.scala
@@ -49,6 +49,8 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) {
lazy val JavaNetRepo = MavenRepository("java.net Repo", "http://download.java.net/maven/2")
lazy val SonatypeSnapshotRepo = MavenRepository("Sonatype OSS Repo", "http://oss.sonatype.org/content/repositories/releases")
lazy val SunJDMKRepo = MavenRepository("Sun JDMK Repo", "http://wp5.e-taxonomy.eu/cdmlib/mavenrepo")
+ lazy val CasbahRepoSnapshots = MavenRepository("Casbah Snapshot Repo", "http://repo.bumnetworks.com/snapshots/")
+ lazy val CasbahRepoReleases = MavenRepository("Casbah Snapshot Repo", "http://repo.bumnetworks.com/releases/")
}
// -------------------------------------------------------------------------------------------------------------------
@@ -75,6 +77,8 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) {
lazy val scalaTestModuleConfig = ModuleConfiguration("org.scalatest", ScalaToolsSnapshots)
lazy val logbackModuleConfig = ModuleConfiguration("ch.qos.logback",sbt.DefaultMavenRepository)
lazy val atomikosModuleConfig = ModuleConfiguration("com.atomikos",sbt.DefaultMavenRepository)
+ lazy val casbahSnapshot = ModuleConfiguration("com.novus",CasbahRepoSnapshots)
+ lazy val casbahRelease = ModuleConfiguration("com.novus",CasbahRepoReleases)
lazy val embeddedRepo = EmbeddedRepo // This is the only exception, because the embedded repo is fast!
// -------------------------------------------------------------------------------------------------------------------
@@ -166,6 +170,10 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) {
lazy val mongo = "org.mongodb" % "mongo-java-driver" % "2.0" % "compile"
+ lazy val casbah = "com.novus" % "casbah_2.8.0" % "1.0.8.5" % "compile"
+
+ lazy val time = "org.scala-tools" % "time" % "2.8.0-SNAPSHOT-0.2-SNAPSHOT" % "compile"
+
lazy val multiverse = "org.multiverse" % "multiverse-alpha" % MULTIVERSE_VERSION % "compile" intransitive
lazy val netty = "org.jboss.netty" % "netty" % "3.2.2.Final" % "compile"
@@ -180,7 +188,7 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) {
lazy val sbinary = "sbinary" % "sbinary" % "2.8.0-0.3.1" % "compile"
- lazy val sjson = "sjson.json" % "sjson" % "0.7-2.8.0" % "compile"
+ lazy val sjson = "sjson.json" % "sjson" % "0.8-SNAPSHOT-2.8.0" % "compile"
lazy val slf4j = "org.slf4j" % "slf4j-api" % SLF4J_VERSION % "compile"
@@ -483,8 +491,9 @@ class AkkaParentProject(info: ProjectInfo) extends DefaultProject(info) {
class AkkaMongoProject(info: ProjectInfo) extends AkkaDefaultProject(info, distPath) {
val mongo = Dependencies.mongo
+ val casbah = Dependencies.casbah
- override def testOptions = TestFilter((name: String) => name.endsWith("Test")) :: Nil
+ // override def testOptions = TestFilter((name: String) => name.endsWith("Test")) :: Nil
}
// -------------------------------------------------------------------------------------------------------------------