+ @Test
+ public void defaultFcpClientCanModifyPeerNoteByName()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<Boolean> noteUpdated = fcpClient.modifyPeerNote().darknetComment("foo").byName("Friend1").execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "ModifyPeerNote",
+ "Identifier=" + identifier,
+ "NodeIdentifier=Friend1",
+ "PeerNoteType=1",
+ "NoteText=Zm9v",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "PeerNote",
+ "Identifier=" + identifier,
+ "NodeIdentifier=Friend1",
+ "NoteText=Zm9v",
+ "PeerNoteType=1",
+ "EndMessage"
+ );
+ assertThat(noteUpdated.get(), is(true));
+ }
+
+ @Test
+ public void defaultFcpClientKnowsPeerNoteWasNotModifiedOnUnknownNodeIdentifier()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<Boolean> noteUpdated = fcpClient.modifyPeerNote().darknetComment("foo").byName("Friend1").execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "ModifyPeerNote",
+ "Identifier=" + identifier,
+ "NodeIdentifier=Friend1",
+ "PeerNoteType=1",
+ "NoteText=Zm9v",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "UnknownNodeIdentifier",
+ "Identifier=" + identifier,
+ "NodeIdentifier=Friend1",
+ "EndMessage"
+ );
+ assertThat(noteUpdated.get(), is(false));
+ }
+
+ @Test
+ public void defaultFcpClientFailsToModifyPeerNoteWithoutPeerNote()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<Boolean> noteUpdated = fcpClient.modifyPeerNote().byName("Friend1").execute();
+ assertThat(noteUpdated.get(), is(false));
+ }
+
+ @Test
+ public void defaultFcpClientCanModifyPeerNoteByIdentifier()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<Boolean> noteUpdated = fcpClient.modifyPeerNote().darknetComment("foo").byIdentifier("id1").execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "ModifyPeerNote",
+ "Identifier=" + identifier,
+ "NodeIdentifier=id1",
+ "PeerNoteType=1",
+ "NoteText=Zm9v",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "PeerNote",
+ "Identifier=" + identifier,
+ "NodeIdentifier=id1",
+ "NoteText=Zm9v",
+ "PeerNoteType=1",
+ "EndMessage"
+ );
+ assertThat(noteUpdated.get(), is(true));
+ }
+
+ @Test
+ public void defaultFcpClientCanModifyPeerNoteByHostAndPort()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<Boolean> noteUpdated =
+ fcpClient.modifyPeerNote().darknetComment("foo").byHostAndPort("1.2.3.4", 5678).execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "ModifyPeerNote",
+ "Identifier=" + identifier,
+ "NodeIdentifier=1.2.3.4:5678",
+ "PeerNoteType=1",
+ "NoteText=Zm9v",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "PeerNote",
+ "Identifier=" + identifier,
+ "NodeIdentifier=1.2.3.4:5678",
+ "NoteText=Zm9v",
+ "PeerNoteType=1",
+ "EndMessage"
+ );
+ assertThat(noteUpdated.get(), is(true));
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithoutDetails()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "EndMessage"
+ );
+ assertThat(configData.get(), notNullValue());
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithCurrent()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().withCurrent().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "WithCurrent=true",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "current.foo=bar",
+ "EndMessage"
+ );
+ assertThat(configData.get().getCurrent("foo"), is("bar"));
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithDefaults()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().withDefaults().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "WithDefaults=true",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "default.foo=bar",
+ "EndMessage"
+ );
+ assertThat(configData.get().getDefault("foo"), is("bar"));
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithSortOrder()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().withSortOrder().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "WithSortOrder=true",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "sortOrder.foo=17",
+ "EndMessage"
+ );
+ assertThat(configData.get().getSortOrder("foo"), is(17));
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithExpertFlag()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().withExpertFlag().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "WithExpertFlag=true",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "expertFlag.foo=true",
+ "EndMessage"
+ );
+ assertThat(configData.get().getExpertFlag("foo"), is(true));
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithForceWriteFlag()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().withForceWriteFlag().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "WithForceWriteFlag=true",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "forceWriteFlag.foo=true",
+ "EndMessage"
+ );
+ assertThat(configData.get().getForceWriteFlag("foo"), is(true));
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithShortDescription()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().withShortDescription().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "WithShortDescription=true",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "shortDescription.foo=bar",
+ "EndMessage"
+ );
+ assertThat(configData.get().getShortDescription("foo"), is("bar"));
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithLongDescription()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().withLongDescription().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "WithLongDescription=true",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "longDescription.foo=bar",
+ "EndMessage"
+ );
+ assertThat(configData.get().getLongDescription("foo"), is("bar"));
+ }
+
+ @Test
+ public void defaultFcpClientCanGetConfigWithDataTypes()
+ throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> configData = fcpClient.getConfig().withDataTypes().execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "GetConfig",
+ "Identifier=" + identifier,
+ "WithDataTypes=true",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "dataType.foo=number",
+ "EndMessage"
+ );
+ assertThat(configData.get().getDataType("foo"), is("number"));
+ }
+
+ @Test
+ public void defaultFcpClientCanModifyConfigData() throws InterruptedException, ExecutionException, IOException {
+ Future<ConfigData> newConfigData = fcpClient.modifyConfig().set("foo.bar").to("baz").execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ assertThat(lines, matchesFcpMessage(
+ "ModifyConfig",
+ "Identifier=" + identifier,
+ "foo.bar=baz",
+ "EndMessage"
+ ));
+ fcpServer.writeLine(
+ "ConfigData",
+ "Identifier=" + identifier,
+ "current.foo.bar=baz",
+ "EndMessage"
+ );
+ assertThat(newConfigData.get().getCurrent("foo.bar"), is("baz"));
+ }
+
+ public class PluginCommands {
+
+ private List<String> lines;
+ private String identifier;
+
+ private void connectAndAssert(Supplier<Matcher<List<String>>> requestMatcher)
+ throws InterruptedException, ExecutionException, IOException {
+ connectNode();
+ lines = fcpServer.collectUntil(is("EndMessage"));
+ identifier = extractIdentifier(lines);
+ assertThat(lines, requestMatcher.get());
+ }
+
+ private void replyWithPluginInfo() throws IOException {
+ fcpServer.writeLine(
+ "PluginInfo",
+ "Identifier=" + identifier,
+ "PluginName=superPlugin",
+ "IsTalkable=true",
+ "LongVersion=1.2.3",
+ "Version=42",
+ "OriginUri=superPlugin",
+ "Started=true",
+ "EndMessage"
+ );
+ }
+
+ private void verifyPluginInfo(Future<Optional<PluginInfo>> pluginInfo)
+ throws InterruptedException, ExecutionException {
+ assertThat(pluginInfo.get().get().getPluginName(), is("superPlugin"));
+ assertThat(pluginInfo.get().get().getOriginalURI(), is("superPlugin"));
+ assertThat(pluginInfo.get().get().isTalkable(), is(true));
+ assertThat(pluginInfo.get().get().getVersion(), is("42"));
+ assertThat(pluginInfo.get().get().getLongVersion(), is("1.2.3"));
+ assertThat(pluginInfo.get().get().isStarted(), is(true));
+ }
+
+ public class LoadPlugin {
+
+ public class OfficialPlugins {
+
+ @Test
+ public void fromFreenet() throws ExecutionException, InterruptedException, IOException {
+ Future<Optional<PluginInfo>> pluginInfo =
+ fcpClient.loadPlugin().officialFromFreenet("superPlugin").execute();
+ connectAndAssert(() -> createMatcherForOfficialSource("freenet"));
+ assertThat(lines, not(contains(startsWith("Store="))));
+ replyWithPluginInfo();
+ verifyPluginInfo(pluginInfo);
+ }
+
+ @Test
+ public void persistentFromFreenet() throws ExecutionException, InterruptedException, IOException {
+ Future<Optional<PluginInfo>> pluginInfo =
+ fcpClient.loadPlugin().addToConfig().officialFromFreenet("superPlugin").execute();
+ connectAndAssert(() -> createMatcherForOfficialSource("freenet"));
+ assertThat(lines, hasItem("Store=true"));
+ replyWithPluginInfo();
+ verifyPluginInfo(pluginInfo);
+ }
+
+ @Test
+ public void fromHttps() throws ExecutionException, InterruptedException, IOException {
+ Future<Optional<PluginInfo>> pluginInfo =
+ fcpClient.loadPlugin().officialFromHttps("superPlugin").execute();
+ connectAndAssert(() -> createMatcherForOfficialSource("https"));
+ replyWithPluginInfo();
+ verifyPluginInfo(pluginInfo);
+ }
+
+ private Matcher<List<String>> createMatcherForOfficialSource(String officialSource) {
+ return matchesFcpMessage(
+ "LoadPlugin",
+ "Identifier=" + identifier,
+ "PluginURL=superPlugin",
+ "URLType=official",
+ "OfficialSource=" + officialSource,
+ "EndMessage"
+ );
+ }
+
+ }
+
+ public class FromOtherSources {
+
+ private static final String FILE_PATH = "/path/to/plugin.jar";
+ private static final String URL = "http://server.com/plugin.jar";
+ private static final String KEY = "KSK@plugin.jar";
+
+ @Test
+ public void fromFile() throws ExecutionException, InterruptedException, IOException {
+ Future<Optional<PluginInfo>> pluginInfo = fcpClient.loadPlugin().fromFile(FILE_PATH).execute();
+ connectAndAssert(() -> createMatcher("file", FILE_PATH));
+ replyWithPluginInfo();
+ verifyPluginInfo(pluginInfo);
+ }
+
+ @Test
+ public void fromUrl() throws ExecutionException, InterruptedException, IOException {
+ Future<Optional<PluginInfo>> pluginInfo = fcpClient.loadPlugin().fromUrl(URL).execute();
+ connectAndAssert(() -> createMatcher("url", URL));
+ replyWithPluginInfo();
+ verifyPluginInfo(pluginInfo);
+ }
+
+ @Test
+ public void fromFreenet() throws ExecutionException, InterruptedException, IOException {
+ Future<Optional<PluginInfo>> pluginInfo = fcpClient.loadPlugin().fromFreenet(KEY).execute();
+ connectAndAssert(() -> createMatcher("freenet", KEY));
+ replyWithPluginInfo();
+ verifyPluginInfo(pluginInfo);
+ }
+
+ private Matcher<List<String>> createMatcher(String urlType, String url) {
+ return matchesFcpMessage(
+ "LoadPlugin",
+ "Identifier=" + identifier,
+ "PluginURL=" + url,
+ "URLType=" + urlType,
+ "EndMessage"
+ );
+ }
+
+ }
+
+ public class Failed {
+
+ @Test
+ public void failedLoad() throws ExecutionException, InterruptedException, IOException {
+ Future<Optional<PluginInfo>> pluginInfo =
+ fcpClient.loadPlugin().officialFromFreenet("superPlugin").execute();
+ connectNode();
+ List<String> lines = fcpServer.collectUntil(is("EndMessage"));
+ String identifier = extractIdentifier(lines);
+ fcpServer.writeLine(
+ "ProtocolError",
+ "Identifier=" + identifier,
+ "EndMessage"
+ );
+ assertThat(pluginInfo.get().isPresent(), is(false));
+ }
+
+ }
+
+ }
+
+ public class ReloadPlugin {
+
+ private static final String CLASS_NAME = "foo.plugin.Plugin";
+
+ @Test
+ public void reloadingPluginWorks() throws InterruptedException, ExecutionException, IOException {
+ Future<Optional<PluginInfo>> pluginInfo = fcpClient.reloadPlugin().plugin(CLASS_NAME).execute();
+ connectAndAssert(() -> matchesFcpMessage(
+ "ReloadPlugin",
+ "Identifier=" + identifier,
+ "PluginName=" + CLASS_NAME,
+ "EndMessage"
+ ));
+ replyWithPluginInfo();
+ verifyPluginInfo(pluginInfo);
+ }
+
+ }
+
+ }
+