1 package net.pterodactylus.fcp.quelaton;
3 import static org.hamcrest.MatcherAssert.assertThat;
4 import static org.hamcrest.Matchers.containsInAnyOrder;
5 import static org.hamcrest.Matchers.is;
7 import java.io.IOException;
8 import java.nio.charset.StandardCharsets;
10 import java.util.Optional;
11 import java.util.concurrent.ExecutionException;
12 import java.util.concurrent.ExecutorService;
13 import java.util.concurrent.Executors;
14 import java.util.concurrent.Future;
16 import net.pterodactylus.fcp.FcpKeyPair;
17 import net.pterodactylus.fcp.Priority;
18 import net.pterodactylus.fcp.fake.FakeTcpServer;
19 import net.pterodactylus.fcp.quelaton.ClientGetCommand.Data;
21 import com.google.common.io.ByteStreams;
22 import org.hamcrest.Description;
23 import org.hamcrest.Matcher;
24 import org.hamcrest.TypeSafeDiagnosingMatcher;
25 import org.junit.After;
26 import org.junit.Test;
29 * Unit test for {@link DefaultFcpClient}.
31 * @author <a href="bombe@freenetproject.org">David ‘Bombe’ Roden</a>
33 public class DefaultFcpClientTest {
35 private static final String INSERT_URI = "SSK@RVCHbJdkkyTCeNN9AYukEg76eyqmiosSaNKgE3U9zUw,7SHH53gletBVb9JD7nBsyClbLQsBubDPEIcwg908r7Y,AQECAAE/";
36 private static final String REQUEST_URI = "SSK@wtbgd2loNcJCXvtQVOftl2tuWBomDQHfqS6ytpPRhfw,7SHH53gletBVb9JD7nBsyClbLQsBubDPEIcwg908r7Y,AQACAAE/";
38 private static int threadCounter = 0;
39 private final ExecutorService threadPool = Executors.newCachedThreadPool((r) -> new Thread(r, "Test-Thread-" + threadCounter++));
40 private final FakeTcpServer fcpServer;
41 private final DefaultFcpClient fcpClient;
43 public DefaultFcpClientTest() throws IOException {
44 fcpServer = new FakeTcpServer(threadPool);
45 fcpClient = new DefaultFcpClient(threadPool, "localhost", fcpServer.getPort(), () -> "Test", () -> "2.0");
49 public void tearDown() throws IOException {
54 public void defaultFcpClientCanGenerateKeypair() throws ExecutionException, InterruptedException, IOException {
55 Future<FcpKeyPair> keyPairFuture = fcpClient.generateKeypair().execute();
57 fcpServer.collectUntil(is("EndMessage"));
58 fcpServer.writeLine("SSKKeypair",
59 "InsertURI=" + INSERT_URI + "",
60 "RequestURI=" + REQUEST_URI + "",
61 "Identifier=My Identifier from GenerateSSK",
63 FcpKeyPair keyPair = keyPairFuture.get();
64 assertThat(keyPair.getPublicKey(), is(REQUEST_URI));
65 assertThat(keyPair.getPrivateKey(), is(INSERT_URI));
68 private void connectNode() throws InterruptedException, ExecutionException, IOException {
69 fcpServer.connect().get();
70 fcpServer.collectUntil(is("EndMessage"));
71 fcpServer.writeLine("NodeHello",
72 "CompressionCodecs=4 - GZIP(0), BZIP2(1), LZMA(2), LZMA_NEW(3)",
73 "Revision=build01466",
75 "Version=Fred,0.7,1.0,1466",
77 "ConnectionIdentifier=14318898267048452a81b36e7f13a3f0",
81 "NodeLanguage=ENGLISH",
88 public void clientGetCanDownloadData() throws InterruptedException, ExecutionException, IOException {
89 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
91 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
92 assertThat(lines, matchesFcpMessage("ClientGet", "ReturnType=direct", "URI=KSK@foo.txt"));
93 String identifier = extractIdentifier(lines);
96 "Identifier=" + identifier,
98 "StartupTime=1435610539000",
99 "CompletionTime=1435610540000",
100 "Metadata.ContentType=text/plain;charset=utf-8",
104 Optional<Data> data = dataFuture.get();
105 assertThat(data.get().getMimeType(), is("text/plain;charset=utf-8"));
106 assertThat(data.get().size(), is(6L));
107 assertThat(ByteStreams.toByteArray(data.get().getInputStream()), is("Hello\n".getBytes(StandardCharsets.UTF_8)));
110 private String extractIdentifier(List<String> lines) {
111 return lines.stream().filter(s -> s.startsWith("Identifier=")).map(s -> s.substring(s.indexOf('=') + 1)).findFirst().orElse("");
115 public void clientGetDownloadsDataForCorrectIdentifier() throws InterruptedException, ExecutionException, IOException {
116 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
118 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
119 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
120 String identifier = extractIdentifier(lines);
123 "Identifier=not-test",
125 "StartupTime=1435610539000",
126 "CompletionTime=1435610540000",
127 "Metadata.ContentType=text/plain;charset=latin-9",
133 "Identifier=" + identifier,
135 "StartupTime=1435610539000",
136 "CompletionTime=1435610540000",
137 "Metadata.ContentType=text/plain;charset=utf-8",
141 Optional<Data> data = dataFuture.get();
142 assertThat(data.get().getMimeType(), is("text/plain;charset=utf-8"));
143 assertThat(data.get().size(), is(6L));
144 assertThat(ByteStreams.toByteArray(data.get().getInputStream()), is("Hello\n".getBytes(StandardCharsets.UTF_8)));
148 public void clientGetRecognizesGetFailed() throws InterruptedException, ExecutionException, IOException {
149 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
151 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
152 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
153 String identifier = extractIdentifier(lines);
156 "Identifier=" + identifier,
160 Optional<Data> data = dataFuture.get();
161 assertThat(data.isPresent(), is(false));
165 public void clientGetRecognizesGetFailedForCorrectIdentifier() throws InterruptedException, ExecutionException, IOException {
166 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
168 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
169 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
170 String identifier = extractIdentifier(lines);
173 "Identifier=not-test",
179 "Identifier=" + identifier,
183 Optional<Data> data = dataFuture.get();
184 assertThat(data.isPresent(), is(false));
188 public void clientGetRecognizesConnectionClosed() throws InterruptedException, ExecutionException, IOException {
189 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
191 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
192 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
194 Optional<Data> data = dataFuture.get();
195 assertThat(data.isPresent(), is(false));
199 public void clientGetWithIgnoreDataStoreSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
200 fcpClient.clientGet().ignoreDataStore().uri("KSK@foo.txt");
202 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
203 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "IgnoreDS=true"));
207 public void clientGetWithDataStoreOnlySettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
208 fcpClient.clientGet().dataStoreOnly().uri("KSK@foo.txt");
210 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
211 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "DSonly=true"));
215 public void clientGetWithMaxSizeSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
216 fcpClient.clientGet().maxSize(1048576).uri("KSK@foo.txt");
218 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
219 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "MaxSize=1048576"));
223 public void clientGetWithPrioritySettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
224 fcpClient.clientGet().priority(Priority.interactive).uri("KSK@foo.txt");
226 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
227 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "PriorityClass=1"));
231 public void clientGetWithRealTimeSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
232 fcpClient.clientGet().realTime().uri("KSK@foo.txt");
234 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
235 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "RealTimeFlag=true"));
239 public void clientGetWithGlobalSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
240 fcpClient.clientGet().global().uri("KSK@foo.txt");
242 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
243 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "Global=true"));
246 private Matcher<List<String>> matchesFcpMessage(String name, String... requiredLines) {
247 return new TypeSafeDiagnosingMatcher<List<String>>() {
249 protected boolean matchesSafely(List<String> item, Description mismatchDescription) {
250 if (!item.get(0).equals(name)) {
251 mismatchDescription.appendText("FCP message is named ").appendValue(item.get(0));
254 for (String requiredLine : requiredLines) {
255 if (item.indexOf(requiredLine) < 1) {
256 mismatchDescription.appendText("FCP message does not contain ").appendValue(requiredLine);
264 public void describeTo(Description description) {
265 description.appendText("FCP message named ").appendValue(name);
266 description.appendValueList(", containing the lines ", ", ", "", requiredLines);