1 package net.pterodactylus.fcp.quelaton;
3 import static org.hamcrest.MatcherAssert.assertThat;
4 import static org.hamcrest.Matchers.is;
6 import java.io.ByteArrayInputStream;
8 import java.io.IOException;
9 import java.nio.charset.StandardCharsets;
10 import java.util.List;
11 import java.util.Optional;
12 import java.util.concurrent.ExecutionException;
13 import java.util.concurrent.ExecutorService;
14 import java.util.concurrent.Executors;
15 import java.util.concurrent.Future;
17 import net.pterodactylus.fcp.FcpKeyPair;
18 import net.pterodactylus.fcp.Key;
19 import net.pterodactylus.fcp.Priority;
20 import net.pterodactylus.fcp.fake.FakeTcpServer;
21 import net.pterodactylus.fcp.quelaton.ClientGetCommand.Data;
23 import com.google.common.io.ByteStreams;
24 import org.hamcrest.Description;
25 import org.hamcrest.Matcher;
26 import org.hamcrest.TypeSafeDiagnosingMatcher;
27 import org.junit.After;
28 import org.junit.Test;
31 * Unit test for {@link DefaultFcpClient}.
33 * @author <a href="bombe@freenetproject.org">David ‘Bombe’ Roden</a>
35 public class DefaultFcpClientTest {
37 private static final String INSERT_URI = "SSK@RVCHbJdkkyTCeNN9AYukEg76eyqmiosSaNKgE3U9zUw,7SHH53gletBVb9JD7nBsyClbLQsBubDPEIcwg908r7Y,AQECAAE/";
38 private static final String REQUEST_URI = "SSK@wtbgd2loNcJCXvtQVOftl2tuWBomDQHfqS6ytpPRhfw,7SHH53gletBVb9JD7nBsyClbLQsBubDPEIcwg908r7Y,AQACAAE/";
40 private static int threadCounter = 0;
41 private final ExecutorService threadPool = Executors.newCachedThreadPool((r) -> new Thread(r, "Test-Thread-" + threadCounter++));
42 private final FakeTcpServer fcpServer;
43 private final DefaultFcpClient fcpClient;
45 public DefaultFcpClientTest() throws IOException {
46 fcpServer = new FakeTcpServer(threadPool);
47 fcpClient = new DefaultFcpClient(threadPool, "localhost", fcpServer.getPort(), () -> "Test", () -> "2.0");
51 public void tearDown() throws IOException {
56 public void defaultFcpClientCanGenerateKeypair() throws ExecutionException, InterruptedException, IOException {
57 Future<FcpKeyPair> keyPairFuture = fcpClient.generateKeypair().execute();
59 fcpServer.collectUntil(is("EndMessage"));
60 fcpServer.writeLine("SSKKeypair",
61 "InsertURI=" + INSERT_URI + "",
62 "RequestURI=" + REQUEST_URI + "",
63 "Identifier=My Identifier from GenerateSSK",
65 FcpKeyPair keyPair = keyPairFuture.get();
66 assertThat(keyPair.getPublicKey(), is(REQUEST_URI));
67 assertThat(keyPair.getPrivateKey(), is(INSERT_URI));
70 private void connectNode() throws InterruptedException, ExecutionException, IOException {
71 fcpServer.connect().get();
72 fcpServer.collectUntil(is("EndMessage"));
73 fcpServer.writeLine("NodeHello",
74 "CompressionCodecs=4 - GZIP(0), BZIP2(1), LZMA(2), LZMA_NEW(3)",
75 "Revision=build01466",
77 "Version=Fred,0.7,1.0,1466",
79 "ConnectionIdentifier=14318898267048452a81b36e7f13a3f0",
83 "NodeLanguage=ENGLISH",
90 public void clientGetCanDownloadData() throws InterruptedException, ExecutionException, IOException {
91 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
93 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
94 assertThat(lines, matchesFcpMessage("ClientGet", "ReturnType=direct", "URI=KSK@foo.txt"));
95 String identifier = extractIdentifier(lines);
98 "Identifier=" + identifier,
100 "StartupTime=1435610539000",
101 "CompletionTime=1435610540000",
102 "Metadata.ContentType=text/plain;charset=utf-8",
106 Optional<Data> data = dataFuture.get();
107 assertThat(data.get().getMimeType(), is("text/plain;charset=utf-8"));
108 assertThat(data.get().size(), is(6L));
109 assertThat(ByteStreams.toByteArray(data.get().getInputStream()), is("Hello\n".getBytes(StandardCharsets.UTF_8)));
112 private String extractIdentifier(List<String> lines) {
113 return lines.stream().filter(s -> s.startsWith("Identifier=")).map(s -> s.substring(s.indexOf('=') + 1)).findFirst().orElse("");
117 public void clientGetDownloadsDataForCorrectIdentifier() throws InterruptedException, ExecutionException, IOException {
118 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
120 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
121 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
122 String identifier = extractIdentifier(lines);
125 "Identifier=not-test",
127 "StartupTime=1435610539000",
128 "CompletionTime=1435610540000",
129 "Metadata.ContentType=text/plain;charset=latin-9",
135 "Identifier=" + identifier,
137 "StartupTime=1435610539000",
138 "CompletionTime=1435610540000",
139 "Metadata.ContentType=text/plain;charset=utf-8",
143 Optional<Data> data = dataFuture.get();
144 assertThat(data.get().getMimeType(), is("text/plain;charset=utf-8"));
145 assertThat(data.get().size(), is(6L));
146 assertThat(ByteStreams.toByteArray(data.get().getInputStream()), is("Hello\n".getBytes(StandardCharsets.UTF_8)));
150 public void clientGetRecognizesGetFailed() throws InterruptedException, ExecutionException, IOException {
151 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
153 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
154 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
155 String identifier = extractIdentifier(lines);
158 "Identifier=" + identifier,
162 Optional<Data> data = dataFuture.get();
163 assertThat(data.isPresent(), is(false));
167 public void clientGetRecognizesGetFailedForCorrectIdentifier() throws InterruptedException, ExecutionException, IOException {
168 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
170 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
171 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
172 String identifier = extractIdentifier(lines);
175 "Identifier=not-test",
181 "Identifier=" + identifier,
185 Optional<Data> data = dataFuture.get();
186 assertThat(data.isPresent(), is(false));
190 public void clientGetRecognizesConnectionClosed() throws InterruptedException, ExecutionException, IOException {
191 Future<Optional<Data>> dataFuture = fcpClient.clientGet().uri("KSK@foo.txt");
193 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
194 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt"));
196 Optional<Data> data = dataFuture.get();
197 assertThat(data.isPresent(), is(false));
201 public void clientGetWithIgnoreDataStoreSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
202 fcpClient.clientGet().ignoreDataStore().uri("KSK@foo.txt");
204 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
205 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "IgnoreDS=true"));
209 public void clientGetWithDataStoreOnlySettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
210 fcpClient.clientGet().dataStoreOnly().uri("KSK@foo.txt");
212 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
213 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "DSonly=true"));
217 public void clientGetWithMaxSizeSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
218 fcpClient.clientGet().maxSize(1048576).uri("KSK@foo.txt");
220 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
221 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "MaxSize=1048576"));
225 public void clientGetWithPrioritySettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
226 fcpClient.clientGet().priority(Priority.interactive).uri("KSK@foo.txt");
228 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
229 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "PriorityClass=1"));
233 public void clientGetWithRealTimeSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
234 fcpClient.clientGet().realTime().uri("KSK@foo.txt");
236 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
237 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "RealTimeFlag=true"));
241 public void clientGetWithGlobalSettingSendsCorrectCommands() throws InterruptedException, ExecutionException, IOException {
242 fcpClient.clientGet().global().uri("KSK@foo.txt");
244 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
245 assertThat(lines, matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "Global=true"));
248 private Matcher<List<String>> matchesFcpMessage(String name, String... requiredLines) {
249 return new TypeSafeDiagnosingMatcher<List<String>>() {
251 protected boolean matchesSafely(List<String> item, Description mismatchDescription) {
252 if (!item.get(0).equals(name)) {
253 mismatchDescription.appendText("FCP message is named ").appendValue(item.get(0));
256 for (String requiredLine : requiredLines) {
257 if (item.indexOf(requiredLine) < 1) {
258 mismatchDescription.appendText("FCP message does not contain ").appendValue(requiredLine);
266 public void describeTo(Description description) {
267 description.appendText("FCP message named ").appendValue(name);
268 description.appendValueList(", containing the lines ", ", ", "", requiredLines);
274 public void clientPutWithDirectDataSendsCorrectCommand()
275 throws IOException, ExecutionException, InterruptedException {
276 fcpClient.clientPut()
277 .from(new ByteArrayInputStream("Hello\n".getBytes()))
279 .key(new Key("KSK@foo.txt"));
281 List<String> lines = fcpServer.collectUntil(is("Hello"));
282 assertThat(lines, matchesFcpMessage("ClientPut", "UploadFrom=direct", "DataLength=6", "URI=KSK@foo.txt"));
286 public void clientPutWithDirectDataSucceedsOnCorrectIdentifier()
287 throws InterruptedException, ExecutionException, IOException {
288 Future<Optional<Key>> key = fcpClient.clientPut()
289 .from(new ByteArrayInputStream("Hello\n".getBytes()))
291 .key(new Key("KSK@foo.txt"));
293 List<String> lines = fcpServer.collectUntil(is("Hello"));
294 String identifier = extractIdentifier(lines);
297 "Identifier=not-the-right-one",
303 "Identifier=" + identifier,
306 assertThat(key.get().get().getKey(), is("KSK@foo.txt"));
310 public void clientPutWithDirectDataFailsOnCorrectIdentifier()
311 throws InterruptedException, ExecutionException, IOException {
312 Future<Optional<Key>> key = fcpClient.clientPut()
313 .from(new ByteArrayInputStream("Hello\n".getBytes()))
315 .key(new Key("KSK@foo.txt"));
317 List<String> lines = fcpServer.collectUntil(is("Hello"));
318 String identifier = extractIdentifier(lines);
321 "Identifier=not-the-right-one",
327 "Identifier=" + identifier,
330 assertThat(key.get().isPresent(), is(false));
334 public void clientPutWithRenamedDirectDataSendsCorrectCommand()
335 throws InterruptedException, ExecutionException, IOException {
336 fcpClient.clientPut()
337 .named("otherName.txt")
338 .from(new ByteArrayInputStream("Hello\n".getBytes()))
340 .key(new Key("KSK@foo.txt"));
342 List<String> lines = fcpServer.collectUntil(is("Hello"));
343 assertThat(lines, matchesFcpMessage("ClientPut", "TargetFilename=otherName.txt", "UploadFrom=direct",
344 "DataLength=6", "URI=KSK@foo.txt"));
348 public void clientPutWithRedirectSendsCorrectCommand()
349 throws IOException, ExecutionException, InterruptedException {
350 fcpClient.clientPut().redirectTo(new Key("KSK@bar.txt")).key(new Key("KSK@foo.txt"));
352 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
354 matchesFcpMessage("ClientPut", "UploadFrom=redirect", "URI=KSK@foo.txt", "TargetURI=KSK@bar.txt"));
358 public void clientPutWithFileSendsCorrectCommand() throws InterruptedException, ExecutionException, IOException {
359 fcpClient.clientPut().from(new File("/tmp/data.txt")).key(new Key("KSK@foo.txt"));
361 List<String> lines = fcpServer.collectUntil(is("EndMessage"));
363 matchesFcpMessage("ClientPut", "UploadFrom=disk", "URI=KSK@foo.txt", "Filename=/tmp/data.txt"));