Extract interface from the web of trust updater.
[Sone.git] / src / test / java / net / pterodactylus / sone / core / WebOfTrustUpdaterTest.java
1 package net.pterodactylus.sone.core;
2
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;
16
17 import java.util.concurrent.CountDownLatch;
18 import java.util.concurrent.atomic.AtomicInteger;
19
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;
32
33 import org.junit.Test;
34 import org.mockito.invocation.InvocationOnMock;
35 import org.mockito.stubbing.Answer;
36
37 /**
38  * Unit test for {@link WebOfTrustUpdaterImpl} and its subclasses.
39  *
40  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
41  */
42 public class WebOfTrustUpdaterTest {
43
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();
58
59         private WebOfTrustUpdateJob createWebOfTrustUpdateJob(final boolean success) {
60                 return webOfTrustUpdater.new WebOfTrustUpdateJob() {
61                         @Override
62                         public void run() {
63                                 super.run();
64                                 try {
65                                         sleep(100);
66                                 } catch (InterruptedException ie1) {
67                                         throw new RuntimeException(ie1);
68                                 }
69                                 finish(success);
70                         }
71                 };
72         }
73
74         @Test
75         public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsSuccess() throws InterruptedException {
76                 new Thread(successfulWebOfTrustUpdateJob).start();
77                 assertThat(successfulWebOfTrustUpdateJob.waitForCompletion(), is(true));
78         }
79
80         @Test
81         public void webOfTrustUpdateJobWaitsUntilFinishedHasBeenCalledAndReturnsFailure() throws InterruptedException {
82                 new Thread(failingWebOfTrustUpdateJob).start();
83                 assertThat(failingWebOfTrustUpdateJob.waitForCompletion(), is(false));
84         }
85
86         @Test
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()));
92         }
93
94         @Test
95         public void webOfTrustContextUpdatesJobsAreNotEqualIfTheirClassDiffers() {
96                 assertThat(contextUpdateJob.equals(addContextJob), is(false));
97         }
98
99         @Test
100         public void webOfTrustContextUpdateJobToStringContainsIdentityAndContext() {
101                 assertThat(contextUpdateJob.toString(), containsString(ownIdentity.toString()));
102                 assertThat(contextUpdateJob.toString(), containsString(CONTEXT));
103         }
104
105         @Test
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));
111         }
112
113         @Test
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));
118         }
119
120         @Test
121         public void webOfTrustContextUpdateJobsAreNotEqualToNull() {
122                 assertThat(contextUpdateJob.equals(null), is(false));
123         }
124
125         @Test
126         public void addContextJobAddsTheContext() throws PluginException {
127                 addContextJob.run();
128                 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
129                 verify(ownIdentity).addContext(eq(CONTEXT));
130                 assertThat(addContextJob.waitForCompletion(), is(true));
131         }
132
133         @Test
134         public void exceptionWhileAddingAContextIsExposed() throws PluginException {
135                 doThrow(PluginException.class).when(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
136                 addContextJob.run();
137                 verify(webOfTrustConnector).addContext(eq(ownIdentity), eq(CONTEXT));
138                 verify(ownIdentity, never()).addContext(eq(CONTEXT));
139                 assertThat(addContextJob.waitForCompletion(), is(false));
140         }
141
142         @Test
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));
148         }
149
150         @Test
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));
157         }
158
159         @Test
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));
168         }
169
170         @Test
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));
178         }
179
180         @Test
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));
190         }
191
192         @Test
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()));
201         }
202
203         @Test
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) {
209                 };
210                 assertThat(firstSetPropertyJob, not(is(secondSetPropertyJob)));
211         }
212
213         @Test
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)));
219         }
220
221         @Test
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)));
228         }
229
230         @Test
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)));
238         }
239
240         @Test
241         public void setTrustJobSetsTrust() throws PluginException {
242                 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
243                 setTrustJob.run();
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));
247         }
248
249         @Test
250         public void settingNullTrustRemovesTrust() throws WebOfTrustException {
251                 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, null, TRUST_COMMENT);
252                 setTrustJob.run();
253                 verify(webOfTrustConnector).removeTrust(eq(ownIdentity), eq(trustee));
254                 verify(trustee).removeTrust(eq(ownIdentity));
255                 assertThat(setTrustJob.waitForCompletion(), is(true));
256         }
257
258         @Test
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);
262                 setTrustJob.run();
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));
266         }
267
268         @Test
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) {
272                 };
273                 assertThat(firstSetTrustJob, not(is(secondSetTrustJob)));
274                 assertThat(secondSetTrustJob, not(is(firstSetTrustJob)));
275         }
276
277         @Test
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)));
283         }
284
285         @Test
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)));
291         }
292
293         @Test
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()));
300         }
301
302         @Test
303         public void setTrustJobDoesNotEqualNull() {
304                 SetTrustJob setTrustJob = webOfTrustUpdater.new SetTrustJob(ownIdentity, trustee, SCORE, TRUST_COMMENT);
305                 assertThat(setTrustJob, not(is((Object) null)));
306         }
307
308         @Test
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()));
313         }
314
315         @Test
316         public void webOfTrustUpdaterStopsWhenItShould() {
317                 webOfTrustUpdater.stop();
318                 webOfTrustUpdater.serviceRun();
319         }
320
321         @Test
322         public void webOfTrustUpdaterStopsAfterItWasStarted() {
323                 webOfTrustUpdater.start();
324                 webOfTrustUpdater.stop();
325         }
326
327         @Test
328         public void removePropertyRemovesProperty() throws InterruptedException, PluginException {
329                 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
330                 doAnswer(new Answer<Void>() {
331                         @Override
332                         public Void answer(InvocationOnMock invocation) throws Throwable {
333                                 wotCallTriggered.countDown();
334                                 return null;
335                         }
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));
340         }
341
342         @Test
343         public void multipleCallsToSetPropertyAreCollapsed() throws InterruptedException, PluginException {
344                 final CountDownLatch wotCallTriggered = new CountDownLatch(1);
345                 doAnswer(new Answer<Void>() {
346                         @Override
347                         public Void answer(InvocationOnMock invocation) throws Throwable {
348                                 wotCallTriggered.countDown();
349                                 return null;
350                         }
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));
357         }
358
359         @Test
360         public void addContextWaitWaitsForTheContextToBeAdded() {
361                 webOfTrustUpdater.start();
362                 assertThat(webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT), is(true));
363                 verify(ownIdentity).addContext(eq(CONTEXT));
364         }
365
366         @Test
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. */
372                         if (i > 1) {
373                                 sleep(200);
374                         }
375                         new Thread(new Runnable() {
376                                 public void run() {
377                                         if (!webOfTrustUpdater.addContextWait(ownIdentity, CONTEXT)) {
378                                                 errorCount.incrementAndGet();
379                                         }
380                                         addContextsFinished.countDown();
381                                 }
382                         }).start();
383                 }
384                 webOfTrustUpdater.start();
385                 assertThat(addContextsFinished.await(1, SECONDS), is(true));
386                 verify(ownIdentity).addContext(eq(CONTEXT));
387                 assertThat(errorCount.get(), is(0));
388         }
389
390         @Test
391         public void removeContextRemovesAContext() throws InterruptedException, PluginException {
392                 webOfTrustUpdater.start();
393                 final CountDownLatch removeContextTrigger = new CountDownLatch(1);
394                 doAnswer(new Answer<Void>() {
395                         @Override
396                         public Void answer(InvocationOnMock invocation) throws Throwable {
397                                 removeContextTrigger.countDown();
398                                 return null;
399                         }
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));
405         }
406
407         @Test
408         public void removeContextRequestsAreCoalesced() throws InterruptedException, PluginException {
409                 final CountDownLatch contextRemovedTrigger = new CountDownLatch(1);
410                 doAnswer(new Answer<Void>() {
411                         @Override
412                         public Void answer(InvocationOnMock invocation) throws Throwable {
413                                 contextRemovedTrigger.countDown();
414                                 return null;
415                         }
416                 }).when(ownIdentity).removeContext(eq(CONTEXT));
417                 for (int i = 1; i <= 2; i++) {
418                         /* this is so fucking volatile. */
419                         if (i > 1) {
420                                 sleep(200);
421                         }
422                         new Thread(new Runnable() {
423                                 public void run() {
424                                         webOfTrustUpdater.removeContext(ownIdentity, CONTEXT);
425                                 }
426                         }).start();
427                 }
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));
432         }
433
434         @Test
435         public void setTrustSetsTrust() throws InterruptedException, PluginException {
436                 final CountDownLatch trustSetTrigger =new CountDownLatch(1);
437                 doAnswer(new Answer<Void>() {
438                         @Override
439                         public Void answer(InvocationOnMock invocation) throws Throwable {
440                                 trustSetTrigger.countDown();
441                                 return null;
442                         }
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));
449         }
450
451         @Test
452         public void setTrustRequestsAreCoalesced() throws InterruptedException, PluginException {
453                 final CountDownLatch trustSetTrigger = new CountDownLatch(1);
454                 doAnswer(new Answer<Void>() {
455                         @Override
456                         public Void answer(InvocationOnMock invocation) throws Throwable {
457                                 trustSetTrigger.countDown();
458                                 return null;
459                         }
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. */
463                         if (i > 1) {
464                                 sleep(200);
465                         }
466                         new Thread(new Runnable() {
467                                 public void run() {
468                                         webOfTrustUpdater.setTrust(ownIdentity, trustee, SCORE, TRUST_COMMENT);
469                                 }
470                         }).start();
471                 }
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));
476         }
477
478 }