From 1b5f7e6540842f7366e8c233f0acb856be2a43f7 Mon Sep 17 00:00:00 2001 From: J-cztery Date: Sat, 21 Nov 2015 13:15:11 +0800 Subject: [PATCH] Add support for running promotions on inheritance projects 1. Add unit tests. 2. Remove assert from PromotionProcess as in InheritanceProject it no longer holds. 3. Try to resolve build from jobName and build number first and if this fails, try others. 4. Implement an extension for inheritance-plugin --- pom.xml | 6 + .../promoted_builds/JobPropertyImpl.java | 46 ++-- .../promoted_builds/PromotionProcess.java | 2 - .../PromotionTargetAction.java | 5 + .../inheritance/JobPropertyImplSelector.java | 67 ++++++ ...ownstreamPassConditionInheritanceTest.java | 99 ++++++++ .../ManualConditionInheritanceTest.java | 204 +++++++++++++++++ .../SelfPromotionInheritanceTest.java | 215 ++++++++++++++++++ .../helpers/InheritanceProjectRule.java | 28 +++ .../helpers/InheritanceProjectsPair.java | 22 ++ 10 files changed, 675 insertions(+), 19 deletions(-) create mode 100644 src/main/java/hudson/plugins/promoted_builds/inheritance/JobPropertyImplSelector.java create mode 100644 src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/DownstreamPassConditionInheritanceTest.java create mode 100644 src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/ManualConditionInheritanceTest.java create mode 100644 src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/SelfPromotionInheritanceTest.java create mode 100644 src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectRule.java create mode 100644 src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectsPair.java diff --git a/pom.xml b/pom.xml index 1462d644..d896cc0b 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,12 @@ 1.10 true + + hudson.plugins + project-inheritance + 1.5.3 + true + diff --git a/src/main/java/hudson/plugins/promoted_builds/JobPropertyImpl.java b/src/main/java/hudson/plugins/promoted_builds/JobPropertyImpl.java index c809929d..82d2a76c 100644 --- a/src/main/java/hudson/plugins/promoted_builds/JobPropertyImpl.java +++ b/src/main/java/hudson/plugins/promoted_builds/JobPropertyImpl.java @@ -64,13 +64,6 @@ public final class JobPropertyImpl extends JobProperty> imp * These {@link PromotionProcess}es are active. */ private final Set activeProcessNames = new HashSet(); - -// /** -// * Names of the processes that are configured. -// * Used to construct {@link #processes}. -// */ -// private final List names = new ArrayList(); - /** * Programmatic construction. */ @@ -78,7 +71,11 @@ public JobPropertyImpl(AbstractProject owner) throws Descriptor.FormExcepti this.owner = owner; init(); } - + public JobPropertyImpl(JobPropertyImpl other, AbstractProject owner) throws Descriptor.FormException, IOException { + this.owner = owner; + this.activeProcessNames.addAll(other.activeProcessNames); + loadAllProcesses(other.getRootDir()); + } private JobPropertyImpl(StaplerRequest req, JSONObject json) throws Descriptor.FormException, IOException { // a hack to get the owning AbstractProject. // this is needed here so that we can load items @@ -112,7 +109,15 @@ private JobPropertyImpl(StaplerRequest req, JSONObject json) throws Descriptor.F } init(); } + private void loadAllProcesses(File rootDir) throws IOException { + File[] subdirs = rootDir.listFiles(new FileFilter() { + public boolean accept(File child) { + return child.isDirectory(); + } + }); + loadProcesses(subdirs); + } private void init() throws IOException { // load inactive processes File[] subdirs = getRootDir().listFiles(new FileFilter() { @@ -120,6 +125,9 @@ public boolean accept(File child) { return child.isDirectory() && !isActiveProcessNameIgnoreCase(child.getName()); } }); + loadProcesses(subdirs); + } + private void loadProcesses(File[] subdirs) throws IOException { if(subdirs!=null) { for (File subdir : subdirs) { try { @@ -179,7 +187,7 @@ protected synchronized void setOwner(AbstractProject owner) { // so use this as the initialization opportunity. // CopyListener is also using setOwner to re-init after copying config from another job. processes = new ArrayList(ItemGroupMixIn.loadChildren( - this,getRootDir(),ItemGroupMixIn.KEYED_BY_NAME).values()); + this,getRootDir(),ItemGroupMixIn.KEYED_BY_NAME).values()); try { buildActiveProcess(); } catch (IOException e) { @@ -201,7 +209,11 @@ private void buildActiveProcess() throws IOException { // ensure that the name casing matches what's given in the activeProcessName // this is because in case insensitive file system, we may end up resolving // to a directory name that differs only in their case. - p.renameTo(getActiveProcessName(p.getName())); + String processName = p.getName(); + String activeProcessName = getActiveProcessName(processName); + if (!activeProcessName.equals(processName)){ + p.renameTo(activeProcessName); + } } } @@ -352,16 +364,16 @@ public Action getJobAction(AbstractProject job) { @Extension public static final class DescriptorImpl extends JobPropertyDescriptor { - + public DescriptorImpl() { - super(); - } + super(); + } - public DescriptorImpl(Class> clazz) { - super(clazz); - } + public DescriptorImpl(Class> clazz) { + super(clazz); + } - public String getDisplayName() { + public String getDisplayName() { return "Promote Builds When..."; } diff --git a/src/main/java/hudson/plugins/promoted_builds/PromotionProcess.java b/src/main/java/hudson/plugins/promoted_builds/PromotionProcess.java index 7c7f1561..ab331831 100644 --- a/src/main/java/hudson/plugins/promoted_builds/PromotionProcess.java +++ b/src/main/java/hudson/plugins/promoted_builds/PromotionProcess.java @@ -415,9 +415,7 @@ public boolean scheduleBuild(AbstractBuild build, Cause cause) { } public Future scheduleBuild2(AbstractBuild build, Cause cause, List params) { - assert build.getProject()==getOwner(); - List actions = new ArrayList(); Promotion.buildParametersAction(actions, build, params); actions.add(new PromotionTargetAction(build)); diff --git a/src/main/java/hudson/plugins/promoted_builds/PromotionTargetAction.java b/src/main/java/hudson/plugins/promoted_builds/PromotionTargetAction.java index 1d5f0061..55f2bfb2 100644 --- a/src/main/java/hudson/plugins/promoted_builds/PromotionTargetAction.java +++ b/src/main/java/hudson/plugins/promoted_builds/PromotionTargetAction.java @@ -26,6 +26,11 @@ public AbstractBuild resolve() { } public AbstractBuild resolve(PromotionProcess parent) { + AbstractBuild build = this.resolve(); + if (build !=null){ + return build; + } + //In case of project renamed. AbstractProject j = parent.getOwner(); if (j==null) return null; return j.getBuildByNumber(number); diff --git a/src/main/java/hudson/plugins/promoted_builds/inheritance/JobPropertyImplSelector.java b/src/main/java/hudson/plugins/promoted_builds/inheritance/JobPropertyImplSelector.java new file mode 100644 index 00000000..342095f3 --- /dev/null +++ b/src/main/java/hudson/plugins/promoted_builds/inheritance/JobPropertyImplSelector.java @@ -0,0 +1,67 @@ + +package hudson.plugins.promoted_builds.inheritance; + +import org.apache.log4j.Logger; + +import hudson.Extension; +import hudson.model.JobProperty; + +import hudson.plugins.project_inheritance.projects.InheritanceProject; +import hudson.plugins.project_inheritance.projects.inheritance.InheritanceSelector; + +import hudson.plugins.promoted_builds.JobPropertyImpl; + +/** + * + * @author Jacek Tomaka + * @since TODO + */ +@Extension(optional=true) +public class JobPropertyImplSelector extends InheritanceSelector> { + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(JobPropertyImplSelector.class); + + @Override + public boolean isApplicableFor(Class clazz){ + return JobProperty.class.isAssignableFrom(clazz); + } + + @Override + public InheritanceSelector.MODE getModeFor(Class clazz){ + if (JobPropertyImpl.class.isAssignableFrom(clazz)) return MODE.USE_LAST; + return MODE.NOT_RESPONSIBLE; + } + + @Override + public String getObjectIdentifier(JobProperty obj){ + if ( obj!=null && JobPropertyImpl.class.getName().equals(obj.getClass().getName())){ + return JobPropertyImplSelector.class.getName(); + } + return null; + } + + @Override + public JobPropertyImpl merge(JobProperty prior, JobProperty latter, InheritanceProject caller){ + return null; + } + + @Override + public JobProperty handleSingleton(JobProperty jobProperty, InheritanceProject caller){ + if (jobProperty == null || caller == null) return jobProperty; + if (caller.isAbstract) return jobProperty; + + if (!JobPropertyImpl.class.isAssignableFrom(jobProperty.getClass())) return jobProperty; + + + JobPropertyImpl jobPropertyImpl = (JobPropertyImpl)jobProperty; + + try { + JobPropertyImpl newJobProperty = new JobPropertyImpl(jobPropertyImpl, caller); + return newJobProperty; + } catch (Exception ex){ + logger.error("Error during hacking up JobPropertyImpl", ex ); + } + return jobProperty; + } +} + diff --git a/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/DownstreamPassConditionInheritanceTest.java b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/DownstreamPassConditionInheritanceTest.java new file mode 100644 index 00000000..130cf9b5 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/DownstreamPassConditionInheritanceTest.java @@ -0,0 +1,99 @@ +/* + * The MIT License + * + * Copyright 2015 Franta Mejta + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package hudson.plugins.promoted_builds.conditions.inheritance; + +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Bug; + +import hudson.model.Result; +import hudson.plugins.project_inheritance.projects.InheritanceBuild; +import hudson.plugins.project_inheritance.projects.InheritanceProject.IMode; +import hudson.plugins.promoted_builds.JobPropertyImpl; +import hudson.plugins.promoted_builds.PromotedBuildAction; +import hudson.plugins.promoted_builds.PromotionProcess; +import hudson.plugins.promoted_builds.Status; +import hudson.plugins.promoted_builds.conditions.DownstreamPassCondition; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectRule; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectsPair; +import hudson.tasks.BuildTrigger; +import jenkins.model.Jenkins; + +public final class DownstreamPassConditionInheritanceTest { + + @Rule + public InheritanceProjectRule j = new InheritanceProjectRule(); + + @Test + @Bug(7739) + public void shouldEvaluateUpstreamRecursively() throws Exception { + final InheritanceProjectsPair pair1 = j.createInheritanceProjectDerivedWithBase(); + final InheritanceProjectsPair pair2 = j.createInheritanceProjectDerivedWithBase(); + final InheritanceProjectsPair pair3 = j.createInheritanceProjectDerivedWithBase(); + + + final JobPropertyImpl property = new JobPropertyImpl(pair1.getBase()); + pair1.getBase().addProperty(property); + + final PromotionProcess process = property.addProcess("promotion"); + process.conditions.add(new DownstreamPassCondition(pair3.getDerived().getFullName())); + + pair1.getDerived().getPublishersList().add(new BuildTrigger(pair2.getDerived().getFullName(), Result.SUCCESS)); + pair2.getDerived().getPublishersList().add(new BuildTrigger(pair3.getDerived().getFullName(), Result.SUCCESS)); + Jenkins.getInstance().rebuildDependencyGraph(); + + final InheritanceBuild run1 = j.buildAndAssertSuccess(pair1.getDerived()); + j.assertBuildStatusSuccess(run1); + j.waitUntilNoActivity(); + j.assertBuildStatusSuccess(pair2.getDerived().getLastBuild()); + j.waitUntilNoActivity(); + final InheritanceBuild run3 = j.assertBuildStatusSuccess(pair3.getDerived().getLastBuild()); + j.waitUntilNoActivity(); + + //We cannot assume that the process will contain builds because the process added to base project is different to the one in derived. + JobPropertyImpl jobProperty = pair1.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + + assertNotNull("derived jobProperty is null", jobProperty); + PromotionProcess processDerived = jobProperty.getItem("promotion"); + + assertEquals("fingerprint relation", run3.getUpstreamRelationship(pair1.getDerived()), -1); + assertFalse("no promotion process", processDerived.getBuilds().isEmpty()); + + final PromotedBuildAction action = run1.getAction(PromotedBuildAction.class); + assertNotNull("no promoted action", action); + + final Status promotion = action.getPromotion("promotion"); + assertNotNull("promotion not found", promotion); + assertTrue("promotion not successful", promotion.isPromotionSuccessful()); + } + +} diff --git a/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/ManualConditionInheritanceTest.java b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/ManualConditionInheritanceTest.java new file mode 100644 index 00000000..c6071604 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/ManualConditionInheritanceTest.java @@ -0,0 +1,204 @@ +package hudson.plugins.promoted_builds.conditions.inheritance; + +import hudson.ExtensionList; +import hudson.model.FreeStyleBuild; +import hudson.model.ParameterDefinition; +import hudson.model.ParameterValue; +import hudson.model.Descriptor; +import hudson.model.FreeStyleProject; +import hudson.model.StringParameterDefinition; +import hudson.plugins.project_inheritance.projects.InheritanceBuild; +import hudson.plugins.project_inheritance.projects.InheritanceProject.IMode; +import hudson.plugins.promoted_builds.JobPropertyImpl; +import hudson.plugins.promoted_builds.PromotedBuildAction; +import hudson.plugins.promoted_builds.Promotion; +import hudson.plugins.promoted_builds.PromotionProcess; +import hudson.plugins.promoted_builds.Status; + +import hudson.plugins.promoted_builds.conditions.ManualCondition; +import hudson.plugins.promoted_builds.conditions.ManualCondition.ManualApproval; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectRule; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectsPair; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.SortedMap; + +import org.junit.Rule; +import org.junit.Test; + +import jenkins.model.Jenkins; + +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; + +/** + * @author Jacek Tomaka + */ +public class ManualConditionInheritanceTest { + @Rule + public InheritanceProjectRule j = new InheritanceProjectRule(); + public static List getFormsByName(HtmlPage page, String name){ + List forms=new ArrayList(); + for (HtmlForm f:page.getForms()){ + if (name.equals(f.getNameAttribute())){ + forms.add(f); + } + } + return forms; + } + public static List getFormParameters(HtmlForm form){ + return form.getElementsByAttribute("div", "name", "parameter"); + } + @Test + public void testManualPromotionProcess() throws Exception { + InheritanceProjectsPair inheritanceProjectsPair = j.createInheritanceProjectDerivedWithBase(); + + ExtensionList list=Jenkins.getInstance().getExtensionList(Descriptor.class); + list.add(new JobPropertyImpl.DescriptorImpl(JobPropertyImpl.class)); + JobPropertyImpl base = new JobPropertyImpl(inheritanceProjectsPair.getBase()); + inheritanceProjectsPair.getBase().addProperty(base); + PromotionProcess foo = base.addProcess("foo"); + + ManualCondition condition=new ManualCondition(); + condition.getParameterDefinitions().add(new StringParameterDefinition("bogus_string_param_1", "bogus_value_1", "Bog parameter")); + condition.getParameterDefinitions().add(new StringParameterDefinition("bogus_string_param_2", "bogus_value_2", "Bog parameter")); + foo.conditions.add(condition); + + InheritanceBuild b1 = j.assertBuildStatusSuccess(inheritanceProjectsPair.getDerived().scheduleBuild2(0)); + + // promote a build + + List paramValues = condition.createDefaultValues(); + //try to add duplicate values + paramValues.addAll(condition.createDefaultValues()); + //We cannot assume that the process will contain builds because the process added to base project is different to the one in derived. + JobPropertyImpl jobProperty = inheritanceProjectsPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + assertNotNull("derived jobProperty is null", jobProperty); + PromotionProcess fooDerived = jobProperty.getItem("foo"); + + j.assertBuildStatusSuccess(condition.approve(b1, fooDerived, paramValues)); + ManualApproval manualApproval=b1.getAction(ManualApproval.class); + assertNotNull(manualApproval); + + PromotedBuildAction statuses=b1.getAction(PromotedBuildAction.class); + assertNotNull(statuses); + assertNotNull(statuses.getPromotions()); + assertFalse(statuses.getPromotions().isEmpty()); + } + + + @Test + public void testManualPromotionProcessViaWebClient() throws Exception { + InheritanceProjectsPair inheritanceProjectsPair = j.createInheritanceProjectDerivedWithBase(); + + ExtensionList list=Jenkins.getInstance().getExtensionList(Descriptor.class); + list.add(new JobPropertyImpl.DescriptorImpl(JobPropertyImpl.class)); + JobPropertyImpl base = new JobPropertyImpl(inheritanceProjectsPair.getBase()); + inheritanceProjectsPair.getDerived().addProperty(base); + PromotionProcess foo = base.addProcess("foo"); + ManualCondition condition=new ManualCondition(); + condition.getParameterDefinitions().add(new StringParameterDefinition("bogus_string_param_1", "bogus_value_1", "Bog parameter")); + condition.getParameterDefinitions().add(new StringParameterDefinition("bogus_string_param_2", "bogus_value_2", "Bog parameter")); + foo.conditions.add(condition); + + InheritanceBuild b1 = j.assertBuildStatusSuccess(inheritanceProjectsPair.getDerived().scheduleBuild2(0)); + assertNull(b1.getAction(ManualApproval.class)); + HtmlPage page=j.createWebClient().getPage(b1, "promotion"); + //Approve Promotion + List forms=getFormsByName(page, "approve"); + assertFalse(forms.isEmpty()); + assertTrue(forms.size()==1); + + HtmlForm form=forms.get(0); + List parameters=getFormParameters(form); + assertTrue(parameters.size()==condition.getParameterDefinitions().size()); + for(HtmlElement param:parameters){ + HtmlElement v=param.getElementsByAttribute("input", "name", "value").get(0); + v.setAttribute("value", v.getAttribute("value")+"1"); + } + j.submit(forms.get(0)); + j.waitUntilNoActivity(); + //We cannot assume that the process will contain builds because the process added to base project is different to the one in derived. + final JobPropertyImpl jobProperty = inheritanceProjectsPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + assertNotNull("derived jobProperty is null", jobProperty); + final PromotionProcess fooDerived = jobProperty.getItem("foo"); + ManualApproval approval=b1.getAction(ManualApproval.class); + assertNotNull(approval); + SortedMap builds=fooDerived.getBuildsAsMap(); + assertNotNull(builds); + assertTrue(builds.size()==1); + + //Re-Execute approved promotion + page=j.createWebClient().getPage(b1, "promotion"); + forms=getFormsByName(page,"build"); + assertFalse(forms.isEmpty()); + assertTrue(forms.size()==1); + form=forms.get(0); + parameters=getFormParameters(form); + assertTrue(parameters.size()==condition.getParameterDefinitions().size()); + + for(HtmlElement param:parameters){ + HtmlElement v=param.getElementsByAttribute("input", "name", "value").get(0); + v.setAttribute("value", v.getAttribute("value")+"2"); + } + j.submit(form); + j.waitUntilNoActivity(); + final JobPropertyImpl jobProperty2 = inheritanceProjectsPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + assertNotNull("derived jobProperty is null", jobProperty2); + final PromotionProcess fooDerived2 = jobProperty2.getItem("foo"); + + builds=fooDerived2.getBuildsAsMap(); + assertTrue(builds.size()==2); + List actions=b1.getActions(ManualApproval.class); + assertTrue(actions.size()==1); + + PromotedBuildAction buildActions=b1.getAction(PromotedBuildAction.class); + int buildIndex=1; + String valueSufix="1"; + List promotions=new ArrayList(); + promotions.addAll(builds.values()); + + Collections.reverse(promotions); + for (Promotion build:promotions){ + List values=build.getParameterDefinitionsWithValue(); + assertTrue(values.size()==condition.getParameterDefinitions().size()); + for (ParameterDefinition v:values){ + assertTrue(v instanceof StringParameterDefinition); + String pvalue=((StringParameterDefinition)v).getDefaultValue(); + assertTrue(pvalue.endsWith(valueSufix)); + } + buildIndex++; + valueSufix+=buildIndex; + } + + } +} diff --git a/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/SelfPromotionInheritanceTest.java b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/SelfPromotionInheritanceTest.java new file mode 100644 index 00000000..912ceab1 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/conditions/inheritance/SelfPromotionInheritanceTest.java @@ -0,0 +1,215 @@ +package hudson.plugins.promoted_builds.conditions.inheritance; + +import hudson.model.Cause; +import hudson.model.ParametersAction; +import hudson.model.ParametersDefinitionProperty; +import hudson.model.Result; +import hudson.model.StringParameterDefinition; +import hudson.model.StringParameterValue; +import hudson.plugins.project_inheritance.projects.InheritanceBuild; +import hudson.plugins.project_inheritance.projects.InheritanceProject.IMode; +import hudson.plugins.promoted_builds.JobPropertyImpl; +import hudson.plugins.promoted_builds.PromotedBuildAction; +import hudson.plugins.promoted_builds.Promotion; +import hudson.plugins.promoted_builds.PromotionProcess; +import hudson.plugins.promoted_builds.conditions.FixedResultBuilder; +import hudson.plugins.promoted_builds.conditions.SelfPromotionCondition; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectRule; +import hudson.plugins.promoted_builds.inheritance.helpers.InheritanceProjectsPair; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Bug; + + +/** + * @author Jacek Tomaka + */ +public class SelfPromotionInheritanceTest { + @Rule + public InheritanceProjectRule j = new InheritanceProjectRule(); + @Test + public void testBasic() throws Exception { + InheritanceProjectsPair inheritanceProjectPair = j.createInheritanceProjectDerivedWithBase(); + + // promote if the downstream passes + JobPropertyImpl promotion = new JobPropertyImpl(inheritanceProjectPair.getBase()); + inheritanceProjectPair.getBase().addProperty(promotion); + + PromotionProcess promo1 = promotion.addProcess("promo1"); + promo1.conditions.add(new SelfPromotionCondition(false)); + + PromotionProcess promo2 = promotion.addProcess("promo2"); + promo2.conditions.add(new SelfPromotionCondition(false)); + + + InheritanceBuild b = j.assertBuildStatusSuccess(inheritanceProjectPair.getDerived().scheduleBuild2(0)); + + // internally, the promotion is still an asynchronous process. It just happens + // right away after the build is complete. + j.waitUntilNoActivity(); + + // rebind + promotion = inheritanceProjectPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + promo1 = promotion.getItem("promo1"); + promo2 = promotion.getItem("promo2"); + + + // verify that both promotions happened + Promotion pb = promo1.getBuilds().get(0); + assertSame(pb.getTarget(),b); + + pb = promo2.getBuilds().get(0); + assertSame(pb.getTarget(),b); + + PromotedBuildAction badge = (PromotedBuildAction) b.getBadgeActions().get(0); + assertTrue(badge.contains(promo1)); + assertTrue(badge.contains(promo2)); + } + @Test + public void testUnstable() throws Exception { + InheritanceProjectsPair inheritanceProjectPair = j.createInheritanceProjectDerivedWithBase(); + + // promote if the downstream passes + JobPropertyImpl promotion = new JobPropertyImpl(inheritanceProjectPair.getBase()); + inheritanceProjectPair.getBase().addProperty(promotion); + + PromotionProcess promo1 = promotion.addProcess("promo1"); + promo1.conditions.add(new SelfPromotionCondition(false)); + + PromotionProcess promo2 = promotion.addProcess("promo2"); + promo2.conditions.add(new SelfPromotionCondition(true)); + + + + inheritanceProjectPair.getDerived().getBuildersList().add(unstableBuilder()); + InheritanceBuild b = j.assertBuildStatus(Result.UNSTABLE, inheritanceProjectPair.getDerived().scheduleBuild2(0).get()); + j.waitUntilNoActivity(); + // rebind + promotion = inheritanceProjectPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + promo1 = promotion.getItem("promo1"); + promo2 = promotion.getItem("promo2"); + // internally, the promotion is still an asynchronous process. It just happens + // right away after the build is complete. + + + // verify that only one promotions happened + assertTrue(promo1.getBuilds().isEmpty()); + + Promotion pb = promo2.getBuilds().get(0); + assertSame(pb.getTarget(),b); + + PromotedBuildAction badge = (PromotedBuildAction) b.getBadgeActions().get(0); + assertFalse(badge.contains(promo1)); + assertTrue(badge.contains(promo2)); + } + + @Test + public void testFailure() throws Exception { + InheritanceProjectsPair inheritanceProjectPair = j.createInheritanceProjectDerivedWithBase(); + + // promote if the downstream passes + JobPropertyImpl promotion = new JobPropertyImpl(inheritanceProjectPair.getBase()); + inheritanceProjectPair.getBase().addProperty(promotion); + + PromotionProcess promo1 = promotion.addProcess("promo1"); + promo1.conditions.add(new SelfPromotionCondition(false)); + + PromotionProcess promo2 = promotion.addProcess("promo2"); + promo2.conditions.add(new SelfPromotionCondition(true)); + + inheritanceProjectPair.getDerived().getBuildersList().add(failureBuilder()); + InheritanceBuild b = j.assertBuildStatus(Result.FAILURE, inheritanceProjectPair.getDerived().scheduleBuild2(0).get()); + + // internally, the promotion is still an asynchronous process. It just happens + // right away after the build is complete. + j.waitUntilNoActivity(); + + // rebind + promotion = inheritanceProjectPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + promo1 = promotion.getItem("promo1"); + promo2 = promotion.getItem("promo2"); + + + // verify that neither promotions happened + assertTrue("promo1 did not occur", promo1.getBuilds().isEmpty()); + assertTrue("promo2 did not occur", promo2.getBuilds().isEmpty()); + + PromotedBuildAction badge = (PromotedBuildAction) b.getBadgeActions().get(0); + assertFalse(badge.contains(promo1)); + assertFalse(badge.contains(promo2)); + } + + @Test + @Bug(22679) + public void testPromotionEnvironmentShouldIncludeTargetParameters() throws Exception { + String paramName = "param"; + + InheritanceProjectsPair inheritanceProjectPair = j.createInheritanceProjectDerivedWithBase(); + + // promote if the downstream passes + JobPropertyImpl promotion = new JobPropertyImpl(inheritanceProjectPair.getBase()); + inheritanceProjectPair.getBase().addProperty(promotion); + + inheritanceProjectPair.getBase().addProperty(new ParametersDefinitionProperty(new StringParameterDefinition(paramName, ""))); + PromotionProcess promo1 = promotion.addProcess("promo1"); + promo1.conditions.add(new SelfPromotionCondition(false)); + + String paramValue = "someString"; + j.assertBuildStatusSuccess(inheritanceProjectPair.getDerived().scheduleBuild2(0, new Cause.UserCause(), + new ParametersAction(new StringParameterValue(paramName, paramValue)))); + // internally, the promotion is still an asynchronous process. It just happens + // right away after the build is complete. + j.waitUntilNoActivity(); + + // rebind + promotion = inheritanceProjectPair.getDerived().getProperty(JobPropertyImpl.class, + /*Forcing inheritance as temporary hack for inheritance plugin 1.53 + because that version of the plugin uses inheritance only for certain predefined cases: + -specific methods on the call stack + -url paths. + This has been changed as pull request https://github.com/i-m-c/jenkins-inheritance-plugin/pull/40 + */ + IMode.INHERIT_FORCED); + promo1 = promotion.getItem("promo1"); + + // verify that the promotion's environment contains the parameter from the target build. + Promotion pb = promo1.getBuildByNumber(1); + assertEquals(paramValue, pb.getEnvironment(null).get(paramName, null)); + } + + private FixedResultBuilder failureBuilder() { + return new FixedResultBuilder(Result.FAILURE); + } + + private FixedResultBuilder unstableBuilder() { + return new FixedResultBuilder(Result.UNSTABLE); + } + +} diff --git a/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectRule.java b/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectRule.java new file mode 100644 index 00000000..af3fd938 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectRule.java @@ -0,0 +1,28 @@ +package hudson.plugins.promoted_builds.inheritance.helpers; + +import java.io.IOException; + +import org.jvnet.hudson.test.JenkinsRule; + +import hudson.plugins.project_inheritance.projects.InheritanceProject; +import hudson.plugins.project_inheritance.projects.references.SimpleProjectReference; + +public class InheritanceProjectRule extends JenkinsRule { + InheritanceProject createInheritanceProject() throws IOException{ + return createInheritanceProject(createUniqueProjectName()); + } + InheritanceProject createInheritanceProject(String name) throws IOException{ + return jenkins.createProject(InheritanceProject.class, name); + } + /** + * Returns BASE,DERIVED projects + * @throws IOException + */ + public InheritanceProjectsPair createInheritanceProjectDerivedWithBase() throws IOException{ + String baseProjectName = createUniqueProjectName(); + InheritanceProject base = createInheritanceProject(baseProjectName); + InheritanceProject derived = createInheritanceProject(); + derived.addParentReference(new SimpleProjectReference(baseProjectName)); + return new InheritanceProjectsPair(base, derived); + } +} diff --git a/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectsPair.java b/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectsPair.java new file mode 100644 index 00000000..3c839064 --- /dev/null +++ b/src/test/java/hudson/plugins/promoted_builds/inheritance/helpers/InheritanceProjectsPair.java @@ -0,0 +1,22 @@ +package hudson.plugins.promoted_builds.inheritance.helpers; + +import hudson.plugins.project_inheritance.projects.InheritanceProject; +/** + * @author Jacek Tomaka + */ +public class InheritanceProjectsPair { + + private InheritanceProject base; + private InheritanceProject derived; + public InheritanceProject getBase() { + return base; + } + public InheritanceProject getDerived() { + return derived; + } + + public InheritanceProjectsPair(InheritanceProject base, InheritanceProject derived){ + this.base = base; + this.derived = derived; + } +}