Merge branch 'release/0.9-rc1'
[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 UpdateChecker updateChecker = new UpdateChecker(eventBus, freenetInterface);
48
49         @Before
50         public void startUpdateChecker() {
51                 updateChecker.start();
52         }
53
54         @Test
55         public void newUpdateCheckerDoesNotHaveALatestVersion() {
56                 assertThat(updateChecker.hasLatestVersion(), is(false));
57                 assertThat(updateChecker.getLatestVersion(), is(VERSION));
58         }
59
60         @Test
61         public void startingAnUpdateCheckerRegisterAUsk() {
62                 verify(freenetInterface).registerUsk(any(FreenetURI.class), any(Callback.class));
63         }
64
65         @Test
66         public void stoppingAnUpdateCheckerUnregistersAUsk() {
67                 updateChecker.stop();
68                 verify(freenetInterface).unregisterUsk(any(FreenetURI.class));
69         }
70
71         @Test
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)));
76         }
77
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);
83         }
84
85         @Test
86         public void callbackStartsIfNewEditionIsFound() {
87                 setupFetchResult(createFutureFetchResult());
88                 setupCallbackWithEdition(MAX_VALUE, true, false);
89                 verifyAFreenetUriIsFetched();
90                 ArgumentCaptor<UpdateFoundEvent> updateFoundEvent = forClass(UpdateFoundEvent.class);
91                 verify(eventBus, times(1)).post(updateFoundEvent.capture());
92                 assertThat(updateFoundEvent.getValue().version(), is(new Version(99, 0, 0)));
93                 assertThat(updateFoundEvent.getValue().releaseTime(), is(11865368297000L));
94                 assertThat(updateChecker.getLatestVersion(), is(new Version(99, 0, 0)));
95                 assertThat(updateChecker.getLatestVersionDate(), is(11865368297000L));
96                 assertThat(updateChecker.hasLatestVersion(), is(true));
97         }
98
99         private FetchResult createFutureFetchResult() {
100                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
101                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
102                                 "CurrentVersion/Version: 99.0.0\n" +
103                                 "CurrentVersion/ReleaseTime: 11865368297000").getBytes());
104                 return new FetchResult(clientMetadata, fetched);
105         }
106
107         @Test
108         public void callbackDoesNotStartIfNoNewEditionIsFound() {
109                 setupFetchResult(createPastFetchResult());
110                 setupCallbackWithEdition(updateChecker.getLatestEdition(), true, false);
111                 verifyAFreenetUriIsFetched();
112                 verifyNoUpdateFoundEventIsFired();
113         }
114
115         private void setupFetchResult(final FetchResult pastFetchResult) {
116                 when(freenetInterface.fetchUri(any(FreenetURI.class))).thenAnswer(new Answer<Fetched>() {
117                         @Override
118                         public Fetched answer(InvocationOnMock invocation) throws Throwable {
119                                 FreenetURI freenetUri = (FreenetURI) invocation.getArguments()[0];
120                                 return new Fetched(freenetUri, pastFetchResult);
121                         }
122                 });
123         }
124
125         private FetchResult createPastFetchResult() {
126                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
127                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
128                                 "CurrentVersion/Version: 0.2\n" +
129                                 "CurrentVersion/ReleaseTime: 1289417883000").getBytes());
130                 return new FetchResult(clientMetadata, fetched);
131         }
132
133         @Test
134         public void invalidUpdateFileDoesNotStartCallback() {
135                 setupFetchResult(createInvalidFetchResult());
136                 setupCallbackWithEdition(MAX_VALUE, true, false);
137                 verifyAFreenetUriIsFetched();
138                 verifyNoUpdateFoundEventIsFired();
139         }
140
141         private FetchResult createInvalidFetchResult() {
142                 ClientMetadata clientMetadata = new ClientMetadata("text/plain");
143                 Bucket fetched = new ArrayBucket("Some other data.".getBytes());
144                 return new FetchResult(clientMetadata, fetched);
145         }
146
147         @Test
148         public void nonExistingPropertiesWillNotCauseUpdateToBeFound() {
149                 setupCallbackWithEdition(MAX_VALUE, true, false);
150                 verifyAFreenetUriIsFetched();
151                 verifyNoUpdateFoundEventIsFired();
152         }
153
154         private void verifyNoUpdateFoundEventIsFired() {
155                 verify(eventBus, never()).post(any(UpdateFoundEvent.class));
156         }
157
158         private void verifyAFreenetUriIsFetched() {
159                 verify(freenetInterface).fetchUri(any(FreenetURI.class));
160         }
161
162         @Test
163         public void brokenBucketDoesNotCauseUpdateToBeFound() {
164                 setupFetchResult(createBrokenBucketFetchResult());
165                 setupCallbackWithEdition(MAX_VALUE, true, false);
166                 verifyAFreenetUriIsFetched();
167                 verifyNoUpdateFoundEventIsFired();
168         }
169
170         private FetchResult createBrokenBucketFetchResult() {
171                 ClientMetadata clientMetadata = new ClientMetadata("text/plain");
172                 Bucket fetched = new ArrayBucket("Some other data.".getBytes()) {
173                         @Override
174                         public InputStream getInputStream() {
175                                 try {
176                                         return when(mock(InputStream.class).read()).thenThrow(IOException.class).getMock();
177                                 } catch (IOException ioe1) {
178                                         /* won’t throw here. */
179                                         return null;
180                                 }
181                         }
182                 };
183                 return new FetchResult(clientMetadata, fetched);
184         }
185
186         @Test
187         public void invalidTimeDoesNotCauseAnUpdateToBeFound() {
188                 setupFetchResult(createInvalidTimeFetchResult());
189                 setupCallbackWithEdition(MAX_VALUE, true, false);
190                 verifyAFreenetUriIsFetched();
191                 verifyNoUpdateFoundEventIsFired();
192         }
193
194         private FetchResult createInvalidTimeFetchResult() {
195                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
196                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
197                                 "CurrentVersion/Version: 0.2\n" +
198                                 "CurrentVersion/ReleaseTime: invalid").getBytes());
199                 return new FetchResult(clientMetadata, fetched);
200         }
201
202         @Test
203         public void invalidPropertiesDoesNotCauseAnUpdateToBeFound() {
204                 setupFetchResult(createMissingTimeFetchResult());
205                 setupCallbackWithEdition(MAX_VALUE, true, false);
206                 verifyAFreenetUriIsFetched();
207                 verifyNoUpdateFoundEventIsFired();
208         }
209
210         private FetchResult createMissingTimeFetchResult() {
211                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
212                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
213                                 "CurrentVersion/Version: 0.2\n").getBytes());
214                 return new FetchResult(clientMetadata, fetched);
215         }
216
217         @Test
218         public void invalidVersionDoesNotCauseAnUpdateToBeFound() {
219                 setupFetchResult(createInvalidVersionFetchResult());
220                 setupCallbackWithEdition(MAX_VALUE, true, false);
221                 verifyAFreenetUriIsFetched();
222                 verifyNoUpdateFoundEventIsFired();
223         }
224
225         private FetchResult createInvalidVersionFetchResult() {
226                 ClientMetadata clientMetadata = new ClientMetadata("application/xml");
227                 Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
228                                 "CurrentVersion/Version: foo\n" +
229                                 "CurrentVersion/ReleaseTime: 1289417883000").getBytes());
230                 return new FetchResult(clientMetadata, fetched);
231         }
232
233 }