1 package net.pterodactylus.sone.core
3 import com.google.common.base.*
4 import com.google.common.base.Optional
5 import com.google.common.eventbus.*
6 import com.google.common.io.ByteStreams.*
7 import com.google.common.util.concurrent.MoreExecutors.*
9 import net.pterodactylus.sone.core.SoneInserter.*
10 import net.pterodactylus.sone.core.event.*
11 import net.pterodactylus.sone.data.*
12 import net.pterodactylus.sone.main.*
13 import net.pterodactylus.sone.test.*
14 import org.hamcrest.MatcherAssert.*
15 import org.hamcrest.Matchers.*
18 import org.mockito.ArgumentMatchers.any
19 import org.mockito.ArgumentMatchers.anyString
20 import org.mockito.ArgumentMatchers.eq
21 import org.mockito.Mockito.doAnswer
22 import org.mockito.Mockito.never
23 import org.mockito.Mockito.times
24 import org.mockito.Mockito.verify
25 import org.mockito.hamcrest.MockitoHamcrest.*
26 import org.mockito.stubbing.*
27 import java.lang.System.*
31 * Unit test for [SoneInserter] and its subclasses.
33 class SoneInserterTest {
35 private val core = mock<Core>()
36 private val eventBus = mock<EventBus>()
37 private val freenetInterface = mock<FreenetInterface>()
41 val updateChecker = mock<UpdateChecker>()
42 whenever(core.updateChecker).thenReturn(updateChecker)
43 whenever(core.getSone(anyString())).thenReturn(null)
47 fun `insertion delay is forwarded to sone inserter`() {
48 val eventBus = AsyncEventBus(directExecutor())
49 eventBus.register(SoneInserter(core, eventBus, freenetInterface, "SoneId"))
50 eventBus.post(InsertionDelayChangedEvent(15))
51 assertThat(SoneInserter.getInsertionDelay().get(), equalTo(15))
54 private fun createSone(insertUri: FreenetURI, fingerprint: String = "fingerprint"): Sone {
55 val sone = mock<Sone>()
56 whenever(sone.insertUri).thenReturn(insertUri)
57 whenever(sone.fingerprint).thenReturn(fingerprint)
58 whenever(sone.rootAlbum).thenReturn(mock())
59 whenever(core.getSone(anyString())).thenReturn(sone)
64 fun `isModified is true if modification detector says so`() {
65 val soneModificationDetector = mock<SoneModificationDetector>()
66 whenever(soneModificationDetector.isModified).thenReturn(true)
67 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
68 assertThat(soneInserter.isModified, equalTo(true))
72 fun `isModified is false if modification detector says so`() {
73 val soneModificationDetector = mock<SoneModificationDetector>()
74 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
75 assertThat(soneInserter.isModified, equalTo(false))
79 fun `last fingerprint is stored correctly`() {
80 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId")
81 soneInserter.lastInsertFingerprint = "last-fingerprint"
82 assertThat(soneInserter.lastInsertFingerprint, equalTo("last-fingerprint"))
86 fun `sone inserter stops when it should`() {
87 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId")
89 soneInserter.serviceRun()
93 fun `sone inserter inserts a sone if it is eligible`() {
94 val insertUri = mock<FreenetURI>()
95 val finalUri = mock<FreenetURI>()
96 val sone = createSone(insertUri)
97 val soneModificationDetector = mock<SoneModificationDetector>()
98 whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true)
99 whenever(freenetInterface.insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))).thenReturn(finalUri)
100 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
104 }.`when`(core).touchConfiguration()
105 soneInserter.serviceRun()
106 val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java)
107 verify(freenetInterface).insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))
108 verify(eventBus, times(2)).post(soneEvents.capture())
109 assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java))
110 assertThat(soneEvents.allValues[0].sone, equalTo(sone))
111 assertThat(soneEvents.allValues[1], instanceOf(SoneInsertedEvent::class.java))
112 assertThat(soneEvents.allValues[1].sone, equalTo(sone))
116 fun `sone inserter bails out if it is stopped while inserting`() {
117 val insertUri = mock<FreenetURI>()
118 val finalUri = mock<FreenetURI>()
119 val sone = createSone(insertUri)
120 val soneModificationDetector = mock<SoneModificationDetector>()
121 whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true)
122 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
123 whenever(freenetInterface.insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))).thenAnswer {
127 soneInserter.serviceRun()
128 val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java)
129 verify(freenetInterface).insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))
130 verify(eventBus, times(2)).post(soneEvents.capture())
131 assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java))
132 assertThat(soneEvents.allValues[0].sone, equalTo(sone))
133 assertThat(soneEvents.allValues[1], instanceOf(SoneInsertedEvent::class.java))
134 assertThat(soneEvents.allValues[1].sone, equalTo(sone))
135 verify(core, never()).touchConfiguration()
139 fun `sone inserter does not insert sone if it is not eligible`() {
140 val insertUri = mock<FreenetURI>()
141 createSone(insertUri)
142 val soneModificationDetector = mock<SoneModificationDetector>()
143 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
147 } catch (ie1: InterruptedException) {
148 throw RuntimeException(ie1)
153 soneInserter.serviceRun()
154 verify(freenetInterface, never()).insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))
155 verify(eventBus, never()).post(argThat(org.hamcrest.Matchers.any(SoneEvent::class.java)))
159 fun `sone inserter posts aborted event if an exception occurs`() {
160 val insertUri = mock<FreenetURI>()
161 val sone = createSone(insertUri)
162 val soneModificationDetector = mock<SoneModificationDetector>()
163 whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true)
164 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
165 val soneException = SoneException(Exception())
166 whenever(freenetInterface.insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))).thenAnswer {
170 soneInserter.serviceRun()
171 val soneEvents = ArgumentCaptor.forClass(SoneEvent::class.java)
172 verify(freenetInterface).insertDirectory(eq(insertUri), any<HashMap<String, Any>>(), eq("index.html"))
173 verify(eventBus, times(2)).post(soneEvents.capture())
174 assertThat(soneEvents.allValues[0], instanceOf(SoneInsertingEvent::class.java))
175 assertThat(soneEvents.allValues[0].sone, equalTo(sone))
176 assertThat(soneEvents.allValues[1], instanceOf(SoneInsertAbortedEvent::class.java))
177 assertThat(soneEvents.allValues[1].sone, equalTo(sone))
178 verify(core, never()).touchConfiguration()
182 fun `sone inserter exits if sone is unknown`() {
183 val soneModificationDetector = mock<SoneModificationDetector>()
184 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
185 whenever(soneModificationDetector.isEligibleForInsert).thenReturn(true)
186 whenever(core.getSone("SoneId")).thenReturn(null)
187 soneInserter.serviceRun()
191 fun `sone inserter catches exception and continues`() {
192 val soneModificationDetector = mock<SoneModificationDetector>()
193 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1)
194 val stopInserterAndThrowException = Answer<Optional<Sone>> {
196 throw NullPointerException()
198 whenever(soneModificationDetector.isEligibleForInsert).thenAnswer(stopInserterAndThrowException)
199 soneInserter.serviceRun()
203 fun `template is rendered correctly for manifest element`() {
204 val soneProperties = HashMap<String, Any>()
205 soneProperties["id"] = "SoneId"
206 val manifestCreator = ManifestCreator(core, soneProperties)
207 val now = currentTimeMillis()
208 whenever(core.startupTime).thenReturn(now)
209 val manifestElement = manifestCreator.createManifestElement("test.txt", "plain/text; charset=utf-8", "sone-inserter-manifest.txt")
210 assertThat(manifestElement!!.name, equalTo("test.txt"))
211 assertThat(manifestElement.mimeTypeOverride, equalTo("plain/text; charset=utf-8"))
212 val templateContent = String(toByteArray(manifestElement.data.inputStream), Charsets.UTF_8)
213 assertThat(templateContent, containsString("Sone Version: ${SonePlugin.getPluginVersion()}\n"))
214 assertThat(templateContent, containsString("Core Startup: $now\n"))
215 assertThat(templateContent, containsString("Sone ID: SoneId\n"))
219 fun `invalid template returns anull manifest element`() {
220 val soneProperties = HashMap<String, Any>()
221 val manifestCreator = ManifestCreator(core, soneProperties)
222 assertThat(manifestCreator.createManifestElement("test.txt",
223 "plain/text; charset=utf-8",
224 "sone-inserter-invalid-manifest.txt"),
229 fun `error while rendering template returns a null manifest element`() {
230 val soneProperties = HashMap<String, Any>()
231 val manifestCreator = ManifestCreator(core, soneProperties)
232 whenever(core.toString()).thenThrow(NullPointerException::class.java)
233 assertThat(manifestCreator.createManifestElement("test.txt",
234 "plain/text; charset=utf-8",
235 "sone-inserter-faulty-manifest.txt"),