/******************************************************************************** * CruiseControl, a Continuous Integration Toolkit * Copyright (c) 2001, ThoughtWorks, Inc. * 200 E. Randolph, 25th Floor * Chicago, IL 60601 USA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * + Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * + Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************************/ package net.sourceforge.cruisecontrol; import java.io.File; import java.net.URL; import java.net.URLDecoder; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.management.JMException; import javax.management.MBeanServer; import junit.framework.TestCase; import net.sourceforge.cruisecontrol.BuildQueueTest.TestListener; import net.sourceforge.cruisecontrol.builders.ExecBuilder; import net.sourceforge.cruisecontrol.labelincrementers.DefaultLabelIncrementer; import net.sourceforge.cruisecontrol.listeners.ListenerTestNestedPlugin; import net.sourceforge.cruisecontrol.listeners.ListenerTestOtherNestedPlugin; import net.sourceforge.cruisecontrol.listeners.ListenerTestPlugin; import net.sourceforge.cruisecontrol.util.OSEnvironment; import net.sourceforge.cruisecontrol.util.Util; import net.sourceforge.cruisecontrol.testutil.TestUtil; import org.jdom.Element; public class CruiseControlConfigTest extends TestCase { private final TestUtil.FilesToDelete filesToDelete = new TestUtil.FilesToDelete(); private CruiseControlConfig config; private File configFile; private File classpathDirectory; private File propertiesFile; private static final int ONE_SECOND = 1000; protected void setUp() throws Exception { URL url; url = this.getClass().getClassLoader().getResource("net/sourceforge/cruisecontrol/test.properties"); propertiesFile = new File(URLDecoder.decode(url.getPath(), "utf-8")); // Set up a CruiseControl config file for testing url = this.getClass().getClassLoader().getResource("net/sourceforge/cruisecontrol/testconfig.xml"); configFile = new File(URLDecoder.decode(url.getPath(), "utf-8")); classpathDirectory = configFile.getParentFile(); Element ccElement = Util.loadRootElement(configFile); Element testpropertiesdir = new Element("property"); testpropertiesdir.setAttribute("name", "test.properties.dir"); testpropertiesdir.setAttribute("value", propertiesFile.getParentFile().getAbsolutePath()); ccElement.addContent(0, testpropertiesdir); // The directory "foo" in the classpath is // created by CruiseControl by the log element // in testconfig.xml. filesToDelete.add(new File(classpathDirectory, "foo")); // The directories "${missing}", "mylogs", and "logs" // created by CruiseControl by the log element // in testconfig.xml. filesToDelete.add(new File(TestUtil.getTargetDir(), "${missing}")); filesToDelete.add(new File(TestUtil.getTargetDir(), "mylogs")); filesToDelete.add(new File(TestUtil.getTargetDir(), "logs")); config = new CruiseControlConfig(ccElement); } protected void tearDown() { filesToDelete.delete(); propertiesFile = null; configFile = null; classpathDirectory = null; config = null; } public void testUseNonDefaultProjects() throws CruiseControlException { Element root = new Element("cruisecontrol"); Element plugin = new Element("plugin"); plugin.setAttribute("name", "foo"); plugin.setAttribute("classname", DummyProject.class.getName()); root.addContent(0, plugin); Element dummy = new Element("foo"); dummy.setAttribute("name", "dummy"); root.addContent(dummy); config = new CruiseControlConfig(root); assertEquals(1, config.getProjectNames().size()); assertNotNull(config.getProject("dummy")); } public void testUseDefaultProjects() throws CruiseControlException { Element root = new Element("cruisecontrol"); Element plugin = new Element("plugin"); plugin.setAttribute("name", "foo"); plugin.setAttribute("from", "project"); // pluin from in-build CC project class root.addContent(0, plugin); Element dummy = new Element("foo"); dummy.setAttribute("name", "dummy"); root.addContent(dummy); Element content = new Element("schedule"); content.addContent(new Element("ant")); dummy.addContent(content); config = new CruiseControlConfig(root); assertEquals(1, config.getProjectNames().size()); assertNotNull(config.getProject("dummy")); } public static class DummyProject implements ProjectInterface { private String name; public void configureProject() throws CruiseControlException { } public void execute() { } public void setName(String name) { this.name = name; } public String getName() { return name; } public void getStateFromOldProject(ProjectInterface project) throws CruiseControlException { } public void register(MBeanServer server) throws JMException { } public void setBuildQueue(BuildQueue buildQueue) { } public void start() { } public void stop() { } public void validate() throws CruiseControlException { } public Map<String, String> getProperties() { return null; } public List<Modification> modificationsSinceLastBuild() { return null; } public Date successLastBuild() { return null; } public List<Modification> modificationsSince(Date since) { return null; } public String getLogDir() { return null; } public String successLastLabel() { return null; } public String successLastLog() { return null; } } public void testProjectNamesShouldMatchOrderInFile() { Set names = config.getProjectNames(); Iterator iter = names.iterator(); assertEquals("project1", (String) iter.next()); assertEquals("preconfigured.project", (String) iter.next()); assertEquals("project2", (String) iter.next()); assertEquals("project.global", (String) iter.next()); assertEquals("project4", (String) iter.next()); } public void testGetProjectNames() { assertEquals(24, config.getProjectNames().size()); } public void testGlobalProperty() throws Exception { String targetProject = "simple.global"; String expectedPropertyValue = "works!"; assertPropertyValue(targetProject, expectedPropertyValue); } private void assertPropertyValue(String targetProject, String expectedPropertyValue) { MockProjectInterface projConfig = (MockProjectInterface) config.getProject(targetProject); MockProjectInterface.Foo foo = projConfig.getFoo(); assertEquals(expectedPropertyValue, foo.getName()); } public void testProjectNameProperty() throws Exception { String targetProject = "project1"; String expectedPropertyValue = "project1"; assertPropertyValue(targetProject, expectedPropertyValue); } public void testProjectNameInGlobalProperty() throws Exception { String targetProject = "project.global"; String expectedPropertyValue = "project=project.global"; assertPropertyValue(targetProject, expectedPropertyValue); } public void testSimpleProperty() throws Exception { String targetProject = "simpleprops"; String expectedPropertyValue = "success!"; assertPropertyValue(targetProject, expectedPropertyValue); } public void testMultipleProperties() throws Exception { String targetProject = "multiprops"; String expectedPropertyValue = "one.two$three"; assertPropertyValue(targetProject, expectedPropertyValue); } public void testNestedProperties() throws Exception { String targetProject = "nestedprops"; String expectedPropertyValue = "threeLevelsDeep"; assertPropertyValue(targetProject, expectedPropertyValue); } public void testPropertyEclipsing() throws Exception { String targetProject = "eclipseprop"; String expectedPropertyValue = "eclipsed"; assertPropertyValue(targetProject, expectedPropertyValue); } public void testLoadPropertiesFromFile() throws Exception { String targetProject = "propsfromfile"; String expectedPropertyValue = "/home/cruise/logs/temp"; assertPropertyValue(targetProject, expectedPropertyValue); } // test that we are capable of resolving properties in all property attributes public void testPropertiesInProperties() throws Exception { String targetProject = "propsinpropsdef"; String expectedPropertyValue = new OSEnvironment().getVariableIgnoreCase("PATH"); assertPropertyValue(targetProject, expectedPropertyValue); } // test that we are capable of resolving properties redefined in various ways public void testPropertiesRedefine() throws Exception { ListenerTestPlugin listener; ProjectConfig projConfig = (ProjectConfig) config.getProject("inherit1"); List<Listener> listeners = projConfig.getListeners(); listener = (ListenerTestPlugin) listeners.get(0); assertEquals("override", listener.getString()); listener = (ListenerTestPlugin) listeners.get(1); assertEquals("test", listener.getString()); listener = (ListenerTestPlugin) listeners.get(2); assertEquals("filled_test", listener.getString()); listener = (ListenerTestPlugin) listeners.get(3); assertEquals("value", listener.getString()); projConfig = (ProjectConfig) config.getProject("inherit2"); listeners = projConfig.getListeners(); listener = (ListenerTestPlugin) listeners.get(0); assertEquals("works!", listener.getString()); listener = (ListenerTestPlugin) listeners.get(1); assertEquals("empty", listener.getString()); listener = (ListenerTestPlugin) listeners.get(2); assertEquals("filled_empty", listener.getString()); listener = (ListenerTestPlugin) listeners.get(3); assertEquals("temp", listener.getString()); } // test that we are capable of resolving properties redefined in various ways public void testCustomProperties() throws Exception { MockProjectInterface projConfig; MockProjectInterface.Foo foo; projConfig = (MockProjectInterface) config.getProject("customprops1"); foo = projConfig.getFoo(); assertEquals("mockval_value", foo.getName()); projConfig = (MockProjectInterface) config.getProject("customprops2"); foo = projConfig.getFoo(); assertEquals("mockval_customprops2", foo.getName()); projConfig = (MockProjectInterface) config.getProject("customprops3"); foo = projConfig.getFoo(); assertEquals("mockval_temp", foo.getName()); projConfig = (MockProjectInterface) config.getProject("customprops4"); foo = projConfig.getFoo(); assertEquals("mockval_justval", foo.getName()); projConfig = (MockProjectInterface) config.getProject("customprops5"); foo = projConfig.getFoo(); assertEquals("local-in-customprops5_filled", foo.getName()); projConfig = (MockProjectInterface) config.getProject("customprops6"); foo = projConfig.getFoo(); assertEquals("local-in-customprops6_filled_works!", foo.getName()); } // TODO backport /* public void testMissingProperty() { // there's in fact little need to check for both cases. // This will be hardcoded at some point and the default case. // Feel free to scrap the first if when checking it in. if (ProjectXMLHelper.FAIL_UPON_MISSING_PROPERTY) { try { createProjectXMLHelper("missingprop"); fail("A missing property should cause an exception!"); } catch (CruiseControlException expected) { } } else { try { createProjectXMLHelper("missingprop"); } catch (CruiseControlException unexpected) { fail(unexpected.getMessage()); } } } */ public void testPluginConfiguration() throws Exception { final ProjectConfig projConfig = (ProjectConfig) config.getProject("project4"); final PluginRegistry plugins = config.getProjectPlugins("project4"); assertEquals(ListenerTestPlugin.class, plugins.getPluginClass("testlistener")); assertEquals(ListenerTestNestedPlugin.class, plugins.getPluginClass("testnested")); final List listeners = projConfig.getListeners(); assertEquals(3, listeners.size()); final Listener listener0 = (Listener) listeners.get(0); assertEquals(ListenerTestPlugin.class, listener0.getClass()); final ListenerTestPlugin testListener0 = (ListenerTestPlugin) listener0; assertEquals("project4-0", testListener0.getString()); final Listener listener1 = (Listener) listeners.get(1); assertEquals(ListenerTestPlugin.class, listener1.getClass()); final ListenerTestPlugin testListener1 = (ListenerTestPlugin) listener1; assertEquals("listener1", testListener1.getString()); assertEquals("wrapper1", testListener1.getStringWrapper().getString()); final Listener listener2 = (Listener) listeners.get(2); assertEquals(ListenerTestPlugin.class, listener2.getClass()); final ListenerTestPlugin testListener2 = (ListenerTestPlugin) listener2; assertEquals("listener2", testListener2.getString()); // note this is in fact undefined behavior!! Because we added twice the stringwrapper // (first for the child, then for the parent). // this could probably fail depending on a different platform, except if Element.setContent() // specifies the order in which children are kept within the element. final String wrapper = testListener2.getStringWrapper().getString(); assertTrue("wrapper2-works!", "wrapper2-works!".equals(wrapper) || "wrapper1".equals(wrapper)); } public void testPluginConfigurationClassOverride() throws Exception { ProjectConfig projConfig = (ProjectConfig) config.getProject("project5"); PluginRegistry plugins = config.getProjectPlugins("project5"); assertEquals(ListenerTestPlugin.class, plugins.getPluginClass("testlistener")); assertEquals(ListenerTestOtherNestedPlugin.class, plugins.getPluginClass("testnested")); List listeners = projConfig.getListeners(); assertEquals(1, listeners.size()); Listener listener0 = (Listener) listeners.get(0); assertEquals(ListenerTestPlugin.class, listener0.getClass()); ListenerTestPlugin testListener0 = (ListenerTestPlugin) listener0; assertEquals("default", testListener0.getString()); ListenerTestNestedPlugin nested = testListener0.getNested(); assertTrue(nested instanceof ListenerTestOtherNestedPlugin); assertEquals("notshadowing", nested.getString()); assertEquals(null, nested.getOtherString()); assertEquals("otherother", ((ListenerTestOtherNestedPlugin) nested).getOtherOtherString()); } public void testPluginConfigurationInherit() throws Exception { ExecBuilder builder = new ExecBuilder(); // Get the working directory when not explicitly set builder.setCommand("foo"); builder.validate(); final String wdir = builder.getWorkingDir(); // project override1 ProjectConfig projConfig = (ProjectConfig) config.getProject("inherit1"); List builders = projConfig.getSchedule().getBuilders(); assertEquals(5, builders.size()); builder = (ExecBuilder)builders.get(0); assertEquals("cX", builder.getCommand()); assertEquals("dA", builder.getWorkingDir()); builder = (ExecBuilder)builders.get(1); assertEquals("cB", builder.getCommand()); assertEquals("dB", builder.getWorkingDir()); builder = (ExecBuilder)builders.get(2); assertEquals("cZ", builder.getCommand()); assertEquals(wdir, builder.getWorkingDir()); builder = (ExecBuilder)builders.get(3); assertEquals("c+", builder.getCommand()); assertEquals(wdir, builder.getWorkingDir()); builder = (ExecBuilder)builders.get(4); assertEquals("c*", builder.getCommand()); assertEquals("dE", builder.getWorkingDir()); // project override2 projConfig = (ProjectConfig) config.getProject("inherit2"); builders = projConfig.getSchedule().getBuilders(); assertEquals(5, builders.size()); builder = (ExecBuilder)builders.get(0); assertEquals("cX", builder.getCommand()); assertEquals("dA", builder.getWorkingDir()); builder = (ExecBuilder)builders.get(1); assertEquals("cB", builder.getCommand()); assertEquals("dB", builder.getWorkingDir()); builder = (ExecBuilder)builders.get(2); assertEquals("cX", builder.getCommand()); assertEquals("dA", builder.getWorkingDir()); builder = (ExecBuilder)builders.get(3); assertEquals("c+", builder.getCommand()); assertEquals(wdir, builder.getWorkingDir()); builder = (ExecBuilder)builders.get(4); assertEquals("c*", builder.getCommand()); assertEquals("dE", builder.getWorkingDir()); // project override1 projConfig = (ProjectConfig) config.getProject("inherit3"); builders = projConfig.getSchedule().getBuilders(); assertEquals(5, builders.size()); builder = (ExecBuilder)builders.get(0); assertEquals("foo", builder.getCommand()); assertEquals(wdir, builder.getWorkingDir()); builder = (ExecBuilder)builders.get(1); assertEquals("cB", builder.getCommand()); assertEquals("dB", builder.getWorkingDir()); builder = (ExecBuilder)builders.get(2); assertEquals("cZ", builder.getCommand()); assertEquals(wdir, builder.getWorkingDir()); builder = (ExecBuilder)builders.get(3); assertEquals("c+", builder.getCommand()); assertEquals(wdir, builder.getWorkingDir()); builder = (ExecBuilder)builders.get(4); assertEquals("c*", builder.getCommand()); assertEquals("dE", builder.getWorkingDir()); } // TODO DateFormat management was moved to Project.init() /* public void testDateFormat() throws Exception { final String originalFormat = DateFormatFactory.getFormat(); createProjectXMLHelper("dateformatfromproperty"); final String formatFromProperty = DateFormatFactory.getFormat(); DateFormatFactory.setFormat(DateFormatFactory.DEFAULT_FORMAT); assertEquals(DateFormatFactory.DEFAULT_FORMAT, originalFormat); assertEquals("MM/dd/yyyy HH:mm:ss a", formatFromProperty); assertFalse(originalFormat.equals(formatFromProperty)); } public void testPreconfigureDateFormat() throws Exception { final String originalFormat = DateFormatFactory.getFormat(); createProjectXMLHelper("dateformatpreconfigured"); final String formatFromProperty = DateFormatFactory.getFormat(); DateFormatFactory.setFormat(DateFormatFactory.DEFAULT_FORMAT); assertEquals(DateFormatFactory.DEFAULT_FORMAT, originalFormat); assertEquals("MM/dd/yyyy HH:mm:ss a", formatFromProperty); assertFalse(originalFormat.equals(formatFromProperty)); } */ public void testGetBootstrappers() { ProjectConfig projConfig = (ProjectConfig) config.getProject("preconfigured.project"); List bootstrappers = projConfig.getBootstrappers(); assertEquals(0, bootstrappers.size()); projConfig = (ProjectConfig) config.getProject("project2"); bootstrappers = projConfig.getBootstrappers(); assertEquals(1, bootstrappers.size()); } public void testGetSchedule() { ProjectConfig projConfig; // TODO /* projConfig = config.getConfig("project1"); try { projConfig.getSchedule(); fail("schedule should be a required element"); } catch (CruiseControlException expected) { } */ projConfig = (ProjectConfig) config.getProject("project2"); Schedule schedule = projConfig.getSchedule(); assertEquals(20 * ONE_SECOND, schedule.getInterval()); } public void testGetModificationSet() { ProjectConfig projConfig; // TODO /* projConfig = config.getConfig("project1"); try { projConfig.getModificationSet(); fail("modificationset should be a required element"); } catch (CruiseControlException expected) { } */ projConfig = (ProjectConfig) config.getProject("project2"); ModificationSet modSet = projConfig.getModificationSet(); assertEquals(10 * ONE_SECOND, modSet.getQuietPeriod()); } public void testGetLabelIncrementer() throws CruiseControlException { Element pluginElement = new Element("plugin"); pluginElement.setAttribute("name", CruiseControlConfig.LABEL_INCREMENTER); pluginElement.setAttribute("classname", DefaultLabelIncrementer.class.getName()); PluginRegistry.registerToRoot(pluginElement); ProjectConfig projConfig = (ProjectConfig) config.getProject("project2"); DefaultLabelIncrementer incrementer = (DefaultLabelIncrementer) projConfig.getLabelIncrementer(); assertTrue(incrementer.isValidLabel("build#9")); projConfig = (ProjectConfig) config.getProject("preconfigured.project"); incrementer = (DefaultLabelIncrementer) projConfig.getLabelIncrementer(); assertFalse(incrementer.isValidLabel("build#9")); } public void testPreconfigureLog() throws Exception { ProjectConfig projConfig = (ProjectConfig) config.getProject("logpreconfigured"); final Log log = projConfig.getLog(); assertEquals("mylogs/logpreconfigured", log.getLogDir()); assertEquals("utf128", log.getLogXmlEncoding()); assertEquals("logpreconfigured", log.getProjectName()); BuildLogger[] loggers = log.getLoggers(); assertEquals(2, loggers.length); } }