1 package net.pterodactylus.fcp.quelaton;
3 import static org.hamcrest.MatcherAssert.assertThat;
4 import static org.hamcrest.Matchers.empty;
5 import static org.hamcrest.Matchers.is;
6 import static org.hamcrest.Matchers.sameInstance;
7 import static org.mockito.Mockito.mock;
8 import static org.mockito.Mockito.verify;
10 import java.io.IOException;
11 import java.util.concurrent.ExecutionException;
12 import java.util.concurrent.ExecutorService;
13 import java.util.concurrent.Executors;
14 import java.util.concurrent.Future;
15 import java.util.concurrent.atomic.AtomicBoolean;
16 import java.util.concurrent.atomic.AtomicReference;
18 import net.pterodactylus.fcp.AllData;
19 import net.pterodactylus.fcp.BaseMessage;
20 import net.pterodactylus.fcp.CloseConnectionDuplicateClientName;
21 import net.pterodactylus.fcp.ConfigData;
22 import net.pterodactylus.fcp.DataFound;
23 import net.pterodactylus.fcp.EndListPeerNotes;
24 import net.pterodactylus.fcp.EndListPeers;
25 import net.pterodactylus.fcp.EndListPersistentRequests;
26 import net.pterodactylus.fcp.FCPPluginReply;
27 import net.pterodactylus.fcp.FcpConnection;
28 import net.pterodactylus.fcp.FcpMessage;
29 import net.pterodactylus.fcp.FinishedCompression;
30 import net.pterodactylus.fcp.GetFailed;
31 import net.pterodactylus.fcp.IdentifierCollision;
32 import net.pterodactylus.fcp.NodeData;
33 import net.pterodactylus.fcp.NodeHello;
34 import net.pterodactylus.fcp.Peer;
35 import net.pterodactylus.fcp.PeerNote;
36 import net.pterodactylus.fcp.PeerRemoved;
37 import net.pterodactylus.fcp.PersistentGet;
38 import net.pterodactylus.fcp.PersistentPut;
39 import net.pterodactylus.fcp.PersistentPutDir;
40 import net.pterodactylus.fcp.PersistentRequestModified;
41 import net.pterodactylus.fcp.PersistentRequestRemoved;
42 import net.pterodactylus.fcp.PluginInfo;
43 import net.pterodactylus.fcp.ProtocolError;
44 import net.pterodactylus.fcp.PutFailed;
45 import net.pterodactylus.fcp.PutFetchable;
46 import net.pterodactylus.fcp.PutSuccessful;
47 import net.pterodactylus.fcp.ReceivedBookmarkFeed;
48 import net.pterodactylus.fcp.SSKKeypair;
49 import net.pterodactylus.fcp.SentFeed;
50 import net.pterodactylus.fcp.SimpleProgress;
51 import net.pterodactylus.fcp.StartedCompression;
52 import net.pterodactylus.fcp.SubscribedUSKUpdate;
53 import net.pterodactylus.fcp.TestDDAComplete;
54 import net.pterodactylus.fcp.TestDDAReply;
55 import net.pterodactylus.fcp.URIGenerated;
56 import net.pterodactylus.fcp.UnknownNodeIdentifier;
57 import net.pterodactylus.fcp.UnknownPeerNoteType;
59 import org.junit.Test;
62 * Unit test for {@link FcpReplySequence}.
64 * @author <a href="bombe@freenetproject.org">David ‘Bombe’ Roden</a>
66 public class FcpReplySequenceTest {
68 private final FcpConnection fcpConnection = mock(FcpConnection.class);
69 private final ExecutorService executorService = Executors.newSingleThreadExecutor();
70 private final TestFcpReplySequence replySequence = new TestFcpReplySequence(executorService, fcpConnection);
71 private final FcpMessage fcpMessage = new FcpMessage("Test");
74 public void canSendMessage() throws IOException, ExecutionException, InterruptedException {
75 FcpReplySequence replySequence = createBasicReplySequence();
76 replySequence.send(fcpMessage).get();
77 verify(fcpConnection).sendMessage(fcpMessage);
80 private FcpReplySequence createBasicReplySequence() {
81 return new FcpReplySequence(executorService, fcpConnection) {
83 protected boolean isFinished() {
90 public void sendingAMessageRegistersTheWaiterAsFcpListener() throws IOException {
91 FcpReplySequence replySequence = createBasicReplySequence();
92 replySequence.send(fcpMessage);
93 verify(fcpConnection).addFcpListener(replySequence);
97 public void closingTheReplyWaiterRemovesTheFcpListener() throws IOException {
98 FcpReplySequence replySequence = createBasicReplySequence();
99 replySequence.send(fcpMessage);
100 replySequence.close();
101 verify(fcpConnection).removeFcpListener(replySequence);
104 private <M extends BaseMessage> void waitForASpecificMessage(MessageReceiver<M> messageReceiver, Class<M> messageClass, MessageCreator<M> messageCreator) throws IOException, InterruptedException, ExecutionException {
105 waitForASpecificMessage(messageReceiver, messageCreator.create(new FcpMessage(messageClass.getSimpleName())));
108 private <M extends BaseMessage> void waitForASpecificMessage(MessageReceiver<M> messageReceiver, M message) throws IOException, InterruptedException, ExecutionException {
109 replySequence.setExpectedMessage(message.getName());
110 Future<Boolean> result = replySequence.send(fcpMessage);
111 messageReceiver.receiveMessage(fcpConnection, message);
112 assertThat(result.get(), is(true));
115 private <M extends BaseMessage> M createMessage(Class<M> messageClass, MessageCreator<M> messageCreator) {
116 return messageCreator.create(new FcpMessage(messageClass.getSimpleName()));
119 private interface MessageCreator<M extends BaseMessage> {
121 M create(FcpMessage fcpMessage);
126 public void waitingForNodeHelloWorks() throws IOException, ExecutionException, InterruptedException {
127 waitForASpecificMessage(replySequence::receivedNodeHello, NodeHello.class, NodeHello::new);
130 @Test(expected = ExecutionException.class)
131 public void waitingForConnectionClosedDuplicateClientNameWorks() throws IOException, ExecutionException, InterruptedException {
132 replySequence.setExpectedMessage("");
133 Future<Boolean> result = replySequence.send(fcpMessage);
134 replySequence.receivedCloseConnectionDuplicateClientName(fcpConnection,
135 new CloseConnectionDuplicateClientName(new FcpMessage("CloseConnectionDuplicateClientName")));
140 public void waitingForSSKKeypairWorks() throws InterruptedException, ExecutionException, IOException {
141 waitForASpecificMessage(replySequence::receivedSSKKeypair, SSKKeypair.class, SSKKeypair::new);
145 public void waitForPeerWorks() throws InterruptedException, ExecutionException, IOException {
146 waitForASpecificMessage(replySequence::receivedPeer, Peer.class, Peer::new);
150 public void waitForEndListPeersWorks() throws InterruptedException, ExecutionException, IOException {
151 waitForASpecificMessage(replySequence::receivedEndListPeers, EndListPeers.class, EndListPeers::new);
155 public void waitForPeerNoteWorks() throws InterruptedException, ExecutionException, IOException {
156 waitForASpecificMessage(replySequence::receivedPeerNote, PeerNote.class, PeerNote::new);
160 public void waitForEndListPeerNotesWorks() throws InterruptedException, ExecutionException, IOException {
161 waitForASpecificMessage(replySequence::receivedEndListPeerNotes, EndListPeerNotes.class, EndListPeerNotes::new);
165 public void waitForPeerRemovedWorks() throws InterruptedException, ExecutionException, IOException {
166 waitForASpecificMessage(replySequence::receivedPeerRemoved, PeerRemoved.class, PeerRemoved::new);
170 public void waitForNodeDataWorks() throws InterruptedException, ExecutionException, IOException {
171 waitForASpecificMessage(replySequence::receivedNodeData, new NodeData(
172 new FcpMessage("NodeData").put("ark.pubURI", "")
173 .put("ark.number", "0")
174 .put("auth.negTypes", "")
175 .put("version", "0,0,0,0")
176 .put("lastGoodVersion", "0,0,0,0")));
180 public void waitForTestDDAReplyWorks() throws InterruptedException, ExecutionException, IOException {
181 waitForASpecificMessage(replySequence::receivedTestDDAReply, TestDDAReply.class, TestDDAReply::new);
185 public void waitForTestDDACompleteWorks() throws InterruptedException, ExecutionException, IOException {
186 waitForASpecificMessage(replySequence::receivedTestDDAComplete, TestDDAComplete.class, TestDDAComplete::new);
190 public void waitForPersistentGetWorks() throws InterruptedException, ExecutionException, IOException {
191 waitForASpecificMessage(replySequence::receivedPersistentGet, PersistentGet.class, PersistentGet::new);
195 public void waitForPersistentPutWorks() throws InterruptedException, ExecutionException, IOException {
196 waitForASpecificMessage(replySequence::receivedPersistentPut, PersistentPut.class, PersistentPut::new);
200 public void waitForEndListPersistentRequestsWorks() throws InterruptedException, ExecutionException, IOException {
201 waitForASpecificMessage(replySequence::receivedEndListPersistentRequests, EndListPersistentRequests.class, EndListPersistentRequests::new);
205 public void waitForURIGeneratedWorks() throws InterruptedException, ExecutionException, IOException {
206 waitForASpecificMessage(replySequence::receivedURIGenerated, URIGenerated.class, URIGenerated::new);
210 public void waitForDataFoundWorks() throws InterruptedException, ExecutionException, IOException {
211 waitForASpecificMessage(replySequence::receivedDataFound, DataFound.class, DataFound::new);
215 public void waitForAllDataWorks() throws InterruptedException, ExecutionException, IOException {
216 waitForASpecificMessage(replySequence::receivedAllData, new AllData(new FcpMessage("AllData"), null));
220 public void waitForSimpleProgressWorks() throws InterruptedException, ExecutionException, IOException {
221 waitForASpecificMessage(replySequence::receivedSimpleProgress, SimpleProgress.class, SimpleProgress::new);
225 public void waitForStartedCompressionWorks() throws InterruptedException, ExecutionException, IOException {
226 waitForASpecificMessage(replySequence::receivedStartedCompression, StartedCompression.class, StartedCompression::new);
230 public void waitForFinishedCompressionWorks() throws InterruptedException, ExecutionException, IOException {
231 waitForASpecificMessage(replySequence::receivedFinishedCompression, FinishedCompression.class, FinishedCompression::new);
235 public void waitForUnknownPeerNoteTypeWorks() throws InterruptedException, ExecutionException, IOException {
236 waitForASpecificMessage(replySequence::receivedUnknownPeerNoteType, UnknownPeerNoteType.class, UnknownPeerNoteType::new);
240 public void waitForUnknownNodeIdentifierWorks() throws InterruptedException, ExecutionException, IOException {
241 waitForASpecificMessage(replySequence::receivedUnknownNodeIdentifier, UnknownNodeIdentifier.class, UnknownNodeIdentifier::new);
245 public void waitForConfigDataWorks() throws InterruptedException, ExecutionException, IOException {
246 waitForASpecificMessage(replySequence::receivedConfigData, ConfigData.class, ConfigData::new);
250 public void waitForGetFailedWorks() throws InterruptedException, ExecutionException, IOException {
251 waitForASpecificMessage(replySequence::receivedGetFailed, GetFailed.class, GetFailed::new);
255 public void waitForPutFailedWorks() throws InterruptedException, ExecutionException, IOException {
256 waitForASpecificMessage(replySequence::receivedPutFailed, PutFailed.class, PutFailed::new);
260 public void waitForIdentifierCollisionWorks() throws InterruptedException, ExecutionException, IOException {
261 waitForASpecificMessage(replySequence::receivedIdentifierCollision, IdentifierCollision.class, IdentifierCollision::new);
265 public void waitForPersistentPutDirWorks() throws InterruptedException, ExecutionException, IOException {
266 waitForASpecificMessage(replySequence::receivedPersistentPutDir, PersistentPutDir.class, PersistentPutDir::new);
270 public void waitForPersistentRequestRemovedWorks() throws InterruptedException, ExecutionException, IOException {
271 waitForASpecificMessage(replySequence::receivedPersistentRequestRemoved, PersistentRequestRemoved.class, PersistentRequestRemoved::new);
275 public void waitForSubscribedUSKUpdateWorks() throws InterruptedException, ExecutionException, IOException {
276 waitForASpecificMessage(replySequence::receivedSubscribedUSKUpdate, SubscribedUSKUpdate.class, SubscribedUSKUpdate::new);
280 public void waitForPluginInfoWorks() throws InterruptedException, ExecutionException, IOException {
281 waitForASpecificMessage(replySequence::receivedPluginInfo, PluginInfo.class, PluginInfo::new);
285 public void waitForFCPPluginReply() throws InterruptedException, ExecutionException, IOException {
286 waitForASpecificMessage(replySequence::receivedFCPPluginReply, new FCPPluginReply(new FcpMessage("FCPPluginReply"), null));
290 public void waitForPersistentRequestModifiedWorks() throws InterruptedException, ExecutionException, IOException {
291 waitForASpecificMessage(replySequence::receivedPersistentRequestModified, PersistentRequestModified.class, PersistentRequestModified::new);
295 public void waitForPutSuccessfulWorks() throws InterruptedException, ExecutionException, IOException {
296 waitForASpecificMessage(replySequence::receivedPutSuccessful, PutSuccessful.class, PutSuccessful::new);
300 public void waitForPutFetchableWorks() throws InterruptedException, ExecutionException, IOException {
301 waitForASpecificMessage(replySequence::receivedPutFetchable, PutFetchable.class, PutFetchable::new);
305 public void waitForSentFeedWorks() throws InterruptedException, ExecutionException, IOException {
306 waitForASpecificMessage(replySequence::receivedSentFeed, SentFeed.class, SentFeed::new);
310 public void waitForReceivedBookmarkFeedWorks() throws InterruptedException, ExecutionException, IOException {
311 waitForASpecificMessage(replySequence::receivedBookmarkFeed, ReceivedBookmarkFeed.class, ReceivedBookmarkFeed::new);
315 public void waitForProtocolErrorWorks() throws InterruptedException, ExecutionException, IOException {
316 waitForASpecificMessage(replySequence::receivedProtocolError, ProtocolError.class, ProtocolError::new);
320 public void waitForUnknownMessageWorks() throws IOException, ExecutionException, InterruptedException {
321 replySequence.setExpectedMessage("SomeFcpMessage");
322 Future<Boolean> result = replySequence.send(fcpMessage);
323 replySequence.receivedMessage(fcpConnection, new FcpMessage("SomeFcpMessage"));
324 assertThat(result.get(), is(true));
328 public void waitingForMultipleMessagesWorks() throws IOException, ExecutionException, InterruptedException {
329 TestFcpReplySequence replySequence = new TestFcpReplySequence(executorService, fcpConnection) {
330 private final AtomicBoolean gotPutFailed = new AtomicBoolean();
331 private final AtomicBoolean gotGetFailed = new AtomicBoolean();
334 protected boolean isFinished() {
335 return gotPutFailed.get() && gotGetFailed.get();
339 protected Boolean getResult() {
344 protected void consumePutFailed(PutFailed putFailed) {
345 gotPutFailed.set(true);
349 protected void consumeGetFailed(GetFailed getFailed) {
350 gotGetFailed.set(true);
353 Future<?> result = replySequence.send(fcpMessage);
354 assertThat(result.isDone(), is(false));
355 replySequence.receivedGetFailed(fcpConnection, new GetFailed(new FcpMessage("GetFailed")));
356 assertThat(result.isDone(), is(false));
357 replySequence.receivedPutFailed(fcpConnection, new PutFailed(new FcpMessage("PutFailed")));
358 assertThat(result.get(), is(true));
362 public void waitingForConnectionClosureWorks() throws IOException, ExecutionException, InterruptedException {
363 replySequence.setExpectedMessage("none");
364 Future<Boolean> result = replySequence.send(fcpMessage);
365 Throwable throwable = new Throwable();
366 replySequence.connectionClosed(fcpConnection, throwable);
369 } catch (ExecutionException e) {
371 while (t.getCause() != null) {
374 assertThat(t, sameInstance(throwable));
379 private interface MessageReceiver<M> {
381 void receiveMessage(FcpConnection fcpConnection, M message);
385 private static class TestFcpReplySequence extends FcpReplySequence<Boolean> {
387 private final AtomicReference<String> gotMessage = new AtomicReference<>();
388 private final AtomicReference<String> expectedMessage = new AtomicReference<>();
390 public TestFcpReplySequence(ExecutorService executorService, FcpConnection fcpConnection) {
391 super(executorService, fcpConnection);
394 public void setExpectedMessage(String expectedMessage) {
395 this.expectedMessage.set(expectedMessage);
399 protected boolean isFinished() {
404 protected Boolean getResult() {
405 return expectedMessage.get().equals(gotMessage.get());
409 protected void consumeNodeHello(NodeHello nodeHello) {
410 gotMessage.set(nodeHello.getName());
414 protected void consumeSSKKeypair(SSKKeypair sskKeypair) {
415 gotMessage.set(sskKeypair.getName());
419 protected void consumePeer(Peer peer) {
420 gotMessage.set(peer.getName());
424 protected void consumeEndListPeers(EndListPeers endListPeers) {
425 gotMessage.set(endListPeers.getName());
429 protected void consumePeerNote(PeerNote peerNote) {
430 gotMessage.set(peerNote.getName());
434 protected void consumeEndListPeerNotes(EndListPeerNotes endListPeerNotes) {
435 gotMessage.set(endListPeerNotes.getName());
439 protected void consumePeerRemoved(PeerRemoved peerRemoved) {
440 gotMessage.set(peerRemoved.getName());
444 protected void consumeNodeData(NodeData nodeData) {
445 gotMessage.set(nodeData.getName());
449 protected void consumeTestDDAReply(TestDDAReply testDDAReply) {
450 gotMessage.set(testDDAReply.getName());
454 protected void consumeTestDDAComplete(TestDDAComplete testDDAComplete) {
455 gotMessage.set(testDDAComplete.getName());
459 protected void consumePersistentGet(PersistentGet persistentGet) {
460 gotMessage.set(persistentGet.getName());
464 protected void consumePersistentPut(PersistentPut persistentPut) {
465 gotMessage.set(persistentPut.getName());
469 protected void consumeEndListPersistentRequests(EndListPersistentRequests endListPersistentRequests) {
470 gotMessage.set(endListPersistentRequests.getName());
474 protected void consumeURIGenerated(URIGenerated uriGenerated) {
475 gotMessage.set(uriGenerated.getName());
479 protected void consumeDataFound(DataFound dataFound) {
480 gotMessage.set(dataFound.getName());
484 protected void consumeAllData(AllData allData) {
485 gotMessage.set(allData.getName());
489 protected void consumeSimpleProgress(SimpleProgress simpleProgress) {
490 gotMessage.set(simpleProgress.getName());
494 protected void consumeStartedCompression(StartedCompression startedCompression) {
495 gotMessage.set(startedCompression.getName());
499 protected void consumeFinishedCompression(FinishedCompression finishedCompression) {
500 gotMessage.set(finishedCompression.getName());
504 protected void consumeUnknownPeerNoteType(UnknownPeerNoteType unknownPeerNoteType) {
505 gotMessage.set(unknownPeerNoteType.getName());
509 protected void consumeUnknownNodeIdentifier(UnknownNodeIdentifier unknownNodeIdentifier) {
510 gotMessage.set(unknownNodeIdentifier.getName());
514 protected void consumeConfigData(ConfigData configData) {
515 gotMessage.set(configData.getName());
519 protected void consumeGetFailed(GetFailed getFailed) {
520 gotMessage.set(getFailed.getName());
524 protected void consumePutFailed(PutFailed putFailed) {
525 gotMessage.set(putFailed.getName());
529 protected void consumeIdentifierCollision(IdentifierCollision identifierCollision) {
530 gotMessage.set(identifierCollision.getName());
534 protected void consumePersistentPutDir(PersistentPutDir persistentPutDir) {
535 gotMessage.set(persistentPutDir.getName());
539 protected void consumePersistentRequestRemoved(PersistentRequestRemoved persistentRequestRemoved) {
540 gotMessage.set(persistentRequestRemoved.getName());
544 protected void consumeSubscribedUSKUpdate(SubscribedUSKUpdate subscribedUSKUpdate) {
545 gotMessage.set(subscribedUSKUpdate.getName());
549 protected void consumePluginInfo(PluginInfo pluginInfo) {
550 gotMessage.set(pluginInfo.getName());
554 protected void consumeFCPPluginReply(FCPPluginReply fcpPluginReply) {
555 gotMessage.set(fcpPluginReply.getName());
559 protected void consumePersistentRequestModified(PersistentRequestModified persistentRequestModified) {
560 gotMessage.set(persistentRequestModified.getName());
564 protected void consumePutSuccessful(PutSuccessful putSuccessful) {
565 gotMessage.set(putSuccessful.getName());
569 protected void consumePutFetchable(PutFetchable putFetchable) {
570 gotMessage.set(putFetchable.getName());
574 protected void consumeSentFeed(SentFeed sentFeed) {
575 gotMessage.set(sentFeed.getName());
579 protected void consumeReceivedBookmarkFeed(ReceivedBookmarkFeed receivedBookmarkFeed) {
580 gotMessage.set(receivedBookmarkFeed.getName());
584 protected void consumeProtocolError(ProtocolError protocolError) {
585 gotMessage.set(protocolError.getName());
589 protected void consumeUnknownMessage(FcpMessage fcpMessage) {
590 gotMessage.set(fcpMessage.getName());