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