1 package net.pterodactylus.fcp.quelaton;
3 import static org.hamcrest.MatcherAssert.assertThat;
4 import static org.hamcrest.Matchers.is;
5 import static org.hamcrest.Matchers.sameInstance;
6 import static org.mockito.Mockito.mock;
7 import static org.mockito.Mockito.verify;
9 import java.io.IOException;
10 import java.util.concurrent.ExecutionException;
11 import java.util.concurrent.ExecutorService;
12 import java.util.concurrent.Executors;
13 import java.util.concurrent.Future;
14 import java.util.concurrent.atomic.AtomicBoolean;
15 import java.util.concurrent.atomic.AtomicReference;
17 import net.pterodactylus.fcp.AllData;
18 import net.pterodactylus.fcp.BaseMessage;
19 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
20 import net.pterodactylus.fcp.ConfigData;
21 import net.pterodactylus.fcp.DataFound;
22 import net.pterodactylus.fcp.EndListPeerNotes;
23 import net.pterodactylus.fcp.EndListPeers;
24 import net.pterodactylus.fcp.EndListPersistentRequests;
25 import net.pterodactylus.fcp.FCPPluginReply;
26 import net.pterodactylus.fcp.FcpConnection;
27 import net.pterodactylus.fcp.FcpMessage;
28 import net.pterodactylus.fcp.FinishedCompression;
29 import net.pterodactylus.fcp.GetFailed;
30 import net.pterodactylus.fcp.IdentifierCollision;
31 import net.pterodactylus.fcp.NodeData;
32 import net.pterodactylus.fcp.NodeHello;
33 import net.pterodactylus.fcp.Peer;
34 import net.pterodactylus.fcp.PeerNote;
35 import net.pterodactylus.fcp.PeerRemoved;
36 import net.pterodactylus.fcp.PersistentGet;
37 import net.pterodactylus.fcp.PersistentPut;
38 import net.pterodactylus.fcp.PersistentPutDir;
39 import net.pterodactylus.fcp.PersistentRequestModified;
40 import net.pterodactylus.fcp.PersistentRequestRemoved;
41 import net.pterodactylus.fcp.PluginInfo;
42 import net.pterodactylus.fcp.ProtocolError;
43 import net.pterodactylus.fcp.PutFailed;
44 import net.pterodactylus.fcp.PutFetchable;
45 import net.pterodactylus.fcp.PutSuccessful;
46 import net.pterodactylus.fcp.ReceivedBookmarkFeed;
47 import net.pterodactylus.fcp.SSKKeypair;
48 import net.pterodactylus.fcp.SentFeed;
49 import net.pterodactylus.fcp.SimpleProgress;
50 import net.pterodactylus.fcp.StartedCompression;
51 import net.pterodactylus.fcp.SubscribedUSKUpdate;
52 import net.pterodactylus.fcp.TestDDAComplete;
53 import net.pterodactylus.fcp.TestDDAReply;
54 import net.pterodactylus.fcp.URIGenerated;
55 import net.pterodactylus.fcp.UnknownNodeIdentifier;
56 import net.pterodactylus.fcp.UnknownPeerNoteType;
58 import org.junit.Test;
61 * Unit test for {@link FcpDialog}.
63 * @author <a href="bombe@freenetproject.org">David ‘Bombe’ Roden</a>
65 public class FcpDialogTest {
67 private final FcpConnection fcpConnection = mock(FcpConnection.class);
68 private final ExecutorService executorService = Executors.newSingleThreadExecutor();
69 private final TestFcpDialog dialog = new TestFcpDialog(executorService, fcpConnection);
70 private final FcpMessage fcpMessage = new FcpMessage("Test");
73 public void canSendMessage() throws IOException, ExecutionException, InterruptedException {
74 FcpDialog dialog = createBasicDialog();
75 dialog.send(fcpMessage).get();
76 verify(fcpConnection).sendMessage(fcpMessage);
79 private FcpDialog createBasicDialog() {
80 return new FcpDialog(executorService, fcpConnection, true) {
88 public void sendingAMessageRegistersTheWaiterAsFcpListener() throws IOException {
89 FcpDialog dialog = createBasicDialog();
90 dialog.send(fcpMessage);
91 verify(fcpConnection).addFcpListener(dialog);
95 public void closingTheReplyWaiterRemovesTheFcpListener() throws IOException {
96 FcpDialog dialog = createBasicDialog();
97 dialog.send(fcpMessage);
99 verify(fcpConnection).removeFcpListener(dialog);
102 private <M extends BaseMessage> void waitForASpecificMessage(MessageReceiver<M> messageReceiver, Class<M> messageClass, MessageCreator<M> messageCreator) throws IOException, InterruptedException, ExecutionException {
103 waitForASpecificMessage(messageReceiver, messageCreator.create(new FcpMessage(messageClass.getSimpleName())));
106 private <M extends BaseMessage> void waitForASpecificMessage(MessageReceiver<M> messageReceiver, M message) throws IOException, InterruptedException, ExecutionException {
107 dialog.setExpectedMessage(message.getName());
108 Future<Boolean> result = dialog.send(fcpMessage);
109 messageReceiver.receiveMessage(fcpConnection, message);
110 assertThat(result.get(), is(true));
113 private <M extends BaseMessage> M createMessage(Class<M> messageClass, MessageCreator<M> messageCreator) {
114 return messageCreator.create(new FcpMessage(messageClass.getSimpleName()));
117 private interface MessageCreator<M extends BaseMessage> {
119 M create(FcpMessage fcpMessage);
124 public void waitingForNodeHelloWorks() throws IOException, ExecutionException, InterruptedException {
125 waitForASpecificMessage(dialog::receivedNodeHello, NodeHello.class, NodeHello::new);
128 @Test(expected = ExecutionException.class)
129 public void waitingForConnectionClosedDuplicateClientNameWorks() throws IOException, ExecutionException, InterruptedException {
130 dialog.setExpectedMessage("");
131 Future<Boolean> result = dialog.send(fcpMessage);
132 dialog.receivedCloseConnectionDuplicateClientName(fcpConnection,
133 new CloseConnectionDuplicateClientName(new FcpMessage("CloseConnectionDuplicateClientName")));
138 public void waitingForSSKKeypairWorks() throws InterruptedException, ExecutionException, IOException {
139 waitForASpecificMessage(dialog::receivedSSKKeypair, SSKKeypair.class, SSKKeypair::new);
143 public void waitForPeerWorks() throws InterruptedException, ExecutionException, IOException {
144 waitForASpecificMessage(dialog::receivedPeer, Peer.class, Peer::new);
148 public void waitForEndListPeersWorks() throws InterruptedException, ExecutionException, IOException {
149 waitForASpecificMessage(dialog::receivedEndListPeers, EndListPeers.class, EndListPeers::new);
153 public void waitForPeerNoteWorks() throws InterruptedException, ExecutionException, IOException {
154 waitForASpecificMessage(dialog::receivedPeerNote, PeerNote.class, PeerNote::new);
158 public void waitForEndListPeerNotesWorks() throws InterruptedException, ExecutionException, IOException {
159 waitForASpecificMessage(dialog::receivedEndListPeerNotes, EndListPeerNotes.class, EndListPeerNotes::new);
163 public void waitForPeerRemovedWorks() throws InterruptedException, ExecutionException, IOException {
164 waitForASpecificMessage(dialog::receivedPeerRemoved, PeerRemoved.class, PeerRemoved::new);
168 public void waitForNodeDataWorks() throws InterruptedException, ExecutionException, IOException {
169 waitForASpecificMessage(dialog::receivedNodeData, new NodeData(
170 new FcpMessage("NodeData").put("ark.pubURI", "")
171 .put("ark.number", "0")
172 .put("auth.negTypes", "")
173 .put("version", "0,0,0,0")
174 .put("lastGoodVersion", "0,0,0,0")));
178 public void waitForTestDDAReplyWorks() throws InterruptedException, ExecutionException, IOException {
179 waitForASpecificMessage(dialog::receivedTestDDAReply, TestDDAReply.class, TestDDAReply::new);
183 public void waitForTestDDACompleteWorks() throws InterruptedException, ExecutionException, IOException {
184 waitForASpecificMessage(dialog::receivedTestDDAComplete, TestDDAComplete.class, TestDDAComplete::new);
188 public void waitForPersistentGetWorks() throws InterruptedException, ExecutionException, IOException {
189 waitForASpecificMessage(dialog::receivedPersistentGet, PersistentGet.class, PersistentGet::new);
193 public void waitForPersistentPutWorks() throws InterruptedException, ExecutionException, IOException {
194 waitForASpecificMessage(dialog::receivedPersistentPut, PersistentPut.class, PersistentPut::new);
198 public void waitForEndListPersistentRequestsWorks() throws InterruptedException, ExecutionException, IOException {
199 waitForASpecificMessage(dialog::receivedEndListPersistentRequests, EndListPersistentRequests.class, EndListPersistentRequests::new);
203 public void waitForURIGeneratedWorks() throws InterruptedException, ExecutionException, IOException {
204 waitForASpecificMessage(dialog::receivedURIGenerated, URIGenerated.class, URIGenerated::new);
208 public void waitForDataFoundWorks() throws InterruptedException, ExecutionException, IOException {
209 waitForASpecificMessage(dialog::receivedDataFound, DataFound.class, DataFound::new);
213 public void waitForAllDataWorks() throws InterruptedException, ExecutionException, IOException {
214 waitForASpecificMessage(dialog::receivedAllData, new AllData(new FcpMessage("AllData"), null));
218 public void waitForSimpleProgressWorks() throws InterruptedException, ExecutionException, IOException {
219 waitForASpecificMessage(dialog::receivedSimpleProgress, SimpleProgress.class, SimpleProgress::new);
223 public void waitForStartedCompressionWorks() throws InterruptedException, ExecutionException, IOException {
224 waitForASpecificMessage(dialog::receivedStartedCompression, StartedCompression.class, StartedCompression::new);
228 public void waitForFinishedCompressionWorks() throws InterruptedException, ExecutionException, IOException {
229 waitForASpecificMessage(dialog::receivedFinishedCompression, FinishedCompression.class, FinishedCompression::new);
233 public void waitForUnknownPeerNoteTypeWorks() throws InterruptedException, ExecutionException, IOException {
234 waitForASpecificMessage(dialog::receivedUnknownPeerNoteType, UnknownPeerNoteType.class, UnknownPeerNoteType::new);
238 public void waitForUnknownNodeIdentifierWorks() throws InterruptedException, ExecutionException, IOException {
239 waitForASpecificMessage(dialog::receivedUnknownNodeIdentifier, UnknownNodeIdentifier.class, UnknownNodeIdentifier::new);
243 public void waitForConfigDataWorks() throws InterruptedException, ExecutionException, IOException {
244 waitForASpecificMessage(dialog::receivedConfigData, ConfigData.class, ConfigData::new);
248 public void waitForGetFailedWorks() throws InterruptedException, ExecutionException, IOException {
249 waitForASpecificMessage(dialog::receivedGetFailed, GetFailed.class, GetFailed::new);
253 public void waitForPutFailedWorks() throws InterruptedException, ExecutionException, IOException {
254 waitForASpecificMessage(dialog::receivedPutFailed, PutFailed.class, PutFailed::new);
258 public void waitForIdentifierCollisionWorks() throws InterruptedException, ExecutionException, IOException {
259 waitForASpecificMessage(dialog::receivedIdentifierCollision, IdentifierCollision.class, IdentifierCollision::new);
263 public void waitForPersistentPutDirWorks() throws InterruptedException, ExecutionException, IOException {
264 waitForASpecificMessage(dialog::receivedPersistentPutDir, PersistentPutDir.class, PersistentPutDir::new);
268 public void waitForPersistentRequestRemovedWorks() throws InterruptedException, ExecutionException, IOException {
269 waitForASpecificMessage(dialog::receivedPersistentRequestRemoved, PersistentRequestRemoved.class, PersistentRequestRemoved::new);
273 public void waitForSubscribedUSKUpdateWorks() throws InterruptedException, ExecutionException, IOException {
274 waitForASpecificMessage(dialog::receivedSubscribedUSKUpdate, SubscribedUSKUpdate.class, SubscribedUSKUpdate::new);
278 public void waitForPluginInfoWorks() throws InterruptedException, ExecutionException, IOException {
279 waitForASpecificMessage(dialog::receivedPluginInfo, PluginInfo.class, PluginInfo::new);
283 public void waitForFCPPluginReply() throws InterruptedException, ExecutionException, IOException {
284 waitForASpecificMessage(dialog::receivedFCPPluginReply, new FCPPluginReply(new FcpMessage("FCPPluginReply"), null));
288 public void waitForPersistentRequestModifiedWorks() throws InterruptedException, ExecutionException, IOException {
289 waitForASpecificMessage(dialog::receivedPersistentRequestModified, PersistentRequestModified.class, PersistentRequestModified::new);
293 public void waitForPutSuccessfulWorks() throws InterruptedException, ExecutionException, IOException {
294 waitForASpecificMessage(dialog::receivedPutSuccessful, PutSuccessful.class, PutSuccessful::new);
298 public void waitForPutFetchableWorks() throws InterruptedException, ExecutionException, IOException {
299 waitForASpecificMessage(dialog::receivedPutFetchable, PutFetchable.class, PutFetchable::new);
303 public void waitForSentFeedWorks() throws InterruptedException, ExecutionException, IOException {
304 waitForASpecificMessage(dialog::receivedSentFeed, SentFeed.class, SentFeed::new);
308 public void waitForReceivedBookmarkFeedWorks() throws InterruptedException, ExecutionException, IOException {
309 waitForASpecificMessage(dialog::receivedBookmarkFeed, ReceivedBookmarkFeed.class, ReceivedBookmarkFeed::new);
313 public void waitForProtocolErrorWorks() throws InterruptedException, ExecutionException, IOException {
314 waitForASpecificMessage(dialog::receivedProtocolError, ProtocolError.class, ProtocolError::new);
318 public void waitForUnknownMessageWorks() throws IOException, ExecutionException, InterruptedException {
319 dialog.setExpectedMessage("SomeFcpMessage");
320 Future<Boolean> result = dialog.send(fcpMessage);
321 dialog.receivedMessage(fcpConnection, new FcpMessage("SomeFcpMessage"));
322 assertThat(result.get(), is(true));
326 public void waitingForMultipleMessagesWorks() throws IOException, ExecutionException, InterruptedException {
327 TestFcpDialog testFcpDialog = new TestFcpDialog(executorService, fcpConnection) {
328 private final AtomicBoolean gotPutFailed = new AtomicBoolean();
329 private final AtomicBoolean gotGetFailed = new AtomicBoolean();
331 private void checkIfBothFailedsWereReceived() {
332 if (gotPutFailed.get() && gotGetFailed.get()) {
338 protected void consumePutFailed(PutFailed putFailed) {
339 gotPutFailed.set(true);
340 checkIfBothFailedsWereReceived();
344 protected void consumeGetFailed(GetFailed getFailed) {
345 gotGetFailed.set(true);
346 checkIfBothFailedsWereReceived();
349 Future<?> result = testFcpDialog.send(fcpMessage);
350 assertThat(result.isDone(), is(false));
351 testFcpDialog.receivedGetFailed(fcpConnection, new GetFailed(new FcpMessage("GetFailed")));
352 assertThat(result.isDone(), is(false));
353 testFcpDialog.receivedPutFailed(fcpConnection, new PutFailed(new FcpMessage("PutFailed")));
354 assertThat(result.get(), is(true));
358 public void waitingForConnectionClosureWorks() throws IOException, ExecutionException, InterruptedException {
359 dialog.setExpectedMessage("none");
360 Future<Boolean> result = dialog.send(fcpMessage);
361 Throwable throwable = new Throwable();
362 dialog.connectionClosed(fcpConnection, throwable);
365 } catch (ExecutionException e) {
367 while (t.getCause() != null) {
370 assertThat(t, sameInstance(throwable));
375 private interface MessageReceiver<M> {
377 void receiveMessage(FcpConnection fcpConnection, M message);
381 private static class TestFcpDialog extends FcpDialog<Boolean> {
383 private final AtomicReference<String> expectedMessage = new AtomicReference<>();
385 public TestFcpDialog(ExecutorService executorService, FcpConnection fcpConnection) {
386 super(executorService, fcpConnection, false);
389 public void setExpectedMessage(String expectedMessage) {
390 this.expectedMessage.set(expectedMessage);
393 private void verifyReceivedMessage(String message) {
394 if (expectedMessage.get().equals(message)) {
400 protected void consumeNodeHello(NodeHello nodeHello) {
401 verifyReceivedMessage(nodeHello.getName());
405 protected void consumeSSKKeypair(SSKKeypair sskKeypair) {
406 verifyReceivedMessage(sskKeypair.getName());
410 protected void consumePeer(Peer peer) {
411 verifyReceivedMessage(peer.getName());
415 protected void consumeEndListPeers(EndListPeers endListPeers) {
416 verifyReceivedMessage(endListPeers.getName());
420 protected void consumePeerNote(PeerNote peerNote) {
421 verifyReceivedMessage(peerNote.getName());
425 protected void consumeEndListPeerNotes(EndListPeerNotes endListPeerNotes) {
426 verifyReceivedMessage(endListPeerNotes.getName());
430 protected void consumePeerRemoved(PeerRemoved peerRemoved) {
431 verifyReceivedMessage(peerRemoved.getName());
435 protected void consumeNodeData(NodeData nodeData) {
436 verifyReceivedMessage(nodeData.getName());
440 protected void consumeTestDDAReply(TestDDAReply testDDAReply) {
441 verifyReceivedMessage(testDDAReply.getName());
445 protected void consumeTestDDAComplete(TestDDAComplete testDDAComplete) {
446 verifyReceivedMessage(testDDAComplete.getName());
450 protected void consumePersistentGet(PersistentGet persistentGet) {
451 verifyReceivedMessage(persistentGet.getName());
455 protected void consumePersistentPut(PersistentPut persistentPut) {
456 verifyReceivedMessage(persistentPut.getName());
460 protected void consumeEndListPersistentRequests(EndListPersistentRequests endListPersistentRequests) {
461 verifyReceivedMessage(endListPersistentRequests.getName());
465 protected void consumeURIGenerated(URIGenerated uriGenerated) {
466 verifyReceivedMessage(uriGenerated.getName());
470 protected void consumeDataFound(DataFound dataFound) {
471 verifyReceivedMessage(dataFound.getName());
475 protected void consumeAllData(AllData allData) {
476 verifyReceivedMessage(allData.getName());
480 protected void consumeSimpleProgress(SimpleProgress simpleProgress) {
481 verifyReceivedMessage(simpleProgress.getName());
485 protected void consumeStartedCompression(StartedCompression startedCompression) {
486 verifyReceivedMessage(startedCompression.getName());
490 protected void consumeFinishedCompression(FinishedCompression finishedCompression) {
491 verifyReceivedMessage(finishedCompression.getName());
495 protected void consumeUnknownPeerNoteType(UnknownPeerNoteType unknownPeerNoteType) {
496 verifyReceivedMessage(unknownPeerNoteType.getName());
500 protected void consumeUnknownNodeIdentifier(UnknownNodeIdentifier unknownNodeIdentifier) {
501 verifyReceivedMessage(unknownNodeIdentifier.getName());
505 protected void consumeConfigData(ConfigData configData) {
506 verifyReceivedMessage(configData.getName());
510 protected void consumeGetFailed(GetFailed getFailed) {
511 verifyReceivedMessage(getFailed.getName());
515 protected void consumePutFailed(PutFailed putFailed) {
516 verifyReceivedMessage(putFailed.getName());
520 protected void consumeIdentifierCollision(IdentifierCollision identifierCollision) {
521 verifyReceivedMessage(identifierCollision.getName());
525 protected void consumePersistentPutDir(PersistentPutDir persistentPutDir) {
526 verifyReceivedMessage(persistentPutDir.getName());
530 protected void consumePersistentRequestRemoved(PersistentRequestRemoved persistentRequestRemoved) {
531 verifyReceivedMessage(persistentRequestRemoved.getName());
535 protected void consumeSubscribedUSKUpdate(SubscribedUSKUpdate subscribedUSKUpdate) {
536 verifyReceivedMessage(subscribedUSKUpdate.getName());
540 protected void consumePluginInfo(PluginInfo pluginInfo) {
541 verifyReceivedMessage(pluginInfo.getName());
545 protected void consumeFCPPluginReply(FCPPluginReply fcpPluginReply) {
546 verifyReceivedMessage(fcpPluginReply.getName());
550 protected void consumePersistentRequestModified(PersistentRequestModified persistentRequestModified) {
551 verifyReceivedMessage(persistentRequestModified.getName());
555 protected void consumePutSuccessful(PutSuccessful putSuccessful) {
556 verifyReceivedMessage(putSuccessful.getName());
560 protected void consumePutFetchable(PutFetchable putFetchable) {
561 verifyReceivedMessage(putFetchable.getName());
565 protected void consumeSentFeed(SentFeed sentFeed) {
566 verifyReceivedMessage(sentFeed.getName());
570 protected void consumeReceivedBookmarkFeed(ReceivedBookmarkFeed receivedBookmarkFeed) {
571 verifyReceivedMessage(receivedBookmarkFeed.getName());
575 protected void consumeProtocolError(ProtocolError protocolError) {
576 verifyReceivedMessage(protocolError.getName());
580 protected void consumeUnknownMessage(FcpMessage fcpMessage) {
581 verifyReceivedMessage(fcpMessage.getName());