Friday, October 23, 2009

Implementing a Diameter Peer State Machine using Test Driven Development (Part 2).

So, next step is to test what happens if (following the state machine picture on the previous post) a START signal is sent to our peer.
According with RFC 3588 specification, if a peer, that is in CLOSED state, successfully processes the START signal two things happen:
  • the peer must take a "I-Snd-Conn-Req" action;
  • a state transition occurs : the peer passes from CLOSED to WAIT-CONN_ACK state;
In this article we will take care about the second point.
Well, returning to our test case, we have to add another @Test method :

public class PeerStateMachineTestCase
{

....@Test
....public void startSignal()
....{
.......Peer peer = new Peer();
.......peer.signal(PeerEventType.START);

.......assertTrue(peer.currentStateIs(peer.WAIT_CONN_ACK);
....}
}

Obviously, this test method doesn't compile : we don't have a signal() method and a WAIT_CONN_ACK member variable on our Peer class.
So first of all we will insert the missing method :

public void signal(PeerEventType eventType)
{
}

after that, Peer class needs a new State instance member :

final State WAIT_CONN_ACK = new State(){};

This is how our Peer class behaves :

public class Peer
{
....final State CLOSED = new State(){};
....final State WAIT_CONN_ACK = new State(){};

....public void signal(PeerEventType eventType){}

....boolean currentStateIs(State state)
....{
........return true;
....}
}
Now the test method (and the enclosing testcase) compiles fine. But after running, we get a red bar. Why? There is one explicit problem : transition state doesn't really happen on peer instance so the assertion fails. I mean, the peer is not on WAIT_CONN_ACK State. Actually is not in any state because the currentStateIs() method is returning true everytime :)
In order to see that all is properly working we need to introduce another peer member instance that represents the current state of the peer.
Well, considering that we already have a type for this new member (State class), we can insert (in Peer class):

private State currentState;

With this new variable, I can rewrite the currentStateIs() method in the following way :

boolean currentStateIs(State state)
{
....return currentState == state;
}

Introducing that change causes a failure in the first test we saw in part I. Well, in order to fix that we need to initialize the "currentState" member instance :

private State currentState = CLOSED;

Now the @Test initialState() is working while the @Test startSignal() is failing :(.
Why? because nothing on the peer instance is causing the required state transition and the assertion on the currentStateIs() fails because the peer is still in CLOSED state.
Again, what is the minimum change / adjustment we would do in order to get things working? This is the failing test :

public class PeerStateMachineTestCase
{
....@Test
....public void startSignal()
...{
......Peer peer = new Peer();
......peer.signal(PeerEventType.START);

......assertTrue(peer.currentStateIs(peer.WAIT_CONN_ACK);
...}
}

Yes, we can do the state transition in the signal() method :

public void signal(PeerEventType type)
{
....currentState = WAIT_CONN_ACK;
}

In this way, the test will succeed because after calling the signal() method the peer state is WAIT_CONN_ACK as required.

See you soon for third episode :)
Bye
Andrea

No comments: