1 package net.pterodactylus.sone.core;
3 import static java.lang.Thread.sleep;
4 import static java.util.concurrent.TimeUnit.SECONDS;
5 import static org.hamcrest.MatcherAssert.assertThat;
6 import static org.hamcrest.Matchers.containsString;
7 import static org.hamcrest.Matchers.is;
8 import static org.hamcrest.Matchers.not;
9 import static org.mockito.ArgumentMatchers.eq;
10 import static org.mockito.Mockito.*;
12 import java.util.concurrent.CountDownLatch;
14 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.AddContextJob;
15 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.RemoveContextJob;
16 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.SetPropertyJob;
17 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.WebOfTrustContextUpdateJob;
18 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.WebOfTrustUpdateJob;
19 import net.pterodactylus.sone.freenet.plugin.PluginException;
20 import net.pterodactylus.sone.freenet.wot.Identity;
21 import net.pterodactylus.sone.freenet.wot.OwnIdentity;
22 import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
24 import org.junit.Test;
25 import org.mockito.invocation.InvocationOnMock;
26 import org.mockito.stubbing.Answer;
29 * Unit test for {@link WebOfTrustUpdaterImpl} and its subclasses.
31 public class WebOfTrustUpdaterTest {
33 private static final String CONTEXT = "test-context";
34 private static final String PROPERTY_NAME = "test-property";
35 private final WebOfTrustConnector webOfTrustConnector = mock(WebOfTrustConnector.class);
36 private final WebOfTrustUpdaterImpl webOfTrustUpdater = new WebOfTrustUpdaterImpl(webOfTrustConnector);
37 private final OwnIdentity ownIdentity = when(mock(OwnIdentity.class).getId()).thenReturn("own-identity-id").getMock();
38 private final WebOfTrustUpdateJob successfulWebOfTrustUpdateJob = createWebOfTrustUpdateJob(true);
39 private final WebOfTrustUpdateJob failingWebOfTrustUpdateJob = createWebOfTrustUpdateJob(false);
40 private final WebOfTrustContextUpdateJob contextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
41 private final AddContextJob addContextJob = webOfTrustUpdater.new AddContextJob(ownIdentity, CONTEXT);
42 private final RemoveContextJob removeContextJob = webOfTrustUpdater.new RemoveContextJob(ownIdentity, CONTEXT);
44 private WebOfTrustUpdateJob createWebOfTrustUpdateJob(final boolean success) {
45 return webOfTrustUpdater.new WebOfTrustUpdateJob() {
51 } catch (InterruptedException ie1) {
52 throw new RuntimeException(ie1);
60 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsSuccess() throws InterruptedException {
61 new Thread(successfulWebOfTrustUpdateJob).start();
62 assertThat(successfulWebOfTrustUpdateJob.waitForCompletion(), is(true));
66 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsFailure() throws InterruptedException {
67 new Thread(failingWebOfTrustUpdateJob).start();
68 assertThat(failingWebOfTrustUpdateJob.waitForCompletion(), is(false));
72 public void webOfTrustContextUpdateJobsAreEqualIfTheirClassOwnIdentityAndContextAreEqual() {
73 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
74 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(true));
75 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(true));
76 assertThat(contextUpdateJob.hashCode(), is(secondContextUpdateJob.hashCode()));
80 public void webOfTrustContextUpdatesJobsAreNotEqualIfTheirClassDiffers() {
81 assertThat(contextUpdateJob.equals(addContextJob), is(false));
85 public void webOfTrustContextUpdateJobToStringContainsIdentityAndContext() {
86 assertThat(contextUpdateJob.toString(), containsString(ownIdentity.toString()));
87 assertThat(contextUpdateJob.toString(), containsString(CONTEXT));
91 public void webOfTrustContextUpdateJobsAreNotEqualIfTheIdentitiesDiffer() {
92 OwnIdentity ownIdentity = mock(OwnIdentity.class);
93 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
94 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
95 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
99 public void webOfTrustContextUpdateJobsAreNotEqualIfTheirContextsDiffer() {
100 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT + CONTEXT);
101 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
102 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
106 public void webOfTrustContextUpdateJobsAreNotEqualToNull() {
107 assertThat(contextUpdateJob.equals(null), is(false));
111 public void addContextJobAddsTheContext() throws PluginException {
113 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
114 verify(ownIdentity).addContext(eq(CONTEXT));
115 assertThat(addContextJob.waitForCompletion(), is(true));
119 public void exceptionWhileAddingAContextIsExposed() throws PluginException {
120 doThrow(PluginException.class).when(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
122 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
123 verify(ownIdentity, never()).addContext(eq(CONTEXT));
124 assertThat(addContextJob.waitForCompletion(), is(false));
128 public void removeContextJobRemovesTheContext() throws PluginException {
129 removeContextJob.run();
130 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
131 verify(ownIdentity).removeContext(eq(CONTEXT));
132 assertThat(removeContextJob.waitForCompletion(), is(true));
136 public void exceptionWhileRemovingAContextIsExposed() throws PluginException {
137 doThrow(PluginException.class).when(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
138 removeContextJob.run();
139 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
140 verify(ownIdentity, never()).removeContext(eq(CONTEXT));
141 assertThat(removeContextJob.waitForCompletion(), is(false));
145 public void settingAPropertySetsTheProperty() throws PluginException {
146 String propertyName = "property-name";
147 String propertyValue = "property-value";
148 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
149 setPropertyJob.run();
150 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
151 verify(ownIdentity).setProperty(eq(propertyName), eq(propertyValue));
152 assertThat(setPropertyJob.waitForCompletion(), is(true));
156 public void settingAPropertyToNullRemovesTheProperty() throws PluginException {
157 String propertyName = "property-name";
158 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, null);
159 setPropertyJob.run();
160 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(propertyName));
161 verify(ownIdentity).removeProperty(eq(propertyName));
162 assertThat(setPropertyJob.waitForCompletion(), is(true));
166 public void pluginExceptionWhileSettingAPropertyIsHandled() throws PluginException {
167 String propertyName = "property-name";
168 String propertyValue = "property-value";
169 doThrow(PluginException.class).when(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
170 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
171 setPropertyJob.run();
172 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
173 verify(ownIdentity, never()).setProperty(eq(propertyName), eq(propertyValue));
174 assertThat(setPropertyJob.waitForCompletion(), is(false));
178 public void setPropertyJobsWithSameClassPropertyAndValueAreEqual() {
179 String propertyName = "property-name";
180 String propertyValue = "property-value";
181 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
182 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
183 assertThat(firstSetPropertyJob, is(secondSetPropertyJob));
184 assertThat(secondSetPropertyJob, is(firstSetPropertyJob));
185 assertThat(firstSetPropertyJob.hashCode(), is(secondSetPropertyJob.hashCode()));
189 public void setPropertyJobsWithDifferentClassesAreNotEqual() {
190 String propertyName = "property-name";
191 String propertyValue = "property-value";
192 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
193 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue) {
195 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
199 public void nullIsNotASetProjectJobEither() {
200 String propertyName = "property-name";
201 String propertyValue = "property-value";
202 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
203 assertThat(setPropertyJob, not(is((Object) null)));
207 public void setPropertyJobsWithDifferentPropertiesAreNotEqual() {
208 String propertyName = "property-name";
209 String propertyValue = "property-value";
210 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
211 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName + "2", propertyValue);
212 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
216 public void setPropertyJobsWithDifferentOwnIdentitiesAreNotEqual() {
217 OwnIdentity otherOwnIdentity = mock(OwnIdentity.class);
218 String propertyName = "property-name";
219 String propertyValue = "property-value";
220 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
221 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(otherOwnIdentity, propertyName, propertyValue);
222 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
226 public void webOfTrustUpdaterStopsWhenItShould() {
227 webOfTrustUpdater.stop();
228 webOfTrustUpdater.serviceRun();
232 public void webOfTrustUpdaterStopsAfterItWasStarted() {
233 webOfTrustUpdater.start();
234 webOfTrustUpdater.stop();
238 public void removePropertyRemovesProperty() throws InterruptedException, PluginException {
239 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
240 doAnswer(new Answer<Void>() {
242 public Void answer(InvocationOnMock invocation) throws Throwable {
243 wotCallTriggered.countDown();
246 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
247 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
248 webOfTrustUpdater.start();
249 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
253 public void multipleCallsToSetPropertyAreCollapsed() throws InterruptedException, PluginException {
254 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
255 doAnswer(new Answer<Void>() {
257 public Void answer(InvocationOnMock invocation) throws Throwable {
258 wotCallTriggered.countDown();
261 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
262 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
263 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
264 webOfTrustUpdater.start();
265 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
266 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
270 public void addContextWaitWaitsForTheContextToBeAdded() {
271 webOfTrustUpdater.start();
272 assertThat(webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT), is(true));
273 verify(ownIdentity).addContext(eq(CONTEXT));
277 public void removeContextRemovesAContext() throws InterruptedException, PluginException {
278 webOfTrustUpdater.start();
279 final CountDownLatch removeContextTrigger = new CountDownLatch(1);
280 doAnswer(new Answer<Void>() {
282 public Void answer(InvocationOnMock invocation) throws Throwable {
283 removeContextTrigger.countDown();
286 }).when(ownIdentity).removeContext(eq(CONTEXT));
287 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
288 removeContextTrigger.await(1, SECONDS);
289 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
290 verify(ownIdentity).removeContext(eq(CONTEXT));
294 public void removeContextRequestsAreCoalesced() throws InterruptedException, PluginException {
295 final CountDownLatch contextRemovedTrigger = new CountDownLatch(1);
296 doAnswer(new Answer<Void>() {
298 public Void answer(InvocationOnMock invocation) throws Throwable {
299 contextRemovedTrigger.countDown();
302 }).when(ownIdentity).removeContext(eq(CONTEXT));
303 for (int i = 1; i <= 2; i++) {
304 /* this is so fucking volatile. */
308 new Thread(new Runnable() {
310 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
314 webOfTrustUpdater.start();
315 assertThat(contextRemovedTrigger.await(1, SECONDS), is(true));
316 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
317 verify(ownIdentity).removeContext(eq(CONTEXT));