90439743ee9ee784fb3902e5af05440ca3d5e17d
[Sone.git] / src / test / java / net / pterodactylus / sone / core / SoneDownloaderTest.java
1 package net.pterodactylus.sone.core;
2
3 import static freenet.keys.InsertableClientSSK.createRandom;
4 import static java.lang.System.currentTimeMillis;
5 import static java.util.concurrent.TimeUnit.DAYS;
6 import static net.pterodactylus.sone.data.Sone.SoneStatus.downloading;
7 import static net.pterodactylus.sone.data.Sone.SoneStatus.idle;
8 import static net.pterodactylus.sone.data.Sone.SoneStatus.unknown;
9 import static org.hamcrest.MatcherAssert.assertThat;
10 import static org.hamcrest.Matchers.is;
11 import static org.mockito.ArgumentCaptor.forClass;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.ArgumentMatchers.eq;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.never;
16 import static org.mockito.Mockito.times;
17 import static org.mockito.Mockito.verify;
18 import static org.mockito.Mockito.when;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22
23 import net.pterodactylus.sone.core.FreenetInterface.Fetched;
24 import net.pterodactylus.sone.data.Sone;
25 import net.pterodactylus.sone.data.Sone.SoneStatus;
26 import net.pterodactylus.sone.freenet.wot.Identity;
27
28 import freenet.client.ClientMetadata;
29 import freenet.client.FetchResult;
30 import freenet.client.async.USKCallback;
31 import freenet.crypt.DummyRandomSource;
32 import freenet.keys.FreenetURI;
33 import freenet.keys.InsertableClientSSK;
34 import freenet.support.api.Bucket;
35
36 import org.junit.Before;
37 import org.junit.Test;
38 import org.mockito.ArgumentCaptor;
39 import org.mockito.invocation.InvocationOnMock;
40 import org.mockito.stubbing.Answer;
41
42 /**
43  * Unit test for {@link SoneDownloaderImpl} and its subclasses.
44  *
45  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
46  */
47 public class SoneDownloaderTest {
48
49         private final Core core = mock(Core.class);
50         private final FreenetInterface freenetInterface = mock(FreenetInterface.class);
51         private final SoneParser soneParser = mock(SoneParser.class);
52         private final SoneDownloaderImpl soneDownloader = new SoneDownloaderImpl(core, freenetInterface, soneParser);
53         private FreenetURI requestUri = mock(FreenetURI.class);
54         private Sone sone = mock(Sone.class);
55
56         @Before
57         public void setupSone() {
58                 Sone sone = SoneDownloaderTest.this.sone;
59                 Identity identity = mock(Identity.class);
60                 InsertableClientSSK clientSSK = createRandom(new DummyRandomSource(), "WoT");
61                 when(identity.getRequestUri()).thenReturn(clientSSK.getURI().toString());
62                 when(identity.getId()).thenReturn("identity");
63                 when(sone.getId()).thenReturn("identity");
64                 when(sone.getIdentity()).thenReturn(identity);
65                 requestUri = clientSSK.getURI().setKeyType("USK").setDocName("Sone");
66                 when(sone.getRequestUri()).thenAnswer(new Answer<FreenetURI>() {
67                         @Override
68                         public FreenetURI answer(InvocationOnMock invocation)
69                         throws Throwable {
70                                 return requestUri;
71                         }
72                 });
73                 when(sone.getTime()).thenReturn(currentTimeMillis() - DAYS.toMillis(1));
74         }
75
76         private void setupSoneAsUnknown() {
77                 when(sone.getTime()).thenReturn(0L);
78         }
79
80         @Test
81         public void addingASoneWillRegisterItsKey() {
82                 soneDownloader.addSone(sone);
83                 verify(freenetInterface).registerActiveUsk(eq(sone.getRequestUri()), any(
84                                 USKCallback.class));
85                 verify(freenetInterface, never()).unregisterUsk(sone);
86         }
87
88         @Test
89         public void addingASoneTwiceWillAlsoDeregisterItsKey() {
90                 soneDownloader.addSone(sone);
91                 soneDownloader.addSone(sone);
92                 verify(freenetInterface, times(2)).registerActiveUsk(eq(
93                                 sone.getRequestUri()), any(USKCallback.class));
94                 verify(freenetInterface).unregisterUsk(sone);
95         }
96
97
98         @Test
99         public void stoppingTheSoneDownloaderUnregistersTheSone() {
100                 soneDownloader.addSone(sone);
101                 soneDownloader.stop();
102                 verify(freenetInterface).unregisterUsk(sone);
103         }
104
105         @Test
106         public void notBeingAbleToFetchAnUnknownSoneDoesNotUpdateCore() {
107                 FreenetURI finalRequestUri = requestUri.sskForUSK()
108                                 .setMetaString(new String[] { "sone.xml" });
109                 setupSoneAsUnknown();
110                 soneDownloader.fetchSoneAction(sone).run();
111                 verify(freenetInterface).fetchUri(finalRequestUri);
112                 verifyThatSoneStatusWasChangedToDownloadingAndBackTo(unknown);
113                 verify(core, never()).updateSone(any(Sone.class));
114         }
115
116         private void verifyThatSoneStatusWasChangedToDownloadingAndBackTo(SoneStatus soneStatus) {
117                 ArgumentCaptor<SoneStatus> soneStatuses = forClass(SoneStatus.class);
118                 verify(sone, times(2)).setStatus(soneStatuses.capture());
119                 assertThat(soneStatuses.getAllValues().get(0), is(downloading));
120                 assertThat(soneStatuses.getAllValues().get(1), is(soneStatus));
121         }
122
123         @Test
124         public void notBeingAbleToFetchAKnownSoneDoesNotUpdateCore() {
125                 FreenetURI finalRequestUri = requestUri.sskForUSK()
126                                 .setMetaString(new String[] { "sone.xml" });
127                 soneDownloader.fetchSoneAction(sone).run();
128                 verify(freenetInterface).fetchUri(finalRequestUri);
129                 verifyThatSoneStatusWasChangedToDownloadingAndBackTo(idle);
130                 verify(core, never()).updateSone(any(Sone.class));
131         }
132
133         @Test(expected = NullPointerException.class)
134         public void exceptionWhileFetchingAnUnknownSoneDoesNotUpdateCore() {
135                 FreenetURI finalRequestUri = requestUri.sskForUSK()
136                                 .setMetaString(new String[] { "sone.xml" });
137                 setupSoneAsUnknown();
138                 when(freenetInterface.fetchUri(finalRequestUri)).thenThrow(NullPointerException.class);
139                 try {
140                         soneDownloader.fetchSoneAction(sone).run();
141                 } finally {
142                         verify(freenetInterface).fetchUri(finalRequestUri);
143                         verifyThatSoneStatusWasChangedToDownloadingAndBackTo(unknown);
144                         verify(core, never()).updateSone(any(Sone.class));
145                 }
146         }
147
148         @Test(expected = NullPointerException.class)
149         public void exceptionWhileFetchingAKnownSoneDoesNotUpdateCore() {
150                 FreenetURI finalRequestUri = requestUri.sskForUSK()
151                                 .setMetaString(new String[] { "sone.xml" });
152                 when(freenetInterface.fetchUri(finalRequestUri)).thenThrow( NullPointerException.class);
153                 try {
154                         soneDownloader.fetchSoneAction(sone).run();
155                 } finally {
156                         verify(freenetInterface).fetchUri(finalRequestUri);
157                         verifyThatSoneStatusWasChangedToDownloadingAndBackTo(idle);
158                         verify(core, never()).updateSone(any(Sone.class));
159                 }
160         }
161
162         @Test
163         public void fetchingSoneWithInvalidXmlWillNotUpdateTheCore() throws IOException {
164                 final Fetched fetchResult = createFetchResult(requestUri, getClass().getResourceAsStream("sone-parser-not-xml.xml"));
165                 when(freenetInterface.fetchUri(requestUri)).thenReturn(fetchResult);
166                 soneDownloader.fetchSoneAction(sone).run();
167                 verify(core, never()).updateSone(any(Sone.class));
168         }
169
170         @Test
171         public void exceptionWhileFetchingSoneWillNotUpdateTheCore() throws IOException {
172                 final Fetched fetchResult = createFetchResult(requestUri, getClass().getResourceAsStream("sone-parser-no-payload.xml"));
173                 when(core.soneBuilder()).thenReturn(null);
174                 when(freenetInterface.fetchUri(requestUri)).thenReturn(fetchResult);
175                 soneDownloader.fetchSoneAction(sone).run();
176                 verify(core, never()).updateSone(any(Sone.class));
177         }
178
179         @Test
180         public void onlyFetchingASoneWillNotUpdateTheCore() throws IOException {
181                 final Fetched fetchResult = createFetchResult(requestUri, getClass().getResourceAsStream("sone-parser-no-payload.xml"));
182                 when(freenetInterface.fetchUri(requestUri)).thenReturn(fetchResult);
183                 soneDownloader.fetchSone(sone, sone.getRequestUri(), true);
184                 verify(core, never()).updateSone(any(Sone.class));
185                 verifyThatSoneStatusWasChangedToDownloadingAndBackTo(idle);
186         }
187
188         private Fetched createFetchResult(FreenetURI uri, InputStream inputStream) throws IOException {
189                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
190                 Bucket bucket = mock(Bucket.class);
191                 when(bucket.getInputStream()).thenReturn(inputStream);
192                 FetchResult fetchResult = new FetchResult(clientMetadata, bucket);
193                 return new Fetched(uri, fetchResult);
194         }
195
196 }