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