Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Registering the ProjectStatus module among default plugins
- Loading branch information
Showing
2 changed files
with
377 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 0 additions & 1 deletion
1
main/test/net/sourceforge/cruisecontrol/sourcecontrols/ProjectStatusTest.java
This file was deleted.
Oops, something went wrong.
376 changes: 376 additions & 0 deletions
376
main/test/net/sourceforge/cruisecontrol/sourcecontrols/ProjectStatusTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,376 @@ | ||
/******************************************************************************** | ||
* 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.sourcecontrols; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.File; | ||
import java.util.Date; | ||
import java.util.List; | ||
|
||
import javax.management.RuntimeErrorException; | ||
|
||
import org.jdom.Element; | ||
import org.junit.Test; | ||
|
||
import junit.framework.TestCase; | ||
import net.sourceforge.cruisecontrol.BuildQueue; | ||
import net.sourceforge.cruisecontrol.Builder; | ||
import net.sourceforge.cruisecontrol.CruiseControlConfig; | ||
import net.sourceforge.cruisecontrol.CruiseControlException; | ||
import net.sourceforge.cruisecontrol.Modification; | ||
import net.sourceforge.cruisecontrol.ProjectConfig; | ||
import net.sourceforge.cruisecontrol.ProjectInterface; | ||
import net.sourceforge.cruisecontrol.builders.MockBuilder; | ||
import net.sourceforge.cruisecontrol.testutil.TestUtil.FilesToDelete; | ||
import net.sourceforge.cruisecontrol.util.IO; | ||
import net.sourceforge.cruisecontrol.util.Util; | ||
|
||
/** | ||
* Unit tests for {@link ProjectStatus} | ||
* @author Dan Tihelka | ||
*/ | ||
public class ProjectStatusTest extends TestCase { | ||
|
||
private final FilesToDelete filesToDelete = new FilesToDelete(); | ||
private CruiseControlConfig config; | ||
private BuildQueue queue; | ||
private File proj1Data; | ||
|
||
protected void setUp() throws Exception { | ||
proj1Data = filesToDelete.add(this); | ||
IO.write(proj1Data, ""); | ||
|
||
final String xml = "<cruisecontrol>" | ||
+ " <plugin name='mock.builder' classname='" + MockBuilder.class.getName() + "' />" | ||
|
||
+ " <project name='proj1'>" | ||
+ " <modificationset quietperiod='0'>" | ||
+ " <filesystem folder='" + proj1Data.getAbsoluteFile() + "'/>" | ||
+ " </modificationset>" | ||
+ " <schedule interval='1'><mock.builder/></schedule>" | ||
+ " </project>" | ||
|
||
+ " <project name='proj.main'>" | ||
+ " <modificationset quietperiod='0'>" | ||
+ " <projectstatus project='proj1' buildonsuccess='true'/>" | ||
+ " </modificationset>" | ||
+ " <schedule interval='1'><mock.builder/></schedule>" | ||
+ " </project>" | ||
+ "</cruisecontrol>"; | ||
|
||
// Create the config | ||
Element ccElement = Util.loadRootElement(new ByteArrayInputStream(xml.getBytes())); | ||
config = new CruiseControlConfig(ccElement); | ||
|
||
// Set the build queue to all projects | ||
queue = new BuildQueue(); | ||
for (String proj : config.getProjectNames()) { | ||
ProjectInterface pi = config.getProject(proj); | ||
// Configure and set the queue | ||
pi.configureProject(); | ||
pi.setBuildQueue(queue); | ||
// Prepare *.ser project files for removal | ||
final File serFile = new File(Builder.getFileSystemSafeProjectName(pi.getName()) + ".ser"); | ||
filesToDelete.add(serFile); | ||
// clear log files as well | ||
filesToDelete.add(new File(pi.getLogDir())); | ||
} | ||
} | ||
|
||
protected void tearDown() { | ||
// Stop all projects | ||
for (String proj : config.getProjectNames()) { | ||
config.getProject(proj).stop(); | ||
} | ||
// Clear the rest | ||
config = null; | ||
filesToDelete.delete(); | ||
} | ||
/** | ||
* Make sure the validate() method works properly. | ||
*/ | ||
@Test | ||
public void testValidate() throws Exception { | ||
ProjectStatus status = new ProjectStatus(); | ||
|
||
// Project is not set | ||
assertInvalid(status, "'project' is required for ProjectStatus"); | ||
|
||
// Project is set, but it is not valid | ||
status.setProject("p1"); | ||
assertInvalid(status, "No project named 'p1'"); | ||
} | ||
|
||
/** | ||
* Tests, if a modification is returned when successful build of <code>proj1</code> is after the | ||
* last build of the main project. It means that default values are used for all values. | ||
*/ | ||
@Test | ||
public void testBuildOnSuccess() throws Exception { | ||
final ProjectStatus status = new ProjectStatus(); | ||
final ProjectConfig proj1 = (ProjectConfig) config.getProject("proj1"); | ||
long lastP1; | ||
|
||
// configure the status watcher | ||
status.setProject("proj1"); | ||
status.validate(); | ||
lastP1 = new Date().getTime(); | ||
// Check the status - proj1 was not build yet. The status must return 'not modified' | ||
// since the proj1 has not been built yet and we are waiting for its successful build here | ||
assertNoModifs(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Force the build. | ||
proj1.start(); | ||
proj1.execute(); | ||
lastP1 = proj1.successLastBuild().getTime(); | ||
|
||
// the last successful build of proj1 (just made at time lastP1) is after the last build of | ||
// proj.main. Therefore, it must report "have modification" to trigger the build of proj.main | ||
assertModified(status, lastP1 -1000, lastP1 +1000); | ||
// the last successful build of proj1 is before the last build of proj.main, so it looks like | ||
// there is no modification of which should trigger the build of proj.main | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Write to the file which will introduce modification in proj1 since its last build | ||
// Sleep ensures that the file modification time will be AFTER lastP1, which is crucial for | ||
// the test | ||
Thread.sleep(1100 - lastP1 % 1000); | ||
IO.write(proj1Data, "test.BuildOnSuccess: " + new Date()); | ||
|
||
// The same as the previous check - although there is a modification in proj1 waiting for | ||
// the build, it is not taken into account here (VetoIfModified was not set) | ||
assertModified(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Force the build. The status must return 'has modifications' now | ||
proj1.execute(); | ||
lastP1 = proj1.successLastBuild().getTime(); | ||
|
||
// the last successful build of proj1 (just made at time lastP1) is after the last build of | ||
// proj.main. Therefore, it must report "have modification" to trigger the build of proj.main | ||
assertModified(status, lastP1 -1000, lastP1 +1000); | ||
// the last successful build of proj1 is before the last build of proj.main, so it looks like | ||
// there is no modification of which should trigger the build of proj.main | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
} | ||
|
||
/** | ||
* The same as {@link #testBuildOnSuccess()}, plus veto must be signalized if checked when there | ||
* is a modification in <code>proj1</code> after its successful build. It means that | ||
* {@link ProjectStatus#setVetoIfModified(boolean)} is set to <code>true</code>. | ||
*/ | ||
@Test | ||
public void testVetoIfModified() throws Exception { | ||
final ProjectStatus status = new ProjectStatus(); | ||
final ProjectConfig proj1 = (ProjectConfig) config.getProject("proj1"); | ||
long lastP1; | ||
|
||
// configure the status watcher | ||
status.setProject("proj1"); | ||
status.setVetoIfModified(true); | ||
status.validate(); | ||
lastP1 = new Date().getTime(); | ||
|
||
// The proj1 has not been built yet and we depend on it. Therefore, our build must be | ||
// delayed until the successful build of proj1 | ||
assertVeto(status, lastP1 -1000, lastP1 +1000); | ||
// Here the last build is after ... | ||
// TODO: DOPSAT!!!! | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Force the build. | ||
proj1.start(); | ||
proj1.execute(); | ||
lastP1 = proj1.successLastBuild().getTime(); | ||
|
||
// The same as in testBuildOnSuccess | ||
assertModified(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Write to the file ... (the same as in testBuildOnSuccess) | ||
Thread.sleep(1100 - lastP1 % 1000); | ||
IO.write(proj1Data, "test.VetoIfModified: " + new Date()); | ||
|
||
// The successful build of proj1 after the last build of proj.main should trigger the build | ||
// of proj.main. However, there is a modification which must veto the the build. | ||
assertVeto(status, lastP1 -1000, lastP1 +1000); | ||
// The same as in testBuildOnSuccess | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Force the build. The status must return 'has modifications' now | ||
proj1.execute(); | ||
lastP1 = proj1.successLastBuild().getTime(); | ||
|
||
// The same as in testBuildOnSuccess | ||
assertModified(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
} | ||
|
||
/** | ||
* The same as {@link #testVetoIfModified()}, except the modifications are not reported. It means | ||
* that {@link ProjectStatus#setVetoIfModified(boolean)} is set to <code>true</code> and | ||
* {@link ProjectStatus#setTriggerOnSuccess(boolean)} is set to <code>false</code>. | ||
*/ | ||
@Test | ||
public void testVetoNoTrigger() throws Exception { | ||
final ProjectStatus status = new ProjectStatus(); | ||
final ProjectConfig proj1 = (ProjectConfig) config.getProject("proj1"); | ||
long lastP1; | ||
|
||
// configure the status watcher | ||
status.setProject("proj1"); | ||
status.setVetoIfModified(true); | ||
status.setTriggerOnSuccess(false); // Do not report modifications | ||
status.validate(); | ||
lastP1 = new Date().getTime(); | ||
|
||
// The same as in #testVetoIfModified() | ||
assertVeto(status, lastP1 -1000, lastP1 +1000); | ||
// Never returns any modification | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Force the build. | ||
proj1.start(); | ||
proj1.execute(); | ||
lastP1 = proj1.successLastBuild().getTime(); | ||
|
||
// Never returns any modification | ||
assertNoModifs(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Write to the file ... (the same as in testBuildOnSuccess) | ||
Thread.sleep(1100 - lastP1 % 1000); | ||
IO.write(proj1Data, "test.VetoIfModified: " + new Date()); | ||
|
||
// The same as in #testVetoIfModified() | ||
assertVeto(status, lastP1 -1000, lastP1 +1000); | ||
// Never returns any modification | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Force the build. The status must return 'has modifications' now | ||
proj1.execute(); | ||
lastP1 = proj1.successLastBuild().getTime(); | ||
|
||
// Never returns any modification | ||
assertNoModifs(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
} | ||
|
||
/** | ||
* The case when no modification and no veto is set, It means that only | ||
* {@link ProjectStatus#setTriggerOnSuccess(boolean)} is set to <code>false</code>. | ||
*/ | ||
@Test | ||
public void testNoTriggerOnSuccess() throws Exception { | ||
final ProjectStatus status = new ProjectStatus(); | ||
final ProjectConfig proj1 = (ProjectConfig) config.getProject("proj1"); | ||
long lastP1; | ||
|
||
// configure the status watcher | ||
status.setProject("proj1"); | ||
status.setTriggerOnSuccess(false); | ||
status.validate(); | ||
lastP1 = new Date().getTime(); | ||
|
||
// Never returns any modification | ||
assertNoModifs(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Force the build. | ||
proj1.start(); | ||
proj1.execute(); | ||
lastP1 = proj1.successLastBuild().getTime(); | ||
|
||
// Never returns any modification | ||
assertNoModifs(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Write to the file ... (the same as in testBuildOnSuccess) | ||
Thread.sleep(1100 - lastP1 % 1000); | ||
IO.write(proj1Data, "test.BuildOnSuccess: " + new Date()); | ||
|
||
// Never returns any modification | ||
assertNoModifs(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
// Force the build | ||
proj1.execute(); | ||
lastP1 = proj1.successLastBuild().getTime(); | ||
|
||
// Never returns any modification | ||
assertNoModifs(status, lastP1 -1000, lastP1 +1000); | ||
assertNoModifs(status, lastP1 +1000, lastP1 +2000); | ||
|
||
} | ||
|
||
|
||
/** Expects that {@link ProjectStatus#getModifications(Date, Date)} returns non-empty array */ | ||
private void assertModified(ProjectStatus status, long lastBuild, long now) { | ||
assertFalse("At least one modification expected, none got", | ||
status.getModifications(new Date(lastBuild), new Date(now)).isEmpty()); | ||
} | ||
/** Expects that {@link ProjectStatus#getModifications(Date, Date)} returns empty array */ | ||
private void assertNoModifs(ProjectStatus status, long lastBuild, long now) { | ||
final List<Modification> modifs = status.getModifications(new Date(lastBuild), new Date(now)); | ||
assertTrue("No modification expected, " + modifs.size() + " got", modifs.isEmpty()); | ||
} | ||
|
||
/** Expects that {@link ProjectStatus#getModifications(Date, Date)} throws {@link RuntimeErrorException} | ||
* exception */ | ||
private void assertVeto(ProjectStatus status, long lastBuild, long now) { | ||
try { | ||
status.getModifications(new Date(lastBuild), new Date(now)); | ||
fail("Invalid status returned"); | ||
} catch (RuntimeException exc) { | ||
// OK | ||
} | ||
} | ||
|
||
/** Expects that {@link ProjectStatus#validate()} throws {@link CruiseControlException} | ||
* exception with the given message */ | ||
private void assertInvalid(ProjectStatus status, String message) { | ||
// Verify log directory is mandatory | ||
try { | ||
status.validate(); | ||
fail("Validation passed while it should not"); | ||
} catch (CruiseControlException exc) { | ||
assertEquals("Wrong exception", message, exc.getMessage()); | ||
} | ||
} | ||
} |