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