From b5b5dc1e92d49b4686cb2150eeb63f60ae586525 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Tue, 7 Jan 2025 21:31:08 +0100 Subject: [PATCH] =?utf8?q?=E2=9C=85=20Add=20test=20for=20WebOfTrustPlugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../pterodactylus/fcp/plugin/WebOfTrustPlugin.java | 62 ++++--- .../fcp/plugin/WebOfTrustPluginTest.java | 206 +++++++++++++++++++++ .../pterodactylus/fcp/test/IdentityMatchers.java | 42 +++++ .../java/net/pterodactylus/fcp/test/Matchers.java | 18 ++ 4 files changed, 298 insertions(+), 30 deletions(-) create mode 100644 src/test/java/net/pterodactylus/fcp/plugin/WebOfTrustPluginTest.java create mode 100644 src/test/java/net/pterodactylus/fcp/test/IdentityMatchers.java diff --git a/src/main/java/net/pterodactylus/fcp/plugin/WebOfTrustPlugin.java b/src/main/java/net/pterodactylus/fcp/plugin/WebOfTrustPlugin.java index 83f65b1..464c6da 100644 --- a/src/main/java/net/pterodactylus/fcp/plugin/WebOfTrustPlugin.java +++ b/src/main/java/net/pterodactylus/fcp/plugin/WebOfTrustPlugin.java @@ -50,49 +50,35 @@ public class WebOfTrustPlugin { /** * Creates a new identity. * - * @param nickname - * The nickname of the new identity - * @param context - * The context for the new identity - * @param publishTrustList - * {@code true} if the new identity should publish its trust list + * @param nickname The nickname of the new identity + * @param context The context for the new identity + * @param publishTrustList {@code true} if the new identity should publish its trust list * @return The new identity - * @throws IOException - * if an I/O error occurs - * @throws FcpException - * if an FCP error occurs + * @throws IOException if an I/O error occurs + * @throws FcpException if an FCP error occurs */ public OwnIdentity createIdentity(String nickname, String context, boolean publishTrustList) throws IOException, FcpException { - return createIdentity(nickname, context, publishTrustList, null, null); + return createIdentity(nickname, context, publishTrustList, null); } /** - * Creates a new identity from the given request and insert URI. + * Creates a new identity from the given insert URI. * - * @param nickname - * The nickname of the new identity - * @param context - * The context for the new identity - * @param publishTrustList - * {@code true} if the new identity should publish its trust list - * @param requestUri - * The request URI of the identity - * @param insertUri - * The insert URI of the identity + * @param nickname The nickname of the new identity + * @param context The context for the new identity + * @param publishTrustList {@code true} if the new identity should publish its trust list + * @param insertUri The insert URI of the identity * @return The new identity - * @throws IOException - * if an I/O error occurs - * @throws FcpException - * if an FCP error occurs + * @throws IOException if an I/O error occurs + * @throws FcpException if an FCP error occurs */ - public OwnIdentity createIdentity(String nickname, String context, boolean publishTrustList, String requestUri, String insertUri) throws IOException, FcpException { - Map parameters = new HashMap(); + public OwnIdentity createIdentity(String nickname, String context, boolean publishTrustList, String insertUri) throws IOException, FcpException { + Map parameters = new HashMap<>(); parameters.put("Message", "CreateIdentity"); parameters.put("Nickname", nickname); parameters.put("Context", context); parameters.put("PublishTrustList", String.valueOf(publishTrustList)); - if ((requestUri != null) && (insertUri != null)) { - parameters.put("RequestURI", requestUri); + if (insertUri != null) { parameters.put("InsertURI", insertUri); } Map replies = fcpClient.sendPluginMessage(webOfTrustPluginName, parameters); @@ -106,6 +92,22 @@ public class WebOfTrustPlugin { } /** + * Creates a new identity from the given request and insert URI. + * + * @param nickname The nickname of the new identity + * @param context The context for the new identity + * @param publishTrustList {@code true} if the new identity should publish its trust list + * @param requestUri The request URI of the identity (ignored) + * @param insertUri The insert URI of the identity + * @return The new identity + * @throws IOException if an I/O error occurs + * @throws FcpException if an FCP error occurs + */ + public OwnIdentity createIdentity(String nickname, String context, boolean publishTrustList, @SuppressWarnings("unused") String requestUri, String insertUri) throws IOException, FcpException { + return createIdentity(nickname, context, publishTrustList, insertUri); + } + + /** * Returns all own identities of the web-of-trust plugins. Almost all other * commands require an {@link OwnIdentity} to return meaningful values. * diff --git a/src/test/java/net/pterodactylus/fcp/plugin/WebOfTrustPluginTest.java b/src/test/java/net/pterodactylus/fcp/plugin/WebOfTrustPluginTest.java new file mode 100644 index 0000000..1063947 --- /dev/null +++ b/src/test/java/net/pterodactylus/fcp/plugin/WebOfTrustPluginTest.java @@ -0,0 +1,206 @@ +package net.pterodactylus.fcp.plugin; + +import net.pterodactylus.fcp.FCPPluginReply; +import net.pterodactylus.fcp.FcpConnection; +import net.pterodactylus.fcp.FcpListener; +import net.pterodactylus.fcp.FcpMessage; +import net.pterodactylus.fcp.highlevel.FcpClient; +import net.pterodactylus.fcp.highlevel.FcpException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.Timeout; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; + +import static net.pterodactylus.fcp.test.IdentityMatchers.isOwnIdentity; +import static net.pterodactylus.fcp.test.Matchers.hasField; +import static net.pterodactylus.fcp.test.Matchers.isNamed; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThrows; + +public class WebOfTrustPluginTest { + + @Test + public void creatingIdentityWithoutKeysSendsCorrectMessage() throws IOException, FcpException { + TestFcpConnection fcpConnection = createConnectionThatCreatesOwnIdentity(); + WebOfTrustPlugin webOfTrustPlugin = createWebOfTrustPlugin(fcpConnection); + webOfTrustPlugin.createIdentity("Test Nickname", "test-context", true); + assertThat(fcpConnection.sentMessages.get(0), allOf( + isNamed(equalTo("FCPPluginMessage")), + hasField("Identifier", not(nullValue())), + hasField("PluginName", equalTo("plugins.WebOfTrust.WebOfTrust")), + hasField("Param.Message", equalTo("CreateIdentity")), + hasField("Param.Nickname", equalTo("Test Nickname")), + hasField("Param.Context", equalTo("test-context")), + hasField("Param.PublishTrustList", equalTo("true")), + hasField("Param.InsertURI", nullValue()) + )); + } + + @Test + public void creatingIdentityWithoutKeysCreatesCorrectOwnIdentityFromReply() throws IOException, FcpException { + TestFcpConnection fcpConnection = createConnectionThatCreatesOwnIdentity(); + WebOfTrustPlugin webOfTrustPlugin = createWebOfTrustPlugin(fcpConnection); + OwnIdentity ownIdentity = webOfTrustPlugin.createIdentity("Test Nickname", "test-context", true); + assertThat(ownIdentity, isOwnIdentity(equalTo("identity"), equalTo("Test Nickname"), equalTo("request-uri"), equalTo("insert-uri"))); + } + + @Test + public void creatingIdentityWithInsertKeySendsCorrectMessage() throws IOException, FcpException { + TestFcpConnection fcpConnection = createConnectionThatCreatesOwnIdentity(); + WebOfTrustPlugin webOfTrustPlugin = createWebOfTrustPlugin(fcpConnection); + webOfTrustPlugin.createIdentity("Test Nickname", "test-context", true, "insert-uri"); + assertThat(fcpConnection.sentMessages.get(0), allOf( + isNamed(equalTo("FCPPluginMessage")), + hasField("Identifier", not(nullValue())), + hasField("PluginName", equalTo("plugins.WebOfTrust.WebOfTrust")), + hasField("Param.Message", equalTo("CreateIdentity")), + hasField("Param.Nickname", equalTo("Test Nickname")), + hasField("Param.Context", equalTo("test-context")), + hasField("Param.PublishTrustList", equalTo("true")), + hasField("Param.InsertURI", equalTo("insert-uri")) + )); + } + + @Test + public void creatingIdentityWithInsertKeyCreatesCorrectOwnIdentityFromReply() throws IOException, FcpException { + TestFcpConnection fcpConnection = createConnectionThatCreatesOwnIdentity(); + WebOfTrustPlugin webOfTrustPlugin = createWebOfTrustPlugin(fcpConnection); + OwnIdentity ownIdentity = webOfTrustPlugin.createIdentity("Test Nickname", "test-context", true, "insert-uri"); + assertThat(ownIdentity, isOwnIdentity(equalTo("identity"), equalTo("Test Nickname"), equalTo("request-uri"), equalTo("insert-uri"))); + } + + @Test + public void creatingIdentityWithInsertAndRequestKeysSendsCorrectMessage() throws IOException, FcpException { + TestFcpConnection fcpConnection = createConnectionThatCreatesOwnIdentity(); + WebOfTrustPlugin webOfTrustPlugin = createWebOfTrustPlugin(fcpConnection); + webOfTrustPlugin.createIdentity("Test Nickname", "test-context", true, "some-request-uri", "insert-uri"); + assertThat(fcpConnection.sentMessages.get(0), allOf( + isNamed(equalTo("FCPPluginMessage")), + hasField("Identifier", not(nullValue())), + hasField("PluginName", equalTo("plugins.WebOfTrust.WebOfTrust")), + hasField("Param.Message", equalTo("CreateIdentity")), + hasField("Param.Nickname", equalTo("Test Nickname")), + hasField("Param.Context", equalTo("test-context")), + hasField("Param.PublishTrustList", equalTo("true")), + hasField("Param.InsertURI", equalTo("insert-uri")) + )); + } + + @Test + public void creatingIdentityWithInsertAndRequestKeysCreatesCorrectOwnIdentityFromReply() throws IOException, FcpException { + TestFcpConnection fcpConnection = createConnectionThatCreatesOwnIdentity(); + WebOfTrustPlugin webOfTrustPlugin = createWebOfTrustPlugin(fcpConnection); + OwnIdentity ownIdentity = webOfTrustPlugin.createIdentity("Test Nickname", "test-context", true, "some-request-uri", "insert-uri"); + assertThat(ownIdentity, isOwnIdentity(equalTo("identity"), equalTo("Test Nickname"), equalTo("request-uri"), equalTo("insert-uri"))); + } + + private TestFcpConnection createConnectionThatCreatesOwnIdentity() { + return createFcpConnection(message -> (listener, connection) -> { + Map fields = createWebOfTrustReplyFields("IdentityCreated", true, + "Success", "true", "Replies.Message", "IdentityCreated", "Replies.ID", "identity", "Replies.InsertURI", "insert-uri", "Replies.RequestURI", "request-uri"); + FcpMessage replyMessage = createPluginReply(message, fields); + listener.receivedFCPPluginReply(connection, new FCPPluginReply(replyMessage, null)); + }); + } + + @Test + public void creatingIdentityFailsWhenDifferentReplyIsSentByPlugin() { + FcpConnection fcpConnection = createFcpConnection(message -> (listener, connection) -> { + Map fields = createWebOfTrustReplyFields("OtherMessage", true); + FcpMessage replyMessage = createPluginReply(message, fields); + listener.receivedFCPPluginReply(connection, new FCPPluginReply(replyMessage, null)); + }); + WebOfTrustPlugin webOfTrustPlugin = createWebOfTrustPlugin(fcpConnection); + assertThrows(FcpException.class, () -> webOfTrustPlugin.createIdentity("Test Nickname", "test-context", true, "some-request-uri", "insert-uri")); + } + + private static WebOfTrustPlugin createWebOfTrustPlugin(FcpConnection fcpConnection) { + return new WebOfTrustPlugin(new FcpClient(fcpConnection)); + } + + private Map createWebOfTrustReplyFields(String message, boolean success, String... fields) { + Map replyFields = new HashMap<>(); + replyFields.put("Success", String.valueOf(success)); + replyFields.put("Replies.Message", message); + for (int fieldIndex = 0; fieldIndex < fields.length - 1; fieldIndex += 2) { + replyFields.put(fields[fieldIndex], fields[fieldIndex + 1]); + } + return replyFields; + } + + private FcpMessage createPluginReply(FcpMessage pluginMessage, Map fields) { + FcpMessage replyMessage = new FcpMessage("FCPPluginReply"); + replyMessage.setField("Identifier", pluginMessage.getField("Identifier")); + replyMessage.setField("PluginName", pluginMessage.getField("PluginName")); + fields.forEach(replyMessage::setField); + return replyMessage; + } + + private static TestFcpConnection createFcpConnection(Function> messageConsumer) { + return new TestFcpConnection(messageConsumer); + } + + @Rule + public final Timeout timeout = Timeout.seconds(5); + + private static class TestFcpConnection implements FcpConnection { + + public TestFcpConnection(Function> messageConsumer) { + this.messageConsumer = messageConsumer; + } + + @Override + public void addFcpListener(FcpListener fcpListener) { + listeners.add(fcpListener); + } + + @Override + public void removeFcpListener(FcpListener fcpListener) { + listeners.remove(fcpListener); + } + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public void connect() throws IllegalStateException { + } + + @Override + public void disconnect() { + close(); + } + + @Override + public void close() { + closed = true; + } + + @Override + public void sendMessage(FcpMessage fcpMessage) { + sentMessages.add(fcpMessage); + BiConsumer listenerNotifier = messageConsumer.apply(fcpMessage); + listeners.forEach(listener -> new Thread(() -> listenerNotifier.accept(listener, this)).start()); + } + + private final Function> messageConsumer; + private final List listeners = new ArrayList<>(); + private volatile boolean closed = false; + private final List sentMessages = new ArrayList<>(); + + } + +} diff --git a/src/test/java/net/pterodactylus/fcp/test/IdentityMatchers.java b/src/test/java/net/pterodactylus/fcp/test/IdentityMatchers.java new file mode 100644 index 0000000..80ddde5 --- /dev/null +++ b/src/test/java/net/pterodactylus/fcp/test/IdentityMatchers.java @@ -0,0 +1,42 @@ +package net.pterodactylus.fcp.test; + +import net.pterodactylus.fcp.plugin.OwnIdentity; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +public class IdentityMatchers { + + public static Matcher isOwnIdentity(Matcher identifier, Matcher nickname, Matcher requestUri, Matcher insertUri) { + return new TypeSafeDiagnosingMatcher(OwnIdentity.class) { + @Override + protected boolean matchesSafely(OwnIdentity ownIdentity, Description mismatchDescription) { + if (!identifier.matches(ownIdentity.getIdentifier())) { + mismatchDescription.appendText("identifier is ").appendValue(ownIdentity.getIdentifier()); + return false; + } + if (!nickname.matches(ownIdentity.getNickname())) { + mismatchDescription.appendText("nickname is ").appendValue(ownIdentity.getNickname()); + return false; + } + if (!requestUri.matches(ownIdentity.getRequestUri())) { + mismatchDescription.appendText("public uri is ").appendValue(ownIdentity.getRequestUri()); + return false; + } + if (!insertUri.matches(ownIdentity.getInsertUri())) { + mismatchDescription.appendText("private uri is ").appendValue(ownIdentity.getInsertUri()); + return false; + } + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText("is identity (").appendValue(identifier).appendText(", nicknamed ").appendValue(nickname) + .appendText(", public uri ").appendValue(requestUri).appendText(", private uri ").appendValue(insertUri).appendText(")"); + } + + }; + } + +} diff --git a/src/test/java/net/pterodactylus/fcp/test/Matchers.java b/src/test/java/net/pterodactylus/fcp/test/Matchers.java index 264851f..85985c6 100644 --- a/src/test/java/net/pterodactylus/fcp/test/Matchers.java +++ b/src/test/java/net/pterodactylus/fcp/test/Matchers.java @@ -101,6 +101,24 @@ public class Matchers { }; } + public static Matcher isNamed(Matcher nameMatcher) { + return new TypeSafeDiagnosingMatcher(FcpMessage.class) { + @Override + protected boolean matchesSafely(FcpMessage fcpMessage, Description mismatchDescription) { + if (!nameMatcher.matches(fcpMessage.getName())) { + nameMatcher.describeMismatch(fcpMessage.getName(), mismatchDescription); + return false; + } + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText("is named ").appendValue(nameMatcher); + } + }; + } + public static Matcher matches(String name, Predicate predicate) { return new TypeSafeDiagnosingMatcher() { @Override -- 2.7.4