@Test public void shouldResumePullingUpdatesWhenThisInstanceSwitchesFromMasterToSlave() throws Throwable { // GIVEN final UpdatePullerClient puller = new UpdatePullerClient(1, scheduler, logging, updatePuller, availabilityGuard); // WHEN puller.init(); puller.start(); updatePuller.unpause(); scheduler.runJob(); // THEN verify(lastUpdateTime, times(1)).setLastUpdateTime(anyLong()); verify(availabilityGuard, times(1)).isAvailable(anyLong()); verify(master, times(1)).pullUpdates(Matchers.<RequestContext>any()); stateMachine.masterIsElected(); // pauses the update puller // This job should be ignored, since I'm now master scheduler.runJob(); updatePuller.unpause(); scheduler.runJob(); verify(lastUpdateTime, times(2)).setLastUpdateTime(anyLong()); verify(availabilityGuard, times(2)).isAvailable(anyLong()); verify(master, times(2)).pullUpdates(Matchers.<RequestContext>any()); }
@Test public void shouldStartAndStopPullingUpdatesWhenStartAndStopIsCalled() throws Throwable { // GIVEN final UpdatePullerClient puller = new UpdatePullerClient(1, scheduler, logging, updatePuller, availabilityGuard); // WHEN puller.init(); // THEN // Asserts the puller set the job assertNotNull(scheduler.getJob()); puller.start(); updatePuller.unpause(); scheduler.runJob(); verify(lastUpdateTime, times(1)).setLastUpdateTime(anyLong()); verify(availabilityGuard, times(1)).isAvailable(anyLong()); verify(master, times(1)).pullUpdates(Matchers.<RequestContext>any()); updatePuller.stop(); scheduler.runJob(); verifyNoMoreInteractions(lastUpdateTime, availabilityGuard); }
@Before public void setup() throws Throwable { when(config.get(HaSettings.pull_interval)).thenReturn(1000l); when(config.get(ClusterSettings.server_id)).thenReturn(myId); when(availabilityGuard.isAvailable(anyLong())).thenReturn(true); updatePuller.init(); updatePuller.start(); }
@Test public void shouldReturnFalseIfPullerInitiallyInactiveNonStrict() throws Exception { // GIVEN Condition condition = mock(Condition.class); updatePuller.pause(); // WHEN boolean result = updatePuller.await(condition, false); // THEN assertFalse(result); verifyNoMoreInteractions(condition); }
@Test public void shouldThrowIfPullerInitiallyInactiveStrict() throws Exception { // GIVEN Condition condition = mock(Condition.class); updatePuller.pause(); // WHEN try { updatePuller.await(condition, true); fail("Should have thrown"); } catch (IllegalStateException e) { // THEN Good verifyNoMoreInteractions(condition); } }
@Test public void shouldResumePullingUpdatesWhenThisInstanceSwitchesFromSlaveToMaster() throws Throwable { final UpdatePullerClient puller = new UpdatePullerClient(1, scheduler, logging, updatePuller, availabilityGuard); puller.init(); puller.start(); updatePuller.unpause(); scheduler.runJob(); verify(lastUpdateTime, times(1)).setLastUpdateTime(anyLong()); verify(availabilityGuard, times(1)).isAvailable(anyLong()); verify(master, times(1)).pullUpdates(Matchers.<RequestContext>any()); scheduler.runJob(); verify(lastUpdateTime, times(2)).setLastUpdateTime(anyLong()); verify(availabilityGuard, times(2)).isAvailable(anyLong()); verify(master, times(2)).pullUpdates(Matchers.<RequestContext>any()); stateMachine.masterIsElected(); // pauses the update puller verifyNoMoreInteractions(lastUpdateTime, availabilityGuard); }
/** * Triggers pulling of updates up until at least {@code toTxId} if no pulling is currently * happening and returns immediately. * * @return {@link Future} which will block on {@link Future#get()} until {@code toTxId} has been * applied. */ @Override public void fulfill(final long toTxId) throws InterruptedException { if (!updatePuller.isActive()) { throw new IllegalStateException("Update puller not active " + updatePuller); } updatePuller.await( new Condition() { @Override public boolean evaluate(int currentTicket, int targetTicket) { /** * We need to await last *closed* transaction id, not last *committed* transaction id * since right after leaving this method we might read records off of disk, and they had * better be up to date, otherwise we read stale data. */ return transactionIdStore.getLastClosedTransactionId() >= toTxId; } }); }
@Test public void shouldReturnFalseIfPullerBecomesInactiveWhileWaitingNonStrict() throws Exception { // GIVEN Condition condition = mock(Condition.class); updatePuller.unpause(); when(condition.evaluate(anyInt(), anyInt())) .thenAnswer( new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock invocation) throws Throwable { updatePuller.pause(); return false; } }); // WHEN boolean result = updatePuller.await(condition, false); // THEN assertFalse(result); verify(condition, times(1)).evaluate(anyInt(), anyInt()); }
@Test public void shouldThrowIfPullerBecomesInactiveWhileWaitingStrict() throws Exception { // GIVEN Condition condition = mock(Condition.class); updatePuller.unpause(); when(condition.evaluate(anyInt(), anyInt())) .thenAnswer( new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock invocation) throws Throwable { updatePuller.pause(); return false; } }); // WHEN try { updatePuller.await(condition, true); fail("Should have thrown"); } catch (IllegalStateException e) { // THEN Good verify(condition, times(1)).evaluate(anyInt(), anyInt()); } }
@Test public void shouldKeepPullingUpdatesWhenThisInstanceBecomesASlave() throws Throwable { // GIVEN final UpdatePullerClient puller = new UpdatePullerClient(1, scheduler, logging, updatePuller, availabilityGuard); // WHEN puller.init(); puller.start(); updatePuller.unpause(); scheduler.runJob(); // THEN verify(lastUpdateTime, times(1)).setLastUpdateTime(anyLong()); verify(availabilityGuard, times(1)).isAvailable(anyLong()); verify(master, times(1)).pullUpdates(Matchers.<RequestContext>any()); scheduler.runJob(); verify(lastUpdateTime, times(2)).setLastUpdateTime(anyLong()); verify(availabilityGuard, times(2)).isAvailable(anyLong()); verify(master, times(2)).pullUpdates(Matchers.<RequestContext>any()); }