Search code examples
javaakkafsmakka-testkitakka-fsm

Updating data in a Finite state machine


I am using the FSM framework with AKKA using its Java API to manage state transitions . Here is the relevant portion of the state machine

     when(QUEUED,
            matchEvent(Exception.class, Service.class,
                (exception, dservice) -> goTo(ERROR)
                    .replying(ERROR)));


        // TODO:It seems missing from the DOC that to transition from a state , every state must be
        // listed

        // a service is in a errored state
        when(ERROR,
            matchAnyEvent((state, data) -> stay().replying("Staying in Errored state")));

        onTransition(matchState(QUEUED, ERROR, () -> {
   // Update the Service object and save it to the database


        }));

This works as expected and the correct state changes happen with the actor. IN the onTansition() block , I want to update the Service object which is the finite state machine data in this case, something as follows

Service.setProperty(someProperty)
dbActor.tell(saveService);

Is this possible? Am I using this framework in the right way?

I think I was able to do something like the following

 onTransition(matchState(QUEUED,ERROR, () -> {
      nextStateData().setServiceStatus(ERROR);
      // Get the actual exception message here to save to the database
      databaseWriter.tell(nextStateData(), getSelf());

    }));

How do I now actually test the data thats changed as a result of this transition?

The test looks like this

   @Test
      public void testErrorState() {
        new TestKit(system) {
          {
            TestProbe probe = new TestProbe(system);
            final ActorRef underTest = system.actorOf(ServiceFSMActor.props(dbWriter));
            underTest.tell(new Exception(), getRef());
            expectMsgEquals(ERROR); // This works
           // How do I make sure the data is updated here as part of the OnTransition declaration??

          }
        };
      }

Solution

  • You've defined a probe in the test but you're not using it. Since the FSM actor sends the updated state to the database writer actor, you could test the updated state by replacing the database writer actor with the probe:

    new TestKit(system) {{
      final TestProbe probe = new TestProbe(system);
    
      final ActorRef underTest = system.actorOf(ServiceFSMActor.props(probe.ref()));
      underTest.tell(new Exception(), getRef());
      expectMsgEquals(ERROR);
    
      final Service state = probe.expectMsgClass(Service.class);
      assertEquals(ERROR, state.getServiceStatus());
    }};