🔀 Merge branch “release-80”
[Sone.git] / src / test / java / net / pterodactylus / sone / core / UpdateCheckerTest.java
1 package net.pterodactylus.sone.core;
2
3 import static java.lang.Long.MAX_VALUE;
4 import static org.hamcrest.MatcherAssert.assertThat;
5 import static org.hamcrest.Matchers.instanceOf;
6 import static org.hamcrest.Matchers.is;
7 import static org.mockito.ArgumentCaptor.forClass;
8 import static org.mockito.ArgumentMatchers.any;
9 import static org.mockito.Mockito.mock;
10 import static org.mockito.Mockito.never;
11 import static org.mockito.Mockito.times;
12 import static org.mockito.Mockito.verify;
13 import static org.mockito.Mockito.when;
14 import static org.mockito.hamcrest.MockitoHamcrest.argThat;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18
19 import net.pterodactylus.sone.core.FreenetInterface.Callback;
20 import net.pterodactylus.sone.core.event.UpdateFoundEvent;
21 import net.pterodactylus.sone.main.PluginHomepage;
22 import net.pterodactylus.util.version.Version;
23
24 import freenet.client.ClientMetadata;
25 import freenet.client.FetchResult;
26 import freenet.keys.FreenetURI;
27 import freenet.support.api.Bucket;
28 import freenet.support.io.ArrayBucket;
29
30 import com.google.common.eventbus.EventBus;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.mockito.ArgumentCaptor;
34 import org.mockito.invocation.InvocationOnMock;
35 import org.mockito.stubbing.Answer;
36
37 /**
38  * Unit test for {@link UpdateChecker}.
39  */
40 public class UpdateCheckerTest {
41
42         private final EventBus eventBus = mock(EventBus.class);
43         private final FreenetInterface freenetInterface = mock(FreenetInterface.class);
44         private final Version currentVersion = new Version(1, 0, 0);
45         private final PluginHomepage pluginHomepage = new PluginHomepage("KSK@homepage");
46         private final UpdateChecker updateChecker = new UpdateChecker(eventBus, freenetInterface, currentVersion, pluginHomepage);
47
48         @Before
49         public void startUpdateChecker() {
50                 updateChecker.start();
51         }
52
53         @Test
54         public void newUpdateCheckerDoesNotHaveALatestVersion() {
55                 assertThat(updateChecker.hasLatestVersion(), is(false));
56                 assertThat(updateChecker.getLatestVersion(), is(currentVersion));
57         }
58
59         @Test
60         public void startingAnUpdateCheckerRegisterAUsk() {
61                 verify(freenetInterface).registerUsk(any(FreenetURI.class), any(Callback.class));
62         }
63
64         @Test
65         public void stoppingAnUpdateCheckerUnregistersAUsk() {
66                 updateChecker.stop();
67                 verify(freenetInterface).unregisterUsk(any(FreenetURI.class));
68         }
69
70         @Test
71         public void callbackDoesNotDownloadIfNewEditionIsNotFound() {
72                 setupCallbackWithEdition(MAX_VALUE, false, false);
73                 verify(freenetInterface, never()).fetchUri(any(FreenetURI.class));
74                 verify(eventBus, never()).post(argThat(instanceOf(UpdateFoundEvent.class)));
75         }
76
77         private void setupCallbackWithEdition(long edition, boolean newKnownGood, boolean newSlot) {
78                 ArgumentCaptor<FreenetURI> uri = forClass(FreenetURI.class);
79                 ArgumentCaptor<Callback> callback = forClass(Callback.class);
80                 verify(freenetInterface).registerUsk(uri.capture(), callback.capture());
81                 callback.getValue().editionFound(uri.getValue(), edition, newKnownGood, newSlot);
82         }
83
84         @Test
85         public void callbackStartsIfNewEditionIsFound() {
86                 setupFetchResult(createFutureFetchResult());
87                 setupCallbackWithEdition(MAX_VALUE, true, false);
88                 verifyAFreenetUriIsFetched();
89                 verifyEventIsFired(new Version(99, 0, 0), 11865368297000L, false);
90                 verifyThatUpdateCheckerKnowsLatestVersion(new Version(99, 0, 0), 11865368297000L);
91         }
92
93         private FetchResult createFutureFetchResult() {
94                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
95                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
96                                 "CurrentVersion/Version: 99.0.0\n" +
97                                 "CurrentVersion/ReleaseTime: 11865368297000\n" +
98                                 "DisruptiveVersion/0.1.2: true").getBytes());
99                 return new FetchResult(clientMetadata, fetched);
100         }
101
102         private void verifyEventIsFired(Version version, long releaseTime, boolean disruptive) {
103                 ArgumentCaptor<UpdateFoundEvent> updateFoundEvent = forClass(UpdateFoundEvent.class);
104                 verify(eventBus, times(1)).post(updateFoundEvent.capture());
105                 assertThat(updateFoundEvent.getValue().version(), is(version));
106                 assertThat(updateFoundEvent.getValue().releaseTime(), is(releaseTime));
107                 assertThat(updateFoundEvent.getValue().disruptive(), is(disruptive));
108         }
109
110         private void verifyThatUpdateCheckerKnowsLatestVersion(Version version, long releaseTime) {
111                 assertThat(updateChecker.getLatestVersion(), is(version));
112                 assertThat(updateChecker.getLatestVersionDate(), is(releaseTime));
113                 assertThat(updateChecker.hasLatestVersion(), is(true));
114         }
115
116         @Test
117         public void callbackDoesNotStartIfNoNewEditionIsFound() {
118                 setupFetchResult(createPastFetchResult());
119                 setupCallbackWithEdition(updateChecker.getLatestEdition(), true, false);
120                 verifyAFreenetUriIsFetched();
121                 verifyNoUpdateFoundEventIsFired();
122         }
123
124         private void setupFetchResult(final FetchResult pastFetchResult) {
125                 when(freenetInterface.fetchUri(any(FreenetURI.class))).thenAnswer(new Answer<Fetched>() {
126                         @Override
127                         public Fetched answer(InvocationOnMock invocation) throws Throwable {
128                                 FreenetURI freenetUri = (FreenetURI) invocation.getArguments()[0];
129                                 return new Fetched(freenetUri, pastFetchResult);
130                         }
131                 });
132         }
133
134         private FetchResult createPastFetchResult() {
135                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
136                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
137                                 "CurrentVersion/Version: 0.2\n" +
138                                 "CurrentVersion/ReleaseTime: 1289417883000").getBytes());
139                 return new FetchResult(clientMetadata, fetched);
140         }
141
142         @Test
143         public void invalidUpdateFileDoesNotStartCallback() {
144                 setupFetchResult(createInvalidFetchResult());
145                 setupCallbackWithEdition(MAX_VALUE, true, false);
146                 verifyAFreenetUriIsFetched();
147                 verifyNoUpdateFoundEventIsFired();
148         }
149
150         private FetchResult createInvalidFetchResult() {
151                 ClientMetadata clientMetadata = new ClientMetadata("text/plain");
152                 Bucket fetched = new ArrayBucket("Some other data.".getBytes());
153                 return new FetchResult(clientMetadata, fetched);
154         }
155
156         @Test
157         public void nonExistingPropertiesWillNotCauseUpdateToBeFound() {
158                 setupCallbackWithEdition(MAX_VALUE, true, false);
159                 verifyAFreenetUriIsFetched();
160                 verifyNoUpdateFoundEventIsFired();
161         }
162
163         private void verifyNoUpdateFoundEventIsFired() {
164                 verify(eventBus, never()).post(any(UpdateFoundEvent.class));
165         }
166
167         private void verifyAFreenetUriIsFetched() {
168                 verify(freenetInterface).fetchUri(any(FreenetURI.class));
169         }
170
171         @Test
172         public void brokenBucketDoesNotCauseUpdateToBeFound() {
173                 setupFetchResult(createBrokenBucketFetchResult());
174                 setupCallbackWithEdition(MAX_VALUE, true, false);
175                 verifyAFreenetUriIsFetched();
176                 verifyNoUpdateFoundEventIsFired();
177         }
178
179         private FetchResult createBrokenBucketFetchResult() {
180                 ClientMetadata clientMetadata = new ClientMetadata("text/plain");
181                 Bucket fetched = new ArrayBucket("Some other data.".getBytes()) {
182                         @Override
183                         public InputStream getInputStream() {
184                                 try {
185                                         return when(mock(InputStream.class).read()).thenThrow(IOException.class).getMock();
186                                 } catch (IOException ioe1) {
187                                         /* won’t throw here. */
188                                         return null;
189                                 }
190                         }
191                 };
192                 return new FetchResult(clientMetadata, fetched);
193         }
194
195         @Test
196         public void invalidTimeDoesNotCauseAnUpdateToBeFound() {
197                 setupFetchResult(createInvalidTimeFetchResult());
198                 setupCallbackWithEdition(MAX_VALUE, true, false);
199                 verifyAFreenetUriIsFetched();
200                 verifyNoUpdateFoundEventIsFired();
201         }
202
203         private FetchResult createInvalidTimeFetchResult() {
204                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
205                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
206                                 "CurrentVersion/Version: 0.2\n" +
207                                 "CurrentVersion/ReleaseTime: invalid").getBytes());
208                 return new FetchResult(clientMetadata, fetched);
209         }
210
211         @Test
212         public void invalidPropertiesDoesNotCauseAnUpdateToBeFound() {
213                 setupFetchResult(createMissingTimeFetchResult());
214                 setupCallbackWithEdition(MAX_VALUE, true, false);
215                 verifyAFreenetUriIsFetched();
216                 verifyNoUpdateFoundEventIsFired();
217         }
218
219         private FetchResult createMissingTimeFetchResult() {
220                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
221                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
222                                 "CurrentVersion/Version: 0.2\n").getBytes());
223                 return new FetchResult(clientMetadata, fetched);
224         }
225
226         @Test
227         public void invalidVersionDoesNotCauseAnUpdateToBeFound() {
228                 setupFetchResult(createInvalidVersionFetchResult());
229                 setupCallbackWithEdition(MAX_VALUE, true, false);
230                 verifyAFreenetUriIsFetched();
231                 verifyNoUpdateFoundEventIsFired();
232         }
233
234         private FetchResult createInvalidVersionFetchResult() {
235                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
236                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
237                                 "CurrentVersion/Version: foo\n" +
238                                 "CurrentVersion/ReleaseTime: 1289417883000").getBytes());
239                 return new FetchResult(clientMetadata, fetched);
240         }
241
242         @Test
243         public void disruptiveVersionGetsNotification() {
244                 setupFetchResult(createDisruptiveVersionFetchResult());
245                 setupCallbackWithEdition(MAX_VALUE, true, false);
246                 verifyAFreenetUriIsFetched();
247                 verifyEventIsFired(new Version(1, 2, 3), 1289417883000L, true);
248                 verifyThatUpdateCheckerKnowsLatestVersion(new Version(1, 2, 3), 1289417883000L);
249         }
250
251         private FetchResult createDisruptiveVersionFetchResult() {
252                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
253                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
254                                 "CurrentVersion/Version: 1.2.3\n" +
255                                 "CurrentVersion/ReleaseTime: 1289417883000\n" +
256                                 "DisruptiveVersion/1.2.3: true").getBytes());
257                 return new FetchResult(clientMetadata, fetched);
258         }
259
260 }