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:
Patrik Nordwall 2020-01-13 09:46:43 +01:00 committed by GitHub
parent 4749b11be8
commit cdc45c128d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 177 additions and 10 deletions

View file

@ -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

View file

@ -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))
}
}
}