1 @file:Suppress("DEPRECATION")
3 package net.pterodactylus.sone.fcp
5 import com.google.inject.Guice
6 import freenet.pluginmanager.PluginNotFoundException
7 import freenet.pluginmanager.PluginReplySender
8 import freenet.support.SimpleFieldSet
9 import net.pterodactylus.sone.core.Core
10 import net.pterodactylus.sone.fcp.FcpInterface.CommandSupplier
11 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired
12 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.ALWAYS
13 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.NO
14 import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.WRITING
15 import net.pterodactylus.sone.fcp.event.FcpInterfaceActivatedEvent
16 import net.pterodactylus.sone.fcp.event.FcpInterfaceDeactivatedEvent
17 import net.pterodactylus.sone.fcp.event.FullAccessRequiredChanged
18 import net.pterodactylus.sone.freenet.fcp.Command.AccessType.FULL_FCP
19 import net.pterodactylus.sone.freenet.fcp.Command.AccessType.RESTRICTED_FCP
20 import net.pterodactylus.sone.freenet.fcp.Command.Response
21 import net.pterodactylus.sone.test.bindAs
22 import net.pterodactylus.sone.test.capture
23 import net.pterodactylus.sone.test.mock
24 import net.pterodactylus.sone.test.whenever
25 import org.hamcrest.MatcherAssert.assertThat
26 import org.hamcrest.Matchers.containsInAnyOrder
27 import org.hamcrest.Matchers.equalTo
28 import org.hamcrest.Matchers.sameInstance
30 import org.mockito.ArgumentMatchers
31 import org.mockito.Mockito.any
32 import org.mockito.Mockito.verify
35 * Unit test for [FcpInterface] and its subclasses.
37 class FcpInterfaceTest {
39 private val core = mock<Core>()
40 private val workingCommand = mock<AbstractSoneCommand>().apply {
41 whenever(execute(any(), any(), any())).thenReturn(Response("Working", SimpleFieldSet(true).apply {
42 putSingle("ReallyWorking", "true")
45 private val brokenCommand = mock<AbstractSoneCommand>().apply {
46 whenever(execute(any(), any(), any())).thenThrow(RuntimeException::class.java)
48 private val commandSupplier = object : CommandSupplier() {
49 override fun supplyCommands(core: Core): Map<String, AbstractSoneCommand> {
51 "Working" to workingCommand,
52 "Broken" to brokenCommand
56 private val fcpInterface = FcpInterface(core, commandSupplier)
57 private val pluginReplySender = mock<PluginReplySender>()
58 private val parameters = SimpleFieldSet(true)
59 private val replyParameters = capture<SimpleFieldSet>()
62 fun `fcp interface is instantiated as singleton`() {
63 val injector = Guice.createInjector(core.bindAs(Core::class))
64 assertThat(injector.getInstance(FcpInterface::class.java), sameInstance(injector.getInstance(FcpInterface::class.java)))
68 fun `fcp interface can be activated`() {
69 fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent())
70 assertThat(fcpInterface.isActive, equalTo(true))
74 fun `fcp interface can be deactivated`() {
75 fcpInterface.fcpInterfaceDeactivated(FcpInterfaceDeactivatedEvent())
76 assertThat(fcpInterface.isActive, equalTo(false))
79 private fun setAndVerifyAccessRequired(fullAccessRequired: FullAccessRequired) {
80 fcpInterface.fullAccessRequiredChanged(FullAccessRequiredChanged(fullAccessRequired))
81 assertThat(fcpInterface.fullAccessRequired, equalTo(fullAccessRequired))
85 fun `set full access required can set access to no`() {
86 setAndVerifyAccessRequired(NO)
90 fun `set full access required can set access to writing`() {
91 setAndVerifyAccessRequired(WRITING)
95 fun `set full access required can set access to always`() {
96 setAndVerifyAccessRequired(ALWAYS)
100 fun `sending command to inactive fcp interface results in 400 error reply`() {
101 fcpInterface.fcpInterfaceDeactivated(FcpInterfaceDeactivatedEvent())
102 fcpInterface.handle(pluginReplySender, parameters, null, 0)
103 verify(pluginReplySender).send(replyParameters.capture())
104 assertThat(replyParameters.value["Message"], equalTo("Error"))
105 assertThat(replyParameters.value["ErrorCode"], equalTo("503"))
109 fun `exception while sending reply does not result in exception`() {
110 fcpInterface.fcpInterfaceDeactivated(FcpInterfaceDeactivatedEvent())
111 whenever(pluginReplySender.send(ArgumentMatchers.any())).thenThrow(PluginNotFoundException::class.java)
112 fcpInterface.handle(pluginReplySender, parameters, null, 0)
116 fun `sending command over restricted fcp connection results in 401 error reply`() {
117 fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent())
118 fcpInterface.handle(pluginReplySender, parameters, null, RESTRICTED_FCP.ordinal)
119 verify(pluginReplySender).send(replyParameters.capture())
120 assertThat(replyParameters.value["Message"], equalTo("Error"))
121 assertThat(replyParameters.value["ErrorCode"], equalTo("401"))
125 fun `sending unknown command over full access connection results in 404 error reply`() {
126 fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent())
127 fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal)
128 verify(pluginReplySender).send(replyParameters.capture())
129 assertThat(replyParameters.value["Message"], equalTo("Error"))
130 assertThat(replyParameters.value["ErrorCode"], equalTo("404"))
134 fun `sending working command without identifier results in 400 error code`() {
135 fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent())
136 parameters.putSingle("Message", "Working")
137 fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal)
138 verify(pluginReplySender).send(replyParameters.capture())
139 assertThat(replyParameters.value["Message"], equalTo("Error"))
140 assertThat(replyParameters.value["ErrorCode"], equalTo("400"))
144 fun `sending working command with empty identifier results in 400 error code`() {
145 fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent())
146 parameters.putSingle("Message", "Working")
147 parameters.putSingle("Identifier", "")
148 fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal)
149 verify(pluginReplySender).send(replyParameters.capture())
150 assertThat(replyParameters.value["Message"], equalTo("Error"))
151 assertThat(replyParameters.value["ErrorCode"], equalTo("400"))
155 fun `sending working command with identifier results in working reply`() {
156 fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent())
157 parameters.putSingle("Message", "Working")
158 parameters.putSingle("Identifier", "Test")
159 fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal)
160 verify(pluginReplySender).send(replyParameters.capture())
161 assertThat(replyParameters.value["Message"], equalTo("Working"))
162 assertThat(replyParameters.value["ReallyWorking"], equalTo("true"))
166 fun `sending broken command with identifier results in 500 error reply`() {
167 fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent())
168 parameters.putSingle("Message", "Broken")
169 parameters.putSingle("Identifier", "Test")
170 fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal)
171 verify(pluginReplySender).send(replyParameters.capture())
172 assertThat(replyParameters.value["Message"], equalTo("Error"))
173 assertThat(replyParameters.value["ErrorCode"], equalTo("500"))
178 class CommandSupplierTest {
180 private val core = mock<Core>()
181 private val commandSupplier = CommandSupplier()
184 fun `command supplier supplies all commands`() {
185 val commands = commandSupplier.supplyCommands(core)
186 assertThat(commands.keys, containsInAnyOrder(
206 fun `command supplier is instantiated as singleton`() {
207 val injector = Guice.createInjector()
208 assertThat(injector.getInstance(CommandSupplier::class.java), sameInstance(injector.getInstance(CommandSupplier::class.java)))