Add unit test for WebOfTrustConnector.
[Sone.git] / src / test / java / net / pterodactylus / sone / freenet / wot / WebOfTrustConnectorTest.java
1 /*
2  * Sone - WebOfTrustConnectorTest.java - Copyright © 2013 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.freenet.wot;
19
20 import static com.google.common.base.Objects.equal;
21 import static com.google.common.collect.FluentIterable.from;
22 import static com.google.common.collect.ImmutableSet.of;
23 import static com.google.common.collect.Iterators.size;
24 import static org.hamcrest.MatcherAssert.assertThat;
25 import static org.hamcrest.Matchers.containsInAnyOrder;
26 import static org.hamcrest.Matchers.hasSize;
27 import static org.hamcrest.Matchers.is;
28 import static org.mockito.Matchers.any;
29 import static org.mockito.Matchers.anyString;
30 import static org.mockito.Matchers.argThat;
31 import static org.mockito.Matchers.eq;
32 import static org.mockito.Mockito.doAnswer;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.verify;
35
36 import java.util.Collection;
37 import java.util.Iterator;
38 import java.util.Map.Entry;
39 import java.util.Set;
40
41 import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder;
42 import net.pterodactylus.sone.freenet.plugin.PluginConnector;
43 import net.pterodactylus.sone.freenet.plugin.PluginException;
44 import net.pterodactylus.sone.freenet.plugin.event.ReceivedReplyEvent;
45
46 import freenet.support.SimpleFieldSet;
47 import freenet.support.api.Bucket;
48
49 import com.google.common.base.Function;
50 import com.google.common.collect.ImmutableSet;
51 import org.hamcrest.Description;
52 import org.hamcrest.Matcher;
53 import org.hamcrest.TypeSafeMatcher;
54 import org.junit.Test;
55 import org.mockito.invocation.InvocationOnMock;
56 import org.mockito.stubbing.Answer;
57
58 /**
59  * Unit test for {@link WebOfTrustConnector}.
60  *
61  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
62  */
63 public class WebOfTrustConnectorTest {
64
65         private static final String WOT_PLUGIN_NAME = "plugins.WebOfTrust.WebOfTrust";
66         private final PluginConnector pluginConnector = mock(PluginConnector.class);
67         private final WebOfTrustConnector webOfTrustConnector = new WebOfTrustConnector(pluginConnector);
68
69         @Test
70         public void loadingAllOwnIdentities() throws WebOfTrustException {
71                 final Set<OwnIdentity> ownIdentities = ImmutableSet.of(
72                                 new DefaultOwnIdentity("Id0", "Nickname0", "RequestURI0", "InsertURI0").addContext("TestA").setProperty("Key A", "Value A").setProperty("Key B", "Value B"),
73                                 new DefaultOwnIdentity("Id1", "Nickname1", "RequestURI1", "InsertURI1").addContext("TestB").addContext("TestC").setProperty("Key C", "Value C")
74                 );
75                 providerAnswer(createFieldSetForOwnIdentities(ownIdentities));
76                 Set<OwnIdentity> parsedOwnIdentities = webOfTrustConnector.loadAllOwnIdentities();
77                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "GetOwnIdentities").get())), any(Bucket.class));
78                 verifyOwnIdentities(parsedOwnIdentities, ownIdentities);
79         }
80
81         @Test
82         public void loadingTrustedIdentities() throws PluginException {
83                 final OwnIdentity ownIdentity = new DefaultOwnIdentity("OwnId", "OwnNick", "OwnRequest", "OwnInsert");
84                 final Collection<Identity> identities = of(
85                                 new DefaultIdentity("Id1", "Nickname1", "Request1").addContext("TestA").addContext("TestB").setProperty("Key A", "Value A").setTrust(ownIdentity, new Trust(5, 17, 2)),
86                                 new DefaultIdentity("Id2", "Nickname2", "Request2").addContext("TestC").setProperty("Key B", "Value B").setProperty("Key C", "Value C").setTrust(ownIdentity, new Trust(80, 23, 1))
87                 );
88                 providerAnswer(createFieldSetForIdentities(identities, ownIdentity));
89                 Set<Identity> parsedIdentities = webOfTrustConnector.loadTrustedIdentities(ownIdentity, "Test");
90                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "GetIdentitiesByScore").put("Truster", ownIdentity.getId()).put("Selection", "+").put("Context", "Test").put("WantTrustValues", "true").get())), any(Bucket.class));
91                 verifyIdentities(parsedIdentities, identities, ownIdentity);
92         }
93
94         private static void verifyIdentities(Set<Identity> parsedIdentities, Collection<Identity> identities, final OwnIdentity ownIdentity) {
95                 assertThat(parsedIdentities, hasSize(identities.size()));
96                 assertThat(parsedIdentities, containsInAnyOrder(from(identities).transform(new Function<Identity, Matcher<? super Identity>>() {
97                         @Override
98                         public Matcher<Identity> apply(Identity identity) {
99                                 return matches(identity, ownIdentity);
100                         }
101                 }).toSet()));
102         }
103
104         private static SimpleFieldSet createFieldSetForIdentities(Collection<Identity> identities, OwnIdentity ownIdentity) {
105                 SimpleFieldSetBuilder identitiesBuilder = new SimpleFieldSetBuilder();
106                 int identityIndex = 0;
107                 for (Identity identity : identities) {
108                         addIdentityToFieldSet(identitiesBuilder, identityIndex++, identity, ownIdentity);
109                 }
110                 return identitiesBuilder.get();
111         }
112
113         private static void addIdentityToFieldSet(SimpleFieldSetBuilder identitiesBuilder, int index, Identity identity, OwnIdentity ownIdentity) {
114                 addCommonIdentityFieldsToFieldSet(identitiesBuilder, index, identity);
115                 Trust trust = identity.getTrust(ownIdentity);
116                 identitiesBuilder.put("Trust" + index, trust.getExplicit()).put("Score" + index, trust.getImplicit()).put("Rank" + index, trust.getDistance());
117         }
118
119         @Test
120         public void addingAContext() throws PluginException {
121                 final OwnIdentity ownIdentity = new DefaultOwnIdentity("OwnId", "OwnNick", "OwnRequest", "OwnInsert");
122                 providerAnswer(new SimpleFieldSetBuilder().get());
123                 webOfTrustConnector.addContext(ownIdentity, "Test");
124                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "AddContext").put("Identity", ownIdentity.getId()).put("Context", "Test").get())), any(Bucket.class));
125         }
126
127         @Test
128         public void removingAContext() throws PluginException {
129                 final OwnIdentity ownIdentity = new DefaultOwnIdentity("OwnId", "OwnNick", "OwnRequest", "OwnInsert");
130                 providerAnswer(new SimpleFieldSetBuilder().get());
131                 webOfTrustConnector.removeContext(ownIdentity, "Test");
132                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "RemoveContext").put("Identity", ownIdentity.getId()).put("Context", "Test").get())), any(Bucket.class));
133         }
134
135         @Test
136         public void gettingAProperty() throws PluginException {
137                 final Identity identity = new DefaultIdentity("Id", "Nick", "R").setProperty("KeyA", "ValueA");
138                 providerAnswer(createFieldSetForGettingAProperty(identity, "KeyA"));
139                 String value = webOfTrustConnector.getProperty(identity, "KeyA");
140                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "GetProperty").put("Identity", identity.getId()).put("Property", "KeyA").get())), any(Bucket.class));
141                 assertThat(value, is("ValueA"));
142         }
143
144         private static SimpleFieldSet createFieldSetForGettingAProperty(Identity identity, String key) {
145                 return new SimpleFieldSetBuilder()
146                                 .put("Property", identity.getProperty(key))
147                                 .get();
148         }
149
150         @Test
151         public void settingAProperty() throws PluginException {
152                 OwnIdentity ownIdentity = new DefaultOwnIdentity("Id", "Nick", "R", "I");
153                 providerAnswer(new SimpleFieldSetBuilder().get());
154                 webOfTrustConnector.setProperty(ownIdentity, "KeyA", "ValueA");
155                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "SetProperty").put("Identity", ownIdentity.getId()).put("Property", "KeyA").put("Value", "ValueA").get())), any(Bucket.class));
156         }
157
158         @Test
159         public void removingAProperty() throws PluginException {
160                 OwnIdentity ownIdentity = new DefaultOwnIdentity("Id", "Nick", "R", "I");
161                 providerAnswer(new SimpleFieldSetBuilder().get());
162                 webOfTrustConnector.removeProperty(ownIdentity, "KeyA");
163                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "RemoveProperty").put("Identity", ownIdentity.getId()).put("Property", "KeyA").get())), any(Bucket.class));
164         }
165
166         @Test
167         public void gettingTrust() throws PluginException {
168                 OwnIdentity ownIdentity = new DefaultOwnIdentity("OId", "ONick", "OR", "OI");
169                 Identity identity = new DefaultIdentity("Id", "Nick", "R");
170                 providerAnswer(createFieldSetForGettingTrust(5, 17, 2));
171                 Trust trust = webOfTrustConnector.getTrust(ownIdentity, identity);
172                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "GetIdentity").put("Truster", ownIdentity.getId()).put("Identity", identity.getId()).get())), any(Bucket.class));
173                 assertThat(trust.getExplicit(), is(5));
174                 assertThat(trust.getImplicit(), is(17));
175                 assertThat(trust.getDistance(), is(2));
176         }
177
178         private SimpleFieldSet createFieldSetForGettingTrust(int explicit, int implicit, int distance) {
179                 return new SimpleFieldSetBuilder()
180                                 .put("Trust", explicit)
181                                 .put("Score", implicit)
182                                 .put("Rank", distance)
183                                 .get();
184         }
185
186         @Test
187         public void settingTrust() throws PluginException {
188                 OwnIdentity ownIdentity = new DefaultOwnIdentity("OId", "ONick", "OR", "OI");
189                 Identity identity = new DefaultIdentity("Id", "Nick", "R");
190                 providerAnswer(new SimpleFieldSetBuilder().get());
191                 webOfTrustConnector.setTrust(ownIdentity, identity, 45, "Set manually.");
192                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "SetTrust").put("Truster", ownIdentity.getId()).put("Trustee", identity.getId()).put("Value", 45).put("Comment", "Set manually.").get())), any(Bucket.class));
193         }
194
195         @Test
196         public void removingTrust() throws WebOfTrustException {
197                 OwnIdentity ownIdentity = new DefaultOwnIdentity("OId", "ONick", "OR", "OI");
198                 Identity identity = new DefaultIdentity("Id", "Nick", "R");
199                 providerAnswer(new SimpleFieldSetBuilder().get());
200                 webOfTrustConnector.removeTrust(ownIdentity, identity);
201                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "RemoveTrust").put("Truster", ownIdentity.getId()).put("Trustee", identity.getId()).get())), any(Bucket.class));
202         }
203
204         @Test
205         public void pinging() throws PluginException {
206                 providerAnswer(new SimpleFieldSetBuilder().get());
207                 webOfTrustConnector.ping();
208                 verify(pluginConnector).sendRequest(eq(WOT_PLUGIN_NAME), anyString(), argThat(matches(new SimpleFieldSetBuilder().put("Message", "Ping").get())), any(Bucket.class));
209         }
210
211         private void providerAnswer(final SimpleFieldSet fieldSet) throws PluginException {
212                 doAnswer(new Answer<Void>() {
213                         @Override
214                         public Void answer(InvocationOnMock invocation) throws Throwable {
215                                 String identifier = (String) invocation.getArguments()[1];
216                                 SimpleFieldSet replyFieldSet = fieldSet;
217                                 ReceivedReplyEvent receivedReplyEvent = new ReceivedReplyEvent(pluginConnector, WOT_PLUGIN_NAME, identifier, replyFieldSet, null);
218                                 webOfTrustConnector.receivedReply(receivedReplyEvent);
219                                 return null;
220                         }
221                 }).when(pluginConnector).sendRequest(anyString(), anyString(), any(SimpleFieldSet.class), any(Bucket.class));
222         }
223
224         private static void addCommonIdentityFieldsToFieldSet(SimpleFieldSetBuilder identitiesBuilder, int index, Identity identity) {
225                 identitiesBuilder
226                                 .put("Identity" + index, identity.getId())
227                                 .put("Nickname" + index, identity.getNickname())
228                                 .put("RequestURI" + index, identity.getRequestUri());
229                 int contextIndex = 0;
230                 for (String context : identity.getContexts()) {
231                         identitiesBuilder.put("Contexts" + index + ".Context" + contextIndex++, context);
232                 }
233                 int propertyIndex = 0;
234                 for (Entry<String, String> property : identity.getProperties().entrySet()) {
235                         identitiesBuilder
236                                         .put("Properties" + index + ".Property" + propertyIndex + ".Name", property.getKey())
237                                         .put("Properties" + index + ".Property" + propertyIndex++ + ".Value", property.getValue());
238                 }
239         }
240
241         private static SimpleFieldSet createFieldSetForOwnIdentities(Collection<OwnIdentity> ownIdentities) {
242                 SimpleFieldSetBuilder ownIdentitiesBuilder = new SimpleFieldSetBuilder();
243                 int ownIdentityIndex = 0;
244                 for (OwnIdentity ownIdentity : ownIdentities) {
245                         addOwnIdentityToFieldSet(ownIdentitiesBuilder, ownIdentityIndex++, ownIdentity);
246                 }
247                 return ownIdentitiesBuilder.get();
248         }
249
250         private static void addOwnIdentityToFieldSet(SimpleFieldSetBuilder fieldSetBuilder, int index, OwnIdentity ownIdentity) {
251                 addCommonIdentityFieldsToFieldSet(fieldSetBuilder, index, ownIdentity);
252                 fieldSetBuilder.put("InsertURI" + index, ownIdentity.getInsertUri());
253         }
254
255         private static void verifyOwnIdentities(Set<OwnIdentity> ownIdentities, Set<OwnIdentity> ownIdentitiesToMatch) {
256                 assertThat(ownIdentities, hasSize(ownIdentities.size()));
257                 assertThat(ownIdentities, containsInAnyOrder(from(ownIdentitiesToMatch).transform(new Function<OwnIdentity, Matcher<? super OwnIdentity>>() {
258                         @Override
259                         public Matcher<OwnIdentity> apply(OwnIdentity ownIdentity) {
260                                 return matches(ownIdentity);
261                         }
262                 }).toSet()));
263         }
264
265         private static Matcher<Identity> matches(final Identity identity, final OwnIdentity ownIdentity) {
266                 return new TypeSafeMatcher<Identity>() {
267                         @Override
268                         protected boolean matchesSafely(Identity item) {
269                                 if (!matchesCommonFields(identity).matches(item)) {
270                                         return false;
271                                 }
272                                 if (!equal(item.getTrust(ownIdentity), identity.getTrust(ownIdentity))) {
273                                         return false;
274                                 }
275                                 return true;
276                         }
277
278                         @Override
279                         public void describeTo(Description description) {
280                                 description.appendValue(identity);
281                         }
282                 };
283         }
284
285         private static Matcher<OwnIdentity> matches(final OwnIdentity ownIdentity) {
286                 return new TypeSafeMatcher<OwnIdentity>() {
287                         @Override
288                         protected boolean matchesSafely(OwnIdentity item) {
289                                 if (!matchesCommonFields(ownIdentity).matches(item)) {
290                                         return false;
291                                 }
292                                 if (!equal(item.getInsertUri(), ownIdentity.getInsertUri())) {
293                                         return false;
294                                 }
295                                 return true;
296                         }
297
298                         @Override
299                         public void describeTo(Description description) {
300                                 description.appendValue(ownIdentity);
301                         }
302                 };
303         }
304
305         private static Matcher<? extends Identity> matchesCommonFields(final Identity identity) {
306                 return new TypeSafeMatcher<Identity>() {
307                         @Override
308                         protected boolean matchesSafely(Identity item) {
309                                 if (!equal(item.getId(), identity.getId()) || !equal(item.getNickname(), identity.getNickname()) || !equal(item.getRequestUri(), identity.getRequestUri())) {
310                                         return false;
311                                 }
312                                 if (!containsInAnyOrder(identity.getContexts().toArray(new String[identity.getContexts().size()])).matches(item.getContexts())) {
313                                         return false;
314                                 }
315                                 if (!equal(item.getProperties(), identity.getProperties())) {
316                                         return false;
317                                 }
318                                 return true;
319                         }
320
321                         @Override
322                         public void describeTo(Description description) {
323                                 description.appendValue(identity);
324                         }
325                 };
326         }
327
328         private static Matcher<SimpleFieldSet> matches(final SimpleFieldSet fieldSetToMatch) {
329                 return new TypeSafeMatcher<SimpleFieldSet>() {
330                         @Override
331                         protected boolean matchesSafely(SimpleFieldSet fieldSet) {
332                                 if (size(fieldSet.keyIterator()) != size(fieldSetToMatch.keyIterator())) {
333                                         return false;
334                                 }
335                                 for (Iterator<String> keys = fieldSetToMatch.keyIterator(); keys.hasNext(); ) {
336                                         String key = keys.next();
337                                         if (!equal(fieldSet.get(key), fieldSetToMatch.get(key))) {
338                                                 return false;
339                                         }
340                                 }
341                                 return true;
342                         }
343
344                         @Override
345                         public void describeTo(Description description) {
346                                 description.appendText("is ").appendValue(fieldSetToMatch);
347                         }
348                 };
349         }
350
351 }