/******************************************************************************** * CruiseControl, a Continuous Integration Toolkit * Copyright (c) 2003, 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.builders; import junit.framework.TestCase; import net.sourceforge.cruisecontrol.CruiseControlException; import net.sourceforge.cruisecontrol.testutil.TestUtil; import net.sourceforge.cruisecontrol.util.Commandline; import net.sourceforge.cruisecontrol.util.IO; import net.sourceforge.cruisecontrol.util.Util; import org.jdom.Element; import java.io.File; import java.util.List; import java.util.HashMap; public class MavenBuilderTest extends TestCase { private static final String MOCK_SUCCESS = "successful build"; private static final String MOCK_BUILD_FAILURE = "failed build"; private static final String MOCK_DOWNLOAD_FAILURE = "download failure"; public void testValidate() throws Exception { MavenBuilder mb = new MavenBuilder(); try { mb.validate(); fail("MavenBuilder should throw exceptions when required fields are not set."); } catch (CruiseControlException e) { assertTrue(true); } // these files must also exist for MavenBuilder to be happy. File testScript = File.createTempFile("MavenBuilderTest.testValidate", "_testmaven.bat"); testScript.deleteOnExit(); makeTestFile(testScript, "@echo This is a fake maven.bat\n", true, filesToDelete); File testProject = File.createTempFile("MavenBuilderTest.testValidate", "_testproject.xml"); testProject.deleteOnExit(); makeTestFile(testProject, "<project><!-- This is a fake Maven project file --></project>\n", true, filesToDelete); mb.setMultiple(1); mb.setMavenScript(testScript.getAbsolutePath()); try { mb.validate(); fail("MavenBuilder should throw exceptions when required fields are not set."); } catch (CruiseControlException e) { assertTrue(true); } mb.setProjectFile(testProject.getAbsolutePath()); try { mb.validate(); fail("MavenBuilder should throw exceptions when required fields are not set."); } catch (CruiseControlException e) { assertTrue(true); } mb.setGoal(""); try { mb.validate(); fail("MavenBuilder should throw exceptions when required fields are not set."); } catch (CruiseControlException e) { assertTrue(true); } mb.setGoal("mygoal"); try { mb.validate(); assertTrue(true); } catch (CruiseControlException e) { fail("MavenBuilder should not throw exceptions when required fields are set. Exception [" + e.getMessage() + "]."); } } public void testBuild_Success() throws Exception { MavenBuilder mb = new MavenBuilder(); internalTestBuild(MOCK_SUCCESS, mb); } public void testBuild_BuildFailure() throws Exception { MavenBuilder mb = new MavenBuilder(); internalTestBuild(MOCK_BUILD_FAILURE, mb); } public void testBuild_DownloadFailure() throws Exception { MavenBuilder mb = new MavenBuilder(); internalTestBuild(MOCK_DOWNLOAD_FAILURE, mb); } /** * Element build(Map). mockFailure == (Mock a failure?). * * @param mb a maven build instance * @param statusType The exit status to be tested * @throws Exception if something breaks */ private void internalTestBuild(String statusType, MavenBuilder mb) throws Exception { final File testScript; final boolean buildSuccessful = statusType.equals(MOCK_SUCCESS); final String statusText = getStatusText(statusType); // Prepare mock files. final String prefix = "MavenBuilderTest.internalTestBuild"; if (Util.isWindows()) { testScript = File.createTempFile(prefix, "_testmaven.bat"); testScript.deleteOnExit(); makeTestFile( testScript, "@rem This is a fake maven.bat\n" + "@echo java:compile:\n" + "@echo Bla-bla-compile\n" + "@echo test:test:\n" + "@echo " + statusText + "\n", true, filesToDelete); } else { testScript = File.createTempFile(prefix, "_testmaven.sh"); testScript.deleteOnExit(); makeTestFile( testScript, "#!/bin/sh\n" + "\n" + "# This is a fake maven.sh\n" + "echo java:compile:\n" + "echo Bla-bla-compile\n" + "echo test:test:\n" + "echo " + statusText + "\n", false, filesToDelete); } mb.setMavenScript(testScript.getAbsolutePath()); // pom must exist before call to build() final File testPom = File.createTempFile(prefix, "don-t-care-pom.xml", new File(".")); filesToDelete.add(testPom); testPom.deleteOnExit(); mb.setProjectFile(testPom.getName()); Element we; List goalTags; // some fake goal is still needed to start working (no '|' here!) mb.setGoal("fakegoal"); // this should "succeed" Element logElement = mb.build(new HashMap<String, String>(), null); assertNotNull(statusType, logElement); goalTags = logElement.getChildren("mavengoal"); assertNotNull(statusType, goalTags); assertEquals(statusType, 2, goalTags.size()); we = (Element) goalTags.get(0); assertEquals(statusType, "java:compile", we.getAttribute("name").getValue()); we = (Element) goalTags.get(1); assertEquals(statusType, "test:test", we.getAttribute("name").getValue()); if (!buildSuccessful) { assertNotNull("error attribute not found when " + statusType, logElement.getAttribute("error")); } else { assertNull(statusType, logElement.getAttribute("error")); } // this time let's test multiple runs mb.setGoal("fakegoal|otherfakegoal"); // this should "double succeed" logElement = mb.build(new HashMap<String, String>(), null); assertNotNull(statusType, logElement); goalTags = logElement.getChildren("mavengoal"); assertNotNull(statusType, goalTags); we = (Element) goalTags.get(0); assertEquals(statusType, "java:compile", we.getAttribute("name").getValue()); we = (Element) goalTags.get(1); assertEquals(statusType, "test:test", we.getAttribute("name").getValue()); if (!buildSuccessful) { assertNotNull(statusType, logElement.getAttribute("error")); // if we mocked a failure, the second run should never happen assertEquals(statusType, 2, goalTags.size()); } else { assertNull(statusType, logElement.getAttribute("error")); assertEquals(statusType, 4, goalTags.size()); we = (Element) goalTags.get(2); assertEquals(statusType, "java:compile", we.getAttribute("name").getValue()); we = (Element) goalTags.get(3); assertEquals(statusType, "test:test", we.getAttribute("name").getValue()); } } /** * List getGoalSets() */ public void testGetGoalSets() { MavenBuilder mb = new MavenBuilder(); List gsList; mb.setGoal(null); gsList = mb.getGoalSets(); assertNotNull(gsList); assertEquals("No goal produces non-empty list", 0, gsList.size()); mb.setGoal("clean "); // I want the space there.. gsList = mb.getGoalSets(); assertNotNull(gsList); assertEquals("One goal should produce one item", 1, gsList.size()); // but notice, no space below assertEquals("One goal produces bad list content", "clean", (String) gsList.get(0)); mb.setGoal(" clean|update "); // Notice the spaces here gsList = mb.getGoalSets(); assertNotNull(gsList); assertEquals("Two goals should produce two items", 2, gsList.size()); // but not here assertEquals("First run produces bad goal", "clean", (String) gsList.get(0)); assertEquals("Second run produces bad goal", "update", (String) gsList.get(1)); // full-featured test mb.setGoal("clean update|\ttest||"); // Notice the spaces here gsList = mb.getGoalSets(); assertNotNull(gsList); assertEquals("Complex goal should produce two goalsets", 2, gsList.size()); // but not here assertEquals("First cplx run produces bad goal", "clean update", (String) gsList.get(0)); assertEquals("Second cplx run produces bad goal", "test", (String) gsList.get(1)); } private final TestUtil.FilesToDelete filesToDelete = new TestUtil.FilesToDelete(); protected void tearDown() { filesToDelete.delete(); } /** * Make a test file with specified content. Assumes the file does not exist. * @param testFile the file to create * @param content the data to put into the created file * @param onWindows true if running on Windows OS * @param filesToDelete list of files to be deleted in tearDown * @throws net.sourceforge.cruisecontrol.CruiseControlException if anything breaks */ static void makeTestFile(final File testFile, final String content, final boolean onWindows, final TestUtil.FilesToDelete filesToDelete) throws CruiseControlException { IO.write(testFile.getAbsoluteFile(), content); if (filesToDelete != null) { filesToDelete.add(testFile); } if (!onWindows) { Commandline cmdline = new Commandline(); cmdline.setExecutable("chmod"); cmdline.createArgument("755"); cmdline.createArgument(testFile.getAbsolutePath()); try { Process p = cmdline.execute(); p.waitFor(); } catch (Exception e) { e.printStackTrace(); fail("exception changing permissions on test file " + testFile.getAbsolutePath()); } } } public void testBuildTimeout() throws Exception { MavenBuilder builder = new MavenBuilder(); builder.setTimeout(5); long startTime = System.currentTimeMillis(); internalTestBuild(MOCK_BUILD_FAILURE, builder); assertTrue((System.currentTimeMillis() - startTime) < 9 * 1000L); // assertTrue(buildElement.getAttributeValue("error").indexOf("timeout") >= 0); } /** * Text for build status * * @param statusCode The exit status to be tested * @return the expected script output text for the given build status */ private String getStatusText(String statusCode) { if (statusCode.equals(MOCK_SUCCESS)) { return "BUILD SUCCESSFUL"; } else if (statusCode.equals(MOCK_BUILD_FAILURE)) { return "BUILD FAILED"; } else if (statusCode.equals(MOCK_DOWNLOAD_FAILURE)) { return "The build cannot continue because of the following unsatisfied dependency"; } throw new IllegalArgumentException("please use one of the constants"); } }