🎨 Replace SoneInserterTest with Kotlin version
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 31 Jul 2019 04:53:40 +0000 (06:53 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 31 Jul 2019 04:54:26 +0000 (06:54 +0200)
src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java [deleted file]
src/test/kotlin/net/pterodactylus/sone/core/SoneInserterTest.kt [new file with mode: 0644]

diff --git a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java b/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java
deleted file mode 100644 (file)
index f990500..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-package net.pterodactylus.sone.core;
-
-import static com.google.common.io.ByteStreams.toByteArray;
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static java.lang.System.currentTimeMillis;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.nullValue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-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.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.hamcrest.MockitoHamcrest.argThat;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import net.pterodactylus.sone.core.SoneInserter.ManifestCreator;
-import net.pterodactylus.sone.core.event.InsertionDelayChangedEvent;
-import net.pterodactylus.sone.core.event.SoneEvent;
-import net.pterodactylus.sone.core.event.SoneInsertAbortedEvent;
-import net.pterodactylus.sone.core.event.SoneInsertedEvent;
-import net.pterodactylus.sone.core.event.SoneInsertingEvent;
-import net.pterodactylus.sone.data.Album;
-import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.main.SonePlugin;
-
-import freenet.keys.FreenetURI;
-import freenet.support.api.ManifestElement;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.eventbus.AsyncEventBus;
-import com.google.common.eventbus.EventBus;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-/**
- * Unit test for {@link SoneInserter} and its subclasses.
- */
-public class SoneInserterTest {
-
-       private final Core core = mock(Core.class);
-       private final EventBus eventBus = mock(EventBus.class);
-       private final FreenetInterface freenetInterface = mock(FreenetInterface.class);
-
-       @Before
-       public void setupCore() {
-               UpdateChecker updateChecker = mock(UpdateChecker.class);
-               when(core.getUpdateChecker()).thenReturn(updateChecker);
-               when(core.getSone(anyString())).thenReturn(null);
-       }
-
-       @Test
-       public void insertionDelayIsForwardedToSoneInserter() {
-               EventBus eventBus = new AsyncEventBus(directExecutor());
-               eventBus.register(new SoneInserter(core, eventBus, freenetInterface, "SoneId"));
-               eventBus.post(new InsertionDelayChangedEvent(15));
-               assertThat(SoneInserter.getInsertionDelay().get(), is(15));
-       }
-
-       private Sone createSone(FreenetURI insertUri, String fingerprint) {
-               Sone sone = mock(Sone.class);
-               when(sone.getInsertUri()).thenReturn(insertUri);
-               when(sone.getFingerprint()).thenReturn(fingerprint);
-               when(sone.getRootAlbum()).thenReturn(mock(Album.class));
-               when(core.getSone(anyString())).thenReturn(sone);
-               return sone;
-       }
-
-       @Test
-       public void isModifiedIsTrueIfModificationDetectorSaysSo() {
-               SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
-               when(soneModificationDetector.isModified()).thenReturn(true);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
-               assertThat(soneInserter.isModified(), is(true));
-       }
-
-       @Test
-       public void isModifiedIsFalseIfModificationDetectorSaysSo() {
-               SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
-               assertThat(soneInserter.isModified(), is(false));
-       }
-
-       @Test
-       public void lastFingerprintIsStoredCorrectly() {
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId");
-               soneInserter.setLastInsertFingerprint("last-fingerprint");
-               assertThat(soneInserter.getLastInsertFingerprint(), is("last-fingerprint"));
-       }
-
-       @Test
-       public void soneInserterStopsWhenItShould() {
-               SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId");
-               soneInserter.stop();
-               soneInserter.serviceRun();
-       }
-
-       @Test
-       public void soneInserterInsertsASoneIfItIsEligible() throws SoneException {
-               FreenetURI insertUri = mock(FreenetURI.class);
-               final FreenetURI finalUri = mock(FreenetURI.class);
-               String fingerprint = "fingerprint";
-               Sone sone = createSone(insertUri, fingerprint);
-               SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
-               when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
-               when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenReturn(finalUri);
-               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
-               doAnswer(new Answer<Void>() {
-                       @Override
-                       public Void answer(InvocationOnMock invocation) throws Throwable {
-                               soneInserter.stop();
-                               return null;
-                       }
-               }).when(core).touchConfiguration();
-               soneInserter.serviceRun();
-               ArgumentCaptor<SoneEvent> soneEvents = ArgumentCaptor.forClass(SoneEvent.class);
-               verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"));
-               verify(eventBus, times(2)).post(soneEvents.capture());
-               assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class));
-               assertThat(soneEvents.getAllValues().get(0).getSone(), is(sone));
-               assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertedEvent.class));
-               assertThat(soneEvents.getAllValues().get(1).getSone(), is(sone));
-       }
-
-       @Test
-       public void soneInserterBailsOutIfItIsStoppedWhileInserting() throws SoneException {
-               FreenetURI insertUri = mock(FreenetURI.class);
-               final FreenetURI finalUri = mock(FreenetURI.class);
-               String fingerprint = "fingerprint";
-               Sone sone = createSone(insertUri, fingerprint);
-               SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
-               when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
-               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
-               when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenAnswer(new Answer<FreenetURI>() {
-                       @Override
-                       public FreenetURI answer(InvocationOnMock invocation) throws Throwable {
-                               soneInserter.stop();
-                               return finalUri;
-                       }
-               });
-               soneInserter.serviceRun();
-               ArgumentCaptor<SoneEvent> soneEvents = ArgumentCaptor.forClass(SoneEvent.class);
-               verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"));
-               verify(eventBus, times(2)).post(soneEvents.capture());
-               assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class));
-               assertThat(soneEvents.getAllValues().get(0).getSone(), is(sone));
-               assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertedEvent.class));
-               assertThat(soneEvents.getAllValues().get(1).getSone(), is(sone));
-               verify(core, never()).touchConfiguration();
-       }
-
-       @Test
-       public void soneInserterDoesNotInsertSoneIfItIsNotEligible() throws SoneException {
-               FreenetURI insertUri = mock(FreenetURI.class);
-               String fingerprint = "fingerprint";
-               Sone sone = createSone(insertUri, fingerprint);
-               SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
-               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
-               new Thread(new Runnable() {
-                       @Override
-                       public void run() {
-                               try {
-                                       Thread.sleep(500);
-                               } catch (InterruptedException ie1) {
-                                       throw new RuntimeException(ie1);
-                               }
-                               soneInserter.stop();
-                       }
-               }).start();
-               soneInserter.serviceRun();
-               verify(freenetInterface, never()).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"));
-               verify(eventBus, never()).post(argThat(org.hamcrest.Matchers.any(SoneEvent.class)));
-       }
-
-       @Test
-       public void soneInserterPostsAbortedEventIfAnExceptionOccurs() throws SoneException {
-               FreenetURI insertUri = mock(FreenetURI.class);
-               String fingerprint = "fingerprint";
-               Sone sone = createSone(insertUri, fingerprint);
-               SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
-               when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
-               final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
-               final SoneException soneException = new SoneException(new Exception());
-               when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenAnswer(new Answer<FreenetURI>() {
-                       @Override
-                       public FreenetURI answer(InvocationOnMock invocation) throws Throwable {
-                               soneInserter.stop();
-                               throw soneException;
-                       }
-               });
-               soneInserter.serviceRun();
-               ArgumentCaptor<SoneEvent> soneEvents = ArgumentCaptor.forClass(SoneEvent.class);
-               verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"));
-               verify(eventBus, times(2)).post(soneEvents.capture());
-               assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class));
-               assertThat(soneEvents.getAllValues().get(0).getSone(), is(sone));
-               assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertAbortedEvent.class));
-               assertThat(soneEvents.getAllValues().get(1).getSone(), is(sone));
-               verify(core, never()).touchConfiguration();
-       }
-
-       @Test
-       public void soneInserterExitsIfSoneIsUnknown() {
-               SoneModificationDetector soneModificationDetector =
-                               mock(SoneModificationDetector.class);
-               SoneInserter soneInserter =
-                               new SoneInserter(core, eventBus, freenetInterface, "SoneId",
-                                               soneModificationDetector, 1);
-               when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
-               when(core.getSone("SoneId")).thenReturn(null);
-               soneInserter.serviceRun();
-       }
-
-       @Test
-       public void soneInserterCatchesExceptionAndContinues() {
-               SoneModificationDetector soneModificationDetector =
-                               mock(SoneModificationDetector.class);
-               final SoneInserter soneInserter =
-                               new SoneInserter(core, eventBus, freenetInterface, "SoneId",
-                                               soneModificationDetector, 1);
-               Answer<Optional<Sone>> stopInserterAndThrowException =
-                               new Answer<Optional<Sone>>() {
-                                       @Override
-                                       public Optional<Sone> answer(
-                                                       InvocationOnMock invocation) {
-                                               soneInserter.stop();
-                                               throw new NullPointerException();
-                                       }
-                               };
-               when(soneModificationDetector.isEligibleForInsert()).thenAnswer(
-                               stopInserterAndThrowException);
-               soneInserter.serviceRun();
-       }
-
-       @Test
-       public void templateIsRenderedCorrectlyForManifestElement()
-       throws IOException {
-               Map<String, Object> soneProperties = new HashMap<>();
-               soneProperties.put("id", "SoneId");
-               ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties);
-               long now = currentTimeMillis();
-               when(core.getStartupTime()).thenReturn(now);
-               ManifestElement manifestElement = manifestCreator.createManifestElement("test.txt", "plain/text; charset=utf-8", "sone-inserter-manifest.txt");
-               assertThat(manifestElement.getName(), is("test.txt"));
-               assertThat(manifestElement.getMimeTypeOverride(), is("plain/text; charset=utf-8"));
-               String templateContent = new String(toByteArray(manifestElement.getData().getInputStream()), Charsets.UTF_8);
-               assertThat(templateContent, containsString("Sone Version: " + SonePlugin.getPluginVersion() + "\n"));
-               assertThat(templateContent, containsString("Core Startup: " + now + "\n"));
-               assertThat(templateContent, containsString("Sone ID: " + "SoneId" + "\n"));
-       }
-
-       @Test
-       public void invalidTemplateReturnsANullManifestElement() {
-               Map<String, Object> soneProperties = new HashMap<>();
-               ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties);
-               assertThat(manifestCreator.createManifestElement("test.txt",
-                               "plain/text; charset=utf-8",
-                               "sone-inserter-invalid-manifest.txt"),
-                               nullValue());
-       }
-
-       @Test
-       public void errorWhileRenderingTemplateReturnsANullManifestElement() {
-               Map<String, Object> soneProperties = new HashMap<>();
-               ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties);
-               when(core.toString()).thenThrow(NullPointerException.class);
-               assertThat(manifestCreator.createManifestElement("test.txt",
-                               "plain/text; charset=utf-8",
-                               "sone-inserter-faulty-manifest.txt"),
-                               nullValue());
-       }
-
-}
diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneInserterTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneInserterTest.kt
new file mode 100644 (file)
index 0000000..e541915
--- /dev/null
@@ -0,0 +1,239 @@
+package net.pterodactylus.sone.core
+
+import com.google.common.base.*
+import com.google.common.base.Optional
+import com.google.common.eventbus.*
+import com.google.common.io.ByteStreams.*
+import com.google.common.util.concurrent.MoreExecutors.*
+import freenet.keys.*
+import net.pterodactylus.sone.core.SoneInserter.*
+import net.pterodactylus.sone.core.event.*
+import net.pterodactylus.sone.data.*
+import net.pterodactylus.sone.main.*
+import net.pterodactylus.sone.test.*
+import org.hamcrest.MatcherAssert.*
+import org.hamcrest.Matchers.*
+import org.junit.*
+import org.mockito.*
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.hamcrest.MockitoHamcrest.*
+import org.mockito.stubbing.*
+import java.lang.System.*
+import java.util.*
+
+/**
+ * Unit test for [SoneInserter] and its subclasses.
+ */
+class SoneInserterTest {
+
+       private val core = mock<Core>()
+       private val eventBus = mock<EventBus>()
+       private val freenetInterface = mock<FreenetInterface>()
+
+       @Before
+       fun setupCore() {
+               val updateChecker = mock<UpdateChecker>()
+               whenever(core.updateChecker).thenReturn(updateChecker)
+               whenever(core.getSone(anyString())).thenReturn(null)
+       }
+
+       @Test
+       fun `insertion delay is forwarded to sone inserter`() {
+               val eventBus = AsyncEventBus(directExecutor())
+               eventBus.register(SoneInserter(core, eventBus, freenetInterface, "SoneId"))
+               eventBus.post(InsertionDelayChangedEvent(15))
+               assertThat(SoneInserter.getInsertionDelay().get(), equalTo(15))
+       }
+
+       private fun createSone(insertUri: FreenetURI, fingerprint: String = "fingerprint"): Sone {
+               val sone = mock<Sone>()
+               whenever(sone.insertUri).thenReturn(insertUri)
+               whenever(sone.fingerprint).thenReturn(fingerprint)
+               whenever(sone.rootAlbum).thenReturn(mock())
+               whenever(core.getSone(anyString())).thenReturn(sone)
+               return sone
+       }
+
+       @Test
+       fun `isModified is true if modification detector says so`() {
+               val soneModificationDetector = mock<SoneModificationDetector>()
+               whenever(soneModificationDetector.isModified).thenReturn(true)
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
+               assertThat(soneInserter.isModified, equalTo(true))
+       }
+
+       @Test
+       fun `isModified is false if modification detector says so`() {
+               val soneModificationDetector = mock<SoneModificationDetector>()
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
+               assertThat(soneInserter.isModified, equalTo(false))
+       }
+
+       @Test
+       fun `last fingerprint is stored correctly`() {
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId")
+               soneInserter.lastInsertFingerprint = "last-fingerprint"
+               assertThat(soneInserter.lastInsertFingerprint, equalTo("last-fingerprint"))
+       }
+
+       @Test
+       fun `sone inserter stops when it should`() {
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId")
+               soneInserter.stop()
+               soneInserter.serviceRun()
+       }
+
+       @Test
+       fun `sone inserter inserts a sone if it is eligible`() {
+               val insertUri = mock<FreenetURI>()
+               val finalUri = mock<FreenetURI>()
+               val sone = createSone(insertUri)
+               val soneModificationDetector = mock<SoneModificationDetector>()
+               whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true)
+               whenever(freenetInterface.insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))).thenReturn(finalUri)
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
+               doAnswer {
+                       soneInserter.stop()
+                       null
+               }.`when`(core).touchConfiguration()
+               soneInserter.serviceRun()
+               val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java)
+               verify(freenetInterface).insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))
+               verify(eventBus, times(2)).post(soneEvents.capture())
+               assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java))
+               assertThat(soneEvents.allValues[0].sone, equalTo(sone))
+               assertThat(soneEvents.allValues[1], instanceOf(SoneInsertedEvent::class.java))
+               assertThat(soneEvents.allValues[1].sone, equalTo(sone))
+       }
+
+       @Test
+       fun `sone inserter bails out if it is stopped while inserting`() {
+               val insertUri = mock<FreenetURI>()
+               val finalUri = mock<FreenetURI>()
+               val sone = createSone(insertUri)
+               val soneModificationDetector = mock<SoneModificationDetector>()
+               whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true)
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
+               whenever(freenetInterface.insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))).thenAnswer {
+                       soneInserter.stop()
+                       finalUri
+               }
+               soneInserter.serviceRun()
+               val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java)
+               verify(freenetInterface).insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))
+               verify(eventBus, times(2)).post(soneEvents.capture())
+               assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java))
+               assertThat(soneEvents.allValues[0].sone, equalTo(sone))
+               assertThat(soneEvents.allValues[1], instanceOf(SoneInsertedEvent::class.java))
+               assertThat(soneEvents.allValues[1].sone, equalTo(sone))
+               verify(core, never()).touchConfiguration()
+       }
+
+       @Test
+       fun `sone inserter does not insert sone if it is not eligible`() {
+               val insertUri = mock<FreenetURI>()
+               createSone(insertUri)
+               val soneModificationDetector = mock<SoneModificationDetector>()
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
+               Thread(Runnable {
+                       try {
+                               Thread.sleep(500)
+                       } catch (ie1: InterruptedException) {
+                               throw RuntimeException(ie1)
+                       }
+
+                       soneInserter.stop()
+               }).start()
+               soneInserter.serviceRun()
+               verify(freenetInterface, never()).insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))
+               verify(eventBus, never()).post(argThat(org.hamcrest.Matchers.any(SoneEvent::class.java)))
+       }
+
+       @Test
+       fun `sone inserter posts aborted event if an exception occurs`() {
+               val insertUri = mock<FreenetURI>()
+               val sone = createSone(insertUri)
+               val soneModificationDetector = mock<SoneModificationDetector>()
+               whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true)
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
+               val soneException = SoneException(Exception())
+               whenever(freenetInterface.insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))).thenAnswer {
+                       soneInserter.stop()
+                       throw soneException
+               }
+               soneInserter.serviceRun()
+               val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java)
+               verify(freenetInterface).insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))
+               verify(eventBus, times(2)).post(soneEvents.capture())
+               assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java))
+               assertThat(soneEvents.allValues[0].sone, equalTo(sone))
+               assertThat(soneEvents.allValues[1], instanceOf(SoneInsertAbortedEvent::class.java))
+               assertThat(soneEvents.allValues[1].sone, equalTo(sone))
+               verify(core, never()).touchConfiguration()
+       }
+
+       @Test
+       fun `sone inserter exits if sone is unknown`() {
+               val soneModificationDetector = mock<SoneModificationDetector>()
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
+               whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true)
+               whenever(core.getSone("SoneId")).thenReturn(null)
+               soneInserter.serviceRun()
+       }
+
+       @Test
+       fun `sone inserter catches exception and continues`() {
+               val soneModificationDetector = mock<SoneModificationDetector>()
+               val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
+               val stopInserterAndThrowException = Answer<Optional<Sone>> {
+                       soneInserter.stop()
+                       throw NullPointerException()
+               }
+               whenever(soneModificationDetector.isEligibleForInsert).thenAnswer(stopInserterAndThrowException)
+               soneInserter.serviceRun()
+       }
+
+       @Test
+       fun `template is rendered correctly for manifest element`() {
+               val soneProperties = HashMap<String, Any>()
+               soneProperties["id"] = "SoneId"
+               val manifestCreator = ManifestCreator(core, soneProperties)
+               val now = currentTimeMillis()
+               whenever(core.startupTime).thenReturn(now)
+               val manifestElement = manifestCreator.createManifestElement("test.txt", "plain/text; charset=utf-8", "sone-inserter-manifest.txt")
+               assertThat(manifestElement!!.name, equalTo("test.txt"))
+               assertThat(manifestElement.mimeTypeOverride, equalTo("plain/text; charset=utf-8"))
+               val templateContent = String(toByteArray(manifestElement.data.inputStream), Charsets.UTF_8)
+               assertThat(templateContent, containsString("Sone Version: ${SonePlugin.getPluginVersion()}\n"))
+               assertThat(templateContent, containsString("Core Startup: $now\n"))
+               assertThat(templateContent, containsString("Sone ID: SoneId\n"))
+       }
+
+       @Test
+       fun `invalid template returns anull manifest element`() {
+               val soneProperties = HashMap<String, Any>()
+               val manifestCreator = ManifestCreator(core, soneProperties)
+               assertThat(manifestCreator.createManifestElement("test.txt",
+                               "plain/text; charset=utf-8",
+                               "sone-inserter-invalid-manifest.txt"),
+                               nullValue())
+       }
+
+       @Test
+       fun `error while rendering template returns a null manifest element`() {
+               val soneProperties = HashMap<String, Any>()
+               val manifestCreator = ManifestCreator(core, soneProperties)
+               whenever(core.toString()).thenThrow(NullPointerException::class.java)
+               assertThat(manifestCreator.createManifestElement("test.txt",
+                               "plain/text; charset=utf-8",
+                               "sone-inserter-faulty-manifest.txt"),
+                               nullValue())
+       }
+
+}