package net.pterodactylus.sone.core; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import net.pterodactylus.sone.data.Sone; import freenet.keys.FreenetURI; import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; /** * Unit test for {@link SoneRescuer}. * * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a> */ public class SoneRescuerTest { private static final long CURRENT_EDITION = 12L; private static final long SOME_OTHER_EDITION = 15L; private final Core core = mock(Core.class); private final SoneDownloader soneDownloader = mock(SoneDownloader.class); private final Sone sone = mock(Sone.class); private SoneRescuer soneRescuer; @Before public void setupSone() { FreenetURI soneUri = mock(FreenetURI.class); when(soneUri.getEdition()).thenReturn(CURRENT_EDITION); when(sone.getRequestUri()).thenReturn(soneUri); } @Before public void setupSoneRescuer() { soneRescuer = new SoneRescuer(core, soneDownloader, sone); } @Test public void newSoneRescuerIsNotFetchingAnything() { assertThat(soneRescuer.isFetching(), is(false)); } @Test public void newSoneRescuerStartsAtCurrentEditionOfSone() { assertThat(soneRescuer.getCurrentEdition(), is(CURRENT_EDITION)); } @Test public void newSoneRescuerHasANextEditionToGet() { assertThat(soneRescuer.hasNextEdition(), is(true)); } @Test public void soneRescuerDoesNotHaveANextEditionIfCurrentEditionIsZero() { when(sone.getRequestUri().getEdition()).thenReturn(0L); soneRescuer = new SoneRescuer(core, soneDownloader, sone); assertThat(soneRescuer.hasNextEdition(), is(false)); } @Test public void nextEditionIsOneSmallerThanTheCurrentEdition() { assertThat(soneRescuer.getNextEdition(), is(CURRENT_EDITION - 1)); } @Test public void currentEditionCanBeSet() { soneRescuer.setEdition(SOME_OTHER_EDITION); assertThat(soneRescuer.getCurrentEdition(), is(SOME_OTHER_EDITION)); } @Test public void lastFetchOfANewSoneRescuerWasSuccessful() { assertThat(soneRescuer.isLastFetchSuccessful(), is(true)); } @Test public void mainLoopStopsWhenItShould() { soneRescuer.stop(); soneRescuer.serviceRun(); } @Test public void successfulInsert() { final Sone fetchedSone = mock(Sone.class); returnUriOnInsert(fetchedSone); soneRescuer.startNextFetch(); soneRescuer.serviceRun(); verify(core).lockSone(eq(sone)); verify(core).updateSone(eq(fetchedSone), eq(true)); assertThat(soneRescuer.isLastFetchSuccessful(), is(true)); assertThat(soneRescuer.isFetching(), is(false)); } @Test public void nonSuccessfulInsertIsRecognized() { returnUriOnInsert(null); soneRescuer.startNextFetch(); soneRescuer.serviceRun(); verify(core).lockSone(eq(sone)); verify(core, never()).updateSone(any(Sone.class), eq(true)); assertThat(soneRescuer.isLastFetchSuccessful(), is(false)); assertThat(soneRescuer.isFetching(), is(false)); } private void returnUriOnInsert(final Sone fetchedSone) { FreenetURI keyWithMetaStrings = setupFreenetUri(); doAnswer(new Answer<Sone>() { @Override public Sone answer(InvocationOnMock invocation) throws Throwable { soneRescuer.stop(); return fetchedSone; } }).when(soneDownloader).fetchSone(eq(sone), eq(keyWithMetaStrings), eq(true)); } private FreenetURI setupFreenetUri() { FreenetURI sskKey = mock(FreenetURI.class); FreenetURI keyWithDocName = mock(FreenetURI.class); FreenetURI keyWithMetaStrings = mock(FreenetURI.class); when(keyWithDocName.setMetaString(eq(new String[] { "sone.xml" }))).thenReturn(keyWithMetaStrings); when(sskKey.setDocName(eq("Sone-" + CURRENT_EDITION))).thenReturn(keyWithDocName); when(sone.getRequestUri().setKeyType(eq("SSK"))).thenReturn(sskKey); return keyWithMetaStrings; } }