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.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;
19 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.AddContextJob;
20 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.RemoveContextJob;
21 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.SetPropertyJob;
22 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.SetTrustJob;
23 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.WebOfTrustContextUpdateJob;
24 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.WebOfTrustUpdateJob;
25 import net.pterodactylus.sone.freenet.plugin.PluginException;
26 import net.pterodactylus.sone.freenet.wot.Identity;
27 import net.pterodactylus.sone.freenet.wot.OwnIdentity;
28 import net.pterodactylus.sone.freenet.wot.Trust;
29 import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
30 import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
32 import org.junit.Test;
33 import org.mockito.invocation.InvocationOnMock;
34 import org.mockito.stubbing.Answer;
37 * Unit test for {@link WebOfTrustUpdaterImpl} and its subclasses.
39 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
41 public class WebOfTrustUpdaterTest {
43 private static final String CONTEXT = "test-context";
44 private static final Integer SCORE = 50;
45 private static final Integer OTHER_SCORE = 25;
46 private static final String TRUST_COMMENT = "set in a test";
47 private static final String PROPERTY_NAME = "test-property";
48 private final WebOfTrustConnector webOfTrustConnector = mock(WebOfTrustConnector.class);
49 private final WebOfTrustUpdaterImpl webOfTrustUpdater = new WebOfTrustUpdaterImpl(webOfTrustConnector);
50 private final OwnIdentity ownIdentity = when(mock(OwnIdentity.class).getId()).thenReturn("own-identity-id").getMock();
51 private final WebOfTrustUpdateJob successfulWebOfTrustUpdateJob = createWebOfTrustUpdateJob(true);
52 private final WebOfTrustUpdateJob failingWebOfTrustUpdateJob = createWebOfTrustUpdateJob(false);
53 private final WebOfTrustContextUpdateJob contextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
54 private final AddContextJob addContextJob = webOfTrustUpdater.new AddContextJob(ownIdentity, CONTEXT);
55 private final RemoveContextJob removeContextJob = webOfTrustUpdater.new RemoveContextJob(ownIdentity, CONTEXT);
56 private final Identity trustee = when(mock(Identity.class).getId()).thenReturn("trustee-id").getMock();
58 private WebOfTrustUpdateJob createWebOfTrustUpdateJob(final boolean success) {
59 return webOfTrustUpdater.new WebOfTrustUpdateJob() {
65 } catch (InterruptedException ie1) {
66 throw new RuntimeException(ie1);
74 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsSuccess() throws InterruptedException {
75 new Thread(successfulWebOfTrustUpdateJob).start();
76 assertThat(successfulWebOfTrustUpdateJob.waitForCompletion(), is(true));
80 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsFailure() throws InterruptedException {
81 new Thread(failingWebOfTrustUpdateJob).start();
82 assertThat(failingWebOfTrustUpdateJob.waitForCompletion(), is(false));
86 public void webOfTrustContextUpdateJobsAreEqualIfTheirClassOwnIdentityAndContextAreEqual() {
87 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
88 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(true));
89 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(true));
90 assertThat(contextUpdateJob.hashCode(), is(secondContextUpdateJob.hashCode()));
94 public void webOfTrustContextUpdatesJobsAreNotEqualIfTheirClassDiffers() {
95 assertThat(contextUpdateJob.equals(addContextJob), is(false));
99 public void webOfTrustContextUpdateJobToStringContainsIdentityAndContext() {
100 assertThat(contextUpdateJob.toString(), containsString(ownIdentity.toString()));
101 assertThat(contextUpdateJob.toString(), containsString(CONTEXT));
105 public void webOfTrustContextUpdateJobsAreNotEqualIfTheIdentitiesDiffer() {
106 OwnIdentity ownIdentity = mock(OwnIdentity.class);
107 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
108 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
109 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
113 public void webOfTrustContextUpdateJobsAreNotEqualIfTheirContextsDiffer() {
114 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT + CONTEXT);
115 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
116 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
120 public void webOfTrustContextUpdateJobsAreNotEqualToNull() {
121 assertThat(contextUpdateJob.equals(null), is(false));
125 public void addContextJobAddsTheContext() throws PluginException {
127 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
128 verify(ownIdentity).addContext(eq(CONTEXT));
129 assertThat(addContextJob.waitForCompletion(), is(true));
133 public void exceptionWhileAddingAContextIsExposed() throws PluginException {
134 doThrow(PluginException.class).when(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
136 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
137 verify(ownIdentity, never()).addContext(eq(CONTEXT));
138 assertThat(addContextJob.waitForCompletion(), is(false));
142 public void removeContextJobRemovesTheContext() throws PluginException {
143 removeContextJob.run();
144 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
145 verify(ownIdentity).removeContext(eq(CONTEXT));
146 assertThat(removeContextJob.waitForCompletion(), is(true));
150 public void exceptionWhileRemovingAContextIsExposed() throws PluginException {
151 doThrow(PluginException.class).when(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
152 removeContextJob.run();
153 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
154 verify(ownIdentity, never()).removeContext(eq(CONTEXT));
155 assertThat(removeContextJob.waitForCompletion(), is(false));
159 public void settingAPropertySetsTheProperty() throws PluginException {
160 String propertyName = "property-name";
161 String propertyValue = "property-value";
162 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
163 setPropertyJob.run();
164 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
165 verify(ownIdentity).setProperty(eq(propertyName), eq(propertyValue));
166 assertThat(setPropertyJob.waitForCompletion(), is(true));
170 public void settingAPropertyToNullRemovesTheProperty() throws PluginException {
171 String propertyName = "property-name";
172 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, null);
173 setPropertyJob.run();
174 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(propertyName));
175 verify(ownIdentity).removeProperty(eq(propertyName));
176 assertThat(setPropertyJob.waitForCompletion(), is(true));
180 public void pluginExceptionWhileSettingAPropertyIsHandled() throws PluginException {
181 String propertyName = "property-name";
182 String propertyValue = "property-value";
183 doThrow(PluginException.class).when(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
184 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
185 setPropertyJob.run();
186 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
187 verify(ownIdentity, never()).setProperty(eq(propertyName), eq(propertyValue));
188 assertThat(setPropertyJob.waitForCompletion(), is(false));
192 public void setPropertyJobsWithSameClassPropertyAndValueAreEqual() {
193 String propertyName = "property-name";
194 String propertyValue = "property-value";
195 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
196 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
197 assertThat(firstSetPropertyJob, is(secondSetPropertyJob));
198 assertThat(secondSetPropertyJob, is(firstSetPropertyJob));
199 assertThat(firstSetPropertyJob.hashCode(), is(secondSetPropertyJob.hashCode()));
203 public void setPropertyJobsWithDifferentClassesAreNotEqual() {
204 String propertyName = "property-name";
205 String propertyValue = "property-value";
206 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
207 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue) {
209 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
213 public void nullIsNotASetProjectJobEither() {
214 String propertyName = "property-name";
215 String propertyValue = "property-value";
216 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
217 assertThat(setPropertyJob, not(is((Object) null)));
221 public void setPropertyJobsWithDifferentPropertiesAreNotEqual() {
222 String propertyName = "property-name";
223 String propertyValue = "property-value";
224 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
225 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName + "2", propertyValue);
226 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
230 public void setPropertyJobsWithDifferentOwnIdentitiesAreNotEqual() {
231 OwnIdentity otherOwnIdentity = mock(OwnIdentity.class);
232 String propertyName = "property-name";
233 String propertyValue = "property-value";
234 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
235 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(otherOwnIdentity, propertyName, propertyValue);
236 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
240 public void setTrustJobSetsTrust() throws PluginException {
241 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
243 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
244 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
245 assertThat(setTrustJob.waitForCompletion(), is(true));
249 public void settingNullTrustRemovesTrust() throws WebOfTrustException {
250 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, null, TRUST_COMMENT);
252 verify(webOfTrustConnector).removeTrust(eq(ownIdentity), eq(trustee));
253 verify(trustee).removeTrust(eq(ownIdentity));
254 assertThat(setTrustJob.waitForCompletion(), is(true));
258 public void exceptionWhileSettingTrustIsCaught() throws PluginException {
259 doThrow(PluginException.class).when(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
260 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
262 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
263 verify(trustee, never()).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
264 assertThat(setTrustJob.waitForCompletion(), is(false));
268 public void setTrustJobsWithDifferentClassesAreNotEqual() {
269 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
270 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT) {
272 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
273 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
277 public void setTrustJobsWithDifferentTrustersAreNotEqual() {
278 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
279 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(mock(OwnIdentity.class), trustee, SCORE, TRUST_COMMENT);
280 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
281 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
285 public void setTrustJobsWithDifferentTrusteesAreNotEqual() {
286 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
287 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, mock(Identity.class), SCORE, TRUST_COMMENT);
288 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
289 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
293 public void setTrustJobsWithDifferentScoreAreEqual() {
294 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
295 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, OTHER_SCORE, TRUST_COMMENT);
296 assertThat(firstSetTrustJob, is(secondSetTrustJob));
297 assertThat(secondSetTrustJob, is(firstSetTrustJob));
298 assertThat(firstSetTrustJob.hashCode(), is(secondSetTrustJob.hashCode()));
302 public void setTrustJobDoesNotEqualNull() {
303 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
304 assertThat(setTrustJob, not(is((Object) null)));
308 public void toStringOfSetTrustJobContainsIdsOfTrusterAndTrustee() {
309 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
310 assertThat(setTrustJob.toString(), containsString(ownIdentity.getId()));
311 assertThat(setTrustJob.toString(), containsString(trustee.getId()));
315 public void webOfTrustUpdaterStopsWhenItShould() {
316 webOfTrustUpdater.stop();
317 webOfTrustUpdater.serviceRun();
321 public void webOfTrustUpdaterStopsAfterItWasStarted() {
322 webOfTrustUpdater.start();
323 webOfTrustUpdater.stop();
327 public void removePropertyRemovesProperty() throws InterruptedException, PluginException {
328 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
329 doAnswer(new Answer<Void>() {
331 public Void answer(InvocationOnMock invocation) throws Throwable {
332 wotCallTriggered.countDown();
335 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
336 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
337 webOfTrustUpdater.start();
338 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
342 public void multipleCallsToSetPropertyAreCollapsed() throws InterruptedException, PluginException {
343 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
344 doAnswer(new Answer<Void>() {
346 public Void answer(InvocationOnMock invocation) throws Throwable {
347 wotCallTriggered.countDown();
350 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
351 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
352 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
353 webOfTrustUpdater.start();
354 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
355 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
359 public void addContextWaitWaitsForTheContextToBeAdded() {
360 webOfTrustUpdater.start();
361 assertThat(webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT), is(true));
362 verify(ownIdentity).addContext(eq(CONTEXT));
366 public void removeContextRemovesAContext() throws InterruptedException, PluginException {
367 webOfTrustUpdater.start();
368 final CountDownLatch removeContextTrigger = new CountDownLatch(1);
369 doAnswer(new Answer<Void>() {
371 public Void answer(InvocationOnMock invocation) throws Throwable {
372 removeContextTrigger.countDown();
375 }).when(ownIdentity).removeContext(eq(CONTEXT));
376 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
377 removeContextTrigger.await(1, SECONDS);
378 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
379 verify(ownIdentity).removeContext(eq(CONTEXT));
383 public void removeContextRequestsAreCoalesced() throws InterruptedException, PluginException {
384 final CountDownLatch contextRemovedTrigger = new CountDownLatch(1);
385 doAnswer(new Answer<Void>() {
387 public Void answer(InvocationOnMock invocation) throws Throwable {
388 contextRemovedTrigger.countDown();
391 }).when(ownIdentity).removeContext(eq(CONTEXT));
392 for (int i = 1; i <= 2; i++) {
393 /* this is so fucking volatile. */
397 new Thread(new Runnable() {
399 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
403 webOfTrustUpdater.start();
404 assertThat(contextRemovedTrigger.await(1, SECONDS), is(true));
405 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
406 verify(ownIdentity).removeContext(eq(CONTEXT));
410 public void setTrustSetsTrust() throws InterruptedException, PluginException {
411 final CountDownLatch trustSetTrigger = new CountDownLatch(1);
412 doAnswer(new Answer<Void>() {
414 public Void answer(InvocationOnMock invocation) throws Throwable {
415 trustSetTrigger.countDown();
418 }).when(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
419 webOfTrustUpdater.start();
420 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
421 assertThat(trustSetTrigger.await(1, SECONDS), is(true));
422 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
423 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
427 public void setTrustRequestsAreCoalesced() throws InterruptedException, PluginException {
428 final CountDownLatch trustSetTrigger = new CountDownLatch(1);
429 doAnswer(new Answer<Void>() {
431 public Void answer(InvocationOnMock invocation) throws Throwable {
432 trustSetTrigger.countDown();
435 }).when(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
436 for (int i = 1; i <= 2; i++) {
437 /* this is so fucking volatile. */
441 new Thread(new Runnable() {
443 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
447 webOfTrustUpdater.start();
448 assertThat(trustSetTrigger.await(1, SECONDS), is(true));
449 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
450 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));