package hudson.plugins.promoted_builds; import hudson.AbortException; import hudson.FilePath; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; import hudson.model.Job; import hudson.model.Result; import hudson.plugins.promoted_builds.conditions.DownstreamPassCondition; import hudson.tasks.ArtifactArchiver; import hudson.tasks.Fingerprinter; import hudson.tasks.Recorder; import org.jvnet.hudson.test.HudsonTestCase; import org.jvnet.hudson.test.TestBuilder; import java.io.IOException; import java.util.Arrays; import java.util.List; import static hudson.plugins.promoted_builds.util.ItemListenerHelper.fireItemListeners; public class KeepBuildForeverActionTest extends HudsonTestCase { public void testCanMarkBuildKeepForever() throws Exception { FreeStyleProject upJob = createProject("up"); upJob.getBuildersList().add(successfulBuilder()); FreeStyleProject downJob = createProject("down"); downJob.getBuildersList().add(successfulBuilder()); PromotionProcess promotionJob = createDownstreamSuccessPromotion(upJob, downJob); promotionJob.getBuildSteps().add(new KeepBuildForeverAction()); // fire ItemListeners, this includes ArtifactArchiver,Migrator to make this test compatible with jenkins 1.575+ fireItemListeners(); FreeStyleBuild upBuild = assertBuildStatusSuccess(upJob.scheduleBuild2(0).get()); assertFalse(upBuild.isKeepLog()); assertBuildStatusSuccess(downJob.scheduleBuild2(0).get()); waitForBuild(promotionJob, 1); assertTrue(upBuild.isKeepLog()); } public void testDoesNotMarkBuildIfPromotionNotGoodEnough() throws Exception { FreeStyleProject upJob = createProject("up"); upJob.getBuildersList().add(successfulBuilder()); FreeStyleProject downJob = createProject("down"); downJob.getBuildersList().add(successfulBuilder()); PromotionProcess promotionJob = createDownstreamSuccessPromotion(upJob, downJob); promotionJob.getBuildSteps().add(new FixedResultBuilder(Result.FAILURE)); promotionJob.getBuildSteps().add(new KeepBuildForeverAction()); // fire ItemListeners, this includes ArtifactArchiver,Migrator to make this test compatible with jenkins 1.575+ fireItemListeners(); FreeStyleBuild upBuild = assertBuildStatusSuccess(upJob.scheduleBuild2(0).get()); assertFalse(upBuild.isKeepLog()); assertBuildStatusSuccess(downJob.scheduleBuild2(0).get()); waitForBuild(promotionJob, 1); assertFalse(upBuild.isKeepLog()); } public void testDoesNotCareAboutResultOfOriginalBuild() throws Exception { FreeStyleProject upJob = createProject("up"); upJob.getBuildersList().add(new FixedResultBuilder(Result.FAILURE)); FreeStyleProject downJob = createProject("down"); downJob.getBuildersList().add(successfulBuilder()); PromotionProcess promotionJob = createDownstreamSuccessPromotion(upJob, downJob); promotionJob.getBuildSteps().add(new KeepBuildForeverAction()); // fire ItemListeners, this includes ArtifactArchiver,Migrator to make this test compatible with jenkins 1.575+ fireItemListeners(); FreeStyleBuild upBuild = assertBuildStatus(Result.FAILURE, upJob.scheduleBuild2(0).get()); assertFalse(upBuild.isKeepLog()); assertBuildStatusSuccess(downJob.scheduleBuild2(0).get()); waitForBuild(promotionJob, 1); assertTrue(upBuild.isKeepLog()); } public void testDoesNotMarkBuildIfBuildNotPromotion() throws Exception { FreeStyleProject job = createProject("job"); job.getBuildersList().add(successfulBuilder()); job.getPublishersList().add(new KeepBuildForeverAction()); // fire ItemListeners, this includes ArtifactArchiver,Migrator to make this test compatible with jenkins 1.575+ fireItemListeners(); FreeStyleBuild build = assertBuildStatus(Result.FAILURE, job.scheduleBuild2(0).get()); assertFalse(build.isKeepLog()); } private void waitForBuild(final Job job, final int buildNumber) throws Exception { waitFor(new WaitCondition() { public boolean isMet() { return (job.getBuildByNumber(buildNumber) != null) && !job.getBuildByNumber(buildNumber).isBuilding(); } }, 2000); } private void waitFor(final WaitCondition condition, long timeout) throws Exception { Thread waiter = new Thread() { public void run() { try { while (!condition.isMet()) { Thread.sleep(100); } } catch (InterruptedException ie) { } } }; waiter.start(); waiter.join(timeout); if (waiter.isAlive()) { waiter.interrupt(); } if (!condition.isMet()) fail("Condition not met"); } private PromotionProcess createDownstreamSuccessPromotion(FreeStyleProject upStream, FreeStyleProject downStream) throws Descriptor.FormException, IOException { JobPropertyImpl promotionProperty = new JobPropertyImpl(upStream); upStream.addProperty(promotionProperty); PromotionProcess promotionJob = promotionProperty.addProcess("promotion"); promotionJob.conditions.add(new DownstreamPassCondition(downStream.getName())); return promotionJob; } private FreeStyleProject createProject(String name) throws Exception { FreeStyleProject project = createFreeStyleProject(name); project.getPublishersList().replaceBy(createFingerprinters()); return project; } private List<Recorder> createFingerprinters() { return Arrays.asList( new ArtifactArchiver("*", null, false), new Fingerprinter("", true) ); } private FixedResultBuilder successfulBuilder() { return new FixedResultBuilder(Result.SUCCESS); } public interface WaitCondition { boolean isMet(); } public static class FixedResultBuilder extends TestBuilder { private Result buildResult; FixedResultBuilder(Result buildResult) { this.buildResult = buildResult; } public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { FilePath workspace = build.getWorkspace(); if (workspace == null) { throw new AbortException("Workspace is null in " + FixedResultBuilder.class.getName()); } workspace.child("my.file").write("Hello world!", "UTF-8"); build.setResult(buildResult); return true; } } }