Don't access the Sone in the constructor.
[Sone.git] / src / test / java / net / pterodactylus / sone / core / SoneInserterTest.java
1 package net.pterodactylus.sone.core;
2
3 import static com.google.common.base.Optional.absent;
4 import static com.google.common.base.Optional.of;
5 import static org.hamcrest.MatcherAssert.assertThat;
6 import static org.hamcrest.Matchers.containsInAnyOrder;
7 import static org.hamcrest.Matchers.instanceOf;
8 import static org.hamcrest.Matchers.is;
9 import static org.mockito.Matchers.any;
10 import static org.mockito.Matchers.anyString;
11 import static org.mockito.Matchers.argThat;
12 import static org.mockito.Matchers.eq;
13 import static org.mockito.Mockito.doAnswer;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.never;
16 import static org.mockito.Mockito.times;
17 import static org.mockito.Mockito.verify;
18 import static org.mockito.Mockito.when;
19
20 import java.util.HashMap;
21
22 import net.pterodactylus.sone.core.SoneInserter.InsertInformation;
23 import net.pterodactylus.sone.core.SoneInserter.SetInsertionDelay;
24 import net.pterodactylus.sone.core.event.SoneEvent;
25 import net.pterodactylus.sone.core.event.SoneInsertAbortedEvent;
26 import net.pterodactylus.sone.core.event.SoneInsertedEvent;
27 import net.pterodactylus.sone.core.event.SoneInsertingEvent;
28 import net.pterodactylus.sone.data.Album;
29 import net.pterodactylus.sone.data.Sone;
30
31 import freenet.keys.FreenetURI;
32
33 import com.google.common.base.Optional;
34 import com.google.common.eventbus.EventBus;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.mockito.ArgumentCaptor;
38 import org.mockito.invocation.InvocationOnMock;
39 import org.mockito.stubbing.Answer;
40
41 /**
42  * Unit test for {@link SoneInserter} and its subclasses.
43  *
44  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
45  */
46 public class SoneInserterTest {
47
48         private final Core core = mock(Core.class);
49         private final EventBus eventBus = mock(EventBus.class);
50         private final FreenetInterface freenetInterface = mock(FreenetInterface.class);
51
52         @Before
53         public void setupCore() {
54                 UpdateChecker updateChecker = mock(UpdateChecker.class);
55                 when(core.getUpdateChecker()).thenReturn(updateChecker);
56                 when(core.getSone(anyString())).thenReturn(Optional.<Sone>absent());
57         }
58
59         @Test
60         public void insertionDelayIsForwardedToSoneInserter() {
61                 SetInsertionDelay setInsertionDelay = new SetInsertionDelay();
62                 setInsertionDelay.optionChanged(null, null, 15);
63                 assertThat(SoneInserter.getInsertionDelay().get(), is(15));
64         }
65
66         @Test
67         /* this test is hilariously bad. */
68         public void manifestEntriesAreCreated() {
69                 FreenetURI insertUri = mock(FreenetURI.class);
70                 String fingerprint = "fingerprint";
71                 Sone sone = createSone(insertUri, fingerprint);
72                 SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId");
73                 InsertInformation insertInformation = soneInserter.new InsertInformation(sone);
74                 HashMap<String, Object> manifestEntries = insertInformation.generateManifestEntries();
75                 assertThat(manifestEntries.keySet(), containsInAnyOrder("index.html", "sone.xml"));
76                 assertThat(insertInformation.getInsertUri(), is(insertUri));
77                 assertThat(insertInformation.getFingerprint(), is(fingerprint));
78         }
79
80         private Sone createSone(FreenetURI insertUri, String fingerprint) {
81                 Sone sone = mock(Sone.class);
82                 when(sone.getInsertUri()).thenReturn(insertUri);
83                 when(sone.getFingerprint()).thenReturn(fingerprint);
84                 when(sone.getRootAlbum()).thenReturn(mock(Album.class));
85                 when(core.getSone(anyString())).thenReturn(of(sone));
86                 return sone;
87         }
88
89         @Test
90         public void isModifiedIsTrueIfModificationDetectorSaysSo() {
91                 SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
92                 when(soneModificationDetector.isModified()).thenReturn(true);
93                 SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
94                 assertThat(soneInserter.isModified(), is(true));
95         }
96
97         @Test
98         public void isModifiedIsFalseIfModificationDetectorSaysSo() {
99                 SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
100                 SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
101                 assertThat(soneInserter.isModified(), is(false));
102         }
103
104         @Test
105         public void lastFingerprintIsStoredCorrectly() {
106                 SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId");
107                 soneInserter.setLastInsertFingerprint("last-fingerprint");
108                 assertThat(soneInserter.getLastInsertFingerprint(), is("last-fingerprint"));
109         }
110
111         @Test
112         public void soneInserterStopsWhenItShould() {
113                 SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId");
114                 soneInserter.stop();
115                 soneInserter.serviceRun();
116         }
117
118         @Test
119         public void soneInserterInsertsASoneIfItIsEligible() throws SoneException {
120                 FreenetURI insertUri = mock(FreenetURI.class);
121                 final FreenetURI finalUri = mock(FreenetURI.class);
122                 String fingerprint = "fingerprint";
123                 Sone sone = createSone(insertUri, fingerprint);
124                 SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
125                 when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
126                 when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenReturn(finalUri);
127                 final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
128                 doAnswer(new Answer<Void>() {
129                         @Override
130                         public Void answer(InvocationOnMock invocation) throws Throwable {
131                                 soneInserter.stop();
132                                 return null;
133                         }
134                 }).when(core).touchConfiguration();
135                 soneInserter.serviceRun();
136                 ArgumentCaptor<SoneEvent> soneEvents = ArgumentCaptor.forClass(SoneEvent.class);
137                 verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"));
138                 verify(eventBus, times(2)).post(soneEvents.capture());
139                 assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class));
140                 assertThat(soneEvents.getAllValues().get(0).sone(), is(sone));
141                 assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertedEvent.class));
142                 assertThat(soneEvents.getAllValues().get(1).sone(), is(sone));
143         }
144
145         @Test
146         public void soneInserterBailsOutIfItIsStoppedWhileInserting() throws SoneException {
147                 FreenetURI insertUri = mock(FreenetURI.class);
148                 final FreenetURI finalUri = mock(FreenetURI.class);
149                 String fingerprint = "fingerprint";
150                 Sone sone = createSone(insertUri, fingerprint);
151                 SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
152                 when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
153                 final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
154                 when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenAnswer(new Answer<FreenetURI>() {
155                         @Override
156                         public FreenetURI answer(InvocationOnMock invocation) throws Throwable {
157                                 soneInserter.stop();
158                                 return finalUri;
159                         }
160                 });
161                 soneInserter.serviceRun();
162                 ArgumentCaptor<SoneEvent> soneEvents = ArgumentCaptor.forClass(SoneEvent.class);
163                 verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"));
164                 verify(eventBus, times(2)).post(soneEvents.capture());
165                 assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class));
166                 assertThat(soneEvents.getAllValues().get(0).sone(), is(sone));
167                 assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertedEvent.class));
168                 assertThat(soneEvents.getAllValues().get(1).sone(), is(sone));
169                 verify(core, never()).touchConfiguration();
170         }
171
172         @Test
173         public void soneInserterDoesNotInsertSoneIfItIsNotEligible() throws SoneException {
174                 FreenetURI insertUri = mock(FreenetURI.class);
175                 String fingerprint = "fingerprint";
176                 Sone sone = createSone(insertUri, fingerprint);
177                 SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
178                 final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
179                 new Thread(new Runnable() {
180                         @Override
181                         public void run() {
182                                 try {
183                                         Thread.sleep(500);
184                                 } catch (InterruptedException ie1) {
185                                         throw new RuntimeException(ie1);
186                                 }
187                                 soneInserter.stop();
188                         }
189                 }).start();
190                 soneInserter.serviceRun();
191                 verify(freenetInterface, never()).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"));
192                 verify(eventBus, never()).post(argThat(org.hamcrest.Matchers.any(SoneEvent.class)));
193         }
194
195         @Test
196         public void soneInserterPostsAbortedEventIfAnExceptionOccurs() throws SoneException {
197                 FreenetURI insertUri = mock(FreenetURI.class);
198                 String fingerprint = "fingerprint";
199                 Sone sone = createSone(insertUri, fingerprint);
200                 SoneModificationDetector soneModificationDetector = mock(SoneModificationDetector.class);
201                 when(soneModificationDetector.isEligibleForInsert()).thenReturn(true);
202                 final SoneInserter soneInserter = new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1);
203                 final SoneException soneException = new SoneException(new Exception());
204                 when(freenetInterface.insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"))).thenAnswer(new Answer<FreenetURI>() {
205                         @Override
206                         public FreenetURI answer(InvocationOnMock invocation) throws Throwable {
207                                 soneInserter.stop();
208                                 throw soneException;
209                         }
210                 });
211                 soneInserter.serviceRun();
212                 ArgumentCaptor<SoneEvent> soneEvents = ArgumentCaptor.forClass(SoneEvent.class);
213                 verify(freenetInterface).insertDirectory(eq(insertUri), any(HashMap.class), eq("index.html"));
214                 verify(eventBus, times(2)).post(soneEvents.capture());
215                 assertThat(soneEvents.getAllValues().get(0), instanceOf(SoneInsertingEvent.class));
216                 assertThat(soneEvents.getAllValues().get(0).sone(), is(sone));
217                 assertThat(soneEvents.getAllValues().get(1), instanceOf(SoneInsertAbortedEvent.class));
218                 assertThat(soneEvents.getAllValues().get(1).sone(), is(sone));
219                 verify(core, never()).touchConfiguration();
220         }
221
222 }