✅ Add test for WebOfTrustPlugin
authorDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Tue, 7 Jan 2025 20:31:08 +0000 (21:31 +0100)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Wed, 8 Jan 2025 06:25:17 +0000 (07:25 +0100)
src/main/java/net/pterodactylus/fcp/plugin/WebOfTrustPlugin.java
src/test/java/net/pterodactylus/fcp/plugin/WebOfTrustPluginTest.java [new file with mode: 0644]
src/test/java/net/pterodactylus/fcp/test/IdentityMatchers.java [new file with mode: 0644]
src/test/java/net/pterodactylus/fcp/test/Matchers.java

index 83f65b1..464c6da 100644 (file)
@@ -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<String, String> parameters = new HashMap<String, String>();
+       public OwnIdentity createIdentity(String nickname, String context, boolean publishTrustList, String insertUri) throws IOException, FcpException {
+               Map<String, String> 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<String, String> 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 (file)
index 0000000..1063947
--- /dev/null
@@ -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<String, String> 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<String, String> 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<String, String> createWebOfTrustReplyFields(String message, boolean success, String... fields) {
+               Map<String, String> 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<String, String> 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<FcpMessage, BiConsumer<FcpListener, FcpConnection>> messageConsumer) {
+               return new TestFcpConnection(messageConsumer);
+       }
+
+       @Rule
+       public final Timeout timeout = Timeout.seconds(5);
+
+       private static class TestFcpConnection implements FcpConnection {
+
+               public TestFcpConnection(Function<FcpMessage, BiConsumer<FcpListener, FcpConnection>> 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<FcpListener, FcpConnection> listenerNotifier = messageConsumer.apply(fcpMessage);
+                       listeners.forEach(listener -> new Thread(() -> listenerNotifier.accept(listener, this)).start());
+               }
+
+               private final Function<FcpMessage, BiConsumer<FcpListener, FcpConnection>> messageConsumer;
+               private final List<FcpListener> listeners = new ArrayList<>();
+               private volatile boolean closed = false;
+               private final List<FcpMessage> 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 (file)
index 0000000..80ddde5
--- /dev/null
@@ -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<OwnIdentity> isOwnIdentity(Matcher<? super String> identifier, Matcher<? super String> nickname, Matcher<? super String> requestUri, Matcher<? super String> insertUri) {
+               return new TypeSafeDiagnosingMatcher<OwnIdentity>(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(")");
+                       }
+
+               };
+       }
+
+}
index 264851f..85985c6 100644 (file)
@@ -101,6 +101,24 @@ public class Matchers {
                };
        }
 
+       public static Matcher<FcpMessage> isNamed(Matcher<? super String> nameMatcher) {
+               return new TypeSafeDiagnosingMatcher<FcpMessage>(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 <R extends Request> Matcher<R> matches(String name, Predicate<R> predicate) {
                return new TypeSafeDiagnosingMatcher<R>() {
                        @Override