Generate identifiers randomly
authorDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Mon, 6 Jul 2015 17:28:07 +0000 (19:28 +0200)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Mon, 6 Jul 2015 17:28:07 +0000 (19:28 +0200)
src/main/java/net/pterodactylus/fcp/quelaton/ClientGetCommand.java
src/main/java/net/pterodactylus/fcp/quelaton/ClientGetCommandImpl.java
src/main/java/net/pterodactylus/fcp/quelaton/RandomIdentifierGenerator.java [new file with mode: 0644]
src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java

index 60a46d0..280daae 100644 (file)
@@ -13,7 +13,6 @@ import net.pterodactylus.fcp.Priority;
  */
 public interface ClientGetCommand {
 
-       ClientGetCommand identifier(String identifier);
        ClientGetCommand ignoreDataStore();
        ClientGetCommand dataStoreOnly();
        ClientGetCommand maxSize(long maxSize);
index b4e391a..98c416f 100644 (file)
@@ -6,9 +6,11 @@ import java.util.Optional;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 
 import net.pterodactylus.fcp.AllData;
 import net.pterodactylus.fcp.ClientGet;
+import net.pterodactylus.fcp.FcpMessage;
 import net.pterodactylus.fcp.FcpUtils.TempInputStream;
 import net.pterodactylus.fcp.GetFailed;
 import net.pterodactylus.fcp.Priority;
@@ -24,7 +26,6 @@ class ClientGetCommandImpl implements ClientGetCommand {
        private final ExecutorService threadPool;
        private final ConnectionSupplier connectionSupplier;
 
-       private String identifier;
        private boolean ignoreDataStore;
        private boolean dataStoreOnly;
        private Long maxSize;
@@ -38,12 +39,6 @@ class ClientGetCommandImpl implements ClientGetCommand {
        }
 
        @Override
-       public ClientGetCommand identifier(String identifier) {
-               this.identifier = identifier;
-               return this;
-       }
-
-       @Override
        public ClientGetCommand ignoreDataStore() {
                ignoreDataStore = true;
                return this;
@@ -86,6 +81,7 @@ class ClientGetCommandImpl implements ClientGetCommand {
        }
 
        private ClientGet createClientGetCommand(String uri) {
+               String identifier = new RandomIdentifierGenerator().generate();
                ClientGet clientGet = new ClientGet(uri, identifier, ReturnType.direct);
                if (ignoreDataStore) {
                        clientGet.setIgnoreDataStore(true);
@@ -110,11 +106,10 @@ class ClientGetCommandImpl implements ClientGetCommand {
 
        private class ClientGetReplySequence extends FcpReplySequence<Optional<Data>> {
 
+               private final AtomicReference<String> identifier = new AtomicReference<>();
                private final AtomicBoolean finished = new AtomicBoolean();
                private final AtomicBoolean failed = new AtomicBoolean();
 
-               private final String identifier = ClientGetCommandImpl.this.identifier;
-
                private String contentType;
                private long dataLength;
                private InputStream payload;
@@ -150,7 +145,7 @@ class ClientGetCommandImpl implements ClientGetCommand {
 
                @Override
                protected void consumeAllData(AllData allData) {
-                       if (allData.getIdentifier().equals(identifier)) {
+                       if (allData.getIdentifier().equals(identifier.get())) {
                                synchronized (this) {
                                        contentType = allData.getContentType();
                                        dataLength = allData.getDataLength();
@@ -167,7 +162,7 @@ class ClientGetCommandImpl implements ClientGetCommand {
 
                @Override
                protected void consumeGetFailed(GetFailed getFailed) {
-                       if (getFailed.getIdentifier().equals(identifier)) {
+                       if (getFailed.getIdentifier().equals(identifier.get())) {
                                failed.set(true);
                        }
                }
@@ -177,6 +172,12 @@ class ClientGetCommandImpl implements ClientGetCommand {
                        failed.set(true);
                }
 
+               @Override
+               public Future<Optional<Data>> send(FcpMessage fcpMessage) throws IOException {
+                       identifier.set(fcpMessage.getField("Identifier"));
+                       return super.send(fcpMessage);
+               }
+
        }
 
 }
diff --git a/src/main/java/net/pterodactylus/fcp/quelaton/RandomIdentifierGenerator.java b/src/main/java/net/pterodactylus/fcp/quelaton/RandomIdentifierGenerator.java
new file mode 100644 (file)
index 0000000..df5aaf6
--- /dev/null
@@ -0,0 +1,25 @@
+package net.pterodactylus.fcp.quelaton;
+
+import java.util.Random;
+import java.util.stream.IntStream;
+
+/**
+ * Generates random identifiers.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class RandomIdentifierGenerator {
+
+       private final Random random = new Random();
+
+       public String generate() {
+               StringBuilder stringBuilder = new StringBuilder(32);
+               IntStream.range(0, 32).forEach((i) -> stringBuilder.append(generateRandomLetter()));
+               return stringBuilder.toString();
+       }
+
+       private char generateRandomLetter() {
+               return (char) (65 + (random.nextInt(26)) + (random.nextBoolean() ? 32 : 0));
+       }
+
+}
index 020ee33..7163462 100644 (file)
@@ -19,6 +19,9 @@ import net.pterodactylus.fcp.fake.FakeTcpServer;
 import net.pterodactylus.fcp.quelaton.ClientGetCommand.Data;
 
 import com.google.common.io.ByteStreams;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
 import org.junit.After;
 import org.junit.Test;
 
@@ -83,19 +86,14 @@ public class DefaultFcpClientTest {
 
        @Test
        public void clientGetCanDownloadData() throws InterruptedException, ExecutionException, IOException {
-               Future<Optional<Data>> dataFuture = fcpClient.clientGet().identifier("test").uri("KSK@foo.txt");
+               Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "ReturnType=direct", "URI=KSK@foo.txt"));
+               String identifier = extractIdentifier(lines);
                fcpServer.writeLine(
                        "AllData",
-                       "Identifier=test",
+                       "Identifier=" + identifier,
                        "DataLength=6",
                        "StartupTime=1435610539000",
                        "CompletionTime=1435610540000",
@@ -109,18 +107,17 @@ public class DefaultFcpClientTest {
                assertThat(ByteStreams.toByteArray(data.get().getInputStream()), is("Hello\n".getBytes(StandardCharsets.UTF_8)));
        }
 
+       private String extractIdentifier(List<String> lines) {
+               return lines.stream().filter(s -> s.startsWith("Identifier=")).map(s -> s.substring(s.indexOf('=') + 1)).findFirst().orElse("");
+       }
+
        @Test
        public void clientGetDownloadsDataForCorrectIdentifier() throws InterruptedException, ExecutionException, IOException {
-               Future<Optional<Data>> dataFuture = fcpClient.clientGet().identifier("test").uri("KSK@foo.txt");
+               Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
+               String identifier = extractIdentifier(lines);
                fcpServer.writeLine(
                        "AllData",
                        "Identifier=not-test",
@@ -133,7 +130,7 @@ public class DefaultFcpClientTest {
                );
                fcpServer.writeLine(
                        "AllData",
-                       "Identifier=test",
+                       "Identifier=" + identifier,
                        "DataLength=6",
                        "StartupTime=1435610539000",
                        "CompletionTime=1435610540000",
@@ -149,19 +146,14 @@ public class DefaultFcpClientTest {
 
        @Test
        public void clientGetRecognizesGetFailed() throws InterruptedException, ExecutionException, IOException {
-               Future<Optional<Data>> dataFuture = fcpClient.clientGet().identifier("test").uri("KSK@foo.txt");
+               Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
+               String identifier = extractIdentifier(lines);
                fcpServer.writeLine(
                        "GetFailed",
-                       "Identifier=test",
+                       "Identifier=" + identifier,
                        "Code=3",
                        "EndMessage"
                );
@@ -171,16 +163,11 @@ public class DefaultFcpClientTest {
 
        @Test
        public void clientGetRecognizesGetFailedForCorrectIdentifier() throws InterruptedException, ExecutionException, IOException {
-               Future<Optional<Data>> dataFuture = fcpClient.clientGet().identifier("test").uri("KSK@foo.txt");
+               Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
+               String identifier = extractIdentifier(lines);
                fcpServer.writeLine(
                        "GetFailed",
                        "Identifier=not-test",
@@ -189,7 +176,7 @@ public class DefaultFcpClientTest {
                );
                fcpServer.writeLine(
                        "GetFailed",
-                       "Identifier=test",
+                       "Identifier=" + identifier,
                        "Code=3",
                        "EndMessage"
                );
@@ -199,16 +186,10 @@ public class DefaultFcpClientTest {
 
        @Test
        public void clientGetRecognizesConnectionClosed() throws InterruptedException, ExecutionException, IOException {
-               Future<Optional<Data>> dataFuture = fcpClient.clientGet().identifier("test").uri("KSK@foo.txt");
+               Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
                fcpServer.close();
                Optional<Data> data = dataFuture.get();
                assertThat(data.isPresent(), is(false));
@@ -216,92 +197,75 @@ public class DefaultFcpClientTest {
 
        @Test
        public void clientGetWithIgnoreDataStoreSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
-               fcpClient.clientGet().ignoreDataStore().identifier("test").uri("KSK@foo.txt");
+               fcpClient.clientGet().ignoreDataStore().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "IgnoreDS=true",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "IgnoreDS=true"));
        }
 
        @Test
        public void clientGetWithDataStoreOnlySettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
-               fcpClient.clientGet().dataStoreOnly().identifier("test").uri("KSK@foo.txt");
+               fcpClient.clientGet().dataStoreOnly().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "DSonly=true",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "DSonly=true"));
        }
 
        @Test
        public void clientGetWithMaxSizeSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
-               fcpClient.clientGet().maxSize(1048576).identifier("test").uri("KSK@foo.txt");
+               fcpClient.clientGet().maxSize(1048576).uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "MaxSize=1048576",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "MaxSize=1048576"));
        }
 
        @Test
        public void clientGetWithPrioritySettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
-               fcpClient.clientGet().priority(Priority.interactive).identifier("test").uri("KSK@foo.txt");
+               fcpClient.clientGet().priority(Priority.interactive).uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "PriorityClass=1",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "PriorityClass=1"));
        }
 
        @Test
        public void clientGetWithRealTimeSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
-               fcpClient.clientGet().realTime().identifier("test").uri("KSK@foo.txt");
+               fcpClient.clientGet().realTime().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "RealTimeFlag=true",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "RealTimeFlag=true"));
        }
 
        @Test
        public void clientGetWithGlobalSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
-               fcpClient.clientGet().global().identifier("test").uri("KSK@foo.txt");
+               fcpClient.clientGet().global().uri("KSK@foo.txt");
                connectNode();
                List<String> lines = fcpServer.collectUntil(is("EndMessage"));
-               assertThat(lines, containsInAnyOrder(
-                       "ClientGet",
-                       "Identifier=test",
-                       "ReturnType=direct",
-                       "URI=KSK@foo.txt",
-                       "Global=true",
-                       "EndMessage"
-               ));
+               assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "Global=true"));
+       }
+
+       private Matcher<List<String>> matchesFcpMessage(String name, String... requiredLines) {
+               return new TypeSafeDiagnosingMatcher<List<String>>() {
+                       @Override
+                       protected boolean matchesSafely(List<String> item, Description mismatchDescription) {
+                               if (!item.get(0).equals(name)) {
+                                       mismatchDescription.appendText("FCP message is named ").appendValue(item.get(0));
+                                       return false;
+                               }
+                               for (String requiredLine : requiredLines) {
+                                       if (item.indexOf(requiredLine) < 1) {
+                                               mismatchDescription.appendText("FCP message does not contain ").appendValue(requiredLine);
+                                               return false;
+                                       }
+                               }
+                               return true;
+                       }
+
+                       @Override
+                       public void describeTo(Description description) {
+                               description.appendText("FCP message named ").appendValue(name);
+                               description.appendValueList(", containing the lines", ", ", "", requiredLines);
+                       }
+               };
        }
 
 }