package net.sourceforge.cruisecontrol.jmx; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import junit.framework.TestCase; import net.sourceforge.cruisecontrol.BuildQueue; import net.sourceforge.cruisecontrol.BuildQueueTest; import net.sourceforge.cruisecontrol.BuilderTest; import net.sourceforge.cruisecontrol.CruiseControlException; import net.sourceforge.cruisecontrol.Log; import net.sourceforge.cruisecontrol.MockProject; import net.sourceforge.cruisecontrol.MockSchedule; import net.sourceforge.cruisecontrol.Modification; import net.sourceforge.cruisecontrol.ModificationSet; import net.sourceforge.cruisecontrol.Progress; import net.sourceforge.cruisecontrol.ProgressImplTest; import net.sourceforge.cruisecontrol.Project; import net.sourceforge.cruisecontrol.ProjectConfig; import net.sourceforge.cruisecontrol.ProjectConfigTest; import net.sourceforge.cruisecontrol.ProjectTest; import net.sourceforge.cruisecontrol.SourceControl; import net.sourceforge.cruisecontrol.builders.AntBuilder; import net.sourceforge.cruisecontrol.builders.AntOutputLogger; import net.sourceforge.cruisecontrol.builders.AntScriptTest; import net.sourceforge.cruisecontrol.events.BuildResultEvent; import net.sourceforge.cruisecontrol.events.BuildResultListener; import net.sourceforge.cruisecontrol.util.IO; import net.sourceforge.cruisecontrol.util.Util; import net.sourceforge.cruisecontrol.bootstrappers.AntBootstrapper; import net.sourceforge.cruisecontrol.labelincrementers.DefaultLabelIncrementer; import net.sourceforge.cruisecontrol.sourcecontrols.AlwaysBuild; public class ProjectControllerTest extends TestCase { public void testShouldBeAbleToGetCommitMessage() throws Exception { Project project = new Project(); project.setName("TestProject"); ModificationSet modicationSet = new ModificationSet(); modicationSet.add(new SVNStub()); ProjectConfig projectConfig = new ProjectConfig(); projectConfig.add(new DefaultLabelIncrementer()); projectConfig.add(modicationSet); project.setProjectConfig(projectConfig); ProjectMBean controller = new ProjectController(project); String[][] message = controller.commitMessages(); assertEquals(message[0][0], "user1"); assertEquals(message[0][1], "comment1"); assertEquals(message[1][0], "user2"); assertEquals(message[1][1], "comment2"); } public void testBootstrapperBuildOutputWhenProjectIsBuilding() throws Exception { final Project project = new Project(); project.setName("project1"); final File validFile = new File("project1"); Util.doMkDirs(validFile); try { final AntBootstrapper bootstrapper = new AntBootstrapper(); bootstrapper.setBuildFile(validFile.getAbsolutePath()); final File expectedTempFile = new File(validFile, "notLog.xml"); bootstrapper.setTempFile(expectedTempFile.getName()); bootstrapper.setTarget("init"); bootstrapper.setAntWorkingDir(validFile.getAbsolutePath()); bootstrapper.validate(); try { bootstrapper.bootstrap(); } catch (CruiseControlException e) { assertEquals("ant logfile " + expectedTempFile.getAbsolutePath() + " does not exist.", e.getMessage()); } final ProjectMBean mbean = new ProjectController(project); String[] output = mbean.getBuildOutput(0); assertNotNull(output); assertEquals("AntBuilder/Bootstrapper/Publisher only create build output if useLogger, showOutput are true", 0, output.length); assertFalse("Null data file should NOT have appended anything to ID: " + mbean.getOutputLoggerID(), mbean.getOutputLoggerID().endsWith(AntOutputLogger.DEFAULT_OUTFILE_NAME)); IO.delete(validFile); Util.doMkDirs(validFile); bootstrapper.setUseLogger(true); bootstrapper.setLiveOutput(true); bootstrapper.setProgressLoggerLib("dummyLib"); try { bootstrapper.bootstrap(); } catch (Exception e) { assertEquals("ant logfile " + expectedTempFile.getAbsolutePath() + " is empty. Your build probably failed. Check your CruiseControl logs.", e.getMessage()); } output = mbean.getBuildOutput(0); assertNotNull(output); // @todo this test will likely change if we implement 'live output' for bootstrappers //assertTrue("Unexpected empty bootstrapper build output", output.length > 0); assertEquals("Expected empty bootstrapper build output", 0, output.length); } finally { IO.delete(validFile); } } public void testBuilderShouldRetrieveBuildOutputWhenProjectIsBuilding() throws Exception { final Project project = new Project(); project.setName("project1"); final File validFile = new File("project1"); Util.doMkDirs(validFile); try { final AntBuilder antBuilder = new AntBuilder(); antBuilder.setBuildFile(validFile.getAbsolutePath()); final File expectedTempFile = new File(validFile, "notLog.xml"); antBuilder.setTempFile(expectedTempFile.getName()); antBuilder.setTarget("init"); antBuilder.setAntWorkingDir(validFile.getAbsolutePath()); antBuilder.validate(); // default value of LiveOutput is different between AntBuilder and AntBootstrapper, // must set to false to avoid output logging. antBuilder.setLiveOutput(false); final Map<String, String> buildProperties = BuilderTest.createPropsWithProjectName(project.getName()); try { antBuilder.build(buildProperties, null); } catch (CruiseControlException e) { assertEquals("ant logfile " + expectedTempFile.getAbsolutePath() + " does not exist.", e.getMessage()); } final ProjectMBean mbean = new ProjectController(project); String[] output = mbean.getBuildOutput(0); assertNotNull(output); assertEquals("AntBuilder/Bootstrapper/Publisher only create build output if useLogger, showOutput are true", 0, output.length); IO.delete(validFile); Util.doMkDirs(validFile); final String target = "echoProgress"; final File buildFile = new File(validFile, "testBuild.xml"); stringToFile("<project name=\"testProj\">\n" + "<target name=\"" + target + "\">\n" + "<echo>" + AntScriptTest.MSG_PREFIX_ANT_PROGRESS + "some stuff</echo>\n" + "</target>\n" + "</project>\n", buildFile); antBuilder.setBuildFile(buildFile.getAbsolutePath()); antBuilder.setTarget(target); antBuilder.setUseLogger(true); antBuilder.setLiveOutput(true); antBuilder.setProgressLoggerLib("dummyLib"); // use Progress to make build wait for a while. final String done = "done"; final Progress progress = new ProgressImplTest.MockProgress() { private static final long serialVersionUID = 6607524919179888057L; public void setValue(String value) { synchronized (done) { super.setValue(value); done.notifyAll(); } } }; final String buildDone = "buildDone"; new Thread("RunBuild") { public void run() { try { antBuilder.build(buildProperties, progress); } catch (Exception e) { throw new RuntimeException(e); } finally { synchronized (buildDone) { progress.setValue(buildDone); buildDone.notifyAll(); } } } } .start(); // wait for progress message to come through synchronized (done) { while (progress.getText() == null) { done.wait(5000); } } output = mbean.getBuildOutput(0); assertNotNull(output); assertTrue("Unexpected empty build output", output.length > 0); // wait for build/scriptRun to complete synchronized (buildDone) { while (!buildDone.equals(progress.getText())) { buildDone.wait(5000); } } assertTrue("Cleared data file should have reset ID: " + mbean.getOutputLoggerID(), mbean.getOutputLoggerID().endsWith("__0")); } finally { IO.delete(validFile); } } private static void stringToFile(final String data, final File outFile) throws IOException { final FileOutputStream fos = new FileOutputStream(outFile); try { final OutputStreamWriter oos = new OutputStreamWriter(fos); try { oos.write(data); } finally { oos.close(); } } finally { fos.close(); } } public void testIsLastBuildSuccessful() { final ProjectController mbean = new ProjectController(new Project()); assertTrue(mbean.isLastBuildSuccessful()); } public void testIsLastBuildSuccessfulFromMockProjectFollowsValueChanges() throws Exception { final MockProject project = new MockProject(); final ProjectController mbean = new ProjectController(project); ProjectTest.setWasLastBuildSuccessful(project, false); assertFalse(mbean.isLastBuildSuccessful()); ProjectTest.setWasLastBuildSuccessful(project, true); assertTrue(mbean.isLastBuildSuccessful()); ProjectTest.setWasLastBuildSuccessful(project, false); assertFalse(mbean.isLastBuildSuccessful()); } public void testBuildWithTargetAndAddedProps() throws Exception { final ProjectConfig projectConfig = new ProjectConfig(); projectConfig.setName("testproject"); projectConfig.add(new DefaultLabelIncrementer()); // Override to allow us to read props and check for existence of extra props. final class MockScheduleExposingProps extends MockSchedule { private static final long serialVersionUID = -8394080367390959431L; protected Map<String, String> getBuildProperties() { return super.getBuildProperties(); } } final MockScheduleExposingProps mockSchedule = new MockScheduleExposingProps(); projectConfig.add(mockSchedule); final ModificationSet modificationSet = new ModificationSet(); modificationSet.add(new AlwaysBuild()); modificationSet.setQuietPeriod(0); projectConfig.add(modificationSet); final Log log = new Log() { private static final long serialVersionUID = 1101933013536150534L; public void writeLogFile(final Date now) throws CruiseControlException { // don't write anything, so we don't need to clean up temp files. } }; log.setDir(System.getProperty("java.io.tmpdir")); projectConfig.add(log); projectConfig.configureProject(); final Project project = ProjectConfigTest.getProjectFromProjectConfig(projectConfig); final ProjectController mbean = new ProjectController(project); final Map<String, String> properties = new HashMap<String, String>(); properties.put("environment", "UIT"); properties.put("webbrowser", "IE6"); final BuildQueue buildQueue = new BuildQueue(); projectConfig.setBuildQueue(buildQueue); BuildQueueTest.startBuildQueue(buildQueue); project.setPaused(true); project.start(); final class Result { boolean isBuilt; } final Result result = new Result(); project.addBuildResultListener(new BuildResultListener() { public void handleBuildResult(final BuildResultEvent event) { synchronized (result) { result.isBuilt = true; result.notifyAll(); } } }); project.setPaused(false); // trigger build with added props mbean.buildWithTarget("sometarget", properties); int count = 0; while (!result.isBuilt && count < 5) { count++; synchronized (result) { result.wait(count * 1000); } } final Map<String, String> props = mockSchedule.getBuildProperties(); assertTrue("Property environment should exist", props.containsKey("environment")); assertEquals(props.get("environment"), "UIT"); assertTrue("Property webbrowser should exist", props.containsKey("webbrowser")); assertEquals(props.get("webbrowser"), "IE6"); } private static class SVNStub implements SourceControl { private static final long serialVersionUID = 1L; public List<Modification> getModifications(Date lastBuild, Date now) { final List<Modification> modications = new ArrayList<Modification>(); Modification modification = new Modification(); modification.userName = "user1"; modification.comment = "comment1"; modications.add(modification); modification = new Modification(); modification.userName = "user2"; modification.comment = "comment2"; modications.add(modification); return modications; } public Map<String, String> getProperties() { return null; } public void validate() throws CruiseControlException { } } }