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.Matchers.eq;
10 import static org.mockito.Mockito.doAnswer;
11 import static org.mockito.Mockito.doThrow;
12 import static org.mockito.Mockito.mock;
13 import static org.mockito.Mockito.never;
14 import static org.mockito.Mockito.verify;
15 import static org.mockito.Mockito.when;
17 import java.util.concurrent.CountDownLatch;
18 import java.util.concurrent.atomic.AtomicInteger;
20 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.AddContextJob;
21 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.RemoveContextJob;
22 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.SetPropertyJob;
23 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.SetTrustJob;
24 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.WebOfTrustContextUpdateJob;
25 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.WebOfTrustUpdateJob;
26 import net.pterodactylus.sone.freenet.plugin.PluginException;
27 import net.pterodactylus.sone.freenet.wot.Identity;
28 import net.pterodactylus.sone.freenet.wot.OwnIdentity;
29 import net.pterodactylus.sone.freenet.wot.Trust;
30 import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
31 import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
33 import org.junit.Test;
34 import org.mockito.invocation.InvocationOnMock;
35 import org.mockito.stubbing.Answer;
38 * Unit test for {@link WebOfTrustUpdaterImpl} and its subclasses.
40 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
42 public class WebOfTrustUpdaterTest {
44 private static final String CONTEXT = "test-context";
45 private static final Integer SCORE = 50;
46 private static final Integer OTHER_SCORE = 25;
47 private static final String TRUST_COMMENT = "set in a test";
48 private static final String PROPERTY_NAME = "test-property";
49 private final WebOfTrustConnector webOfTrustConnector = mock(WebOfTrustConnector.class);
50 private final WebOfTrustUpdaterImpl webOfTrustUpdater = new WebOfTrustUpdaterImpl(webOfTrustConnector);
51 private final OwnIdentity ownIdentity = when(mock(OwnIdentity.class).getId()).thenReturn("own-identity-id").getMock();
52 private final WebOfTrustUpdateJob successfulWebOfTrustUpdateJob = createWebOfTrustUpdateJob(true);
53 private final WebOfTrustUpdateJob failingWebOfTrustUpdateJob = createWebOfTrustUpdateJob(false);
54 private final WebOfTrustContextUpdateJob contextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
55 private final AddContextJob addContextJob = webOfTrustUpdater.new AddContextJob(ownIdentity, CONTEXT);
56 private final RemoveContextJob removeContextJob = webOfTrustUpdater.new RemoveContextJob(ownIdentity, CONTEXT);
57 private final Identity trustee = when(mock(Identity.class).getId()).thenReturn("trustee-id").getMock();
59 private WebOfTrustUpdateJob createWebOfTrustUpdateJob(final boolean success) {
60 return webOfTrustUpdater.new WebOfTrustUpdateJob() {
66 } catch (InterruptedException ie1) {
67 throw new RuntimeException(ie1);
75 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsSuccess() throws InterruptedException {
76 new Thread(successfulWebOfTrustUpdateJob).start();
77 assertThat(successfulWebOfTrustUpdateJob.waitForCompletion(), is(true));
81 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsFailure() throws InterruptedException {
82 new Thread(failingWebOfTrustUpdateJob).start();
83 assertThat(failingWebOfTrustUpdateJob.waitForCompletion(), is(false));
87 public void webOfTrustContextUpdateJobsAreEqualIfTheirClassOwnIdentityAndContextAreEqual() {
88 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
89 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(true));
90 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(true));
91 assertThat(contextUpdateJob.hashCode(), is(secondContextUpdateJob.hashCode()));
95 public void webOfTrustContextUpdatesJobsAreNotEqualIfTheirClassDiffers() {
96 assertThat(contextUpdateJob.equals(addContextJob), is(false));
100 public void webOfTrustContextUpdateJobToStringContainsIdentityAndContext() {
101 assertThat(contextUpdateJob.toString(), containsString(ownIdentity.toString()));
102 assertThat(contextUpdateJob.toString(), containsString(CONTEXT));
106 public void webOfTrustContextUpdateJobsAreNotEqualIfTheIdentitiesDiffer() {
107 OwnIdentity ownIdentity = mock(OwnIdentity.class);
108 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
109 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
110 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
114 public void webOfTrustContextUpdateJobsAreNotEqualIfTheirContextsDiffer() {
115 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT + CONTEXT);
116 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
117 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
121 public void webOfTrustContextUpdateJobsAreNotEqualToNull() {
122 assertThat(contextUpdateJob.equals(null), is(false));
126 public void addContextJobAddsTheContext() throws PluginException {
128 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
129 verify(ownIdentity).addContext(eq(CONTEXT));
130 assertThat(addContextJob.waitForCompletion(), is(true));
134 public void exceptionWhileAddingAContextIsExposed() throws PluginException {
135 doThrow(PluginException.class).when(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
137 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
138 verify(ownIdentity, never()).addContext(eq(CONTEXT));
139 assertThat(addContextJob.waitForCompletion(), is(false));
143 public void removeContextJobRemovesTheContext() throws PluginException {
144 removeContextJob.run();
145 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
146 verify(ownIdentity).removeContext(eq(CONTEXT));
147 assertThat(removeContextJob.waitForCompletion(), is(true));
151 public void exceptionWhileRemovingAContextIsExposed() throws PluginException {
152 doThrow(PluginException.class).when(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
153 removeContextJob.run();
154 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
155 verify(ownIdentity, never()).removeContext(eq(CONTEXT));
156 assertThat(removeContextJob.waitForCompletion(), is(false));
160 public void settingAPropertySetsTheProperty() throws PluginException {
161 String propertyName = "property-name";
162 String propertyValue = "property-value";
163 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
164 setPropertyJob.run();
165 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
166 verify(ownIdentity).setProperty(eq(propertyName), eq(propertyValue));
167 assertThat(setPropertyJob.waitForCompletion(), is(true));
171 public void settingAPropertyToNullRemovesTheProperty() throws PluginException {
172 String propertyName = "property-name";
173 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, null);
174 setPropertyJob.run();
175 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(propertyName));
176 verify(ownIdentity).removeProperty(eq(propertyName));
177 assertThat(setPropertyJob.waitForCompletion(), is(true));
181 public void pluginExceptionWhileSettingAPropertyIsHandled() throws PluginException {
182 String propertyName = "property-name";
183 String propertyValue = "property-value";
184 doThrow(PluginException.class).when(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
185 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
186 setPropertyJob.run();
187 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
188 verify(ownIdentity, never()).setProperty(eq(propertyName), eq(propertyValue));
189 assertThat(setPropertyJob.waitForCompletion(), is(false));
193 public void setPropertyJobsWithSameClassPropertyAndValueAreEqual() {
194 String propertyName = "property-name";
195 String propertyValue = "property-value";
196 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
197 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
198 assertThat(firstSetPropertyJob, is(secondSetPropertyJob));
199 assertThat(secondSetPropertyJob, is(firstSetPropertyJob));
200 assertThat(firstSetPropertyJob.hashCode(), is(secondSetPropertyJob.hashCode()));
204 public void setPropertyJobsWithDifferentClassesAreNotEqual() {
205 String propertyName = "property-name";
206 String propertyValue = "property-value";
207 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
208 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue) {
210 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
214 public void nullIsNotASetProjectJobEither() {
215 String propertyName = "property-name";
216 String propertyValue = "property-value";
217 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
218 assertThat(setPropertyJob, not(is((Object) null)));
222 public void setPropertyJobsWithDifferentPropertiesAreNotEqual() {
223 String propertyName = "property-name";
224 String propertyValue = "property-value";
225 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
226 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName + "2", propertyValue);
227 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
231 public void setPropertyJobsWithDifferentOwnIdentitiesAreNotEqual() {
232 OwnIdentity otherOwnIdentity = mock(OwnIdentity.class);
233 String propertyName = "property-name";
234 String propertyValue = "property-value";
235 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
236 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(otherOwnIdentity, propertyName, propertyValue);
237 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
241 public void setTrustJobSetsTrust() throws PluginException {
242 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
244 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
245 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
246 assertThat(setTrustJob.waitForCompletion(), is(true));
250 public void settingNullTrustRemovesTrust() throws WebOfTrustException {
251 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, null, TRUST_COMMENT);
253 verify(webOfTrustConnector).removeTrust(eq(ownIdentity), eq(trustee));
254 verify(trustee).removeTrust(eq(ownIdentity));
255 assertThat(setTrustJob.waitForCompletion(), is(true));
259 public void exceptionWhileSettingTrustIsCaught() throws PluginException {
260 doThrow(PluginException.class).when(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
261 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
263 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
264 verify(trustee, never()).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
265 assertThat(setTrustJob.waitForCompletion(), is(false));
269 public void setTrustJobsWithDifferentClassesAreNotEqual() {
270 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
271 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT) {
273 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
274 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
278 public void setTrustJobsWithDifferentTrustersAreNotEqual() {
279 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
280 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(mock(OwnIdentity.class), trustee, SCORE, TRUST_COMMENT);
281 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
282 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
286 public void setTrustJobsWithDifferentTrusteesAreNotEqual() {
287 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
288 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, mock(Identity.class), SCORE, TRUST_COMMENT);
289 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
290 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
294 public void setTrustJobsWithDifferentScoreAreEqual() {
295 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
296 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, OTHER_SCORE, TRUST_COMMENT);
297 assertThat(firstSetTrustJob, is(secondSetTrustJob));
298 assertThat(secondSetTrustJob, is(firstSetTrustJob));
299 assertThat(firstSetTrustJob.hashCode(), is(secondSetTrustJob.hashCode()));
303 public void setTrustJobDoesNotEqualNull() {
304 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
305 assertThat(setTrustJob, not(is((Object) null)));
309 public void toStringOfSetTrustJobContainsIdsOfTrusterAndTrustee() {
310 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
311 assertThat(setTrustJob.toString(), containsString(ownIdentity.getId()));
312 assertThat(setTrustJob.toString(), containsString(trustee.getId()));
316 public void webOfTrustUpdaterStopsWhenItShould() {
317 webOfTrustUpdater.stop();
318 webOfTrustUpdater.serviceRun();
322 public void webOfTrustUpdaterStopsAfterItWasStarted() {
323 webOfTrustUpdater.start();
324 webOfTrustUpdater.stop();
328 public void removePropertyRemovesProperty() throws InterruptedException, PluginException {
329 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
330 doAnswer(new Answer<Void>() {
332 public Void answer(InvocationOnMock invocation) throws Throwable {
333 wotCallTriggered.countDown();
336 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
337 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
338 webOfTrustUpdater.start();
339 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
343 public void multipleCallsToSetPropertyAreCollapsed() throws InterruptedException, PluginException {
344 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
345 doAnswer(new Answer<Void>() {
347 public Void answer(InvocationOnMock invocation) throws Throwable {
348 wotCallTriggered.countDown();
351 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
352 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
353 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
354 webOfTrustUpdater.start();
355 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
356 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
360 public void addContextWaitWaitsForTheContextToBeAdded() {
361 webOfTrustUpdater.start();
362 assertThat(webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT), is(true));
363 verify(ownIdentity).addContext(eq(CONTEXT));
367 public void multipleCallsToAddContextAreCollapsed() throws InterruptedException, PluginException {
368 final AtomicInteger errorCount = new AtomicInteger();
369 final CountDownLatch addContextsFinished = new CountDownLatch(2);
370 for (int i = 1; i <= 2; i++) {
371 /* this is so fucking volatile. */
375 new Thread(new Runnable() {
377 if (!webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT)) {
378 errorCount.incrementAndGet();
380 addContextsFinished.countDown();
384 webOfTrustUpdater.start();
385 assertThat(addContextsFinished.await(1, SECONDS), is(true));
386 verify(ownIdentity).addContext(eq(CONTEXT));
387 assertThat(errorCount.get(), is(0));
391 public void removeContextRemovesAContext() throws InterruptedException, PluginException {
392 webOfTrustUpdater.start();
393 final CountDownLatch removeContextTrigger = new CountDownLatch(1);
394 doAnswer(new Answer<Void>() {
396 public Void answer(InvocationOnMock invocation) throws Throwable {
397 removeContextTrigger.countDown();
400 }).when(ownIdentity).removeContext(eq(CONTEXT));
401 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
402 removeContextTrigger.await(1, SECONDS);
403 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
404 verify(ownIdentity).removeContext(eq(CONTEXT));
408 public void removeContextRequestsAreCoalesced() throws InterruptedException, PluginException {
409 final CountDownLatch contextRemovedTrigger = new CountDownLatch(1);
410 doAnswer(new Answer<Void>() {
412 public Void answer(InvocationOnMock invocation) throws Throwable {
413 contextRemovedTrigger.countDown();
416 }).when(ownIdentity).removeContext(eq(CONTEXT));
417 for (int i = 1; i <= 2; i++) {
418 /* this is so fucking volatile. */
422 new Thread(new Runnable() {
424 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
428 webOfTrustUpdater.start();
429 assertThat(contextRemovedTrigger.await(1, SECONDS), is(true));
430 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
431 verify(ownIdentity).removeContext(eq(CONTEXT));
435 public void setTrustSetsTrust() throws InterruptedException, PluginException {
436 final CountDownLatch trustSetTrigger =new CountDownLatch(1);
437 doAnswer(new Answer<Void>() {
439 public Void answer(InvocationOnMock invocation) throws Throwable {
440 trustSetTrigger.countDown();
443 }).when(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
444 webOfTrustUpdater.start();
445 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
446 assertThat(trustSetTrigger.await(1, SECONDS), is(true));
447 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
448 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
452 public void setTrustRequestsAreCoalesced() throws InterruptedException, PluginException {
453 final CountDownLatch trustSetTrigger = new CountDownLatch(1);
454 doAnswer(new Answer<Void>() {
456 public Void answer(InvocationOnMock invocation) throws Throwable {
457 trustSetTrigger.countDown();
460 }).when(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
461 for (int i = 1; i <= 2; i++) {
462 /* this is so fucking volatile. */
466 new Thread(new Runnable() {
468 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
472 webOfTrustUpdater.start();
473 assertThat(trustSetTrigger.await(1, SECONDS), is(true));
474 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
475 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));