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.times;
15 import static org.mockito.Mockito.verify;
16 import static org.mockito.Mockito.when;
18 import java.util.concurrent.CountDownLatch;
19 import java.util.concurrent.atomic.AtomicInteger;
21 import net.pterodactylus.sone.core.WebOfTrustUpdater.AddContextJob;
22 import net.pterodactylus.sone.core.WebOfTrustUpdater.RemoveContextJob;
23 import net.pterodactylus.sone.core.WebOfTrustUpdater.SetPropertyJob;
24 import net.pterodactylus.sone.core.WebOfTrustUpdater.SetTrustJob;
25 import net.pterodactylus.sone.core.WebOfTrustUpdater.WebOfTrustContextUpdateJob;
26 import net.pterodactylus.sone.core.WebOfTrustUpdater.WebOfTrustUpdateJob;
27 import net.pterodactylus.sone.freenet.plugin.PluginException;
28 import net.pterodactylus.sone.freenet.wot.Identity;
29 import net.pterodactylus.sone.freenet.wot.OwnIdentity;
30 import net.pterodactylus.sone.freenet.wot.Trust;
31 import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
32 import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
34 import org.junit.Test;
35 import org.mockito.invocation.InvocationOnMock;
36 import org.mockito.stubbing.Answer;
39 * Unit test for {@link WebOfTrustUpdater} and its subclasses.
41 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
43 public class WebOfTrustUpdaterTest {
45 private static final String CONTEXT = "test-context";
46 private static final Integer SCORE = 50;
47 private static final Integer OTHER_SCORE = 25;
48 private static final String TRUST_COMMENT = "set in a test";
49 private static final String PROPERTY_NAME = "test-property";
50 private final WebOfTrustConnector webOfTrustConnector = mock(WebOfTrustConnector.class);
51 private final WebOfTrustUpdater webOfTrustUpdater = new WebOfTrustUpdater(webOfTrustConnector);
52 private final OwnIdentity ownIdentity = when(mock(OwnIdentity.class).getId()).thenReturn("own-identity-id").getMock();
53 private final WebOfTrustUpdateJob successfulWebOfTrustUpdateJob = createWebOfTrustUpdateJob(true);
54 private final WebOfTrustUpdateJob failingWebOfTrustUpdateJob = createWebOfTrustUpdateJob(false);
55 private final WebOfTrustContextUpdateJob contextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
56 private final AddContextJob addContextJob = webOfTrustUpdater.new AddContextJob(ownIdentity, CONTEXT);
57 private final RemoveContextJob removeContextJob = webOfTrustUpdater.new RemoveContextJob(ownIdentity, CONTEXT);
58 private final Identity trustee = when(mock(Identity.class).getId()).thenReturn("trustee-id").getMock();
60 private WebOfTrustUpdateJob createWebOfTrustUpdateJob(final boolean success) {
61 return webOfTrustUpdater.new WebOfTrustUpdateJob() {
67 } catch (InterruptedException ie1) {
68 throw new RuntimeException(ie1);
76 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsSuccess() throws InterruptedException {
77 new Thread(successfulWebOfTrustUpdateJob).start();
78 assertThat(successfulWebOfTrustUpdateJob.waitForCompletion(), is(true));
82 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsFailure() throws InterruptedException {
83 new Thread(failingWebOfTrustUpdateJob).start();
84 assertThat(failingWebOfTrustUpdateJob.waitForCompletion(), is(false));
88 public void webOfTrustContextUpdateJobsAreEqualIfTheirClassOwnIdentityAndContextAreEqual() {
89 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
90 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(true));
91 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(true));
92 assertThat(contextUpdateJob.hashCode(), is(secondContextUpdateJob.hashCode()));
96 public void webOfTrustContextUpdatesJobsAreNotEqualIfTheirClassDiffers() {
97 assertThat(contextUpdateJob.equals(addContextJob), is(false));
101 public void webOfTrustContextUpdateJobToStringContainsIdentityAndContext() {
102 assertThat(contextUpdateJob.toString(), containsString(ownIdentity.toString()));
103 assertThat(contextUpdateJob.toString(), containsString(CONTEXT));
107 public void webOfTrustContextUpdateJobsAreNotEqualIfTheIdentitiesDiffer() {
108 OwnIdentity ownIdentity = mock(OwnIdentity.class);
109 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
110 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
111 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
115 public void webOfTrustContextUpdateJobsAreNotEqualIfTheirContextsDiffer() {
116 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT + CONTEXT);
117 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
118 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
122 public void webOfTrustContextUpdateJobsAreNotEqualToNull() {
123 assertThat(contextUpdateJob.equals(null), is(false));
127 public void addContextJobAddsTheContext() throws PluginException {
129 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
130 verify(ownIdentity).addContext(eq(CONTEXT));
131 assertThat(addContextJob.waitForCompletion(), is(true));
135 public void exceptionWhileAddingAContextIsExposed() throws PluginException {
136 doThrow(PluginException.class).when(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
138 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
139 verify(ownIdentity, never()).addContext(eq(CONTEXT));
140 assertThat(addContextJob.waitForCompletion(), is(false));
144 public void removeContextJobRemovesTheContext() throws PluginException {
145 removeContextJob.run();
146 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
147 verify(ownIdentity).removeContext(eq(CONTEXT));
148 assertThat(removeContextJob.waitForCompletion(), is(true));
152 public void exceptionWhileRemovingAContextIsExposed() throws PluginException {
153 doThrow(PluginException.class).when(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
154 removeContextJob.run();
155 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
156 verify(ownIdentity, never()).removeContext(eq(CONTEXT));
157 assertThat(removeContextJob.waitForCompletion(), is(false));
161 public void settingAPropertySetsTheProperty() throws PluginException {
162 String propertyName = "property-name";
163 String propertyValue = "property-value";
164 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
165 setPropertyJob.run();
166 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
167 verify(ownIdentity).setProperty(eq(propertyName), eq(propertyValue));
168 assertThat(setPropertyJob.waitForCompletion(), is(true));
172 public void settingAPropertyToNullRemovesTheProperty() throws PluginException {
173 String propertyName = "property-name";
174 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, null);
175 setPropertyJob.run();
176 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(propertyName));
177 verify(ownIdentity).removeProperty(eq(propertyName));
178 assertThat(setPropertyJob.waitForCompletion(), is(true));
182 public void pluginExceptionWhileSettingAPropertyIsHandled() throws PluginException {
183 String propertyName = "property-name";
184 String propertyValue = "property-value";
185 doThrow(PluginException.class).when(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
186 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
187 setPropertyJob.run();
188 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
189 verify(ownIdentity, never()).setProperty(eq(propertyName), eq(propertyValue));
190 assertThat(setPropertyJob.waitForCompletion(), is(false));
194 public void setPropertyJobsWithSameClassPropertyAndValueAreEqual() {
195 String propertyName = "property-name";
196 String propertyValue = "property-value";
197 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
198 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
199 assertThat(firstSetPropertyJob, is(secondSetPropertyJob));
200 assertThat(secondSetPropertyJob, is(firstSetPropertyJob));
201 assertThat(firstSetPropertyJob.hashCode(), is(secondSetPropertyJob.hashCode()));
205 public void setPropertyJobsWithDifferentClassesAreNotEqual() {
206 String propertyName = "property-name";
207 String propertyValue = "property-value";
208 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
209 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue) {
211 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
215 public void nullIsNotASetProjectJobEither() {
216 String propertyName = "property-name";
217 String propertyValue = "property-value";
218 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
219 assertThat(setPropertyJob, not(is((Object) null)));
223 public void setPropertyJobsWithDifferentPropertiesAreNotEqual() {
224 String propertyName = "property-name";
225 String propertyValue = "property-value";
226 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
227 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName + "2", propertyValue);
228 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
232 public void setPropertyJobsWithDifferentOwnIdentitiesAreNotEqual() {
233 OwnIdentity otherOwnIdentity = mock(OwnIdentity.class);
234 String propertyName = "property-name";
235 String propertyValue = "property-value";
236 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
237 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(otherOwnIdentity, propertyName, propertyValue);
238 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
242 public void setTrustJobSetsTrust() throws PluginException {
243 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
245 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
246 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
247 assertThat(setTrustJob.waitForCompletion(), is(true));
251 public void settingNullTrustRemovesTrust() throws WebOfTrustException {
252 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, null, TRUST_COMMENT);
254 verify(webOfTrustConnector).removeTrust(eq(ownIdentity), eq(trustee));
255 verify(trustee).removeTrust(eq(ownIdentity));
256 assertThat(setTrustJob.waitForCompletion(), is(true));
260 public void exceptionWhileSettingTrustIsCaught() throws PluginException {
261 doThrow(PluginException.class).when(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
262 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
264 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
265 verify(trustee, never()).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
266 assertThat(setTrustJob.waitForCompletion(), is(false));
270 public void setTrustJobsWithDifferentClassesAreNotEqual() {
271 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
272 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT) {
274 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
275 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
279 public void setTrustJobsWithDifferentTrustersAreNotEqual() {
280 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
281 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(mock(OwnIdentity.class), trustee, SCORE, TRUST_COMMENT);
282 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
283 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
287 public void setTrustJobsWithDifferentTrusteesAreNotEqual() {
288 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
289 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, mock(Identity.class), SCORE, TRUST_COMMENT);
290 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
291 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
295 public void setTrustJobsWithDifferentScoreAreEqual() {
296 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
297 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, OTHER_SCORE, TRUST_COMMENT);
298 assertThat(firstSetTrustJob, is(secondSetTrustJob));
299 assertThat(secondSetTrustJob, is(firstSetTrustJob));
300 assertThat(firstSetTrustJob.hashCode(), is(secondSetTrustJob.hashCode()));
304 public void setTrustJobDoesNotEqualNull() {
305 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
306 assertThat(setTrustJob, not(is((Object) null)));
310 public void toStringOfSetTrustJobContainsIdsOfTrusterAndTrustee() {
311 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
312 assertThat(setTrustJob.toString(), containsString(ownIdentity.getId()));
313 assertThat(setTrustJob.toString(), containsString(trustee.getId()));
317 public void webOfTrustUpdaterStopsWhenItShould() {
318 webOfTrustUpdater.stop();
319 webOfTrustUpdater.serviceRun();
323 public void webOfTrustUpdaterStopsAfterItWasStarted() {
324 webOfTrustUpdater.start();
325 webOfTrustUpdater.stop();
329 public void removePropertyRemovesProperty() throws InterruptedException, PluginException {
330 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
331 doAnswer(new Answer<Void>() {
333 public Void answer(InvocationOnMock invocation) throws Throwable {
334 wotCallTriggered.countDown();
337 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
338 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
339 webOfTrustUpdater.start();
340 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
344 public void multipleCallsToSetPropertyAreCollapsed() throws InterruptedException, PluginException {
345 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
346 doAnswer(new Answer<Void>() {
348 public Void answer(InvocationOnMock invocation) throws Throwable {
349 wotCallTriggered.countDown();
352 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
353 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
354 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
355 webOfTrustUpdater.start();
356 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
357 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
361 public void addContextWaitWaitsForTheContextToBeAdded() {
362 webOfTrustUpdater.start();
363 assertThat(webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT), is(true));
364 verify(ownIdentity).addContext(eq(CONTEXT));
368 public void multipleCallsToAddContextAreCollapsed() throws InterruptedException, PluginException {
369 final AtomicInteger errorCount = new AtomicInteger();
370 final CountDownLatch addContextsFinished = new CountDownLatch(2);
371 for (int i = 1; i <= 2; i++) {
372 /* this is so fucking volatile. */
376 new Thread(new Runnable() {
378 if (!webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT)) {
379 errorCount.incrementAndGet();
381 addContextsFinished.countDown();
385 webOfTrustUpdater.start();
386 assertThat(addContextsFinished.await(1, SECONDS), is(true));
387 verify(ownIdentity).addContext(eq(CONTEXT));
388 assertThat(errorCount.get(), is(0));
392 public void removeContextRemovesAContext() throws InterruptedException, PluginException {
393 webOfTrustUpdater.start();
394 final CountDownLatch removeContextTrigger = new CountDownLatch(1);
395 doAnswer(new Answer<Void>() {
397 public Void answer(InvocationOnMock invocation) throws Throwable {
398 removeContextTrigger.countDown();
401 }).when(ownIdentity).removeContext(eq(CONTEXT));
402 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
403 removeContextTrigger.await(1, SECONDS);
404 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
405 verify(ownIdentity).removeContext(eq(CONTEXT));
409 public void removeContextRequestsAreCoalesced() throws InterruptedException, PluginException {
410 final CountDownLatch contextRemovedTrigger = new CountDownLatch(1);
411 doAnswer(new Answer<Void>() {
413 public Void answer(InvocationOnMock invocation) throws Throwable {
414 contextRemovedTrigger.countDown();
417 }).when(ownIdentity).removeContext(eq(CONTEXT));
418 for (int i = 1; i <= 2; i++) {
419 /* this is so fucking volatile. */
423 new Thread(new Runnable() {
425 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
429 webOfTrustUpdater.start();
430 assertThat(contextRemovedTrigger.await(1, SECONDS), is(true));
431 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
432 verify(ownIdentity).removeContext(eq(CONTEXT));
436 public void setTrustSetsTrust() throws InterruptedException, PluginException {
437 final CountDownLatch trustSetTrigger =new CountDownLatch(1);
438 doAnswer(new Answer<Void>() {
440 public Void answer(InvocationOnMock invocation) throws Throwable {
441 trustSetTrigger.countDown();
444 }).when(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
445 webOfTrustUpdater.start();
446 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
447 assertThat(trustSetTrigger.await(1, SECONDS), is(true));
448 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
449 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
453 public void setTrustRequestsAreCoalesced() throws InterruptedException, PluginException {
454 final CountDownLatch trustSetTrigger = new CountDownLatch(1);
455 doAnswer(new Answer<Void>() {
457 public Void answer(InvocationOnMock invocation) throws Throwable {
458 trustSetTrigger.countDown();
461 }).when(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
462 for (int i = 1; i <= 2; i++) {
463 /* this is so fucking volatile. */
467 new Thread(new Runnable() {
469 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
473 webOfTrustUpdater.start();
474 assertThat(trustSetTrigger.await(1, SECONDS), is(true));
475 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
476 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));