package lsr.paxos; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.util.BitSet; import lsr.common.ProcessDescriptor; import lsr.common.ProcessDescriptorHelper; import lsr.paxos.messages.Message; import lsr.paxos.network.Network; import lsr.paxos.recovery.MockDispatcher; import org.junit.Before; import org.junit.Test; public class RetransmitterTest { private static final int RETRANSMIT_TIMEOUT = 10000; private static final int N_PROCESSES = 3; private Retransmitter retransmitter; private Network network; private MockDispatcher dispatcher; private Message message1; private Message message2; private Message message3; private BitSet all; @Before public void setUp() { ProcessDescriptorHelper.initialize(3, 0); all = new BitSet(); all.set(0, N_PROCESSES); network = mock(Network.class); dispatcher = new MockDispatcher(); retransmitter = new Retransmitter(network, N_PROCESSES, dispatcher); message1 = mock(Message.class); message2 = mock(Message.class); message3 = mock(Message.class); } @Test public void shouldSendMessageToAllExceptItself() { retransmitter.startTransmitting(message1); all.clear(ProcessDescriptor.getInstance().localId); verify(network, times(1)).sendMessage(message1, all); } @Test public void shouldSendMessageToSpecifiedDestinations() { BitSet destinations = new BitSet(); destinations.set(0, 2); retransmitter.startTransmitting(message1, destinations); verify(network, times(1)).sendMessage(message1, destinations); } @Test public void shouldRetransmitMessageAfterTimeout() { retransmitter.startTransmitting(message1, all); dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); verify(network, times(2)).sendMessage(message1, all); } @Test public void shouldStopAll() { retransmitter.startTransmitting(message1, all); retransmitter.stopAll(); dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); verify(network, times(1)).sendMessage(message1, all); } @Test public void shouldAllowToRetransmitMultipleMessages() { // start transmitting 3 messages retransmitter.startTransmitting(message1, all); retransmitter.startTransmitting(message2, all); retransmitter.startTransmitting(message3, all); verify(network, times(1)).sendMessage(message1, all); verify(network, times(1)).sendMessage(message2, all); verify(network, times(1)).sendMessage(message3, all); // simulate waiting RETRANSMIT_TIMEOUT ms dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); // all messages are send twice: at the beginning and after timeout verify(network, times(2)).sendMessage(message1, all); verify(network, times(2)).sendMessage(message2, all); verify(network, times(2)).sendMessage(message3, all); } @Test public void shouldStopRetransmittingSingleMessage() { // start transmitting 3 messages retransmitter.startTransmitting(message1, all); RetransmittedMessage handler = retransmitter.startTransmitting(message2, all); retransmitter.startTransmitting(message3, all); verify(network, times(1)).sendMessage(message1, all); verify(network, times(1)).sendMessage(message2, all); verify(network, times(1)).sendMessage(message3, all); // stop retransmitting message 2 handler.stop(); // simulate waiting RETRANSMIT_TIMEOUT ms dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); // message 2 shouldn't be retransmitted verify(network, times(2)).sendMessage(message1, all); verify(network, times(1)).sendMessage(message2, all); verify(network, times(2)).sendMessage(message3, all); } @Test public void shouldStopRetransmittingToSpecifiedDestination() { // start transmitting message RetransmittedMessage handler = retransmitter.startTransmitting(message1, all); verify(network, times(1)).sendMessage(message1, all); reset(network); // stop retransmitting to replica with id = 1 handler.stop(1); // simulate waiting RETRANSMIT_TIMEOUT ms dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); all.clear(1); verify(network, times(1)).sendMessage(message1, all); } @Test public void shouldStartTransmittingMessageAgain() { // start transmitting message RetransmittedMessage handler = retransmitter.startTransmitting(message1, all); verify(network, times(1)).sendMessage(message1, all); reset(network); // stop retransmitting to replica with id = 1 handler.stop(1); // simulate waiting RETRANSMIT_TIMEOUT ms dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); all.clear(1); verify(network, times(1)).sendMessage(message1, all); handler.start(1); // simulate waiting RETRANSMIT_TIMEOUT ms dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); all.set(1); verify(network, times(2)).sendMessage(message1, all); } @Test public void shouldNotStartRetransmissionAgain() { // start transmitting message RetransmittedMessage handler = retransmitter.startTransmitting(message1, all); verify(network, times(1)).sendMessage(message1, all); reset(network); // stop retransmitting to replica with id = 1 handler.stop(); // simulate waiting RETRANSMIT_TIMEOUT ms dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); handler.start(1); // simulate waiting RETRANSMIT_TIMEOUT ms dispatcher.advanceTime(RETRANSMIT_TIMEOUT); dispatcher.execute(); verify(network, times(0)).sendMessage(message1, all); } }