Move InputStream matcher to Matchers.
[Sone.git] / src / test / java / net / pterodactylus / sone / fcp / FcpInterfaceTest.java
1 /*
2  * Sone - FcpInterfaceTest.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.fcp;
19
20 import static freenet.pluginmanager.FredPluginFCP.ACCESS_DIRECT;
21 import static freenet.pluginmanager.FredPluginFCP.ACCESS_FCP_FULL;
22 import static freenet.pluginmanager.FredPluginFCP.ACCESS_FCP_RESTRICTED;
23 import static net.pterodactylus.sone.Matchers.delivers;
24 import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.ALWAYS;
25 import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.NO;
26 import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.WRITING;
27 import static org.hamcrest.MatcherAssert.assertThat;
28 import static org.hamcrest.Matchers.hasSize;
29 import static org.hamcrest.Matchers.is;
30 import static org.hamcrest.Matchers.notNullValue;
31 import static org.mockito.Mockito.mock;
32
33 import java.io.IOException;
34 import java.util.List;
35
36 import net.pterodactylus.sone.core.Core;
37 import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder;
38 import net.pterodactylus.sone.freenet.fcp.FcpException;
39
40 import freenet.pluginmanager.PluginNotFoundException;
41 import freenet.pluginmanager.PluginReplySender;
42 import freenet.support.SimpleFieldSet;
43 import freenet.support.api.Bucket;
44 import freenet.support.io.ArrayBucket;
45
46 import com.google.common.collect.Lists;
47 import org.junit.Test;
48
49 /**
50  * Unit test for {@link FcpInterface}.
51  *
52  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
53  */
54 public class FcpInterfaceTest {
55
56         private final Core core = mock(Core.class);
57         private final FcpInterface fcpInterface = new FcpInterface(core);
58         private final CapturingPluginReplySender pluginReplySender = new CapturingPluginReplySender();
59
60         public FcpInterfaceTest() {
61                 fcpInterface.setActive(true);
62                 fcpInterface.setFullAccessRequired(ALWAYS);
63         }
64
65         @Test
66         public void testThatAnInactiveFcpInterfaceReturnsAnErrorForDirectAccess() throws PluginNotFoundException {
67                 fcpInterface.setActive(false);
68                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().get();
69                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
70                 verifyErrorWithCode("400");
71         }
72
73         @Test
74         public void testThatAnInactiveFcpInterfaceReturnsAnErrorForRestrictedFcpAccess() throws PluginNotFoundException {
75                 fcpInterface.setActive(false);
76                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().get();
77                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
78                 verifyErrorWithCode("400");
79         }
80
81         @Test
82         public void testThatAnInactiveFcpInterfaceReturnsAnErrorForFullFcpAccess() throws PluginNotFoundException {
83                 fcpInterface.setActive(false);
84                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().get();
85                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
86                 verifyErrorWithCode("400");
87         }
88
89         @Test
90         public void testThatAnActiveFcpInterfaceReturnsAnErrorForAnUnknownMessage() {
91                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "Foo").get();
92                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
93                 verifyError();
94         }
95
96         @Test
97         public void testThatAnActiveFcpInterfaceReturnsAnErrorForAMessageWithoutIdentifier() {
98                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
99                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").get();
100                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
101                 verifyError();
102         }
103
104         @Test
105         public void testThatAnActiveFcpInterfaceRequiringFullAccessAllowsDirectFcpAccessForReadOnlyCommand() {
106                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
107                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
108                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
109                 verifyReplyWithMessage("ReadOnlyPong");
110         }
111
112         @Test
113         public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsDirectFcpAccessForReadOnlyCommand() {
114                 fcpInterface.setFullAccessRequired(WRITING);
115                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
116                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
117                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
118                 verifyReplyWithMessage("ReadOnlyPong");
119         }
120
121         @Test
122         public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsDirectFcpAccessForReadOnlyCommand() {
123                 fcpInterface.setFullAccessRequired(NO);
124                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
125                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
126                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
127                 verifyReplyWithMessage("ReadOnlyPong");
128         }
129
130         @Test
131         public void testThatAnActiveFcpInterfaceRequiringFullAccessAllowsDirectFcpAccessForReadWriteCommand() {
132                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
133                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
134                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
135                 verifyReplyWithMessage("ReadWritePong");
136         }
137
138         @Test
139         public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsDirectFcpAccessForReadWriteCommand() {
140                 fcpInterface.setFullAccessRequired(WRITING);
141                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
142                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
143                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
144                 verifyReplyWithMessage("ReadWritePong");
145         }
146
147         @Test
148         public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsDirectFcpAccessForReadWriteCommand() {
149                 fcpInterface.setFullAccessRequired(NO);
150                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
151                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
152                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
153                 verifyReplyWithMessage("ReadWritePong");
154         }
155
156         @Test
157         public void testThatAnActiveFcpInterfaceRequiringFullAccessAllowsFullFcpAccessForReadOnlyCommand() {
158                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
159                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
160                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
161                 verifyReplyWithMessage("ReadOnlyPong");
162         }
163
164         @Test
165         public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsFullFcpAccessForReadOnlyCommand() {
166                 fcpInterface.setFullAccessRequired(WRITING);
167                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
168                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
169                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
170                 verifyReplyWithMessage("ReadOnlyPong");
171         }
172
173         @Test
174         public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsFullFcpAccessForReadOnlyCommand() {
175                 fcpInterface.setFullAccessRequired(NO);
176                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
177                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
178                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
179                 verifyReplyWithMessage("ReadOnlyPong");
180         }
181
182         private void verifyReplyWithMessage(String messageName) {
183                 assertThat(pluginReplySender.results, hasSize(1));
184                 assertThat(pluginReplySender.results.get(0).fieldSet, notNullValue());
185                 assertThat(pluginReplySender.results.get(0).fieldSet.get("Message"), is(messageName));
186         }
187
188         @Test
189         public void testThatAnActiveFcpInterfaceRequiringFullAccessAllowsFullFcpAccessForReadWriteCommand() {
190                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
191                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
192                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
193                 verifyReplyWithMessage("ReadWritePong");
194         }
195
196         @Test
197         public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsFullFcpAccessForReadWriteCommand() {
198                 fcpInterface.setFullAccessRequired(WRITING);
199                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
200                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
201                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
202                 verifyReplyWithMessage("ReadWritePong");
203         }
204
205         @Test
206         public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsFullFcpAccessForReadWriteCommand() {
207                 fcpInterface.setFullAccessRequired(NO);
208                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
209                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
210                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
211                 verifyReplyWithMessage("ReadWritePong");
212         }
213
214         @Test
215         public void testThatAnActiveFcpInterfaceRequiringFullAccessDoesNotAllowRestrictedFcpAccessForReadOnlyCommand() {
216                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
217                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
218                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
219                 verifyErrorWithCode("401");
220         }
221
222         @Test
223         public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsRestrictedFcpAccessForReadOnlyCommand() {
224                 fcpInterface.setFullAccessRequired(WRITING);
225                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
226                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
227                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
228                 verifyReplyWithMessage("ReadOnlyPong");
229         }
230
231         @Test
232         public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsRestrictedFcpAccessForReadOnlyCommand() {
233                 fcpInterface.setFullAccessRequired(NO);
234                 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
235                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
236                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
237                 verifyReplyWithMessage("ReadOnlyPong");
238         }
239
240         @Test
241         public void testThatAnActiveFcpInterfaceRequiringFullAccessDoesNotAllowRestrictedFcpAccessForReadWriteCommand() {
242                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
243                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
244                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
245                 verifyErrorWithCode("401");
246         }
247
248         @Test
249         public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesDoesNotAllowRestrictedFcpAccessForReadWriteCommand() {
250                 fcpInterface.setFullAccessRequired(WRITING);
251                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
252                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
253                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
254                 verifyErrorWithCode("401");
255         }
256
257         @Test
258         public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsRestrictedFcpAccessForReadWriteCommand() {
259                 fcpInterface.setFullAccessRequired(NO);
260                 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
261                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
262                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
263                 verifyReplyWithMessage("ReadWritePong");
264         }
265
266         @Test
267         public void testThatAFaultyCommandResultsInAnError() {
268                 fcpInterface.addCommand("Faulty", new FaultyCommand());
269                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "Faulty").put("Identifier", "foo").get();
270                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
271                 verifyError();
272         }
273
274         @Test
275         public void testThatAFaultyPluginReplySenderIsHandled() {
276                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "Faulty").put("Identifier", "foo").get();
277                 fcpInterface.handle(new FaultyPluginReplySender(), fieldSet, null, ACCESS_FCP_FULL);
278         }
279
280         @Test
281         public void testThatACommandWithDataIsHandledCorrectly() throws IOException {
282                 fcpInterface.addCommand("CommandWithData", new CommandWithData());
283                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "CommandWithData").put("Identifier", "foo").get();
284                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
285                 verifyReplyWithMessage("ReturnedData");
286                 assertThat(pluginReplySender.results.get(0).bucket, notNullValue());
287                 assertThat(pluginReplySender.results.get(0).bucket.size(), is(3L));
288                 assertThat(pluginReplySender.results.get(0).bucket.getInputStream(), delivers(new byte[] { 1, 2, 3 }));
289         }
290
291         @Test
292         public void testThatACommandWithABucketIsHandledCorrectly() throws IOException {
293                 fcpInterface.addCommand("CommandWithBucket", new CommandWithBucket());
294                 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "CommandWithBucket").put("Identifier", "foo").get();
295                 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
296                 verifyReplyWithMessage("ReturnedBucket");
297                 assertThat(pluginReplySender.results.get(0).bucket, notNullValue());
298                 assertThat(pluginReplySender.results.get(0).bucket.size(), is(3L));
299                 assertThat(pluginReplySender.results.get(0).bucket.getInputStream(), delivers(new byte[] { 4, 5, 6 }));
300         }
301
302         private void verifyError() {
303                 assertThat(pluginReplySender.results, hasSize(1));
304                 assertThat(pluginReplySender.results.get(0).fieldSet, notNullValue());
305                 assertThat(pluginReplySender.results.get(0).fieldSet.get("Message"), is("Error"));
306         }
307
308         private void verifyErrorWithCode(String errorCode) {
309                 verifyError();
310                 assertThat(pluginReplySender.results.get(0).fieldSet.get("ErrorCode"), is(errorCode));
311         }
312
313         private static class CapturingPluginReplySender extends PluginReplySender {
314
315                 public final List<PluginReplySenderResult> results = Lists.newArrayList();
316
317                 public CapturingPluginReplySender() {
318                         super(null, null);
319                 }
320
321                 @Override
322                 public void send(SimpleFieldSet params, Bucket bucket) throws PluginNotFoundException {
323                         results.add(new PluginReplySenderResult(params, bucket));
324                 }
325
326         }
327
328         private static class PluginReplySenderResult {
329
330                 public final SimpleFieldSet fieldSet;
331                 public final Bucket bucket;
332
333                 public PluginReplySenderResult(SimpleFieldSet fieldSet, Bucket bucket) {
334                         this.fieldSet = fieldSet;
335                         this.bucket = bucket;
336                 }
337
338         }
339
340         private static class ReadOnlyPing extends AbstractSoneCommand {
341
342                 public ReadOnlyPing() {
343                         super(null, false);
344                 }
345
346                 @Override
347                 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
348                         return new Response("ReadOnlyPong", new SimpleFieldSetBuilder().get());
349                 }
350
351         }
352
353         private static class ReadWritePing extends AbstractSoneCommand {
354
355                 public ReadWritePing() {
356                         super(null, true);
357                 }
358
359                 @Override
360                 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
361                         return new Response("ReadWritePong", new SimpleFieldSetBuilder().get());
362                 }
363
364         }
365
366         private static class FaultyCommand extends AbstractSoneCommand {
367
368                 public FaultyCommand() {
369                         super(null, false);
370                 }
371
372                 @Override
373                 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
374                         throw new RuntimeException("I’m faulty!");
375                 }
376
377         }
378
379         private static class FaultyPluginReplySender extends PluginReplySender {
380
381                 public FaultyPluginReplySender() {
382                         super(null, null);
383                 }
384
385                 @Override
386                 public void send(SimpleFieldSet params, Bucket bucket) throws PluginNotFoundException {
387                         throw new PluginNotFoundException();
388                 }
389
390         }
391
392         private static class CommandWithData extends AbstractSoneCommand {
393
394                 protected CommandWithData() {
395                         super(null);
396                 }
397
398                 @Override
399                 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
400                         return new Response("ReturnedData", new SimpleFieldSetBuilder().get(), new byte[] { 1, 2, 3 });
401                 }
402
403         }
404
405         private static class CommandWithBucket extends AbstractSoneCommand {
406
407                 protected CommandWithBucket() {
408                         super(null);
409                 }
410
411                 @Override
412                 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
413                         return new Response("ReturnedBucket", new SimpleFieldSetBuilder().get(), new ArrayBucket(new byte[] { 4, 5, 6 }));
414                 }
415
416         }
417
418 }