package lsr.paxos; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import lsr.common.ProcessDescriptorHelper; import lsr.paxos.recovery.MockDispatcher; import lsr.paxos.storage.Log; import lsr.paxos.storage.Storage; import org.junit.Before; import org.junit.Test; public class SnapshotMaintainerTest { private Storage storage; private Log log; private MockDispatcher dispatcher; private SnapshotProvider snapshotProvider; private SnapshotMaintainer snapshotMaintainer; @Before public void setUp() { ProcessDescriptorHelper.initialize(3, 0); storage = mock(Storage.class); log = mock(Log.class); when(storage.getLog()).thenReturn(log); dispatcher = new MockDispatcher(); snapshotProvider = mock(SnapshotProvider.class); snapshotMaintainer = new SnapshotMaintainer(storage, dispatcher, snapshotProvider); dispatcher.forceBeingInDispatcher(); } @Test public void shouldHandleFirstSnapshot() { Snapshot snapshot = new Snapshot(); snapshot.setNextInstanceId(10); snapshot.setValue(new byte[] {1, 2, 3, 4}); snapshotMaintainer.onSnapshotMade(snapshot); dispatcher.execute(); verify(storage).setLastSnapshot(snapshot); verify(log).truncateBelow(0); } @Test public void shouldHandleNextSnapshot() { Snapshot lastSnapshot = new Snapshot(); lastSnapshot.setNextInstanceId(5); when(storage.getLastSnapshot()).thenReturn(lastSnapshot); Snapshot snapshot = new Snapshot(); snapshot.setNextInstanceId(10); snapshot.setValue(new byte[] {1, 2, 3, 4}); snapshotMaintainer.onSnapshotMade(snapshot); dispatcher.execute(); verify(storage).setLastSnapshot(snapshot); verify(log).truncateBelow(5); } @Test public void shouldIgnoreOlderSnapshots() { Snapshot lastSnapshot = new Snapshot(); lastSnapshot.setNextInstanceId(10); when(storage.getLastSnapshot()).thenReturn(lastSnapshot); Snapshot snapshot = new Snapshot(); snapshot.setNextInstanceId(5); snapshot.setValue(new byte[] {1, 2, 3, 4}); snapshotMaintainer.onSnapshotMade(snapshot); dispatcher.execute(); verify(storage).getLastSnapshot(); verifyNoMoreInteractions(storage); verifyNoMoreInteractions(log); } @Test public void shouldAskForSnapshot() { when(log.getNextId()).thenReturn(50); when(log.byteSizeBetween(anyInt(), anyInt())).thenReturn((long) 20000); snapshotMaintainer.logSizeChanged(1); verify(snapshotProvider).askForSnapshot(); } @Test public void shouldNotAskForSnapshotIfLogIsTooSmall() { when(log.getNextId()).thenReturn(10); when(log.byteSizeBetween(anyInt(), anyInt())).thenReturn((long) 20000); snapshotMaintainer.logSizeChanged(1); verifyZeroInteractions(snapshotProvider); } @Test public void shouldNotAskForSnapshotIfLogByteSizeIsTooSmall() { when(log.getNextId()).thenReturn(50); when(log.byteSizeBetween(anyInt(), anyInt())).thenReturn((long) 10000); snapshotMaintainer.logSizeChanged(1); verifyZeroInteractions(snapshotProvider); } @Test public void shouldForceSnapshot() { when(log.getNextId()).thenReturn(50); when(log.byteSizeBetween(anyInt(), anyInt())).thenReturn((long) 20000); snapshotMaintainer.logSizeChanged(1); when(log.getNextId()).thenReturn(100); snapshotMaintainer.logSizeChanged(1); verify(snapshotProvider).forceSnapshot(); } @Test public void shouldForceSnapshotOnlyOnce() { when(log.getNextId()).thenReturn(50); when(log.byteSizeBetween(anyInt(), anyInt())).thenReturn((long) 20000); snapshotMaintainer.logSizeChanged(1); when(log.getNextId()).thenReturn(100); snapshotMaintainer.logSizeChanged(1); verify(snapshotProvider).askForSnapshot(); verify(snapshotProvider).forceSnapshot(); when(log.getNextId()).thenReturn(150); snapshotMaintainer.logSizeChanged(1); verifyNoMoreInteractions(snapshotProvider); } @Test public void shouldWaitBetweenAskAndForceSnapshot() { when(log.getNextId()).thenReturn(50); when(log.byteSizeBetween(anyInt(), anyInt())).thenReturn((long) 20000); snapshotMaintainer.logSizeChanged(10); verify(snapshotProvider).askForSnapshot(); when(log.getNextId()).thenReturn(51); snapshotMaintainer.logSizeChanged(1); verifyNoMoreInteractions(snapshotProvider); } @Test public void shouldStartAskingAgainAfterReceivingNewSnapshot() { when(log.getNextId()).thenReturn(50); when(log.byteSizeBetween(anyInt(), anyInt())).thenReturn((long) 20000); snapshotMaintainer.logSizeChanged(1); when(log.getNextId()).thenReturn(100); snapshotMaintainer.logSizeChanged(1); reset(snapshotProvider); Snapshot snapshot = new Snapshot(); snapshot.setNextInstanceId(10); snapshot.setValue(new byte[] {1, 2, 3, 4}); snapshotMaintainer.onSnapshotMade(snapshot); dispatcher.execute(); when(log.getNextId()).thenReturn(150); snapshotMaintainer.logSizeChanged(1); verify(snapshotProvider).askForSnapshot(); } }