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);
}
}