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.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;
33 import java.io.IOException;
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.junit.Test;
50 * Unit test for {@link FcpInterface}.
52 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
54 public class FcpInterfaceTest {
56 private final Core core = mock(Core.class);
57 private final FcpInterface fcpInterface = new FcpInterface(core);
58 private final CapturingPluginReplySender pluginReplySender = new CapturingPluginReplySender();
60 public FcpInterfaceTest() {
61 fcpInterface.setActive(true);
62 fcpInterface.setFullAccessRequired(ALWAYS);
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");
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");
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");
90 public void testThatAnActiveFcpInterfaceReturnsAnErrorForAnUnknownMessage() {
91 SimpleFieldSet fieldSet = new SimpleFieldSetBuilder().put("Message", "Foo").get();
92 fcpInterface.handle(pluginReplySender, fieldSet, null, ACCESS_DIRECT);
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);
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");
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");
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");
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");
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");
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");
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");
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");
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");
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));
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");
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");
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");
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");
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");
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");
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");
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");
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");
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);
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);
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 }));
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 }));
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"));
308 private void verifyErrorWithCode(String errorCode) {
310 assertThat(pluginReplySender.results.get(0).fieldSet.get("ErrorCode"), is(errorCode));
313 private static class CapturingPluginReplySender extends PluginReplySender {
315 public final List<PluginReplySenderResult> results = Lists.newArrayList();
317 public CapturingPluginReplySender() {
322 public void send(SimpleFieldSet params, Bucket bucket) throws PluginNotFoundException {
323 results.add(new PluginReplySenderResult(params, bucket));
328 private static class PluginReplySenderResult {
330 public final SimpleFieldSet fieldSet;
331 public final Bucket bucket;
333 public PluginReplySenderResult(SimpleFieldSet fieldSet, Bucket bucket) {
334 this.fieldSet = fieldSet;
335 this.bucket = bucket;
340 private static class ReadOnlyPing extends AbstractSoneCommand {
342 public ReadOnlyPing() {
347 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
348 return new Response("ReadOnlyPong", new SimpleFieldSetBuilder().get());
353 private static class ReadWritePing extends AbstractSoneCommand {
355 public ReadWritePing() {
360 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
361 return new Response("ReadWritePong", new SimpleFieldSetBuilder().get());
366 private static class FaultyCommand extends AbstractSoneCommand {
368 public FaultyCommand() {
373 public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
374 throw new RuntimeException("I’m faulty!");
379 private static class FaultyPluginReplySender extends PluginReplySender {
381 public FaultyPluginReplySender() {
386 public void send(SimpleFieldSet params, Bucket bucket) throws PluginNotFoundException {
387 throw new PluginNotFoundException();
392 private static class CommandWithData extends AbstractSoneCommand {
394 protected CommandWithData() {
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 });
405 private static class CommandWithBucket extends AbstractSoneCommand {
407 protected CommandWithBucket() {
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 }));