1 package net.pterodactylus.sone.core;
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;
16 import java.io.IOException;
17 import java.io.InputStream;
19 import net.pterodactylus.sone.core.FreenetInterface.Callback;
20 import net.pterodactylus.sone.core.FreenetInterface.Fetched;
21 import net.pterodactylus.sone.core.event.UpdateFoundEvent;
22 import net.pterodactylus.util.version.Version;
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;
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;
38 * Unit test for {@link UpdateChecker}.
40 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
42 public class UpdateCheckerTest {
44 private final EventBus eventBus = mock(EventBus.class);
45 private final FreenetInterface freenetInterface = mock(FreenetInterface.class);
46 private final Version currentVersion = new Version(1, 0, 0);
47 private final UpdateChecker updateChecker = new UpdateChecker(eventBus, freenetInterface, currentVersion);
50 public void startUpdateChecker() {
51 updateChecker.start();
55 public void newUpdateCheckerDoesNotHaveALatestVersion() {
56 assertThat(updateChecker.hasLatestVersion(), is(false));
57 assertThat(updateChecker.getLatestVersion(), is(currentVersion));
61 public void startingAnUpdateCheckerRegisterAUsk() {
62 verify(freenetInterface).registerUsk(any(FreenetURI.class), any(Callback.class));
66 public void stoppingAnUpdateCheckerUnregistersAUsk() {
68 verify(freenetInterface).unregisterUsk(any(FreenetURI.class));
72 public void callbackDoesNotDownloadIfNewEditionIsNotFound() {
73 setupCallbackWithEdition(MAX_VALUE, false, false);
74 verify(freenetInterface, never()).fetchUri(any(FreenetURI.class));
75 verify(eventBus, never()).post(argThat(instanceOf(UpdateFoundEvent.class)));
78 private void setupCallbackWithEdition(long edition, boolean newKnownGood, boolean newSlot) {
79 ArgumentCaptor<FreenetURI> uri = forClass(FreenetURI.class);
80 ArgumentCaptor<Callback> callback = forClass(Callback.class);
81 verify(freenetInterface).registerUsk(uri.capture(), callback.capture());
82 callback.getValue().editionFound(uri.getValue(), edition, newKnownGood, newSlot);
86 public void callbackStartsIfNewEditionIsFound() {
87 setupFetchResult(createFutureFetchResult());
88 setupCallbackWithEdition(MAX_VALUE, true, false);
89 verifyAFreenetUriIsFetched();
90 verifyEventIsFired(new Version(99, 0, 0), 11865368297000L, false);
91 verifyThatUpdateCheckerKnowsLatestVersion(new Version(99, 0, 0), 11865368297000L);
94 private FetchResult createFutureFetchResult() {
95 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
96 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
97 "CurrentVersion/Version: 99.0.0\n" +
98 "CurrentVersion/ReleaseTime: 11865368297000\n" +
99 "DisruptiveVersion/0.1.2: true").getBytes());
100 return new FetchResult(clientMetadata, fetched);
103 private void verifyEventIsFired(Version version, long releaseTime, boolean disruptive) {
104 ArgumentCaptor<UpdateFoundEvent> updateFoundEvent = forClass(UpdateFoundEvent.class);
105 verify(eventBus, times(1)).post(updateFoundEvent.capture());
106 assertThat(updateFoundEvent.getValue().version(), is(version));
107 assertThat(updateFoundEvent.getValue().releaseTime(), is(releaseTime));
108 assertThat(updateFoundEvent.getValue().disruptive(), is(disruptive));
111 private void verifyThatUpdateCheckerKnowsLatestVersion(Version version, long releaseTime) {
112 assertThat(updateChecker.getLatestVersion(), is(version));
113 assertThat(updateChecker.getLatestVersionDate(), is(releaseTime));
114 assertThat(updateChecker.hasLatestVersion(), is(true));
118 public void callbackDoesNotStartIfNoNewEditionIsFound() {
119 setupFetchResult(createPastFetchResult());
120 setupCallbackWithEdition(updateChecker.getLatestEdition(), true, false);
121 verifyAFreenetUriIsFetched();
122 verifyNoUpdateFoundEventIsFired();
125 private void setupFetchResult(final FetchResult pastFetchResult) {
126 when(freenetInterface.fetchUri(any(FreenetURI.class))).thenAnswer(new Answer<Fetched>() {
128 public Fetched answer(InvocationOnMock invocation) throws Throwable {
129 FreenetURI freenetUri = (FreenetURI) invocation.getArguments()[0];
130 return new Fetched(freenetUri, pastFetchResult);
135 private FetchResult createPastFetchResult() {
136 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
137 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
138 "CurrentVersion/Version: 0.2\n" +
139 "CurrentVersion/ReleaseTime: 1289417883000").getBytes());
140 return new FetchResult(clientMetadata, fetched);
144 public void invalidUpdateFileDoesNotStartCallback() {
145 setupFetchResult(createInvalidFetchResult());
146 setupCallbackWithEdition(MAX_VALUE, true, false);
147 verifyAFreenetUriIsFetched();
148 verifyNoUpdateFoundEventIsFired();
151 private FetchResult createInvalidFetchResult() {
152 ClientMetadata clientMetadata = new ClientMetadata("text/plain");
153 Bucket fetched = new ArrayBucket("Some other data.".getBytes());
154 return new FetchResult(clientMetadata, fetched);
158 public void nonExistingPropertiesWillNotCauseUpdateToBeFound() {
159 setupCallbackWithEdition(MAX_VALUE, true, false);
160 verifyAFreenetUriIsFetched();
161 verifyNoUpdateFoundEventIsFired();
164 private void verifyNoUpdateFoundEventIsFired() {
165 verify(eventBus, never()).post(any(UpdateFoundEvent.class));
168 private void verifyAFreenetUriIsFetched() {
169 verify(freenetInterface).fetchUri(any(FreenetURI.class));
173 public void brokenBucketDoesNotCauseUpdateToBeFound() {
174 setupFetchResult(createBrokenBucketFetchResult());
175 setupCallbackWithEdition(MAX_VALUE, true, false);
176 verifyAFreenetUriIsFetched();
177 verifyNoUpdateFoundEventIsFired();
180 private FetchResult createBrokenBucketFetchResult() {
181 ClientMetadata clientMetadata = new ClientMetadata("text/plain");
182 Bucket fetched = new ArrayBucket("Some other data.".getBytes()) {
184 public InputStream getInputStream() {
186 return when(mock(InputStream.class).read()).thenThrow(IOException.class).getMock();
187 } catch (IOException ioe1) {
188 /* won’t throw here. */
193 return new FetchResult(clientMetadata, fetched);
197 public void invalidTimeDoesNotCauseAnUpdateToBeFound() {
198 setupFetchResult(createInvalidTimeFetchResult());
199 setupCallbackWithEdition(MAX_VALUE, true, false);
200 verifyAFreenetUriIsFetched();
201 verifyNoUpdateFoundEventIsFired();
204 private FetchResult createInvalidTimeFetchResult() {
205 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
206 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
207 "CurrentVersion/Version: 0.2\n" +
208 "CurrentVersion/ReleaseTime: invalid").getBytes());
209 return new FetchResult(clientMetadata, fetched);
213 public void invalidPropertiesDoesNotCauseAnUpdateToBeFound() {
214 setupFetchResult(createMissingTimeFetchResult());
215 setupCallbackWithEdition(MAX_VALUE, true, false);
216 verifyAFreenetUriIsFetched();
217 verifyNoUpdateFoundEventIsFired();
220 private FetchResult createMissingTimeFetchResult() {
221 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
222 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
223 "CurrentVersion/Version: 0.2\n").getBytes());
224 return new FetchResult(clientMetadata, fetched);
228 public void invalidVersionDoesNotCauseAnUpdateToBeFound() {
229 setupFetchResult(createInvalidVersionFetchResult());
230 setupCallbackWithEdition(MAX_VALUE, true, false);
231 verifyAFreenetUriIsFetched();
232 verifyNoUpdateFoundEventIsFired();
235 private FetchResult createInvalidVersionFetchResult() {
236 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
237 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
238 "CurrentVersion/Version: foo\n" +
239 "CurrentVersion/ReleaseTime: 1289417883000").getBytes());
240 return new FetchResult(clientMetadata, fetched);
244 public void disruptiveVersionGetsNotification() {
245 setupFetchResult(createDisruptiveVersionFetchResult());
246 setupCallbackWithEdition(MAX_VALUE, true, false);
247 verifyAFreenetUriIsFetched();
248 verifyEventIsFired(new Version(1, 2, 3), 1289417883000L, true);
249 verifyThatUpdateCheckerKnowsLatestVersion(new Version(1, 2, 3), 1289417883000L);
252 private FetchResult createDisruptiveVersionFetchResult() {
253 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
254 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
255 "CurrentVersion/Version: 1.2.3\n" +
256 "CurrentVersion/ReleaseTime: 1289417883000\n" +
257 "DisruptiveVersion/1.2.3: true").getBytes());
258 return new FetchResult(clientMetadata, fetched);