package lsr.paxos; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import java.util.logging.Level; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import lsr.common.ProcessDescriptorHelper; import lsr.paxos.messages.Accept; import lsr.paxos.recovery.MockDispatcher; import lsr.paxos.storage.ConsensusInstance; import lsr.paxos.storage.Log; import lsr.paxos.storage.Storage; import org.junit.Before; import org.junit.Test; public class LearnerTest { private MockDispatcher dispatcher; private Paxos paxos; private Proposer proposer; private Storage storage; private Learner learner; private Log log; @Before public void setUp() { Logger.getLogger(Learner.class.getCanonicalName()).setLevel(Level.ALL); ProcessDescriptorHelper.initialize(3, 0); dispatcher = new MockDispatcher(); dispatcher.forceBeingInDispatcher(); paxos = mock(Paxos.class); when(paxos.getDispatcher()).thenReturn(dispatcher); proposer = mock(Proposer.class); log = mock(Log.class); storage = mock(Storage.class); when(storage.getLog()).thenReturn(log); learner = new Learner(paxos, proposer, storage); when(storage.getView()).thenReturn(5); } @Test public void shouldInformProposerAboutNewAcceptIfLeader() { when(log.getInstance(10)).thenReturn(new ConsensusInstance(10)); when(paxos.isLeader()).thenReturn(true); Accept accept = new Accept(5, 10); learner.onAccept(accept, 1); verify(proposer).stopPropose(10, 1); } @Test public void shouldNotInformProposerAboutNewAcceptIfLeader() { when(log.getInstance(10)).thenReturn(new ConsensusInstance(10)); when(paxos.isLeader()).thenReturn(false); Accept accept = new Accept(5, 10); learner.onAccept(accept, 1); verifyZeroInteractions(proposer); } @Test public void shouldDecideIfReceivedAcceptFromMajority() { when(log.getInstance(10)).thenReturn(new ConsensusInstance(10)); log.getInstance(10).getAccepts().set(2); log.getInstance(10).setValue(5, new byte[] {1, 2, 3}); when(paxos.isLeader()).thenReturn(false); Accept accept = new Accept(5, 10); learner.onAccept(accept, 1); verifyZeroInteractions(proposer); verify(paxos).decide(10); } @Test public void shouldNotDecideIfInstanceValueIsUnknown() { when(log.getInstance(10)).thenReturn(new ConsensusInstance(10)); log.getInstance(10).getAccepts().set(2); log.getInstance(10).setValue(5, null); when(paxos.isLeader()).thenReturn(false); Accept accept = new Accept(5, 10); learner.onAccept(accept, 1); verifyZeroInteractions(proposer); verify(paxos, never()).decide(10); } @Test public void shouldIgnoreAcceptIfInstanceAlreadyDecided() { when(log.getInstance(10)).thenReturn(new ConsensusInstance(10)); log.getInstance(10).getAccepts().set(2); log.getInstance(10).setValue(5, new byte[] {1, 2, 3}); log.getInstance(10).setDecided(); when(paxos.isLeader()).thenReturn(true); Accept accept = new Accept(5, 10); learner.onAccept(accept, 1); verifyZeroInteractions(proposer); verify(paxos, never()).decide(10); } @Test public void shouldUpdateInstanceValueIfNewerView() { when(log.getInstance(10)).thenReturn(new ConsensusInstance(10)); log.getInstance(10).getAccepts().set(2); log.getInstance(10).setValue(3, new byte[] {1, 2, 3}); when(paxos.isLeader()).thenReturn(false); Accept accept = new Accept(5, 10); learner.onAccept(accept, 1); assertEquals(1, log.getInstance(10).getAccepts().cardinality()); assertEquals(true, log.getInstance(10).getAccepts().get(1)); assertEquals(null, log.getInstance(10).getValue()); assertEquals(5, log.getInstance(10).getView()); verifyZeroInteractions(proposer); verify(paxos, never()).decide(10); } @Test public void shouldIgnoreAcceptForTooOldInstances() { when(log.getInstance(10)).thenReturn(null); Accept accept = new Accept(5, 10); learner.onAccept(accept, 1); verifyZeroInteractions(proposer); verify(paxos, never()).decide(10); } }