2 * Sone - FcpInterfaceTest.java - Copyright © 2013 David Roden
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.
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.
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/>.
18 package net.pterodactylus.sone.fcp;
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.fcp.FcpInterface.FullAccessRequired.ALWAYS;
24 import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.NO;
25 import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.WRITING;
26 import static org.hamcrest.MatcherAssert.assertThat;
27 import static org.hamcrest.Matchers.hasSize;
28 import static org.hamcrest.Matchers.is;
29 import static org.hamcrest.Matchers.notNullValue;
30 import static org.mockito.Mockito.mock;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.util.List;
36 import net.pterodactylus.sone.core.Core;
37 import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder;
38 import net.pterodactylus.sone.freenet.fcp.FcpException;
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;
46 import com.google.common.collect.Lists;
47 import org.hamcrest.Description;
48 import org.hamcrest.Matcher;
49 import org.hamcrest.TypeSafeMatcher;
50 import org.junit.Test;
53 * Unit test for {@link FcpInterface}.
55 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
57 public class FcpInterfaceTest {
59 private final Core core = mock(Core.class);
60 private final FcpInterface fcpInterface = new FcpInterface(core);
61 private final CapturingPluginReplySender pluginReplySender = new CapturingPluginReplySender();
63 public FcpInterfaceTest() {
64 fcpInterface.setActive(true);
65 fcpInterface.setFullAccessRequired(ALWAYS);
69 public void testThatAnInactiveFcpInterfaceReturnsAnErrorForDirectAccess() throws PluginNotFoundException {
70 fcpInterface.setActive(false);
71 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().get();
72 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
73 verifyErrorWithCode("400");
77 public void testThatAnInactiveFcpInterfaceReturnsAnErrorForRestrictedFcpAccess() throws PluginNotFoundException {
78 fcpInterface.setActive(false);
79 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().get();
80 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
81 verifyErrorWithCode("400");
85 public void testThatAnInactiveFcpInterfaceReturnsAnErrorForFullFcpAccess() throws PluginNotFoundException {
86 fcpInterface.setActive(false);
87 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().get();
88 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
89 verifyErrorWithCode("400");
93 public void testThatAnActiveFcpInterfaceReturnsAnErrorForAnUnknownMessage() {
94 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "Foo").get();
95 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
100 public void testThatAnActiveFcpInterfaceReturnsAnErrorForAMessageWithoutIdentifier() {
101 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
102 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").get();
103 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
108 public void testThatAnActiveFcpInterfaceRequiringFullAccessAllowsDirectFcpAccessForReadOnlyCommand() {
109 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
110 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
111 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
112 verifyReplyWithMessage("ReadOnlyPong");
116 public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsDirectFcpAccessForReadOnlyCommand() {
117 fcpInterface.setFullAccessRequired(WRITING);
118 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
119 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
120 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
121 verifyReplyWithMessage("ReadOnlyPong");
125 public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsDirectFcpAccessForReadOnlyCommand() {
126 fcpInterface.setFullAccessRequired(NO);
127 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
128 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
129 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
130 verifyReplyWithMessage("ReadOnlyPong");
134 public void testThatAnActiveFcpInterfaceRequiringFullAccessAllowsDirectFcpAccessForReadWriteCommand() {
135 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
136 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
137 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
138 verifyReplyWithMessage("ReadWritePong");
142 public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsDirectFcpAccessForReadWriteCommand() {
143 fcpInterface.setFullAccessRequired(WRITING);
144 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
145 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
146 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
147 verifyReplyWithMessage("ReadWritePong");
151 public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsDirectFcpAccessForReadWriteCommand() {
152 fcpInterface.setFullAccessRequired(NO);
153 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
154 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
155 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
156 verifyReplyWithMessage("ReadWritePong");
160 public void testThatAnActiveFcpInterfaceRequiringFullAccessAllowsFullFcpAccessForReadOnlyCommand() {
161 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
162 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
163 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
164 verifyReplyWithMessage("ReadOnlyPong");
168 public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsFullFcpAccessForReadOnlyCommand() {
169 fcpInterface.setFullAccessRequired(WRITING);
170 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
171 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
172 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
173 verifyReplyWithMessage("ReadOnlyPong");
177 public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsFullFcpAccessForReadOnlyCommand() {
178 fcpInterface.setFullAccessRequired(NO);
179 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
180 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
181 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
182 verifyReplyWithMessage("ReadOnlyPong");
185 private void verifyReplyWithMessage(String messageName) {
186 assertThat(pluginReplySender.results, hasSize(1));
187 assertThat(pluginReplySender.results.get(0).fieldSet, notNullValue());
188 assertThat(pluginReplySender.results.get(0).fieldSet.get("Message"), is(messageName));
192 public void testThatAnActiveFcpInterfaceRequiringFullAccessAllowsFullFcpAccessForReadWriteCommand() {
193 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
194 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
195 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
196 verifyReplyWithMessage("ReadWritePong");
200 public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsFullFcpAccessForReadWriteCommand() {
201 fcpInterface.setFullAccessRequired(WRITING);
202 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
203 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
204 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
205 verifyReplyWithMessage("ReadWritePong");
209 public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsFullFcpAccessForReadWriteCommand() {
210 fcpInterface.setFullAccessRequired(NO);
211 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
212 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
213 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
214 verifyReplyWithMessage("ReadWritePong");
218 public void testThatAnActiveFcpInterfaceRequiringFullAccessDoesNotAllowRestrictedFcpAccessForReadOnlyCommand() {
219 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
220 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
221 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
222 verifyErrorWithCode("401");
226 public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesAllowsRestrictedFcpAccessForReadOnlyCommand() {
227 fcpInterface.setFullAccessRequired(WRITING);
228 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
229 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
230 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
231 verifyReplyWithMessage("ReadOnlyPong");
235 public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsRestrictedFcpAccessForReadOnlyCommand() {
236 fcpInterface.setFullAccessRequired(NO);
237 fcpInterface.addCommand("ReadOnlyPing", new ReadOnlyPing());
238 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadOnlyPing").put("Identifier", "foo").get();
239 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
240 verifyReplyWithMessage("ReadOnlyPong");
244 public void testThatAnActiveFcpInterfaceRequiringFullAccessDoesNotAllowRestrictedFcpAccessForReadWriteCommand() {
245 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
246 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
247 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
248 verifyErrorWithCode("401");
252 public void testThatAnActiveFcpInterfaceRequiringFullAccessForWritesDoesNotAllowRestrictedFcpAccessForReadWriteCommand() {
253 fcpInterface.setFullAccessRequired(WRITING);
254 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
255 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
256 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
257 verifyErrorWithCode("401");
261 public void testThatAnActiveFcpInterfaceNotRequiringFullAccessAllowsRestrictedFcpAccessForReadWriteCommand() {
262 fcpInterface.setFullAccessRequired(NO);
263 fcpInterface.addCommand("ReadWritePing", new ReadWritePing());
264 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "ReadWritePing").put("Identifier", "foo").get();
265 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_RESTRICTED);
266 verifyReplyWithMessage("ReadWritePong");
270 public void testThatAFaultyCommandResultsInAnError() {
271 fcpInterface.addCommand("Faulty", new FaultyCommand());
272 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "Faulty").put("Identifier", "foo").get();
273 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
278 public void testThatAFaultyPluginReplySenderIsHandled() {
279 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "Faulty").put("Identifier", "foo").get();
280 fcpInterface.handle(new FaultyPluginReplySender(), fieldSet, null, ACCESS_FCP_FULL);
284 public void testThatACommandWithDataIsHandledCorrectly() throws IOException {
285 fcpInterface.addCommand("CommandWithData", new CommandWithData());
286 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "CommandWithData").put("Identifier", "foo").get();
287 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
288 verifyReplyWithMessage("ReturnedData");
289 assertThat(pluginReplySender.results.get(0).bucket, notNullValue());
290 assertThat(pluginReplySender.results.get(0).bucket.size(), is(3L));
291 assertThat(pluginReplySender.results.get(0).bucket.getInputStream(), delivers(new byte[] { 1, 2, 3 }));
295 public void testThatACommandWithABucketIsHandledCorrectly() throws IOException {
296 fcpInterface.addCommand("CommandWithBucket", new CommandWithBucket());
297 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "CommandWithBucket").put("Identifier", "foo").get();
298 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_FCP_FULL);
299 verifyReplyWithMessage("ReturnedBucket");
300 assertThat(pluginReplySender.results.get(0).bucket, notNullValue());
301 assertThat(pluginReplySender.results.get(0).bucket.size(), is(3L));
302 assertThat(pluginReplySender.results.get(0).bucket.getInputStream(), delivers(new byte[] { 4, 5, 6 }));
305 private Matcher<InputStream> delivers(final byte[] data) {
306 return new TypeSafeMatcher<InputStream>() {
307 byte[] readData = new byte[data.length];
310 protected boolean matchesSafely(InputStream inputStream) {
314 int r = inputStream.read();
316 return offset == data.length;
318 if (offset == data.length) {
321 if (data[offset] != (readData[offset] = (byte) r)) {
326 } catch (IOException ioe1) {
332 public void describeTo(Description description) {
333 description.appendValue(data);
337 protected void describeMismatchSafely(InputStream item, Description mismatchDescription) {
338 mismatchDescription.appendValue(readData);
343 private void verifyError() {
344 assertThat(pluginReplySender.results, hasSize(1));
345 assertThat(pluginReplySender.results.get(0).fieldSet, notNullValue());
346 assertThat(pluginReplySender.results.get(0).fieldSet.get("Message"), is("Error"));
349 private void verifyErrorWithCode(String errorCode) {
351 assertThat(pluginReplySender.results.get(0).fieldSet.get("ErrorCode"), is(errorCode));
354 private static class CapturingPluginReplySender extends PluginReplySender {
356 public final List<PluginReplySenderResult> results = Lists.newArrayList();
358 public CapturingPluginReplySender() {
363 public void send(SimpleFieldSet params, Bucket bucket) throws PluginNotFoundException {
364 results.add(new PluginReplySenderResult(params, bucket));
369 private static class PluginReplySenderResult {
371 public final SimpleFieldSet fieldSet;
372 public final Bucket bucket;
374 public PluginReplySenderResult(SimpleFieldSet fieldSet, Bucket bucket) {
375 this.fieldSet = fieldSet;
376 this.bucket = bucket;
381 private static class ReadOnlyPing extends AbstractSoneCommand {
383 public ReadOnlyPing() {
388 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
389 return new Response("ReadOnlyPong", new SimpleFieldSetBuilder().get());
394 private static class ReadWritePing extends AbstractSoneCommand {
396 public ReadWritePing() {
401 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
402 return new Response("ReadWritePong", new SimpleFieldSetBuilder().get());
407 private static class FaultyCommand extends AbstractSoneCommand {
409 public FaultyCommand() {
414 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
415 throw new RuntimeException("I’m faulty!");
420 private static class FaultyPluginReplySender extends PluginReplySender {
422 public FaultyPluginReplySender() {
427 public void send(SimpleFieldSet params, Bucket bucket) throws PluginNotFoundException {
428 throw new PluginNotFoundException();
433 private static class CommandWithData extends AbstractSoneCommand {
435 protected CommandWithData() {
440 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
441 return new Response("ReturnedData", new SimpleFieldSetBuilder().get(), new byte[] { 1, 2, 3 });
446 private static class CommandWithBucket extends AbstractSoneCommand {
448 protected CommandWithBucket() {
453 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
454 return new Response("ReturnedBucket", new SimpleFieldSetBuilder().get(), new ArrayBucket(new byte[] { 4, 5, 6 }));