The Simulator class
The Simulator class is used to test protocol stacks in the absence of a JGroups channel and underlying transport. The Simulator wraps the protocol stack and provides methods to:
send Events down through the stack
receive Events coming up from the stack via a defined callback
A Simulator instance effectively simulates a JChannel instance. Multiple simulator instances can be used to simulate the interaction of multiple JChannels. One key advantage of using the Simulator for testing protocol stacks is that protocol layers can be tested in isolation.
Messages are never transported across a network. Instead, an Event which reaches the bottom of the stack is placed onto a send_queue. A send_thread continuously polls the send_queue, removing messages
and, based on the destinations, transfers them to the receive_queue of one or more destination simulators. Each simulator also has a receive_thread which continously polls the receive_queue and calls bottom.up() to send the Event back up the stack.
In order to make use of multiple simulators, the simulators must be initialized with the following:
a local address (used by the protocol layers)
a current view (containing all current members of the group and their associated simulators)
Schematic of a protocol under test wrapped by a Simulator instance (enclosing dotted rectangle represents a Simulator object instance).
down the stack
client calls s.send(Event e)
top.down(Event e) called
Event makes its way down protocol stack, through the layers under test
bottom.down() calls ProtocolAdapter.down() which puts event on send_queue
send_thread polls for Events in send_queue and depending on destination calls s.receive() on one or more simulator instances
s.receive() places a copy of the Event on the simulator's receive_queue
up the stack
receive_thread polls the receive_queue for Events, and calls bottom.up()
Event makes its way up the stack, when the top layer under test calls top.up()
This results in a call to ProtocolAdapter.up(), which in turn calls the r.receive() method of the simulator instance. This is a callback which the client defines.
See the test case FCTest.java for an example of using the Simulator to test the FC protocol in isolation.
Extension to simulation of failures
In its present state, messages are transported from one JChannel (Simulator instance) to another by the send_thread, which moves messages from send_queue to recv_queue in a reliable fashion. Futhermore, all Simulators perform at the same speed.
We would like to use the Simulator to additionally simulate failures, in order to check the robustness of the protocols:
dropped, reordered, corrupted messages
For example, each Simulator could have methods associated with it which could be used to dynamically modify its behaviour during a test:
In the case of simulating network problems, a Transport class could be used which drops/corrupts/reorders specific messages in a predicatble and repeatable fashion - by making use of state machine descriptions of faulty behaviour. The send_thread could then simply call transport.send() to take messages from send_queue and pass them to other JChannels (simulators). The recv_thread could similarly call transport.recv(). All fault injection would be confined to the Transport class.
In the case of simulating slow processes, send_threads and receive_threads could have delays built in to make them appear to be slow.