提交 ce29cdb3 编写于 作者: O Oliver Gondža

Merge branch 'master' of github.com:jenkinsci/jenkins

......@@ -61,6 +61,9 @@ Upcoming changes</a>
<li class=bug>
Windows JDK installer should not install a public JRE.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-8957">issue 8957</a>)
<li class='major bug'>
After deleting last build, next build of last build is zombie.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-19920">issue 19920</a>)
<li class='rfe'>
Split matrix authorization strategies into an independent plugin.
<li class='rfe'>
......
......@@ -162,10 +162,13 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
* <p>
* Unlike {@link Run}, {@link AbstractBuild}s do lazy-loading, so we don't use
* {@link Run#previousBuild} and {@link Run#nextBuild}, and instead use these
* fields and point to {@link #selfReference} of adjacent builds.
* fields and point to {@link #selfReference} (or {@link #none}) of adjacent builds.
*/
private volatile transient BuildReference<R> previousBuild, nextBuild;
@SuppressWarnings({"unchecked", "rawtypes"}) private static final BuildReference NONE = new BuildReference("NONE", null);
@SuppressWarnings("unchecked") private BuildReference<R> none() {return NONE;}
/*package*/ final transient BuildReference<R> selfReference = new BuildReference<R>(getId(),_this());
......@@ -193,11 +196,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
if(nextBuild!=null) {
AbstractBuild nb = nextBuild.get();
if (nb!=null) {
// remove the oldest build
if (previousBuild == selfReference)
nb.previousBuild = nextBuild;
else
nb.previousBuild = previousBuild;
nb.previousBuild = previousBuild;
}
}
if(previousBuild!=null) {
......@@ -223,13 +222,11 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
this.previousBuild = pb.selfReference;
return pb;
} else {
// this indicates that we know there's no previous build
// (as opposed to we don't know if/what our previous build is.
this.previousBuild = selfReference;
this.previousBuild = none();
return null;
}
}
if (r==selfReference)
if (r==none())
return null;
R referent = r.get();
......@@ -253,13 +250,11 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
this.nextBuild = nb.selfReference;
return nb;
} else {
// this indicates that we know there's no next build
// (as opposed to we don't know if/what our next build is.
this.nextBuild = selfReference;
this.nextBuild = none();
return null;
}
}
if (r==selfReference)
if (r==none())
return null;
R referent = r.get();
......
......@@ -723,7 +723,11 @@ public abstract class AbstractLazyLoadRunMap<R> extends AbstractMap<Integer,R> i
public synchronized boolean removeValue(R run) {
Index copy = copy();
copy.byNumber.remove(getNumberOf(run));
int n = getNumberOf(run);
copy.byNumber.remove(n);
SortedIntList a = new SortedIntList(numberOnDisk);
a.removeValue(n);
numberOnDisk = a;
BuildReference<R> old = copy.byId.remove(getIdOf(run));
this.index = copy;
......
......@@ -15,7 +15,9 @@ import java.io.IOException;
* {@link HudsonTestCase} with more convenience methods for Groovy.
*
* @author Kohsuke Kawaguchi
* @deprecated Use {@link GroovyJenkinsRule} instead.
*/
@Deprecated
public abstract class GroovyHudsonTestCase extends HudsonTestCase {
/**
* Executes the given closure on the server, in the context of an HTTP request.
......
/*
* The MIT License
*
* Copyright 2013 Jesse Glick.
*
* 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 org.jvnet.hudson.test;
import groovy.lang.Closure;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.tasks.Builder;
import java.io.IOException;
import java.util.concurrent.Callable;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* {@link JenkinsRule} variant with special options for tests written in Groovy.
* @since 1.535
*/
public class GroovyJenkinsRule extends JenkinsRule {
/**
* Executes the given closure on the server, in the context of an HTTP request.
* This is useful for testing some methods that require {@link StaplerRequest} and {@link StaplerResponse}.
*
* <p>
* The closure will get the request and response as parameters.
*/
public Object executeOnServer(final Closure c) throws Exception {
return executeOnServer(new Callable<Object>() {
@Override public Object call() throws Exception {
return c.call();
}
});
}
/**
* Wraps a closure as a {@link Builder}.
*/
public Builder builder(final Closure c) {
return new TestBuilder() {
@Override public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
Object r = c.call(new Object[] {build, launcher, listener});
if (r instanceof Boolean) {
return (Boolean) r;
}
return true;
}
};
}
}
......@@ -29,21 +29,29 @@ import hudson.slaves.EnvironmentVariablesNodeProperty
import hudson.slaves.EnvironmentVariablesNodeProperty.Entry
import org.jvnet.hudson.test.CaptureEnvironmentBuilder
import org.jvnet.hudson.test.GroovyHudsonTestCase
import org.jvnet.hudson.test.GroovyJenkinsRule
import org.jvnet.hudson.test.FakeChangeLogSCM
import org.jvnet.hudson.test.FailureBuilder
import org.jvnet.hudson.test.UnstableBuilder
public class AbstractBuildTest extends GroovyHudsonTestCase {
void testVariablesResolved() {
def project = createFreeStyleProject();
jenkins.nodeProperties.replaceBy([
import static org.junit.Assert.*
import org.junit.Rule
import org.junit.Test
import org.jvnet.hudson.test.Bug
public class AbstractBuildTest {
@Rule public GroovyJenkinsRule j = new GroovyJenkinsRule();
@Test void variablesResolved() {
def project = j.createFreeStyleProject();
j.jenkins.nodeProperties.replaceBy([
new EnvironmentVariablesNodeProperty(new Entry("KEY1", "value"), new Entry("KEY2",'$KEY1'))]);
def builder = new CaptureEnvironmentBuilder();
project.buildersList.add(builder);
buildAndAssertSuccess(project);
j.buildAndAssertSuccess(project);
def envVars = builder.getEnvVars();
assertEquals("value", envVars["KEY1"]);
......@@ -53,15 +61,15 @@ public class AbstractBuildTest extends GroovyHudsonTestCase {
/**
* Makes sure that raw console output doesn't get affected by XML escapes.
*/
void testRawConsoleOutput() {
@Test void rawConsoleOutput() {
def out = "<test>&</test>";
def p = createFreeStyleProject();
p.buildersList.add(builder { builder,launcher,BuildListener listener ->
def p = j.createFreeStyleProject();
p.buildersList.add(j.builder { builder,launcher,BuildListener listener ->
listener.logger.println(out);
})
def b = buildAndAssertSuccess(p);
Page rsp = createWebClient().goTo("${b.url}/consoleText", "text/plain");
def b = j.buildAndAssertSuccess(p);
Page rsp = j.createWebClient().goTo("${b.url}/consoleText", "text/plain");
println "Output:\n"+rsp.webResponse.contentAsString
assertTrue(rsp.webResponse.contentAsString.contains(out));
}
......@@ -70,48 +78,62 @@ public class AbstractBuildTest extends GroovyHudsonTestCase {
assertEquals(expectedIds as Set, b.culprits*.id as Set);
}
void testCulprits() {
@Test void culprits() {
def p = createFreeStyleProject();
def p = j.createFreeStyleProject();
def scm = new FakeChangeLogSCM()
p.scm = scm
// 1st build, successful, no culprits
scm.addChange().withAuthor("alice")
def b = assertBuildStatus(Result.SUCCESS,p.scheduleBuild2(0).get())
def b = j.assertBuildStatus(Result.SUCCESS,p.scheduleBuild2(0).get())
assertCulprits(b,["alice"])
// 2nd build
scm.addChange().withAuthor("bob")
p.buildersList.add(new FailureBuilder())
b = assertBuildStatus(Result.FAILURE,p.scheduleBuild2(0).get())
b = j.assertBuildStatus(Result.FAILURE,p.scheduleBuild2(0).get())
assertCulprits(b,["bob"])
// 3rd build. bob continues to be in culprit
scm.addChange().withAuthor("charlie")
b = assertBuildStatus(Result.FAILURE,p.scheduleBuild2(0).get())
b = j.assertBuildStatus(Result.FAILURE,p.scheduleBuild2(0).get())
assertCulprits(b,["bob","charlie"])
// 4th build, unstable. culprit list should continue
scm.addChange().withAuthor("dave")
p.buildersList.replaceBy([new UnstableBuilder()])
b = assertBuildStatus(Result.UNSTABLE,p.scheduleBuild2(0).get())
b = j.assertBuildStatus(Result.UNSTABLE,p.scheduleBuild2(0).get())
assertCulprits(b,["bob","charlie","dave"])
// 5th build, unstable. culprit list should continue
scm.addChange().withAuthor("eve")
b = assertBuildStatus(Result.UNSTABLE,p.scheduleBuild2(0).get())
b = j.assertBuildStatus(Result.UNSTABLE,p.scheduleBuild2(0).get())
assertCulprits(b,["bob","charlie","dave","eve"])
// 6th build, success, accumulation continues up to this point
scm.addChange().withAuthor("fred")
p.buildersList.replaceBy([])
b = assertBuildStatus(Result.SUCCESS,p.scheduleBuild2(0).get())
b = j.assertBuildStatus(Result.SUCCESS,p.scheduleBuild2(0).get())
assertCulprits(b,["bob","charlie","dave","eve","fred"])
// 7th build, back to empty culprits
scm.addChange().withAuthor("george")
b = assertBuildStatus(Result.SUCCESS,p.scheduleBuild2(0).get())
b = j.assertBuildStatus(Result.SUCCESS,p.scheduleBuild2(0).get())
assertCulprits(b,["george"])
}
@Bug(19920)
@Test void lastBuildNextBuild() {
FreeStyleProject p = j.createFreeStyleProject();
AbstractBuild b1 = j.assertBuildStatusSuccess(p.scheduleBuild2(0));
AbstractBuild b2 = j.assertBuildStatusSuccess(p.scheduleBuild2(0));
assertEquals(b2, p.getLastBuild());
b2.getNextBuild(); // force this to be initialized
b2.delete();
assertEquals(b1, p.getLastBuild());
b1 = p.getLastBuild();
assertEquals(null, b1.getNextBuild());
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册