🎨 Replace SoneInserterTest with Kotlin version
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / core / SoneInserterTest.kt
1 package net.pterodactylus.sone.core
2
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.*
8 import freenet.keys.*
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.*
16 import org.junit.*
17 import org.mockito.*
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.*
28 import java.util.*
29
30 /**
31  * Unit test for [SoneInserter] and its subclasses.
32  */
33 class SoneInserterTest {
34
35         private val core = mock<Core>()
36         private val eventBus = mock<EventBus>()
37         private val freenetInterface = mock<FreenetInterface>()
38
39         @Before
40         fun setupCore() {
41                 val updateChecker = mock<UpdateChecker>()
42                 whenever(core.updateChecker).thenReturn(updateChecker)
43                 whenever(core.getSone(anyString())).thenReturn(null)
44         }
45
46         @Test
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))
52         }
53
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)
60                 return sone
61         }
62
63         @Test
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))
69         }
70
71         @Test
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))
76         }
77
78         @Test
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"))
83         }
84
85         @Test
86         fun `sone inserter stops when it should`() {
87                 val soneInserter = SoneInserter(core, eventBus, freenetInterface, "SoneId")
88                 soneInserter.stop()
89                 soneInserter.serviceRun()
90         }
91
92         @Test
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)
101                 doAnswer {
102                         soneInserter.stop()
103                         null
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))
113         }
114
115         @Test
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 {
124                         soneInserter.stop()
125                         finalUri
126                 }
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()
136         }
137
138         @Test
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)
144                 Thread(Runnable {
145                         try {
146                                 Thread.sleep(500)
147                         } catch (ie1: InterruptedException) {
148                                 throw RuntimeException(ie1)
149                         }
150
151                         soneInserter.stop()
152                 }).start()
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)))
156         }
157
158         @Test
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 {
167                         soneInserter.stop()
168                         throw soneException
169                 }
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()
179         }
180
181         @Test
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()
188         }
189
190         @Test
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>> {
195                         soneInserter.stop()
196                         throw NullPointerException()
197                 }
198                 whenever(soneModificationDetector.isEligibleForInsert).thenAnswer(stopInserterAndThrowException)
199                 soneInserter.serviceRun()
200         }
201
202         @Test
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"))
216         }
217
218         @Test
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"),
225                                 nullValue())
226         }
227
228         @Test
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"),
236                                 nullValue())
237         }
238
239 }