Publish operations from InmemJournal (#28332)
* small feature that is useful for verifying that expected events were persisted * doc example * also enable serialization test config
This commit is contained in:
parent
4749b11be8
commit
cdc45c128d
9 changed files with 177 additions and 10 deletions
|
|
@ -9,6 +9,8 @@ import scala.concurrent.Future
|
|||
import scala.util.Try
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
import akka.annotation.ApiMayChange
|
||||
import akka.annotation.InternalApi
|
||||
import akka.persistence.journal.AsyncWriteJournal
|
||||
import akka.persistence.PersistentRepr
|
||||
import akka.persistence.AtomicWrite
|
||||
|
|
@ -17,12 +19,28 @@ import akka.serialization.Serializers
|
|||
import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigFactory
|
||||
|
||||
/**
|
||||
* The InmemJournal publishes writes and deletes to the `eventStream`, which tests may use to
|
||||
* verify that expected events have been persisted or deleted.
|
||||
*
|
||||
* InmemJournal is only intended to be used for tests and therefore binary backwards compatibility
|
||||
* of the published messages are not guaranteed.
|
||||
*/
|
||||
@ApiMayChange
|
||||
object InmemJournal {
|
||||
sealed trait Operation
|
||||
|
||||
final case class Write(event: Any, persistenceId: String, sequenceNr: Long) extends Operation
|
||||
|
||||
final case class Delete(persistenceId: String, toSequenceNr: Long) extends Operation
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API.
|
||||
*
|
||||
* In-memory journal for testing purposes only.
|
||||
*/
|
||||
private[persistence] class InmemJournal(cfg: Config) extends AsyncWriteJournal with InmemMessages {
|
||||
@InternalApi private[persistence] class InmemJournal(cfg: Config) extends AsyncWriteJournal with InmemMessages {
|
||||
|
||||
def this() = this(ConfigFactory.empty())
|
||||
|
||||
|
|
@ -34,11 +52,14 @@ private[persistence] class InmemJournal(cfg: Config) extends AsyncWriteJournal w
|
|||
|
||||
private val serialization = SerializationExtension(context.system)
|
||||
|
||||
private val eventStream = context.system.eventStream
|
||||
|
||||
override def asyncWriteMessages(messages: immutable.Seq[AtomicWrite]): Future[immutable.Seq[Try[Unit]]] = {
|
||||
try {
|
||||
for (w <- messages; p <- w.payload) {
|
||||
verifySerialization(p.payload)
|
||||
add(p)
|
||||
eventStream.publish(InmemJournal.Write(p.payload, p.persistenceId, p.sequenceNr))
|
||||
}
|
||||
Future.successful(Nil) // all good
|
||||
} catch {
|
||||
|
|
@ -67,6 +88,7 @@ private[persistence] class InmemJournal(cfg: Config) extends AsyncWriteJournal w
|
|||
delete(persistenceId, snr)
|
||||
snr += 1
|
||||
}
|
||||
eventStream.publish(InmemJournal.Delete(persistenceId, toSeqNr))
|
||||
Future.successful(())
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +106,7 @@ private[persistence] class InmemJournal(cfg: Config) extends AsyncWriteJournal w
|
|||
/**
|
||||
* INTERNAL API.
|
||||
*/
|
||||
private[persistence] trait InmemMessages {
|
||||
@InternalApi private[persistence] trait InmemMessages {
|
||||
// persistenceId -> persistent message
|
||||
var messages = Map.empty[String, Vector[PersistentRepr]]
|
||||
// persistenceId -> highest used sequence number
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2017-2019 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package akka.persistence.journal.inmem
|
||||
|
||||
import akka.actor.Props
|
||||
import akka.persistence.PersistenceSpec
|
||||
import akka.persistence.PersistentActor
|
||||
import akka.testkit._
|
||||
|
||||
object InmemJournalSpec {
|
||||
|
||||
def testProps(name: String): Props =
|
||||
Props(new TestPersistentActor(name))
|
||||
|
||||
final case class Cmd(s: String)
|
||||
final case class Delete(toSeqNr: Long)
|
||||
final case class Evt(s: String)
|
||||
|
||||
class TestPersistentActor(name: String) extends PersistentActor {
|
||||
|
||||
override def persistenceId: String = name
|
||||
|
||||
override def receiveRecover: Receive = {
|
||||
case Evt(_) =>
|
||||
}
|
||||
override def receiveCommand: Receive = {
|
||||
case Cmd(s) => persist(Evt(s))(_ => ())
|
||||
case Delete(toSeqNr) => deleteMessages(toSeqNr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class InmemJournalSpec
|
||||
extends PersistenceSpec(PersistenceSpec.config("inmem", "InmemJournalSpec"))
|
||||
with ImplicitSender {
|
||||
import InmemJournalSpec._
|
||||
|
||||
system.eventStream.subscribe(testActor, classOf[InmemJournal.Operation])
|
||||
|
||||
"InmemJournal" must {
|
||||
"publish writes" in {
|
||||
val p1 = system.actorOf(testProps("p1"))
|
||||
p1 ! Cmd("A")
|
||||
p1 ! Cmd("B")
|
||||
expectMsg(InmemJournal.Write(Evt("A"), "p1", 1L))
|
||||
expectMsg(InmemJournal.Write(Evt("B"), "p1", 2L))
|
||||
}
|
||||
|
||||
"publish deletes" in {
|
||||
val p1 = system.actorOf(testProps("p2"))
|
||||
p1 ! Cmd("A")
|
||||
p1 ! Cmd("B")
|
||||
p1 ! Cmd("C")
|
||||
p1 ! Delete(2)
|
||||
expectMsg(InmemJournal.Write(Evt("A"), "p2", 1L))
|
||||
expectMsg(InmemJournal.Write(Evt("B"), "p2", 2L))
|
||||
expectMsg(InmemJournal.Write(Evt("C"), "p2", 3L))
|
||||
expectMsg(InmemJournal.Delete("p2", 2L))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue