e658fe2e82b2457251b100825dd27085a263d8d3
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / main / SonePluginTest.kt
1 package net.pterodactylus.sone.main
2
3 import com.google.common.eventbus.*
4 import com.google.inject.*
5 import freenet.client.async.*
6 import freenet.l10n.BaseL10n.LANGUAGE.*
7 import freenet.node.*
8 import freenet.pluginmanager.*
9 import net.pterodactylus.sone.core.*
10 import net.pterodactylus.sone.core.event.*
11 import net.pterodactylus.sone.fcp.*
12 import net.pterodactylus.sone.freenet.wot.*
13 import net.pterodactylus.sone.test.*
14 import net.pterodactylus.sone.web.*
15 import net.pterodactylus.sone.web.notification.*
16 import org.hamcrest.MatcherAssert.*
17 import org.hamcrest.Matchers.*
18 import org.mockito.Mockito.*
19 import java.io.*
20 import java.util.concurrent.atomic.*
21 import kotlin.test.*
22
23 /**
24  * Unit test for [SonePlugin].
25  */
26 @Dirty
27 class SonePluginTest {
28
29         private var sonePlugin = SonePlugin { injector }
30         private val pluginRespirator = deepMock<PluginRespirator>()
31         private val node = deepMock<Node>()
32         private val clientCore = deepMock<NodeClientCore>()
33         private val uskManager = deepMock<USKManager>()
34
35         init {
36                 setField(node, "clientCore", clientCore)
37                 whenever(pluginRespirator.node).thenReturn(node)
38                 setField(clientCore, "uskManager", uskManager)
39         }
40
41         @Test
42         fun `sone plugin can be started`() {
43                 sonePlugin.setLanguage(ENGLISH)
44                 sonePlugin.runPlugin(pluginRespirator)
45         }
46
47         @Test
48         fun `core can be created`() {
49                 val injector: Injector = runSonePluginWithRealInjector()
50                 assertThat(injector.getInstance<Core>(), notNullValue())
51         }
52
53         @Test
54         fun `fcp interface can be created`() {
55                 val injector: Injector = runSonePluginWithRealInjector()
56                 assertThat(injector.getInstance<FcpInterface>(), notNullValue())
57         }
58
59         @Test
60         fun `web interface can be created`() {
61                 val injector: Injector = runSonePluginWithRealInjector()
62                 assertThat(injector.getInstance<WebInterface>(), notNullValue())
63         }
64
65         @Test
66         fun `web of trust connector can be created`() {
67                 val injector: Injector = runSonePluginWithRealInjector()
68                 assertThat(injector.getInstance<WebOfTrustConnector>(), notNullValue())
69         }
70
71         @Test
72         fun `notification handler can be created`() {
73                 val injector: Injector = runSonePluginWithRealInjector()
74                 assertThat(injector.getInstance<NotificationHandler>(), notNullValue())
75         }
76
77         private fun runSonePluginWithRealInjector(injectorConsumer: (Injector) -> Unit = {}): Injector {
78                 lateinit var injector: Injector
79                 sonePlugin = SonePlugin {
80                         Guice.createInjector(*it).also {
81                                 injector = it
82                                 injectorConsumer(it)
83                         }
84                 }
85                 sonePlugin.setLanguage(ENGLISH)
86                 sonePlugin.runPlugin(pluginRespirator)
87                 return injector
88         }
89
90         @Test
91         fun `core is being started`() {
92                 sonePlugin.runPlugin(pluginRespirator)
93                 val core = injector.getInstance<Core>()
94                 verify(core).start()
95         }
96
97         @Test
98         fun `notification handler is being requested`() {
99                 sonePlugin.runPlugin(pluginRespirator)
100                 assertThat(getInjected(NotificationHandler::class.java), notNullValue())
101         }
102
103         @Test
104         fun `ticker shutdown is being requested`() {
105                 sonePlugin.runPlugin(pluginRespirator)
106                 assertThat(getInjected(TickerShutdown::class.java), notNullValue())
107         }
108
109         private class FirstStartListener(private val firstStartReceived: AtomicBoolean) {
110                 @Subscribe
111                 fun firstStart(firstStart: FirstStart) {
112                         firstStartReceived.set(true)
113                 }
114         }
115
116         @Test
117         fun `first-start event is sent to event bus when first start is true`() {
118                 File("sone.properties").delete()
119                 val firstStartReceived = AtomicBoolean()
120                 runSonePluginWithRealInjector {
121                         val eventBus = it.getInstance(EventBus::class.java)
122                         eventBus.register(FirstStartListener(firstStartReceived))
123                 }
124                 assertThat(firstStartReceived.get(), equalTo(true))
125         }
126
127         @Test
128         fun `first-start event is not sent to event bus when first start is false`() {
129                 File("sone.properties").deleteAfter {
130                         writeText("# empty")
131                         val firstStartReceived = AtomicBoolean()
132                         runSonePluginWithRealInjector {
133                                 val eventBus = it.getInstance(EventBus::class.java)
134                                 eventBus.register(FirstStartListener(firstStartReceived))
135                         }
136                         assertThat(firstStartReceived.get(), equalTo(false))
137                 }
138         }
139
140         private class ConfigNotReadListener(private val configNotReadReceiver: AtomicBoolean) {
141                 @Subscribe
142                 fun configNotRead(configNotRead: ConfigNotRead) {
143                         configNotReadReceiver.set(true)
144                 }
145         }
146
147         @Test
148         fun `config-not-read event is sent to event bus when new config is true`() {
149                 File("sone.properties").deleteAfter {
150                         writeText("Invalid")
151                         val configNotReadReceived = AtomicBoolean()
152                         runSonePluginWithRealInjector {
153                                 val eventBus = it.getInstance(EventBus::class.java)
154                                 eventBus.register(ConfigNotReadListener(configNotReadReceived))
155                         }
156                         assertThat(configNotReadReceived.get(), equalTo(true))
157                 }
158         }
159
160         @Test
161         fun `config-not-read event is not sent to event bus when first start is true`() {
162                 File("sone.properties").delete()
163                 val configNotReadReceived = AtomicBoolean()
164                 runSonePluginWithRealInjector {
165                         val eventBus = it.getInstance(EventBus::class.java)
166                         eventBus.register(ConfigNotReadListener(configNotReadReceived))
167                 }
168                 assertThat(configNotReadReceived.get(), equalTo(false))
169         }
170
171         @Test
172         fun `config-not-read event is not sent to event bus when new config is false`() {
173                 File("sone.properties").deleteAfter {
174                         writeText("# comment")
175                         val configNotReadReceived = AtomicBoolean()
176                         runSonePluginWithRealInjector {
177                                 val eventBus = it.getInstance(EventBus::class.java)
178                                 eventBus.register(ConfigNotReadListener(configNotReadReceived))
179                         }
180                         assertThat(configNotReadReceived.get(), equalTo(false))
181                 }
182         }
183
184         private class StartupListener(private val startupReceived: () -> Unit) {
185                 @Subscribe
186                 fun startup(startup: Startup) {
187                         startupReceived()
188                 }
189         }
190
191         @Test
192         fun `startup event is sent to event bus`() {
193                 val startupReceived = AtomicBoolean()
194                 runSonePluginWithRealInjector {
195                         val eventBus = it.getInstance(EventBus::class.java)
196                         eventBus.register(StartupListener { startupReceived.set(true) })
197                 }
198                 assertThat(startupReceived.get(), equalTo(true))
199         }
200
201         private class ShutdownListener(private val shutdownReceived: () -> Unit) {
202                 @Subscribe
203                 fun shutdown(shutdown: Shutdown) {
204                         shutdownReceived()
205                 }
206         }
207
208         @Test
209         fun `shutdown event is sent to event bus on terminate`() {
210                 val shutdownReceived = AtomicBoolean()
211                 runSonePluginWithRealInjector {
212                         val eventBus = it.getInstance(EventBus::class.java)
213                         eventBus.register(ShutdownListener { shutdownReceived.set(true) })
214                 }
215                 sonePlugin.terminate()
216                 assertThat(shutdownReceived.get(), equalTo(true))
217         }
218
219         private fun <T> getInjected(clazz: Class<T>, annotation: Annotation? = null): T? =
220                         injected[TypeLiteral.get(clazz) to annotation] as? T
221
222         private val injected =
223                         mutableMapOf<Pair<TypeLiteral<*>, Annotation?>, Any>()
224
225         private val injector = mock<Injector>().apply {
226                 fun mockValue(clazz: Class<*>) = false.takeIf { clazz.name == java.lang.Boolean::class.java.name } ?: mock(clazz)
227                 whenever(getInstance(any<Key<*>>())).then {
228                         injected.getOrPut((it.getArgument(0) as Key<*>).let { it.typeLiteral to it.annotation }) {
229                                 it.getArgument<Key<*>>(0).typeLiteral.type.typeName.toClass().let(::mockValue)
230                         }
231                 }
232                 whenever(getInstance(any<Class<*>>())).then {
233                         injected.getOrPut(TypeLiteral.get(it.getArgument(0) as Class<*>) to null) {
234                                 it.getArgument<Class<*>>(0).let(::mockValue)
235                         }
236                 }
237         }
238
239 }
240
241 private fun String.toClass(): Class<*> = SonePlugin::class.java.classLoader.loadClass(this)
242
243 private fun File.deleteAfter(action: File.() -> Unit) = try {
244         action(this)
245 } finally {
246         this.delete()
247 }