package net.sourceforge.cruisecontrol.launch; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jdom.Document; import org.jdom.Element; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import net.sourceforge.cruisecontrol.CruiseControlException; import net.sourceforge.cruisecontrol.testutil.TestCase; import net.sourceforge.cruisecontrol.testutil.TestUtil.FilesToDelete; import net.sourceforge.cruisecontrol.testutil.TestUtil.PropertiesRestorer; public class ConfigurationTest extends TestCase { private FilesToDelete filesToDelete = new FilesToDelete(); private PropertiesRestorer propRestorer = new PropertiesRestorer(); @Override protected void setUp() throws IOException { propRestorer.record(); } @Override protected void tearDown() throws Exception { filesToDelete.delete(); propRestorer.restore(); // // Must also release all properties added here // for (String name : System.getProperties().stringPropertyNames()) { // if (name.startsWith("cc.")) { // System.clearProperty(name); // } // } // final Properties props = System.getProperties(); // for (String name : props.stringPropertyNames()) { // if (name.startsWith("cc.")) { // props.remove(name); // } // } } /** Tests the default values of the options, when not overridden by anything else * @throws LaunchException */ public void testDefaultVals() throws CruiseControlException, LaunchException { final Configuration config = Configuration.getInstance(new String[0]); assertEquals("artifacts", config.getOptionRaw(Configuration.KEY_ARTIFACTS)); assertEquals("lib", config.getOptionRaw(Configuration.KEY_LIBRARY_DIR)); assertEquals("logs", config.getOptionRaw(Configuration.KEY_LOG_DIR)); assertEquals("projects", config.getOptionRaw(Configuration.KEY_PROJECTS)); assertEquals("cruisecontrol.xml", config.getOptionRaw(Configuration.KEY_CONFIG_FILE)); assertEquals("log4j.properties", config.getOptionRaw(Configuration.KEY_LOG4J_CONFIG)); assertEquals(false, config.getOptionBool(Configuration.KEY_NO_USER_LIB)); // libs // distDir // homeDir // None was set assertFalse(config.wasOptionSet(Configuration.KEY_ARTIFACTS)); assertFalse(config.wasOptionSet(Configuration.KEY_LIBRARY_DIR)); assertFalse(config.wasOptionSet(Configuration.KEY_LOG_DIR)); assertFalse(config.wasOptionSet(Configuration.KEY_PROJECTS)); assertFalse(config.wasOptionSet(Configuration.KEY_CONFIG_FILE)); assertFalse(config.wasOptionSet(Configuration.KEY_LOG4J_CONFIG)); assertFalse(config.wasOptionSet(Configuration.KEY_NO_USER_LIB)); // public static final String keyNoUserLib = "nouserlib"; // public static final String keyUserLibDirs = "lib"; // public static final String keyDistDir = "dist"; // public static final String keyHomeDir = "home"; // public static final String keyPrintHelp1 = "help"; // public static final String keyPrintHelp2 = "?"; // public static final String keyDebug = "debug"; // public static final String keyRMIPort = "rmiport"; // public static final String keyPort = "port"; // deprecated, use keyJMXPort // public static final String keyJMXPort = "jmxport"; // public static final String keyWebPort = "webport"; // public static final String keyWebAppPath = "webapppath"; // public static final String keyDashboard = "dashboard"; // public static final String keyDashboardUrl = "dashboardurl"; // public static final String keyPostInterval = "postinterval"; // public static final String keyPostEnabled = "postenabled"; // public static final String keyXLSPath = "xslpath"; // public static final String keyJettyXml = "jettyxml"; // public static final String keyPassword = "password"; // public static final String keyUser = "user"; // public static final String keyCCname = "ccname"; // public static final String keyJmxAgentUtil = "agentutil"; } /** Tests the case where there is no -XXX option on the command line */ public void testNoOptName() { String args[] = {"opt1", "val1", // options may be invalid since they are not recognised anyway "param", "a value", "lib", "path/1/with/subpath", "path", "path/3/"}; try { Configuration.getInstance(args); fail("Exception has been expected"); } catch (LaunchException e) { assertEquals("Unknown option opt1", e.getMessage()); } } /** Tests the overwrite of default values through command line arguments */ public void testArgumentVals() throws LaunchException, CruiseControlException { final String[] args = new String[] { "-"+Configuration.KEY_ARTIFACTS, "/tmp/artifacts", "-"+Configuration.KEY_LIBRARY_DIR, "/usr/share/cruisecontrol/lib", "-"+Configuration.KEY_LOG4J_CONFIG,"/var/spool/cruisecontrol/log4j.config", }; final Configuration config = Configuration.getInstance(args); // test changed assertEquals("/tmp/artifacts", config.getOptionRaw(Configuration.KEY_ARTIFACTS)); assertEquals("/usr/share/cruisecontrol/lib", config.getOptionRaw(Configuration.KEY_LIBRARY_DIR)); assertEquals("/var/spool/cruisecontrol/log4j.config", config.getOptionRaw(Configuration.KEY_LOG4J_CONFIG)); // Those has been set assertTrue(config.wasOptionSet(Configuration.KEY_ARTIFACTS)); assertTrue(config.wasOptionSet(Configuration.KEY_LIBRARY_DIR)); assertTrue(config.wasOptionSet(Configuration.KEY_LOG4J_CONFIG)); // Others must remain assertEquals("logs", config.getOptionRaw(Configuration.KEY_LOG_DIR)); assertEquals("projects", config.getOptionRaw(Configuration.KEY_PROJECTS)); assertEquals("cruisecontrol.xml", config.getOptionRaw(Configuration.KEY_CONFIG_FILE)); // So they have not been set assertFalse(config.wasOptionSet(Configuration.KEY_LOG_DIR)); assertFalse(config.wasOptionSet(Configuration.KEY_PROJECTS)); assertFalse(config.wasOptionSet(Configuration.KEY_CONFIG_FILE)); } /** Tests the overwrite of default values through properties */ public void testPropertiesVals() throws LaunchException, CruiseControlException { System.setProperty("cc."+Configuration.KEY_ARTIFACTS, "/tmp/cruise/artifacts"); System.setProperty("cc."+Configuration.KEY_LIBRARY_DIR, "/usr/share/cruise/lib"); System.setProperty("cc."+Configuration.KEY_LOG4J_CONFIG,"/var/spool/cruise/log4j.conf"); final Configuration config = Configuration.getInstance(new String[0]); // test changed assertEquals("/tmp/cruise/artifacts", config.getOptionRaw(Configuration.KEY_ARTIFACTS)); assertEquals("/usr/share/cruise/lib", config.getOptionRaw(Configuration.KEY_LIBRARY_DIR)); assertEquals("/var/spool/cruise/log4j.conf", config.getOptionRaw(Configuration.KEY_LOG4J_CONFIG)); // Those has been set assertTrue(config.wasOptionSet(Configuration.KEY_ARTIFACTS)); assertTrue(config.wasOptionSet(Configuration.KEY_LIBRARY_DIR)); assertTrue(config.wasOptionSet(Configuration.KEY_LOG4J_CONFIG)); // Others must remain assertEquals("logs", config.getOptionRaw(Configuration.KEY_LOG_DIR)); assertEquals("projects", config.getOptionRaw(Configuration.KEY_PROJECTS)); assertEquals("cruisecontrol.xml", config.getOptionRaw(Configuration.KEY_CONFIG_FILE)); // So they have not been set assertFalse(config.wasOptionSet(Configuration.KEY_LOG_DIR)); assertFalse(config.wasOptionSet(Configuration.KEY_PROJECTS)); assertFalse(config.wasOptionSet(Configuration.KEY_CONFIG_FILE)); } public void testConfigVals() throws LaunchException, CruiseControlException, IOException { final Map<String, String> opts = new HashMap<String, String>(); opts.put(Configuration.KEY_ARTIFACTS, "/home/CC/artifacts"); opts.put(Configuration.KEY_LIBRARY_DIR, "/usr/share/CC/lib"); opts.put(Configuration.KEY_LOG4J_CONFIG,"/var/spool/CC/log4j.conf"); final Element data = makeLauchXML(opts); final File xml = storeXML(data, filesToDelete.add("config.xml")); final Configuration config = Configuration.getInstance( new String[] {"-"+Configuration.KEY_CONFIG_FILE, xml.getAbsolutePath()}); // test changed assertEquals("/home/CC/artifacts", config.getOptionRaw(Configuration.KEY_ARTIFACTS)); assertEquals("/usr/share/CC/lib", config.getOptionRaw(Configuration.KEY_LIBRARY_DIR)); assertEquals("/var/spool/CC/log4j.conf", config.getOptionRaw(Configuration.KEY_LOG4J_CONFIG)); // Those has been set assertTrue(config.wasOptionSet(Configuration.KEY_ARTIFACTS)); assertTrue(config.wasOptionSet(Configuration.KEY_LIBRARY_DIR)); assertTrue(config.wasOptionSet(Configuration.KEY_LOG4J_CONFIG)); // Others must remain assertEquals("logs", config.getOptionRaw(Configuration.KEY_LOG_DIR)); assertEquals("projects", config.getOptionRaw(Configuration.KEY_PROJECTS)); assertEquals("cruisecontrol.xml", config.getOptionRaw(Configuration.KEY_CONFIG_FILE)); // must be default since no other has been specified // So they have not been set assertFalse(config.wasOptionSet(Configuration.KEY_LOG_DIR)); assertFalse(config.wasOptionSet(Configuration.KEY_PROJECTS)); assertFalse(config.wasOptionSet(Configuration.KEY_CONFIG_FILE)); } /** Tests various levels of data overriding */ public void testConfigOverride() throws LaunchException, CruiseControlException, IOException { // Configuration file, the lowest priority final Map<String, String> opts = new HashMap<String, String>(); opts.put(Configuration.KEY_ARTIFACTS, "/home/CC/artifacts"); opts.put(Configuration.KEY_LIBRARY_DIR, "/usr/share/CC/lib"); final Element data = makeLauchXML(opts); final File xml = storeXML(data, filesToDelete.add("config.xml")); // Properties - the highest priority, overrides config file System.setProperty("cc."+Configuration.KEY_ARTIFACTS, "/tmp/cruise/artifacts"); System.setProperty("cc."+Configuration.KEY_LIBRARY_DIR, "/usr/share/cruisecontrol/lib"); // command line options - overrides options from config and from properties final String[] args = new String[] { "-"+Configuration.KEY_ARTIFACTS, "/tmp/artifacts", "-"+Configuration.KEY_CONFIG_FILE, xml.getAbsolutePath() }; // Create the object final Configuration config = Configuration.getInstance(args); // test changed assertEquals("/tmp/artifacts", config.getOptionRaw(Configuration.KEY_ARTIFACTS)); assertEquals("/usr/share/cruisecontrol/lib", config.getOptionRaw(Configuration.KEY_LIBRARY_DIR)); } /** Tests if correct path to main config file is returned when the <launcher>...</launcher> * configuration stands on its own and points to an "external" main * <cruisecontrol>...</cruisecontrol> configuration. * * @throws Exception */ public void testLaunchSeparate() throws Exception { // Configuration file, referenced to an external file final Map<String, String> opts = new HashMap<String, String>(); opts.put(Configuration.KEY_CONFIG_FILE, "/home/CC/mainconfig.xml"); final Element launch = makeLauchXML(opts); final File xml = storeXML(launch, filesToDelete.add("launch.xml")); // command line options - overrides options from config final String[] args = new String[] { "-"+Configuration.KEY_CONFIG_FILE, xml.getAbsolutePath() }; // Create the object final Configuration config = Configuration.getInstance(args); // Must return path to the main configuration file! assertEquals("/home/CC/mainconfig.xml", config.getOptionRaw(Configuration.KEY_CONFIG_FILE)); } /** Tests if correct path to main config file is returned when the <launcher>...</launcher> configuration * is embedded in the main <cruisecontrol>...</cruisecontrol> configuration. * * @throws Exception */ public void testLaunchEmbedded() throws Exception { // Configuration file, referenced to an external file final Map<String, String> opts = new HashMap<String, String>(); opts.put(Configuration.KEY_CONFIG_FILE, "/home/CC/mainconfig.xml"); // should be ignored, even if presented! final Element launch = makeLauchXML(opts); final Element main = makeConfigXML(launch); // embeds <launcher> to the main config final File xml = storeXML(main, filesToDelete.add("cruisecontrol.xml")); // command line options - overrides options from config final String[] args = new String[] { "-"+Configuration.KEY_CONFIG_FILE, xml.getAbsolutePath() }; // Create the object final Configuration config = Configuration.getInstance(args); // Must return path to the main configuration file! assertEquals(xml.getAbsolutePath(), config.getOptionRaw(Configuration.KEY_CONFIG_FILE)); } /** Tests if default path to main config file is returned when the <launcher>...</launcher> * configuration stands on its own and DOES NOT point to an "external" main * <cruisecontrol>...</cruisecontrol> configuration. * * @throws Exception */ public void testConfigNotSet() throws Exception { // Configuration file, referenced to an external file final Element launch = makeLauchXML(new HashMap<String, String>()); final File xml = storeXML(launch, filesToDelete.add("launch.xml")); // command line options - overrides options from config final String[] args = new String[] { "-"+Configuration.KEY_CONFIG_FILE, xml.getAbsolutePath() }; // Create the object final Configuration config = Configuration.getInstance(args); // Must return default path to the main configuration file! assertEquals("cruisecontrol.xml", config.getOptionRaw(Configuration.KEY_CONFIG_FILE)); } public void testBoolArgs() throws Exception { Configuration config; config = Configuration.getInstance(new String[] {"-"+Configuration.KEY_DEBUG, "true"}); assertTrue(config.getOptionBool(Configuration.KEY_DEBUG)); config = Configuration.getInstance(new String[] {"-"+Configuration.KEY_DEBUG, "false"}); assertFalse(config.getOptionBool(Configuration.KEY_DEBUG)); // No true/false value set, must be true config = Configuration.getInstance(new String[] {"-"+Configuration.KEY_DEBUG}); assertTrue(config.getOptionBool(Configuration.KEY_DEBUG)); // Default is false to make the previous test meaningful config = Configuration.getInstance(new String[] {}); assertFalse(config.getOptionBool(Configuration.KEY_DEBUG)); } /** Tests the case where an option can be set multiple times in the <launcher>...</launcher> * XML element */ public void testMultiOpts() throws Exception { Configuration config; List<Map.Entry<String,String>> opts = new ArrayList<Map.Entry<String,String>>(); // Fill with values. Paths does not have to exist since Configuration.getOptionRaw() method // is used to ge the value opts.add(new AbstractMap.SimpleEntry<String, String>("lib", "path/1")); opts.add(new AbstractMap.SimpleEntry<String, String>("lib", "path/1/with/subpath/")); opts.add(new AbstractMap.SimpleEntry<String, String>("lib", "path/2")); opts.add(new AbstractMap.SimpleEntry<String, String>("lib", "path/3/with/even/more")); opts.add(new AbstractMap.SimpleEntry<String, String>("lib", "path_4_with_nonsence")); // Make XML config File confFile = storeXML(makeLauchXML(opts), filesToDelete.add("launch", ".conf")); config = Configuration.getInstance(new String[] {"-"+Configuration.KEY_CONFIG_FILE, confFile.getAbsolutePath()}); assertEquals("path/1" + Configuration.ITEM_SEPARATOR + "path/1/with/subpath/" + Configuration.ITEM_SEPARATOR + "path/2" + Configuration.ITEM_SEPARATOR + "path/3/with/even/more" + Configuration.ITEM_SEPARATOR + "path_4_with_nonsence", config.getOptionRaw(Configuration.KEY_USER_LIB_DIRS)); } /** Tests the case where an option can be set multiple times on the command line, i.e. * <code>-lib path/to/lib/1 -lib path/to/lib/3 -lib path/to/lib/2 ...</code> */ public void testMultiArgs() throws Exception { String args[] = { // Paths does not have to exist since Configuration.getOptionRaw() "-lib", "path/1/", // method is used to get the value "-lib", "path/1/with/subpath", "-lib", "path/2/", "-lib", "path/3/"}; Configuration config; config = Configuration.getInstance(args); assertEquals("path/1/" + Configuration.ITEM_SEPARATOR + "path/1/with/subpath" + Configuration.ITEM_SEPARATOR + "path/2/" + Configuration.ITEM_SEPARATOR + "path/3/", config.getOptionRaw(Configuration.KEY_USER_LIB_DIRS)); } /** Tests the case where an option is set multiple times, but an option contains forbidden separator */ public void testMultiArgsInvalid() throws Exception { String args[] = { "-lib", "path/1/", "-lib", "path/1/with/subpath", "-lib", "path/2/" + Configuration.ITEM_SEPARATOR + "and/one/more", "-lib", "path/3/"}; try { Configuration.getInstance(args); fail("Exception was expected!"); } catch(IllegalArgumentException exc) { // OK, here } } public void testFindFile() throws Exception { // Various files final File inAbsolutePath = filesToDelete.add("file1.xml"); final File inWorkingDir = filesToDelete.add(new File("file2.txt")); final File inHomeDir = filesToDelete.add(new File(new File(System.getProperty("user.home")).getAbsoluteFile(), "file3.txt")); Configuration config; String file; // absolute file = inAbsolutePath.getAbsolutePath(); makeLaunchConfig(inAbsolutePath, file); config = Configuration.getInstance(new String[] {"-"+Configuration.KEY_CONFIG_FILE, file}); assertTrue(new File(file).isAbsolute()); assertEquals(inAbsolutePath, config.getOptionFile(Configuration.KEY_CONFIG_FILE)); // in working dir file = inWorkingDir.getName(); makeLaunchConfig(inWorkingDir, file); config = Configuration.getInstance(new String[] {"-"+Configuration.KEY_CONFIG_FILE, file}); assertFalse(new File(file).isAbsolute()); assertEquals(inWorkingDir, config.getOptionFile(Configuration.KEY_CONFIG_FILE)); // in home dir file = inHomeDir.getName(); makeLaunchConfig(inHomeDir, file); config = Configuration.getInstance(new String[] {"-"+Configuration.KEY_CONFIG_FILE, file}); assertFalse(new File(file).isAbsolute()); assertEquals(inHomeDir, config.getOptionFile(Configuration.KEY_CONFIG_FILE)); } /** From the set of entries creates string with <launch> ... </launch> XML fragment with values * filled according to the items in the set */ public static Element makeLauchXML(final Map<String,String> opts) { return makeLauchXML(opts.entrySet()); } /** From the map, where keys are names of options, creates string with <launch> ... </launch> XML * fragment with values filled according to the map */ public static Element makeLauchXML(final Collection<Map.Entry<String,String>> opts) { Element root = new Element("launcher"); for (Map.Entry<String, String> item : opts) { Element conf = new Element(item.getKey()); conf.setText(item.getValue()); root.addContent(conf); } return root; } /** The given <launch> ... </launch> XML element embedds into the <cruisecontrol>...</cruisecontrol> * element */ public static Element makeConfigXML(final Element launchConf) { Element root = new Element("cruisecontrol"); root.addContent((Element) launchConf.clone()); return root; } /** Stores the given element to the given file */ public static File storeXML(final Element xml, final File file) throws IOException { final XMLOutputter out = new XMLOutputter(Format.getPrettyFormat()); out.output(new Document(xml), new FileOutputStream(file)); return file; } /** * Creates the XML file with the following format: * <pre> * <launcher> * <configfile>cruiseconfigFname</configfile> * <launcher> * </pre> * and stores it to launchConfigFname * * @param launchConfigFname the file to be created * @param cruiseConfigFname the content of <configfile>...</configfile> element * @throws IOException if the file cannot be created */ static private void makeLaunchConfig(final File launchConfigFname, final String cruiseConfigFname) throws IOException { Map<String, String> opts = new HashMap<String, String>(); Element xml; opts.put(Configuration.KEY_CONFIG_FILE, cruiseConfigFname); xml = makeLauchXML(opts); storeXML(xml, launchConfigFname); } }