From: David ‘Bombe’ Roden Date: Sun, 8 Jan 2017 14:07:32 +0000 (+0100) Subject: Extract class for supplying commands, improve tests for FCP interface X-Git-Tag: 0.9.7^2~354 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=2d15e85a3ea6c752a792aa918bbb5938760d69ac Extract class for supplying commands, improve tests for FCP interface --- diff --git a/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java b/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java index 36e18e6..7fb4462 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java +++ b/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java @@ -20,7 +20,6 @@ package net.pterodactylus.sone.fcp; import static com.google.common.base.Preconditions.checkNotNull; import static java.util.logging.Logger.getLogger; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -28,6 +27,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; +import javax.inject.Singleton; + import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.fcp.event.FcpInterfaceActivatedEvent; import net.pterodactylus.sone.fcp.event.FcpInterfaceDeactivatedEvent; @@ -45,7 +46,6 @@ import freenet.support.api.Bucket; import com.google.common.annotations.VisibleForTesting; import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; -import com.google.inject.Singleton; /** * Implementation of an FCP interface for other clients or plugins to @@ -84,7 +84,7 @@ public class FcpInterface { private final AtomicReference fullAccessRequired = new AtomicReference(FullAccessRequired.ALWAYS); /** All available FCP commands. */ - private final Map commands = Collections.synchronizedMap(new HashMap()); + private final Map commands; /** * Creates a new FCP interface. @@ -93,22 +93,8 @@ public class FcpInterface { * The core */ @Inject - public FcpInterface(Core core) { - commands.put("Version", new VersionCommand(core)); - commands.put("GetLocalSones", new GetLocalSonesCommand(core)); - commands.put("GetSones", new GetSonesCommand(core)); - commands.put("GetSone", new GetSoneCommand(core)); - commands.put("GetPost", new GetPostCommand(core)); - commands.put("GetPosts", new GetPostsCommand(core)); - commands.put("GetPostFeed", new GetPostFeedCommand(core)); - commands.put("LockSone", new LockSoneCommand(core)); - commands.put("UnlockSone", new UnlockSoneCommand(core)); - commands.put("LikePost", new LikePostCommand(core)); - commands.put("LikeReply", new LikeReplyCommand(core)); - commands.put("CreatePost", new CreatePostCommand(core)); - commands.put("CreateReply", new CreateReplyCommand(core)); - commands.put("DeletePost", new DeletePostCommand(core)); - commands.put("DeleteReply", new DeleteReplyCommand(core)); + public FcpInterface(Core core, CommandSupplier commandSupplier) { + commands = commandSupplier.supplyCommands(core); } // @@ -232,4 +218,29 @@ public class FcpInterface { setFullAccessRequired(fullAccessRequiredChanged.getFullAccessRequired()); } + @Singleton + public static class CommandSupplier { + + public Map supplyCommands(Core core) { + Map commands = new HashMap<>(); + commands.put("Version", new VersionCommand(core)); + commands.put("GetLocalSones", new GetLocalSonesCommand(core)); + commands.put("GetSones", new GetSonesCommand(core)); + commands.put("GetSone", new GetSoneCommand(core)); + commands.put("GetPost", new GetPostCommand(core)); + commands.put("GetPosts", new GetPostsCommand(core)); + commands.put("GetPostFeed", new GetPostFeedCommand(core)); + commands.put("LockSone", new LockSoneCommand(core)); + commands.put("UnlockSone", new UnlockSoneCommand(core)); + commands.put("LikePost", new LikePostCommand(core)); + commands.put("LikeReply", new LikeReplyCommand(core)); + commands.put("CreatePost", new CreatePostCommand(core)); + commands.put("CreateReply", new CreateReplyCommand(core)); + commands.put("DeletePost", new DeletePostCommand(core)); + commands.put("DeleteReply", new DeleteReplyCommand(core)); + return commands; + } + + } + } diff --git a/src/test/java/net/pterodactylus/sone/fcp/FcpInterfaceTest.kt b/src/test/java/net/pterodactylus/sone/fcp/FcpInterfaceTest.kt index 9e9df16..9611196 100644 --- a/src/test/java/net/pterodactylus/sone/fcp/FcpInterfaceTest.kt +++ b/src/test/java/net/pterodactylus/sone/fcp/FcpInterfaceTest.kt @@ -2,10 +2,12 @@ package net.pterodactylus.sone.fcp +import com.google.inject.Guice import freenet.pluginmanager.PluginNotFoundException import freenet.pluginmanager.PluginReplySender import freenet.support.SimpleFieldSet import net.pterodactylus.sone.core.Core +import net.pterodactylus.sone.fcp.FcpInterface.CommandSupplier import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.ALWAYS import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.NO @@ -15,14 +17,18 @@ import net.pterodactylus.sone.fcp.event.FcpInterfaceDeactivatedEvent import net.pterodactylus.sone.fcp.event.FullAccessRequiredChanged import net.pterodactylus.sone.freenet.fcp.Command.AccessType.FULL_FCP import net.pterodactylus.sone.freenet.fcp.Command.AccessType.RESTRICTED_FCP -import net.pterodactylus.sone.main.SonePlugin +import net.pterodactylus.sone.freenet.fcp.Command.Response +import net.pterodactylus.sone.test.bindAs import net.pterodactylus.sone.test.capture import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.containsInAnyOrder import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.sameInstance import org.junit.Test import org.mockito.ArgumentMatchers +import org.mockito.Mockito.any import org.mockito.Mockito.verify /** @@ -31,12 +37,34 @@ import org.mockito.Mockito.verify class FcpInterfaceTest { private val core = mock() - private val fcpInterface = FcpInterface(core) + private val workingCommand = mock().apply { + whenever(execute(any(), any(), any())).thenReturn(Response("Working", SimpleFieldSet(true).apply { + putSingle("ReallyWorking", "true") + })) + } + private val brokenCommand = mock().apply { + whenever(execute(any(), any(), any())).thenThrow(RuntimeException::class.java) + } + private val commandSupplier = object : CommandSupplier() { + override fun supplyCommands(core: Core): Map { + return mapOf( + "Working" to workingCommand, + "Broken" to brokenCommand + ) + } + } + private val fcpInterface = FcpInterface(core, commandSupplier) private val pluginReplySender = mock() private val parameters = SimpleFieldSet(true) private val replyParameters = capture() @Test + fun `fcp interface is instantiated as singleton`() { + val injector = Guice.createInjector(core.bindAs(Core::class)) + assertThat(injector.getInstance(FcpInterface::class.java), sameInstance(injector.getInstance(FcpInterface::class.java))) + } + + @Test fun `fcp interface can be activated`() { fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent()) assertThat(fcpInterface.isActive, equalTo(true)) @@ -103,9 +131,9 @@ class FcpInterfaceTest { } @Test - fun `sending version command without identifier results in 400 error code`() { + fun `sending working command without identifier results in 400 error code`() { fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent()) - parameters.putSingle("Message", "Version") + parameters.putSingle("Message", "Working") fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal) verify(pluginReplySender).send(replyParameters.capture()) assertThat(replyParameters.value["Message"], equalTo("Error")) @@ -113,9 +141,9 @@ class FcpInterfaceTest { } @Test - fun `sending version command with empty identifier results in 400 error code`() { + fun `sending working command with empty identifier results in 400 error code`() { fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent()) - parameters.putSingle("Message", "Version") + parameters.putSingle("Message", "Working") parameters.putSingle("Identifier", "") fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal) verify(pluginReplySender).send(replyParameters.capture()) @@ -124,15 +152,60 @@ class FcpInterfaceTest { } @Test - fun `sending version command with identifier results in version reply`() { + fun `sending working command with identifier results in working reply`() { + fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent()) + parameters.putSingle("Message", "Working") + parameters.putSingle("Identifier", "Test") + fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal) + verify(pluginReplySender).send(replyParameters.capture()) + assertThat(replyParameters.value["Message"], equalTo("Working")) + assertThat(replyParameters.value["ReallyWorking"], equalTo("true")) + } + + @Test + fun `sending broken command with identifier results in 500 error reply`() { fcpInterface.fcpInterfaceActivated(FcpInterfaceActivatedEvent()) - parameters.putSingle("Message", "Version") + parameters.putSingle("Message", "Broken") parameters.putSingle("Identifier", "Test") fcpInterface.handle(pluginReplySender, parameters, null, FULL_FCP.ordinal) verify(pluginReplySender).send(replyParameters.capture()) - assertThat(replyParameters.value["Message"], equalTo("Version")) - assertThat(replyParameters.value["Version"], equalTo(SonePlugin.getPluginVersion())) - assertThat(replyParameters.value["ProtocolVersion"], equalTo("1")) + assertThat(replyParameters.value["Message"], equalTo("Error")) + assertThat(replyParameters.value["ErrorCode"], equalTo("500")) + } + +} + +class CommandSupplierTest { + + private val core = mock() + private val commandSupplier = CommandSupplier() + + @Test + fun `command supplier supplies all commands`() { + val commands = commandSupplier.supplyCommands(core) + assertThat(commands.keys, containsInAnyOrder( + "CreatePost", + "CreateReply", + "DeletePost", + "DeleteReply", + "GetLocalSones", + "GetPost", + "GetPostFeed", + "GetPosts", + "GetSone", + "GetSones", + "LikePost", + "LikeReply", + "LockSone", + "UnlockSone", + "Version" + )) + } + + @Test + fun `command supplier is instantiated as singleton`() { + val injector = Guice.createInjector() + assertThat(injector.getInstance(CommandSupplier::class.java), sameInstance(injector.getInstance(CommandSupplier::class.java))) } } diff --git a/src/test/kotlin/net/pterodactylus/sone/test/Guice.kt b/src/test/kotlin/net/pterodactylus/sone/test/Guice.kt new file mode 100644 index 0000000..f8feeef --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/test/Guice.kt @@ -0,0 +1,6 @@ +package net.pterodactylus.sone.test + +import com.google.inject.Module +import kotlin.reflect.KClass + +fun T.bindAs(bindClass: KClass) = Module { it.bind(bindClass.java).toInstance(this@bindAs) }