Mercurial > hg > release > thermostat-0.6
changeset 982:3723566e9c23
Allow plugins to contribute commands
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-February/005672.html
line wrap: on
line diff
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BasicCommandInfo.java Tue Feb 19 16:22:03 2013 +0100 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/BasicCommandInfo.java Tue Feb 19 12:08:47 2013 -0500 @@ -83,4 +83,8 @@ return resources; } + @Override + public String toString() { + return String.format("%s (description='%s', dependencies='%s')", name, description, resources.toString()); + } }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CompoundCommandInfoSource.java Tue Feb 19 16:22:03 2013 +0100 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CompoundCommandInfoSource.java Tue Feb 19 12:08:47 2013 -0500 @@ -66,8 +66,24 @@ @Override public CommandInfo getCommandInfo(String name) throws CommandInfoNotFoundException { - CommandInfo info1 = source1.getCommandInfo(name); - CommandInfo info2 = source2.getCommandInfo(name); + CommandInfo info1; + CommandInfo info2; + + try { + info1 = source1.getCommandInfo(name); + } catch (CommandInfoNotFoundException notFound) { + info1 = null; + } + try { + info2 = source2.getCommandInfo(name); + } catch (CommandInfoNotFoundException notFound) { + info2 = null; + } + + if (info1 == null && info2 == null) { + throw new CommandInfoNotFoundException(name); + } + if (info1 == null) { return info2; } if (info2 == null) { @@ -91,10 +107,9 @@ String cmdName = info.getName(); if (!result.containsKey(cmdName)) { result.put(cmdName, info); - continue; + } else { + result.put(cmdName, merge(result.get(cmdName), info)); } - - result.put(cmdName, merge(result.get(cmdName), info)); } return result.values();
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java Tue Feb 19 16:22:03 2013 +0100 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java Tue Feb 19 12:08:47 2013 -0500 @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -53,12 +54,16 @@ import com.redhat.thermostat.common.cli.CommandInfoSource; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.launcher.internal.PluginConfiguration.CommandExtensions; +import com.redhat.thermostat.launcher.internal.PluginConfiguration.NewCommand; public class PluginCommandInfoSource implements CommandInfoSource { - private Logger logger = LoggingUtils.getLogger(PluginCommandInfoSource.class); + private static final String PLUGIN_CONFIG_FILE = "plugin.xml"; - private Map<String, List<String>> allInfo = new HashMap<>(); + private static final Logger logger = LoggingUtils.getLogger(PluginCommandInfoSource.class); + + private Map<String, BasicCommandInfo> allNewCommands = new HashMap<>(); + private Map<String, List<String>> additionalBundlesForExistingCommands = new HashMap<>(); public PluginCommandInfoSource(String internalJarRoot, String pluginRootDir) { this(new File(internalJarRoot), new File(pluginRootDir), new PluginConfigurationParser()); @@ -74,28 +79,28 @@ for (File pluginDir : pluginDirs) { try { - File configurationFile = new File(pluginDir, "plugin.conf"); + File configurationFile = new File(pluginDir, PLUGIN_CONFIG_FILE); PluginConfiguration pluginConfig = parser.parse(configurationFile); loadNewAndExtendedCommands(internalJarRoot, pluginDir, pluginConfig); } catch (PluginConfigurationParseException | FileNotFoundException exception) { logger.log(Level.WARNING, "unable to parse plugin configuration", exception); } } + + combineCommands(); } private void loadNewAndExtendedCommands(File coreJarRoot, File pluginDir, PluginConfiguration pluginConfig) { - List<CommandExtensions> allExtensions = pluginConfig.getExtendedCommands(); - - for (CommandExtensions extension : allExtensions) { + for (CommandExtensions extension : pluginConfig.getExtendedCommands()) { String commandName = extension.getCommandName(); - List<String> pluginBundles = extension.getAdditionalBundles(); + List<String> pluginBundles = extension.getPluginBundles(); List<String> dependencyBundles = extension.getDepenedencyBundles(); logger.config("plugin at " + pluginDir + " contributes " + pluginBundles.size() + " bundles to comamnd '" + commandName + "'"); - List<String> bundlePaths = allInfo.get(commandName); + List<String> bundlePaths = additionalBundlesForExistingCommands.get(commandName); if (bundlePaths == null) { bundlePaths = new LinkedList<>(); } @@ -107,23 +112,73 @@ bundlePaths.add(new File(coreJarRoot, bundle).toURI().toString()); } - allInfo.put(commandName, bundlePaths); + additionalBundlesForExistingCommands.put(commandName, bundlePaths); + } + + for (NewCommand command : pluginConfig.getNewCommands()) { + String commandName = command.getCommandName(); + logger.config("plugin at " + pluginDir + " contributes new command '" + commandName + "'"); + + if (allNewCommands.containsKey(commandName)) { + throw new IllegalStateException("multiple plugins are providing the command " + commandName); + } + + List<String> bundlePaths = new LinkedList<>(); + + for (String bundle : command.getPluginBundles()) { + bundlePaths.add(new File(pluginDir, bundle).toURI().toString()); + } + for (String bundle : command.getDepenedencyBundles()) { + bundlePaths.add(new File(coreJarRoot, bundle).toURI().toString()); + } + BasicCommandInfo info = new BasicCommandInfo(commandName, + command.getDescription(), + command.getUsage(), + command.getOptions(), + bundlePaths); + + allNewCommands.put(commandName, info); + } + + } + + private void combineCommands() { + Iterator<Entry<String, List<String>>> iter = additionalBundlesForExistingCommands.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry<String, List<String>> entry = iter.next(); + if (allNewCommands.containsKey(entry.getKey())) { + BasicCommandInfo old = allNewCommands.get(entry.getKey()); + List<String> updatedResources = new ArrayList<>(); + updatedResources.addAll(old.getDependencyResourceNames()); + updatedResources.addAll(entry.getValue()); + BasicCommandInfo updated = new BasicCommandInfo(old.getName(), + old.getDescription(), + old.getUsage(), + old.getOptions(), + updatedResources); + allNewCommands.put(entry.getKey(), updated); + iter.remove(); + } } } @Override public CommandInfo getCommandInfo(String name) throws CommandInfoNotFoundException { - List<String> bundles = allInfo.get(name); - if (bundles == null) { - return null; + if (allNewCommands.containsKey(name)) { + return allNewCommands.get(name); } - return new BasicCommandInfo(name, null, null, null, bundles); + List<String> bundles = additionalBundlesForExistingCommands.get(name); + if (bundles != null) { + return new BasicCommandInfo(name, null, null, null, bundles); + } + throw new CommandInfoNotFoundException(name); } @Override public Collection<CommandInfo> getCommandInfos() { List<CommandInfo> result = new ArrayList<>(); - for (Entry<String, List<String>> entry : allInfo.entrySet()) { + result.addAll(allNewCommands.values()); + for (Entry<String, List<String>> entry : additionalBundlesForExistingCommands.entrySet()) { result.add(new BasicCommandInfo(entry.getKey(), null, null, null, entry.getValue())); } return result;
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java Tue Feb 19 16:22:03 2013 +0100 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java Tue Feb 19 12:08:47 2013 -0500 @@ -75,7 +75,7 @@ return commandName; } - public List<String> getAdditionalBundles() { + public List<String> getPluginBundles() { return Collections.unmodifiableList(additionalResources); } @@ -119,11 +119,11 @@ return options; } - public List<String> getAdditionalBundles() { + public List<String> getPluginBundles() { return Collections.unmodifiableList(additionalResources); } - public List<String> getCoreDepenedencyBundles() { + public List<String> getDepenedencyBundles() { return Collections.unmodifiableList(coreDeps); } }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java Tue Feb 19 16:22:03 2013 +0100 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java Tue Feb 19 12:08:47 2013 -0500 @@ -42,8 +42,10 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -56,18 +58,27 @@ import org.xml.sax.SAXException; import com.redhat.thermostat.common.Pair; +import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.launcher.internal.PluginConfiguration.CommandExtensions; import com.redhat.thermostat.launcher.internal.PluginConfiguration.NewCommand; +/** + * Parses the configuration of a plugin as specified in an {@code File} or an + * {@code InputStream}. + * <p> + * This class is thread-safe + */ public class PluginConfigurationParser { - // no state :) + private static final Logger logger = LoggingUtils.getLogger(PluginConfigurationParser.class); + + // thread safe because there is no state :) public PluginConfiguration parse(File configurationFile) throws FileNotFoundException { - return parse(new FileInputStream(configurationFile)); + return parse(configurationFile.getParentFile().getName(), new FileInputStream(configurationFile)); } - public PluginConfiguration parse(InputStream configurationStream) { + public PluginConfiguration parse(String pluginName, InputStream configurationStream) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); @@ -76,13 +87,13 @@ if (rootNode == null) { throw new PluginConfigurationParseException("no configuration found"); } - return parseRootElement(rootNode); + return parseRootElement(pluginName, rootNode); } catch (ParserConfigurationException | SAXException | IOException exception) { throw new PluginConfigurationParseException("failed to parse plugin configuration", exception); } } - private PluginConfiguration parseRootElement(Node root) { + private PluginConfiguration parseRootElement(String pluginName, Node root) { List<NewCommand> newCommands = Collections.emptyList(); List<CommandExtensions> extensions = Collections.emptyList(); @@ -92,7 +103,7 @@ for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeName().equals("commands")) { - commands = parseCommands(node); + commands = parseCommands(pluginName, node); } } } @@ -100,22 +111,31 @@ return new PluginConfiguration(commands.getFirst(), commands.getSecond()); } - private Pair<List<NewCommand>, List<CommandExtensions>> parseCommands(Node commandsNode) { + private Pair<List<NewCommand>, List<CommandExtensions>> parseCommands(String pluginName, Node commandsNode) { List<NewCommand> newCommands = new ArrayList<NewCommand>(); List<CommandExtensions> extendedCommands = new ArrayList<CommandExtensions>(); NodeList childNodes = commandsNode.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node node = childNodes.item(i); - if (node.getNodeName().equals("new")) { - newCommands.add(parseNewCommand(node)); - } else if (node.getNodeName().equals("existing")) { - extendedCommands.add(parseAdditionsToExistingCommand(node)); + if (node.getNodeName().equals("command")) { + String type = node.getAttributes().getNamedItem("type").getNodeValue(); + if (type.equals("extends")) { + CommandExtensions additions = parseAdditionsToExistingCommand(pluginName, node); + if (additions != null) { + extendedCommands.add(additions); + } + } else if (type.equals("provides")) { + NewCommand newCmd = parseNewCommand(pluginName, node); + if (newCmd != null) { + newCommands.add(newCmd); + } + } } } return new Pair<>(newCommands, extendedCommands); } - private CommandExtensions parseAdditionsToExistingCommand(Node commandNode) { + private CommandExtensions parseAdditionsToExistingCommand(String pluginName, Node commandNode) { String name = null; List<String> bundles = new ArrayList<>(); List<String> dependencies = new ArrayList<>(); @@ -126,31 +146,23 @@ if (node.getNodeName().equals("name")) { name = node.getTextContent(); } else if (node.getNodeName().equals("bundles")) { - String[] bundleNames = node.getTextContent().split(","); - for (String bundleName : bundleNames) { - if (bundleName.trim().length() == 0) { - continue; - } - bundles.add(bundleName.trim()); - } + bundles.addAll(parseBundles(node)); } else if (node.getNodeName().equals("dependencies")) { - String[] dependencyNames = node.getTextContent().split(","); - for (String bundleName : dependencyNames) { - if (bundleName.trim().length() == 0) { - continue; - } - dependencies.add(bundleName); - } + dependencies.addAll(parseDependencies(node)); } } + if (name == null) { + logger.warning("plugin " + pluginName + " provides extensions without specifying the command"); + return null; + } return new CommandExtensions(name, bundles, dependencies); } - private NewCommand parseNewCommand(Node commandNode) { + private NewCommand parseNewCommand(String pluginName, Node commandNode) { String name = null; String usage = null; String description = null; - Options options = null; + Options options = new Options(); List<String> bundles = new ArrayList<>(); List<String> dependencies = new ArrayList<>(); @@ -166,29 +178,50 @@ } else if (node.getNodeName().equals("arguments")) { options = parseArguments(node); } else if (node.getNodeName().equals("bundles")) { - String[] bundleNames = node.getTextContent().split(","); - for (String bundleName : bundleNames) { - if (bundleName.trim().length() == 0) { - continue; - } - bundles.add(bundleName); - } + bundles.addAll(parseBundles(node)); } else if (node.getNodeName().equals("dependencies")) { - String[] dependencyNames = node.getTextContent().split(","); - for (String bundleName : dependencyNames) { - if (bundleName.trim().length() == 0) { - continue; - } - dependencies.add(bundleName); - } + dependencies.addAll(parseDependencies(node)); } } - return new NewCommand(name, usage, description, options, bundles, dependencies); + + if (name == null || usage == null || description == null) { + logger.warning("plugin " + pluginName + " provides an incomplete new command: " + + "name='" + name + "', usage='" + usage + "', description='" + description + "', options='" + options + "'"); + return null; + } else { + return new NewCommand(name, usage, description, options, bundles, dependencies); + } + } + + private Collection<String> parseBundles(Node bundlesNode) { + List<String> bundles = new ArrayList<>(); + NodeList nodes = bundlesNode.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeName().equals("bundle")) { + String bundleName = node.getTextContent(); + bundles.add(bundleName); + } + } + return bundles; + } + + private Collection<String> parseDependencies(Node dependenciesNode) { + List<String> dependencies = new ArrayList<>(); + NodeList nodes = dependenciesNode.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeName().equals("dependency")) { + String bundleName = node.getTextContent(); + dependencies.add(bundleName); + } + } + return dependencies; } private Options parseArguments(Node argumentsNode) { - // need to identify a way to express arguments - return null; + // TODO need to identify a way to express arguments + return new Options(); } }
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BasicCommandInfoTest.java Tue Feb 19 16:22:03 2013 +0100 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/BasicCommandInfoTest.java Tue Feb 19 12:08:47 2013 -0500 @@ -48,9 +48,9 @@ @Test public void testBasics() { - final String NAME = "name"; - final String DESCRIPTION = "description"; - final String USAGE = "usage"; + final String NAME = "the_name"; + final String DESCRIPTION = "some-description"; + final String USAGE = "some-usage"; final Options OPTIONS = new Options(); final List<String> RESOURCES = Collections.emptyList(); @@ -62,5 +62,6 @@ assertEquals(OPTIONS, info.getOptions()); assertEquals(RESOURCES, info.getDependencyResourceNames()); + assertEquals(String.format("%s (description='%s', dependencies='%s')", NAME, DESCRIPTION, RESOURCES.toString()), info.toString()); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/CompoundCommandInfoSourceTest.java Tue Feb 19 12:08:47 2013 -0500 @@ -0,0 +1,154 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher.internal; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.cli.Options; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.cli.CommandInfo; +import com.redhat.thermostat.common.cli.CommandInfoNotFoundException; +import com.redhat.thermostat.common.cli.CommandInfoSource; + +public class CompoundCommandInfoSourceTest { + + private CommandInfoSource source1; + private CommandInfoSource source2; + private CompoundCommandInfoSource compoundSource; + + @Before + public void setUp() { + source1 = mock(CommandInfoSource.class); + source2 = mock(CommandInfoSource.class); + + compoundSource = new CompoundCommandInfoSource(source1, source2); + } + + @Test(expected = CommandInfoNotFoundException.class) + public void verifyExceptionThrownOnUnknownCommand() { + String NAME = "test-command-please-ignore"; + when(source1.getCommandInfo(NAME)).thenThrow(new CommandInfoNotFoundException(NAME)); + when(source2.getCommandInfo(NAME)).thenThrow(new CommandInfoNotFoundException(NAME)); + + compoundSource.getCommandInfo(NAME); + } + + @Test + public void verifyGetCommandInfoDelegatesToSource1() { + CommandInfo cmdInfo = mock(CommandInfo.class); + String NAME = "test-command-please-ignore"; + when(source1.getCommandInfo(NAME)).thenReturn(cmdInfo); + when(source2.getCommandInfo(NAME)).thenThrow(new CommandInfoNotFoundException(NAME)); + + CommandInfo result = compoundSource.getCommandInfo(NAME); + assertEquals(cmdInfo, result); + } + + @Test + public void verifyGetCommandInfoDelegatesToSource2() { + CommandInfo cmdInfo = mock(CommandInfo.class); + String NAME = "test-command-please-ignore"; + when(source1.getCommandInfo(NAME)).thenThrow(new CommandInfoNotFoundException(NAME)); + when(source2.getCommandInfo(NAME)).thenReturn(cmdInfo); + + CommandInfo result = compoundSource.getCommandInfo(NAME); + assertEquals(cmdInfo, result); + } + + @Test + public void verifyGetCommandInfoMergesResultFromBothSources() { + String NAME = "test-command-please-ignore"; + String DESCRIPTION = "test-description"; + String USAGE = "test-usage"; + Options OPTIONS = new Options(); + List<String> DEPS1 = Arrays.asList("1test1", "1test2"); + List<String> DEPS2 = Arrays.asList("2test1"); + + CommandInfo cmdInfo1 = mock(CommandInfo.class); + when(cmdInfo1.getName()).thenReturn(NAME); + when(cmdInfo1.getDescription()).thenReturn(DESCRIPTION); + when(cmdInfo1.getUsage()).thenReturn(USAGE); + when(cmdInfo1.getOptions()).thenReturn(OPTIONS); + when(cmdInfo1.getDependencyResourceNames()).thenReturn(DEPS1); + + CommandInfo cmdInfo2 = mock(CommandInfo.class); + when(cmdInfo2.getName()).thenReturn(NAME); + when(cmdInfo2.getDependencyResourceNames()).thenReturn(DEPS2); + + when(source1.getCommandInfo(NAME)).thenReturn(cmdInfo1); + when(source2.getCommandInfo(NAME)).thenReturn(cmdInfo2); + + CommandInfo result = compoundSource.getCommandInfo(NAME); + assertEquals(NAME, result.getName()); + assertEquals(DESCRIPTION, result.getDescription()); + assertEquals(USAGE, result.getUsage()); + assertEquals(OPTIONS, result.getOptions()); + + ArrayList<String> combined = new ArrayList<>(DEPS1); + combined.addAll(DEPS2); + assertEquals(combined, result.getDependencyResourceNames()); + } + + @Test + public void verifyGetCommandInfosMergesResultsFromBothSources() { + CommandInfo cmdInfo11 = mock(CommandInfo.class); + when(cmdInfo11.getName()).thenReturn("cmd1"); + CommandInfo cmdInfo12 = mock(CommandInfo.class); + when(cmdInfo12.getName()).thenReturn("cmd2"); + + when(source1.getCommandInfos()).thenReturn(Arrays.asList(cmdInfo11, cmdInfo12)); + + CommandInfo cmdInfo21 = mock(CommandInfo.class); + when(cmdInfo21.getName()).thenReturn("cmd3"); + CommandInfo cmdInfo22 = mock(CommandInfo.class); + when(cmdInfo22.getName()).thenReturn("cmd2"); + + when(source2.getCommandInfos()).thenReturn(Arrays.asList(cmdInfo21, cmdInfo22)); + + Collection<CommandInfo> results = compoundSource.getCommandInfos(); + + } +}
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java Tue Feb 19 16:22:03 2013 +0100 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java Tue Feb 19 12:08:47 2013 -0500 @@ -49,18 +49,22 @@ import java.util.Arrays; import java.util.List; +import org.apache.commons.cli.Options; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import com.redhat.thermostat.common.cli.CommandInfo; +import com.redhat.thermostat.common.cli.CommandInfoNotFoundException; import com.redhat.thermostat.launcher.internal.PluginConfiguration.CommandExtensions; +import com.redhat.thermostat.launcher.internal.PluginConfiguration.NewCommand; public class PluginCommandInfoSourceTest { // name paths so anything tying to use them/create them will blow up private static final String PLUGIN_ROOT = "/fake/${PLUGIN_ROOT}"; private static final String JAR_ROOT = "/fake/${JAR_ROOT}"; + private File jarRootDir; private File pluginRootDir; private PluginConfigurationParser parser; @@ -92,7 +96,7 @@ List<File> configurationFiles = configFilesCaptor.getAllValues(); assertEquals(pluginDirs.length, configurationFiles.size()); for (int i = 0; i < pluginDirs.length; i++) { - assertEquals(new File(pluginDirs[i], "plugin.conf"), configurationFiles.get(i)); + assertEquals(new File(pluginDirs[i], "plugin.xml"), configurationFiles.get(i)); } } @@ -106,11 +110,18 @@ PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir, pluginRootDir, parser); } + @Test(expected = CommandInfoNotFoundException.class) + public void verifyMissingCommandInfo() { + PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir, pluginRootDir, parser); + + source.getCommandInfo("TEST"); + } + @Test public void verifyCommandInfoObjectsToExtendExistingCommandsAreCreated() { CommandExtensions extensions = mock(CommandExtensions.class); when(extensions.getCommandName()).thenReturn("command-name"); - when(extensions.getAdditionalBundles()).thenReturn(Arrays.asList("additional-bundle")); + when(extensions.getPluginBundles()).thenReturn(Arrays.asList("additional-bundle")); when(extensions.getDepenedencyBundles()).thenReturn(Arrays.asList("dependency-bundle")); when(parserResult.getExtendedCommands()).thenReturn(Arrays.asList(extensions)); @@ -130,4 +141,43 @@ assertTrue(info.getDependencyResourceNames().contains(expectedDep2Name)); } + @Test + public void verifyCommandInfoObjectsForNewComamndsAreCreated() { + final String NAME = "command-name"; + final String DESCRIPTION = "description of the command"; + final String USAGE = "usage"; + final Options OPTIONS = new Options(); + final String PLUGIN_BUNDLE = "plugin-bundle.jar"; + final String DEPENDENCY_BUNDLE = "dependency-bundle.jar"; + + NewCommand cmd = mock(NewCommand.class); + when(cmd.getCommandName()).thenReturn(NAME); + when(cmd.getDescription()).thenReturn(DESCRIPTION); + when(cmd.getUsage()).thenReturn(USAGE); + when(cmd.getOptions()).thenReturn(OPTIONS); + when(cmd.getPluginBundles()).thenReturn(Arrays.asList(PLUGIN_BUNDLE)); + when(cmd.getDepenedencyBundles()).thenReturn(Arrays.asList(DEPENDENCY_BUNDLE)); + + when(parserResult.getNewCommands()).thenReturn(Arrays.asList(cmd)); + + File[] pluginDirs = new File[] { new File(PLUGIN_ROOT, "plugin1") }; + when(pluginRootDir.listFiles()).thenReturn(pluginDirs); + + PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir, pluginRootDir, parser); + + CommandInfo result = source.getCommandInfo(NAME); + + assertEquals(NAME, result.getName()); + assertEquals(DESCRIPTION, result.getDescription()); + assertEquals(USAGE, result.getUsage()); + assertEquals(OPTIONS, result.getOptions()); + + String expectedDep1Name = new File(PLUGIN_ROOT + "/plugin1/" + PLUGIN_BUNDLE).toURI().toString(); + String expectedDep2Name = new File(JAR_ROOT + "/" + DEPENDENCY_BUNDLE).toURI().toString(); + + List<String> deps = result.getDependencyResourceNames(); + assertEquals(2, deps.size()); + assertTrue(deps.contains(expectedDep1Name)); + assertTrue(deps.contains(expectedDep2Name)); + } }
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java Tue Feb 19 16:22:03 2013 +0100 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java Tue Feb 19 12:08:47 2013 -0500 @@ -37,6 +37,7 @@ package com.redhat.thermostat.launcher.internal; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; @@ -44,6 +45,7 @@ import java.util.Arrays; import java.util.List; +import org.apache.commons.cli.Options; import org.junit.Test; import com.redhat.thermostat.launcher.internal.PluginConfiguration.CommandExtensions; @@ -55,7 +57,7 @@ public void testEmptyConfigurationThrowsException() throws UnsupportedEncodingException { String config = "<?xml version=\"1.0\"?>\n"; PluginConfigurationParser parser = new PluginConfigurationParser(); - parser.parse(new ByteArrayInputStream(config.getBytes("UTF-8"))); + parser.parse("test", new ByteArrayInputStream(config.getBytes("UTF-8"))); fail("should not reach here"); } @@ -66,7 +68,7 @@ "<?xml version=\"1.0\"?>\n" + "<plugin>\n" + "</plugin>"; - PluginConfiguration result = parser.parse(new ByteArrayInputStream(config.getBytes("UTF-8"))); + PluginConfiguration result = parser.parse("test", new ByteArrayInputStream(config.getBytes("UTF-8"))); assertEquals(0, result.getExtendedCommands().size()); assertEquals(0, result.getNewCommands().size()); @@ -77,16 +79,22 @@ String config = "<?xml version=\"1.0\"?>\n" + "<plugin>\n" + " <commands>\n" + - " <existing>\n" + + " <command type='extends'>\n" + " <name>test</name>\n" + - " <bundles>foo,bar,baz,</bundles>\n" + - " <dependencies>thermostat-foo</dependencies>\n" + - " </existing>\n" + + " <bundles>\n" + + " <bundle>foo</bundle>\n" + + " <bundle>bar</bundle>\n" + + " <bundle>baz</bundle>\n" + + " </bundles>\n" + + " <dependencies>\n" + + " <dependency>thermostat-foo</dependency>\n" + + " </dependencies>\n" + + " </command>\n" + " </commands>\n" + "</plugin>"; PluginConfiguration result = new PluginConfigurationParser() - .parse(new ByteArrayInputStream(config.getBytes("UTF-8"))); + .parse("test", new ByteArrayInputStream(config.getBytes("UTF-8"))); assertEquals(0, result.getNewCommands().size()); @@ -95,7 +103,7 @@ CommandExtensions first = extensions.get(0); assertEquals("test", first.getCommandName()); - assertEquals(Arrays.asList("foo", "bar", "baz"), first.getAdditionalBundles()); + assertEquals(Arrays.asList("foo", "bar", "baz"), first.getPluginBundles()); assertEquals(Arrays.asList("thermostat-foo"), first.getDepenedencyBundles()); } @@ -104,18 +112,24 @@ String config = "<?xml version=\"1.0\"?>\n" + "<plugin>\n" + " <commands>\n" + - " <new>\n" + + " <command type='provides'>\n" + " <name>test</name>\n" + " <usage>usage: test</usage>\n" + " <description>description</description>\n" + - " <bundles>foo,bar,baz,</bundles>\n" + - " <dependencies>thermostat-foo</dependencies>\n" + - " </new>\n" + + " <bundles>\n" + + " <bundle>foo</bundle>\n" + + " <bundle>bar</bundle>\n" + + " <bundle>baz</bundle>\n" + + " </bundles>\n" + + " <dependencies>\n" + + " <dependency>thermostat-foo</dependency>\n" + + " </dependencies>\n" + + " </command>\n" + " </commands>\n" + "</plugin>"; PluginConfiguration result = new PluginConfigurationParser() - .parse(new ByteArrayInputStream(config.getBytes("UTF-8"))); + .parse("test", new ByteArrayInputStream(config.getBytes("UTF-8"))); List<CommandExtensions> extensions = result.getExtendedCommands(); assertEquals(0, extensions.size()); @@ -127,9 +141,11 @@ assertEquals("test", newCommand.getCommandName()); assertEquals("usage: test", newCommand.getUsage()); assertEquals("description", newCommand.getDescription()); - assertEquals(null, newCommand.getOptions()); - assertEquals(Arrays.asList("foo", "bar", "baz"), newCommand.getAdditionalBundles()); - assertEquals(Arrays.asList("thermostat-foo"), newCommand.getCoreDepenedencyBundles()); + Options opts = newCommand.getOptions(); + assertTrue(opts.getOptions().isEmpty()); + assertTrue(opts.getRequiredOptions().isEmpty()); + assertEquals(Arrays.asList("foo", "bar", "baz"), newCommand.getPluginBundles()); + assertEquals(Arrays.asList("thermostat-foo"), newCommand.getDepenedencyBundles()); } }