From: David ‘Bombe’ Roden Date: Tue, 3 Sep 2024 12:04:23 +0000 (+0200) Subject: ✅ Add beginning of test for FcpClient X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=767c7612bf6262c384565476af5b6020fcb2731a;p=jFCPlib.git ✅ Add beginning of test for FcpClient --- 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 index 0000000..833a75b --- /dev/null +++ b/src/test/java/net/pterodactylus/fcp/highlevel/FcpClientTest.java @@ -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 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> 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 contains(int... content) { + return new TypeSafeDiagnosingMatcher() { + @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> messageConsumer) { + return new FcpConnection() { + private final List 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); + +}