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.SetTrustJob;
18 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.WebOfTrustContextUpdateJob;
19 import net.pterodactylus.sone.core.WebOfTrustUpdaterImpl.WebOfTrustUpdateJob;
20 import net.pterodactylus.sone.freenet.plugin.PluginException;
21 import net.pterodactylus.sone.freenet.wot.Identity;
22 import net.pterodactylus.sone.freenet.wot.OwnIdentity;
23 import net.pterodactylus.sone.freenet.wot.Trust;
24 import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
25 import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
27 import org.junit.Test;
28 import org.mockito.invocation.InvocationOnMock;
29 import org.mockito.stubbing.Answer;
32 * Unit test for {@link WebOfTrustUpdaterImpl} and its subclasses.
34 public class WebOfTrustUpdaterTest {
36 private static final String CONTEXT = "test-context";
37 private static final Integer SCORE = 50;
38 private static final Integer OTHER_SCORE = 25;
39 private static final String TRUST_COMMENT = "set in a test";
40 private static final String PROPERTY_NAME = "test-property";
41 private final WebOfTrustConnector webOfTrustConnector = mock(WebOfTrustConnector.class);
42 private final WebOfTrustUpdaterImpl webOfTrustUpdater = new WebOfTrustUpdaterImpl(webOfTrustConnector);
43 private final OwnIdentity ownIdentity = when(mock(OwnIdentity.class).getId()).thenReturn("own-identity-id").getMock();
44 private final WebOfTrustUpdateJob successfulWebOfTrustUpdateJob = createWebOfTrustUpdateJob(true);
45 private final WebOfTrustUpdateJob failingWebOfTrustUpdateJob = createWebOfTrustUpdateJob(false);
46 private final WebOfTrustContextUpdateJob contextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
47 private final AddContextJob addContextJob = webOfTrustUpdater.new AddContextJob(ownIdentity, CONTEXT);
48 private final RemoveContextJob removeContextJob = webOfTrustUpdater.new RemoveContextJob(ownIdentity, CONTEXT);
49 private final Identity trustee = when(mock(Identity.class).getId()).thenReturn("trustee-id").getMock();
51 private WebOfTrustUpdateJob createWebOfTrustUpdateJob(final boolean success) {
52 return webOfTrustUpdater.new WebOfTrustUpdateJob() {
58 } catch (InterruptedException ie1) {
59 throw new RuntimeException(ie1);
67 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsSuccess() throws InterruptedException {
68 new Thread(successfulWebOfTrustUpdateJob).start();
69 assertThat(successfulWebOfTrustUpdateJob.waitForCompletion(), is(true));
73 public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsFailure() throws InterruptedException {
74 new Thread(failingWebOfTrustUpdateJob).start();
75 assertThat(failingWebOfTrustUpdateJob.waitForCompletion(), is(false));
79 public void webOfTrustContextUpdateJobsAreEqualIfTheirClassOwnIdentityAndContextAreEqual() {
80 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
81 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(true));
82 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(true));
83 assertThat(contextUpdateJob.hashCode(), is(secondContextUpdateJob.hashCode()));
87 public void webOfTrustContextUpdatesJobsAreNotEqualIfTheirClassDiffers() {
88 assertThat(contextUpdateJob.equals(addContextJob), is(false));
92 public void webOfTrustContextUpdateJobToStringContainsIdentityAndContext() {
93 assertThat(contextUpdateJob.toString(), containsString(ownIdentity.toString()));
94 assertThat(contextUpdateJob.toString(), containsString(CONTEXT));
98 public void webOfTrustContextUpdateJobsAreNotEqualIfTheIdentitiesDiffer() {
99 OwnIdentity ownIdentity = mock(OwnIdentity.class);
100 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT);
101 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
102 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
106 public void webOfTrustContextUpdateJobsAreNotEqualIfTheirContextsDiffer() {
107 WebOfTrustContextUpdateJob secondContextUpdateJob = webOfTrustUpdater.new WebOfTrustContextUpdateJob(ownIdentity, CONTEXT + CONTEXT);
108 assertThat(contextUpdateJob.equals(secondContextUpdateJob), is(false));
109 assertThat(secondContextUpdateJob.equals(contextUpdateJob), is(false));
113 public void webOfTrustContextUpdateJobsAreNotEqualToNull() {
114 assertThat(contextUpdateJob.equals(null), is(false));
118 public void addContextJobAddsTheContext() throws PluginException {
120 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
121 verify(ownIdentity).addContext(eq(CONTEXT));
122 assertThat(addContextJob.waitForCompletion(), is(true));
126 public void exceptionWhileAddingAContextIsExposed() throws PluginException {
127 doThrow(PluginException.class).when(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
129 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
130 verify(ownIdentity, never()).addContext(eq(CONTEXT));
131 assertThat(addContextJob.waitForCompletion(), is(false));
135 public void removeContextJobRemovesTheContext() throws PluginException {
136 removeContextJob.run();
137 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
138 verify(ownIdentity).removeContext(eq(CONTEXT));
139 assertThat(removeContextJob.waitForCompletion(), is(true));
143 public void exceptionWhileRemovingAContextIsExposed() throws PluginException {
144 doThrow(PluginException.class).when(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
145 removeContextJob.run();
146 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
147 verify(ownIdentity, never()).removeContext(eq(CONTEXT));
148 assertThat(removeContextJob.waitForCompletion(), is(false));
152 public void settingAPropertySetsTheProperty() throws PluginException {
153 String propertyName = "property-name";
154 String propertyValue = "property-value";
155 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
156 setPropertyJob.run();
157 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
158 verify(ownIdentity).setProperty(eq(propertyName), eq(propertyValue));
159 assertThat(setPropertyJob.waitForCompletion(), is(true));
163 public void settingAPropertyToNullRemovesTheProperty() throws PluginException {
164 String propertyName = "property-name";
165 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, null);
166 setPropertyJob.run();
167 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(propertyName));
168 verify(ownIdentity).removeProperty(eq(propertyName));
169 assertThat(setPropertyJob.waitForCompletion(), is(true));
173 public void pluginExceptionWhileSettingAPropertyIsHandled() throws PluginException {
174 String propertyName = "property-name";
175 String propertyValue = "property-value";
176 doThrow(PluginException.class).when(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
177 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
178 setPropertyJob.run();
179 verify(webOfTrustConnector).setProperty(eq(ownIdentity), eq(propertyName), eq(propertyValue));
180 verify(ownIdentity, never()).setProperty(eq(propertyName), eq(propertyValue));
181 assertThat(setPropertyJob.waitForCompletion(), is(false));
185 public void setPropertyJobsWithSameClassPropertyAndValueAreEqual() {
186 String propertyName = "property-name";
187 String propertyValue = "property-value";
188 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
189 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
190 assertThat(firstSetPropertyJob, is(secondSetPropertyJob));
191 assertThat(secondSetPropertyJob, is(firstSetPropertyJob));
192 assertThat(firstSetPropertyJob.hashCode(), is(secondSetPropertyJob.hashCode()));
196 public void setPropertyJobsWithDifferentClassesAreNotEqual() {
197 String propertyName = "property-name";
198 String propertyValue = "property-value";
199 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
200 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue) {
202 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
206 public void nullIsNotASetProjectJobEither() {
207 String propertyName = "property-name";
208 String propertyValue = "property-value";
209 SetPropertyJob setPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
210 assertThat(setPropertyJob, not(is((Object) null)));
214 public void setPropertyJobsWithDifferentPropertiesAreNotEqual() {
215 String propertyName = "property-name";
216 String propertyValue = "property-value";
217 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
218 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName + "2", propertyValue);
219 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
223 public void setPropertyJobsWithDifferentOwnIdentitiesAreNotEqual() {
224 OwnIdentity otherOwnIdentity = mock(OwnIdentity.class);
225 String propertyName = "property-name";
226 String propertyValue = "property-value";
227 SetPropertyJob firstSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(ownIdentity, propertyName, propertyValue);
228 SetPropertyJob secondSetPropertyJob = webOfTrustUpdater.new SetPropertyJob(otherOwnIdentity, propertyName, propertyValue);
229 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
233 public void setTrustJobSetsTrust() throws PluginException {
234 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
236 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
237 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
238 assertThat(setTrustJob.waitForCompletion(), is(true));
242 public void settingNullTrustRemovesTrust() throws WebOfTrustException {
243 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, null, TRUST_COMMENT);
245 verify(webOfTrustConnector).removeTrust(eq(ownIdentity), eq(trustee));
246 verify(trustee).removeTrust(eq(ownIdentity));
247 assertThat(setTrustJob.waitForCompletion(), is(true));
251 public void exceptionWhileSettingTrustIsCaught() throws PluginException {
252 doThrow(PluginException.class).when(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
253 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
255 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
256 verify(trustee, never()).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
257 assertThat(setTrustJob.waitForCompletion(), is(false));
261 public void setTrustJobsWithDifferentClassesAreNotEqual() {
262 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
263 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT) {
265 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
266 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
270 public void setTrustJobsWithDifferentTrustersAreNotEqual() {
271 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
272 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(mock(OwnIdentity.class), trustee, SCORE, TRUST_COMMENT);
273 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
274 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
278 public void setTrustJobsWithDifferentTrusteesAreNotEqual() {
279 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
280 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, mock(Identity.class), SCORE, TRUST_COMMENT);
281 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
282 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
286 public void setTrustJobsWithDifferentScoreAreEqual() {
287 SetTrustJob firstSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
288 SetTrustJob secondSetTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, OTHER_SCORE, TRUST_COMMENT);
289 assertThat(firstSetTrustJob, is(secondSetTrustJob));
290 assertThat(secondSetTrustJob, is(firstSetTrustJob));
291 assertThat(firstSetTrustJob.hashCode(), is(secondSetTrustJob.hashCode()));
295 public void setTrustJobDoesNotEqualNull() {
296 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
297 assertThat(setTrustJob, not(is((Object) null)));
301 public void toStringOfSetTrustJobContainsIdsOfTrusterAndTrustee() {
302 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
303 assertThat(setTrustJob.toString(), containsString(ownIdentity.getId()));
304 assertThat(setTrustJob.toString(), containsString(trustee.getId()));
308 public void webOfTrustUpdaterStopsWhenItShould() {
309 webOfTrustUpdater.stop();
310 webOfTrustUpdater.serviceRun();
314 public void webOfTrustUpdaterStopsAfterItWasStarted() {
315 webOfTrustUpdater.start();
316 webOfTrustUpdater.stop();
320 public void removePropertyRemovesProperty() throws InterruptedException, PluginException {
321 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
322 doAnswer(new Answer<Void>() {
324 public Void answer(InvocationOnMock invocation) throws Throwable {
325 wotCallTriggered.countDown();
328 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
329 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
330 webOfTrustUpdater.start();
331 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
335 public void multipleCallsToSetPropertyAreCollapsed() throws InterruptedException, PluginException {
336 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
337 doAnswer(new Answer<Void>() {
339 public Void answer(InvocationOnMock invocation) throws Throwable {
340 wotCallTriggered.countDown();
343 }).when(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
344 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
345 webOfTrustUpdater.removeProperty(ownIdentity, PROPERTY_NAME);
346 webOfTrustUpdater.start();
347 assertThat(wotCallTriggered.await(1, SECONDS), is(true));
348 verify(webOfTrustConnector).removeProperty(eq(ownIdentity), eq(PROPERTY_NAME));
352 public void addContextWaitWaitsForTheContextToBeAdded() {
353 webOfTrustUpdater.start();
354 assertThat(webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT), is(true));
355 verify(ownIdentity).addContext(eq(CONTEXT));
359 public void removeContextRemovesAContext() throws InterruptedException, PluginException {
360 webOfTrustUpdater.start();
361 final CountDownLatch removeContextTrigger = new CountDownLatch(1);
362 doAnswer(new Answer<Void>() {
364 public Void answer(InvocationOnMock invocation) throws Throwable {
365 removeContextTrigger.countDown();
368 }).when(ownIdentity).removeContext(eq(CONTEXT));
369 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
370 removeContextTrigger.await(1, SECONDS);
371 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
372 verify(ownIdentity).removeContext(eq(CONTEXT));
376 public void removeContextRequestsAreCoalesced() throws InterruptedException, PluginException {
377 final CountDownLatch contextRemovedTrigger = new CountDownLatch(1);
378 doAnswer(new Answer<Void>() {
380 public Void answer(InvocationOnMock invocation) throws Throwable {
381 contextRemovedTrigger.countDown();
384 }).when(ownIdentity).removeContext(eq(CONTEXT));
385 for (int i = 1; i <= 2; i++) {
386 /* this is so fucking volatile. */
390 new Thread(new Runnable() {
392 webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
396 webOfTrustUpdater.start();
397 assertThat(contextRemovedTrigger.await(1, SECONDS), is(true));
398 verify(webOfTrustConnector).removeContext(eq(ownIdentity), eq(CONTEXT));
399 verify(ownIdentity).removeContext(eq(CONTEXT));
403 public void setTrustSetsTrust() throws InterruptedException, PluginException {
404 final CountDownLatch trustSetTrigger = new CountDownLatch(1);
405 doAnswer(new Answer<Void>() {
407 public Void answer(InvocationOnMock invocation) throws Throwable {
408 trustSetTrigger.countDown();
411 }).when(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
412 webOfTrustUpdater.start();
413 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
414 assertThat(trustSetTrigger.await(1, SECONDS), is(true));
415 verify(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
416 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));
420 public void setTrustRequestsAreCoalesced() throws InterruptedException, PluginException {
421 final CountDownLatch firstTrigger = new CountDownLatch(1);
422 doAnswer((Answer<Void>) invocation -> {
423 firstTrigger.countDown();
425 }).when(trustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
426 Identity secondTrustee = when(mock(Identity.class).getId()).thenReturn("trustee-id2").getMock();
427 final CountDownLatch secondTrigger = new CountDownLatch(1);
428 doAnswer((Answer<Void>) invocation -> {
429 secondTrigger.countDown();
431 }).when(secondTrustee).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
432 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
433 webOfTrustUpdater.setTrust(ownIdentity, secondTrustee, SCORE, TRUST_COMMENT);
434 webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
435 webOfTrustUpdater.start();
436 assertThat(firstTrigger.await(1, SECONDS), is(true));
437 assertThat(secondTrigger.await(1, SECONDS), is(true));
438 verify(trustee, times(1)).setTrust(eq(ownIdentity), eq(new Trust(SCORE, null, 0)));
439 verify(webOfTrustConnector).setTrust(eq(ownIdentity), eq(trustee), eq(SCORE), eq(TRUST_COMMENT));