✅ Add beginning of test for FcpClient
authorDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Tue, 3 Sep 2024 12:04:23 +0000 (14:04 +0200)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Tue, 3 Sep 2024 13:06:46 +0000 (15:06 +0200)
src/test/java/net/pterodactylus/fcp/highlevel/FcpClientTest.java [new file with mode: 0644]

diff --git a/src/test/java/net/pterodactylus/fcp/highlevel/FcpClientTest.java b/src/test/java/net/pterodactylus/fcp/highlevel/FcpClientTest.java
new file mode 100644 (file)
index 0000000..833a75b
--- /dev/null
@@ -0,0 +1,248 @@
+package net.pterodactylus.fcp.highlevel;
+
+import net.pterodactylus.fcp.AllData;
+import net.pterodactylus.fcp.FcpConnection;
+import net.pterodactylus.fcp.FcpListener;
+import net.pterodactylus.fcp.FcpMessage;
+import net.pterodactylus.fcp.GetFailed;
+import net.pterodactylus.fcp.NodeHello;
+import net.pterodactylus.fcp.SSKKeypair;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.Timeout;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+public class FcpClientTest {
+
+       @Test
+       public void canCreateFcpClient() {
+               FcpConnection fcpConnection = createFcpConnection();
+               try (FcpClient fcpClient = new FcpClient(fcpConnection)) {
+               }
+       }
+
+       @Test
+       public void connectingFcpClientSendsClientHelloWithCorrectClientName() throws IOException, FcpException {
+               sendAndVerifyClientHelloMessage("Name", "Test Client");
+       }
+
+       @Test
+       public void connectingFcpClientSendsClientHelloWithCorrectExpectedVersion() throws IOException, FcpException {
+               sendAndVerifyClientHelloMessage("ExpectedVersion", "2.0");
+       }
+
+       private static void sendAndVerifyClientHelloMessage(String messageField, String expectedValue) throws IOException, FcpException {
+               AtomicReference<String> sentMessageField = new AtomicReference<>();
+               FcpConnection fcpConnection = createFcpConnection(message -> {
+                       if (message.getName().equals("ClientHello")) {
+                               sentMessageField.set(message.getField(messageField));
+                               return (listener, connection) -> listener.receivedNodeHello(connection, new NodeHello(new FcpMessage("NodeHello").put("Node", "TestNode")));
+                       }
+                       return (l, c) -> {
+                       };
+               });
+               try (FcpClient fcpClient = new FcpClient(fcpConnection, false)) {
+                       fcpClient.connect("Test Client");
+                       assertThat(sentMessageField.get(), equalTo(expectedValue));
+               }
+       }
+
+       @Test
+       public void closingFcpClientWillCloseFcpConnection() {
+               FcpConnection fcpConnection = createFcpConnection();
+               try (FcpClient fcpClient = new FcpClient(fcpConnection)) {
+               }
+               assertThat(fcpConnection.isClosed(), equalTo(true));
+       }
+
+       @Test
+       public void getUriReturnsSuccessfulGetResult() throws Exception {
+               sendClientGetAndReturnAllData(message -> (listener, connection) -> {
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test")) {
+                               listener.receivedAllData(connection, new AllData(new FcpMessage("AllData").put("Identifier", message.getField("Identifier")).put("ContentType", "text/plain").put("DataLength", "4"), new ByteArrayInputStream("Data".getBytes())));
+                       }
+               });
+       }
+
+       @Test
+       public void getUriIgnoresAllDataForDifferentIdentifier() throws Exception {
+               sendClientGetAndReturnAllData(message -> (listener, connection) -> {
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test")) {
+                               listener.receivedAllData(connection, new AllData(new FcpMessage("AllData").put("Identifier", "OtherIdentifier").put("ContentType", "text/plain").put("DataLength", "2"), new ByteArrayInputStream("OK".getBytes())));
+                               listener.receivedAllData(connection, new AllData(new FcpMessage("AllData").put("Identifier", message.getField("Identifier")).put("ContentType", "text/plain").put("DataLength", "4"), new ByteArrayInputStream("Data".getBytes())));
+                       }
+               });
+       }
+
+       @Test
+       public void getUriFollowsRedirectForCode27() throws Exception {
+               sendClientGetAndReturnAllData(message -> (listener, connection) -> {
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test")) {
+                               listener.receivedGetFailed(connection, new GetFailed(new FcpMessage("GetFailed").put("Identifier", message.getField("Identifier")).put("Code", "27").put("RedirectURI", "KSK@test-2")));
+                       }
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test-2")) {
+                               listener.receivedAllData(connection, new AllData(new FcpMessage("AllData").put("Identifier", message.getField("Identifier")).put("ContentType", "text/plain").put("DataLength", "4"), new ByteArrayInputStream("Data".getBytes())));
+                       }
+               });
+       }
+
+       @Test
+       public void getUriFollowsRedirectForCode24() throws Exception {
+               sendClientGetAndReturnAllData(message -> (listener, connection) -> {
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test")) {
+                               listener.receivedGetFailed(connection, new GetFailed(new FcpMessage("GetFailed").put("Identifier", message.getField("Identifier")).put("Code", "24").put("RedirectURI", "KSK@test-2")));
+                       }
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test-2")) {
+                               listener.receivedAllData(connection, new AllData(new FcpMessage("AllData").put("Identifier", message.getField("Identifier")).put("ContentType", "text/plain").put("DataLength", "4"), new ByteArrayInputStream("Data".getBytes())));
+                       }
+               });
+       }
+
+       @Test
+       public void getUriIgnoresGetFailedForDifferentIdentifier() throws Exception {
+               sendClientGetAndReturnAllData(message -> (listener, connection) -> {
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test")) {
+                               listener.receivedGetFailed(connection, new GetFailed(new FcpMessage("GetFailed").put("Identifier", "OtherIdentifier").put("Code", "1")));
+                               listener.receivedGetFailed(connection, new GetFailed(new FcpMessage("GetFailed").put("Identifier", message.getField("Identifier")).put("Code", "27").put("RedirectURI", "KSK@test-2")));
+                       }
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test-2")) {
+                               listener.receivedAllData(connection, new AllData(new FcpMessage("AllData").put("Identifier", message.getField("Identifier")).put("ContentType", "text/plain").put("DataLength", "4"), new ByteArrayInputStream("Data".getBytes())));
+                       }
+               });
+       }
+
+       @Test
+       public void getUriFailesOnGetFailed() throws Exception {
+               FcpConnection fcpConnection = createFcpConnection(message -> (listener, connection) -> {
+                       if (message.getName().equals("ClientGet") && message.getField("URI").equals("KSK@test")) {
+                               listener.receivedGetFailed(connection, new GetFailed(new FcpMessage("GetFailed").put("Identifier", message.getField("Identifier")).put("Code", "123").put("RedirectURI", "KSK@test-2")));
+                       }
+               });
+               try (FcpClient fcpClient = new FcpClient(fcpConnection)) {
+                       GetResult getResult = fcpClient.getURI("KSK@test");
+                       assertThat(getResult.isSuccess(), equalTo(false));
+                       assertThat(getResult.getErrorCode(), equalTo(123));
+               }
+       }
+
+       private void sendClientGetAndReturnAllData(Function<FcpMessage, BiConsumer<FcpListener, FcpConnection>> messageReplier) throws Exception {
+               FcpConnection fcpConnection = createFcpConnection(messageReplier);
+               try (FcpClient fcpClient = new FcpClient(fcpConnection)) {
+                       GetResult getResult = fcpClient.getURI("KSK@test");
+                       assertThat(getResult.isSuccess(), equalTo(true));
+                       assertThat(getResult.getContentLength(), equalTo(4L));
+                       assertThat(getResult.getInputStream(), contains('D', 'a', 't', 'a'));
+               }
+       }
+
+       private Matcher<InputStream> contains(int... content) {
+               return new TypeSafeDiagnosingMatcher<InputStream>() {
+                       @Override
+                       protected boolean matchesSafely(InputStream inputStream, Description mismatchDescription) {
+                               try {
+                                       for (int index = 0; index < content.length; index++) {
+                                               int readByte = inputStream.read();
+                                               if (readByte != content[index]) {
+                                                       mismatchDescription.appendText("was ").appendValue(readByte).appendText(" at offset ").appendValue(index);
+                                                       return false;
+                                               }
+                                       }
+                                       int eof = inputStream.read();
+                                       if (eof != -1) {
+                                               mismatchDescription.appendText("contained more than ").appendValue(content.length).appendText(" bytes");
+                                               return false;
+                                       }
+                               } catch (IOException e) {
+                                       mismatchDescription.appendText("could not be read (").appendValue(e).appendText(")");
+                                       return false;
+                               }
+                               return true;
+                       }
+
+                       @Override
+                       public void describeTo(Description description) {
+                               description.appendText("is input stream containing ").appendValue(content);
+                       }
+               };
+       }
+
+       @Test
+       public void generatingKeyPairSendsCorrectMessage() throws IOException, FcpException {
+               FcpConnection fcpConnection = createFcpConnection(message -> {
+                       if (message.getName().equals("GenerateSSK")) {
+                               return ((listener, connection) -> listener.receivedSSKKeypair(connection, new SSKKeypair(new FcpMessage("SSKKeypair").put("InsertURI", "insert-uri").put("RequestURI", "request-uri"))));
+                       }
+                       return (l, c) -> {
+                       };
+               });
+               try (FcpClient fcpClient = new FcpClient(fcpConnection)) {
+                       SSKKeypair keypair = fcpClient.generateKeyPair();
+                       assertThat(keypair.getInsertURI(), equalTo("insert-uri"));
+                       assertThat(keypair.getRequestURI(), equalTo("request-uri"));
+               }
+       }
+
+       private static FcpConnection createFcpConnection() {
+               return createFcpConnection(m -> (l, c) -> {
+               });
+       }
+
+       private static FcpConnection createFcpConnection(Function<FcpMessage, BiConsumer<FcpListener, FcpConnection>> messageConsumer) {
+               return new FcpConnection() {
+                       private final List<FcpListener> listeners = new ArrayList<>();
+                       private volatile boolean closed = false;
+
+                       @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 IOException, IllegalStateException {
+                       }
+
+                       @Override
+                       public void disconnect() {
+                               close();
+                       }
+
+                       @Override
+                       public void close() {
+                               closed = true;
+                       }
+
+                       @Override
+                       public void sendMessage(FcpMessage fcpMessage) {
+                               listeners.forEach(listener -> messageConsumer.apply(fcpMessage).accept(listener, this));
+                       }
+               };
+       }
+
+       @Rule
+       public final Timeout timeout = Timeout.seconds(5);
+
+}