During the test, I've got the following error message:
[ERROR] [07/13/2019 14:25:39.659] [DetectorSystem3-akka.io.pinned-dispatcher-2] [akka://DetectorSystem3/user/DetectorSupervisor] SapActiveConfirmed (of class com.sweetsoft.detector.ServerMonitoring$SapActiveConfirmed$)
scala.MatchError: SapActiveConfirmed (of class com.sweetsoft.detector.ServerMonitoring$SapActiveConfirmed$)
at com.sweetsoft.detector.DetectorStateMachine$.$anonfun$create$2(DetectorStateMachine.scala:20)
at akka.actor.typed.internal.BehaviorImpl$ReceiveMessageBehavior.receive(BehaviorImpl.scala:53)
at akka.actor.typed.Behavior$.interpret(Behavior.scala:437)
at akka.actor.typed.Behavior$.interpretMessage(Behavior.scala:393)
at akka.actor.typed.internal.adapter.ActorAdapter.handleMessage(ActorAdapter.scala:121)
at akka.actor.typed.internal.adapter.ActorAdapter.aroundReceive(ActorAdapter.scala:102)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:612)
at akka.actor.ActorCell.invoke(ActorCell.scala:581)
at akka.testkit.CallingThreadDispatcher.process$1(CallingThreadDispatcher.scala:280)
at akka.testkit.CallingThreadDispatcher.runQueue(CallingThreadDispatcher.scala:313)
at akka.testkit.CallingThreadDispatcher.dispatch(CallingThreadDispatcher.scala:234)
at akka.actor.dungeon.Dispatch.sendMessage(Dispatch.scala:158)
at akka.actor.dungeon.Dispatch.sendMessage$(Dispatch.scala:152)
at akka.actor.ActorCell.sendMessage(ActorCell.scala:447)
I am using akka typed and in my opinion it should not happen like this.
The actor is implemented as follows:
object DetectorStateMachine {
case class State(kafka: ServerHealthEvent, sap: ServerHealthEvent)
def create(informant: ActorRef[InformantEvent]): Behavior[ServerHealthEvent] =
Behaviors.setup { context =>
context.log.info(s"=============> Start DetectorStateMachine <=============")
def loop(state: State): Behavior[ServerHealthEvent] = {
Behaviors.receiveMessage {
case KafkaActiveConfirmed
if state.kafka == KafkaActiveConfirmed || state.sap == SapActiveConfirmed =>
informant ! ServerOnlineConfirmed
loop(state)
case k@KafkaActiveConfirmed if state.kafka == KafkaInactiveConfirmed =>
loop(State(k, state.sap))
case k@KafkaInactiveConfirmed =>
informant ! ServerOfflineConfirmed
loop(State(k, state.sap))
case SapActiveConfirmed
if state.sap == SapActiveConfirmed && state.kafka == KafkaActiveConfirmed =>
informant ! ServerOnlineConfirmed
loop(state)
case s@SapActiveConfirmed if state.sap == SapInactiveConfirmed =>
loop(State(state.kafka, s))
case s@SapInactiveConfirmed =>
informant ! ServerOfflineConfirmed
loop(State(state.kafka, s))
}
}
loop(State(KafkaInactiveConfirmed, SapInactiveConfirmed))
}
}
and the test is implemented as:
final class DetectorSpec extends BddSpec {
private val sap = new SapMock()
.withExposedPorts(8080)
.waitingFor(Wait.forHttp("/"))
private val kafka = new KafkaContainer("5.2.1")
sap.start()
kafka.start()
override def afterAll(): Unit = {
sap.stop()
kafka.stop()
}
private def withKafkaOfflineSapOnline(testCode: TestProbe[ServerEvent] => Unit)
: Unit = {
val config = ConfigFactory.parseString(
s"""akka.actor.default-dispatcher = {
type = akka.testkit.CallingThreadDispatcherConfigurator
}
akka.actor.testkit.typed.single-expect-default = 0s
kafka {
servers = "PLAINTEXT://localhost:9092"
}
sap {
server = "ws://${sap.getContainerIpAddress}:${sap.getMappedPort(8080)}"
}""")
val testKit = ActorTestKit("DetectorSystem3", config)
val inbox = testKit.createTestProbe[ServerEvent]("Receiver")
testKit.spawn(DetectorSupervisor.create(), "DetectorSupervisor")
testKit.system.receptionist ! Receptionist.Register(ServerStateKey, inbox.ref)
testCode(inbox)
testKit.shutdownTestKit()
}
scenario("SAP is online and Kafka is offline") {
withKafkaOfflineSapOnline { inbox =>
Given("I am waiting for the current state message")
When("I am receive the state message")
val msg = inbox.receiveMessage(60.second)
Then("it should contain `Kafka is offline`")
msg should be(ServerOfflineApproved)
}
}
}
}
What am I doing wrong?
Well, you have two branches with SapActiveConfirmed
:
case SapActiveConfirmed
if state.sap == SapActiveConfirmed && state.kafka == KafkaActiveConfirmed =>
...
case s@SapActiveConfirmed if state.sap == SapInactiveConfirmed =>
...
So if neither condition holds (eg state
is State(KafkaInactiveConfirmed, SapActiveConfirmed)
) then you'll get a MatchError
. And withKafkaOfflineSapOnline
certainly sounds like it can produce this state...
It might help if you structure the match differently:
Behaviors.receiveMessage {
case KafkaActiveConfirmed =>
...
case KafkaInactiveConfirmed =>
...
...
}
where the conditions go inside the branches.
如果您想避免匹配错误-最好添加带有错误打印输出的后备空白案例
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.