pekko/docs/src/test/java/jdocs/actor/fsm/FSMDocTest.java

231 lines
6 KiB
Java

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, derived from Akka.
*/
/*
* Copyright (C) 2009-2022 Lightbend Inc. <https://www.lightbend.com>
*/
package jdocs.actor.fsm;
import org.apache.pekko.actor.*;
import jdocs.AbstractJavaTest;
import org.apache.pekko.testkit.javadsl.TestKit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
import static jdocs.actor.fsm.FSMDocTest.StateType.*;
import static jdocs.actor.fsm.FSMDocTest.Messages.*;
import java.time.Duration;
public class FSMDocTest extends AbstractJavaTest {
static ActorSystem system;
@BeforeClass
public static void setup() {
system = ActorSystem.create("FSMDocTest");
}
@AfterClass
public static void tearDown() {
TestKit.shutdownActorSystem(system);
system = null;
}
public enum StateType {
SomeState,
Processing,
Idle,
Active,
Error
}
public enum Messages {
WillDo,
Tick
}
public enum Data {
Foo,
Bar
};
public static interface X {};
public static class DummyFSM extends AbstractFSM<StateType, Integer> {
Integer newData = 42;
// #alt-transition-syntax
public void handler(StateType from, StateType to) {
// handle transition here
}
// #alt-transition-syntax
{
// #modifier-syntax
when(
SomeState,
matchAnyEvent(
(msg, data) -> {
return goTo(Processing)
.using(newData)
.forMax(Duration.ofSeconds(5))
.replying(WillDo);
}));
// #modifier-syntax
// #NullFunction
when(SomeState, AbstractFSM.NullFunction());
// #NullFunction
// #transition-syntax
onTransition(
matchState(
Idle,
Active,
() -> startTimerWithFixedDelay("timeout", Tick, Duration.ofSeconds(1L)))
.state(Active, null, () -> cancelTimer("timeout"))
.state(null, Idle, (f, t) -> log().info("entering Idle from " + f)));
// #transition-syntax
// #alt-transition-syntax
onTransition(this::handler);
// #alt-transition-syntax
// #stop-syntax
when(
Error,
matchEventEquals(
"stop",
(event, data) -> {
// do cleanup ...
return stop();
}));
// #stop-syntax
// #termination-syntax
onTermination(
matchStop(
Normal(),
(state, data) -> {
/* Do something here */
})
.stop(
Shutdown(),
(state, data) -> {
/* Do something here */
})
.stop(
Failure.class,
(reason, state, data) -> {
/* Do something here */
}));
// #termination-syntax
// #unhandled-syntax
whenUnhandled(
matchEvent(
X.class,
(x, data) -> {
log().info("Received unhandled event: " + x);
return stay();
})
.anyEvent(
(event, data) -> {
log().warning("Received unknown event: " + event);
return goTo(Error);
}));
}
// #unhandled-syntax
}
public
// #logging-fsm
static class MyFSM extends AbstractLoggingFSM<StateType, Data> {
// #body-elided
// #logging-fsm
ActorRef target = null;
// #logging-fsm
@Override
public int logDepth() {
return 12;
}
{
onTermination(
matchStop(
Failure.class,
(reason, state, data) -> {
String lastEvents = getLog().mkString("\n\t");
log()
.warning(
"Failure in state "
+ state
+ " with data "
+ data
+ "\n"
+ "Events leading up to this point:\n\t"
+ lastEvents);
// #logging-fsm
target.tell(reason.cause(), getSelf());
target.tell(state, getSelf());
target.tell(data, getSelf());
target.tell(lastEvents, getSelf());
// #logging-fsm
}));
// ...
// #logging-fsm
startWith(SomeState, Data.Foo);
when(
SomeState,
matchEvent(
ActorRef.class,
Data.class,
(ref, data) -> {
target = ref;
target.tell("going active", getSelf());
return goTo(Active);
}));
when(
Active,
matchEventEquals(
"stop",
(event, data) -> {
target.tell("stopping", getSelf());
return stop(new Failure("This is not the error you're looking for"));
}));
initialize();
// #logging-fsm
}
// #body-elided
}
// #logging-fsm
@Test
public void testLoggingFSM() {
new TestKit(system) {
{
final ActorRef logger = system.actorOf(Props.create(MyFSM.class));
final ActorRef probe = getRef();
logger.tell(probe, probe);
expectMsgEquals("going active");
logger.tell("stop", probe);
expectMsgEquals("stopping");
expectMsgEquals("This is not the error you're looking for");
expectMsgEquals(Active);
expectMsgEquals(Data.Foo);
String msg = expectMsgClass(String.class);
assertTrue(msg.startsWith("LogEntry(SomeState,Foo,Actor[akka://FSMDocTest/system/"));
}
};
}
}