Skip to content
Permalink
Browse files

Merge pull request #46 from ikedam/feature/JENKINS-43803_SkewProgressive

[JENKINS-43803] Fix wrong calcuration of `ProgressiveDelay` when 2 series of retries run alternately.
  • Loading branch information...
ikedam committed Feb 23, 2019
2 parents d9558c6 + c8d77b6 commit 789d221f1582dd19ffc96fc62073c129dffa16cf
@@ -40,18 +40,20 @@ public int computeScheduleDelay(AbstractBuild failedBuild) {
//
// so to avoid this problem, progressively introduce delay until the next build

int n = 1;
int delay = increment;
Run r = failedBuild;
while (r != null && r.getAction(NaginatorAction.class) != null) {
r = r.getPreviousBuild();
n++;
delay += n * increment;
}
// delay = increment * n * (n + 1) / 2
int n = getRetryCount(failedBuild);
int factor = (n + 1) * (n + 2) / 2;
int delay = increment * factor;
return max <= 0 ? delay : min(delay, max);
}

private int getRetryCount(AbstractBuild<?, ?> failedBuild) {
NaginatorAction action = failedBuild.getAction(NaginatorAction.class);
if (action == null) {
return 0;
}
return action.getRetryCount();
}

@Extension
public static class DescriptorImpl extends ScheduleDelayDescriptor {
@Override
@@ -1,55 +1,133 @@
package com.chikli.hudson.plugin.naginator;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.Arrays;

import org.junit.ClassRule;
import org.junit.Test;
import org.jvnet.hudson.test.FailureBuilder;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;

import hudson.model.AbstractBuild;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;

/**
* A test suite for {@link ProgressiveDelay}.
*/
public class ProgressiveDelayTest {
@ClassRule
public static JenkinsRule j = new JenkinsRule();

@Test
public void testComputeScheduleDelay() {
public void testComputeScheduleDelay() throws Exception {
FreeStyleProject p = j.createFreeStyleProject();
p.getBuildersList().add(new FailureBuilder());
p.getPublishersList().add(new NaginatorPublisher(
"", // regexpForRerun
true, // rerunIfUnstable
false, // retunForMatrixPart
false, // checkRegexp
2, // maxSchedule
new FixedDelay(0)
));
p.scheduleBuild2(0);
j.waitUntilNoActivity();

FreeStyleBuild build1 = p.getFirstBuild();
FreeStyleBuild build2 = build1.getNextBuild();
FreeStyleBuild build3 = build2.getNextBuild();

final ProgressiveDelay progressiveDelay = new ProgressiveDelay(15, 50);
assertEquals(
15,
progressiveDelay.computeScheduleDelay(createBuild(false, null)));
assertEquals(
45,
progressiveDelay.computeScheduleDelay(createBuild(true, null)));
progressiveDelay.computeScheduleDelay(build1));
assertEquals(
45,
progressiveDelay.computeScheduleDelay(createBuild(true, createBuild(false, null))));
progressiveDelay.computeScheduleDelay(build2));
// Capped at maximum delay
assertEquals(
50,
progressiveDelay.computeScheduleDelay(createBuild(true, createBuild(true, createBuild(false, null)))));
// Only consecutive rescheduled builds count
assertEquals(
15,
progressiveDelay.computeScheduleDelay(createBuild(false, createBuild(true, createBuild(false, null)))));
assertEquals(
45,
progressiveDelay.computeScheduleDelay(createBuild(true, createBuild(false, createBuild(true, null)))));
progressiveDelay.computeScheduleDelay(build3));
}

@Test
public void testComputeScheduleDelayNoMax() {
public void testComputeScheduleDelayNoMax() throws Exception {
FreeStyleProject p = j.createFreeStyleProject();
p.getBuildersList().add(new FailureBuilder());
p.getPublishersList().add(new NaginatorPublisher(
"", // regexpForRerun
true, // rerunIfUnstable
false, // retunForMatrixPart
false, // checkRegexp
2, // maxSchedule
new FixedDelay(0)
));
p.scheduleBuild2(0);
j.waitUntilNoActivity();

FreeStyleBuild build1 = p.getFirstBuild();
FreeStyleBuild build2 = build1.getNextBuild();
FreeStyleBuild build3 = build2.getNextBuild();

final ProgressiveDelay progressiveDelay = new ProgressiveDelay(15, 0);
assertEquals(
15,
progressiveDelay.computeScheduleDelay(createBuild(false, null)));
progressiveDelay.computeScheduleDelay(build1));
assertEquals(
45,
progressiveDelay.computeScheduleDelay(createBuild(true, createBuild(false, null))));
progressiveDelay.computeScheduleDelay(build2));
assertEquals(
90,
progressiveDelay.computeScheduleDelay(createBuild(true, createBuild(true, createBuild(false, null)))));
progressiveDelay.computeScheduleDelay(build3));
}

@Issue("JENKINS-43803")
@Test
public void testBuildsRunAlternately() throws Exception {
FreeStyleProject p = j.createFreeStyleProject();
p.getBuildersList().add(new FailureBuilder());

FreeStyleBuild buildA1 = p.scheduleBuild2(0).get();
assertTrue(NaginatorRetryAction.scheduleBuild(
buildA1,
0, // delay
1, // retyCount
120 // maxRetryCount
));
j.waitUntilNoActivity();
FreeStyleBuild buildA2 = p.getLastBuild();

p.scheduleBuild2(0).get(); // buildB1

assertTrue(NaginatorRetryAction.scheduleBuild(
buildA2,
0, // delay
2, // retyCount
120 // maxRetryCount
));

j.waitUntilNoActivity();
FreeStyleBuild buildA3 = p.getLastBuild();

ProgressiveDelay delay = new ProgressiveDelay(300, 0);
assertEquals(
Arrays.asList(
300,
900,
1800
),
Arrays.asList(
delay.computeScheduleDelay(buildA1),
delay.computeScheduleDelay(buildA2),
delay.computeScheduleDelay(buildA3)
)
);
}

private static AbstractBuild createBuild(final boolean hasNaginatorAction, final AbstractBuild previousBuild) {

0 comments on commit 789d221

Please sign in to comment.
You can’t perform that action at this time.