Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve queue restart tests #6453

Merged
merged 1 commit into from
Apr 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions test/src/test/java/hudson/model/QueueCrashTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package hudson.model;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import hudson.ExtensionList;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RestartableJenkinsRule;

public class QueueCrashTest {

@Rule public RestartableJenkinsRule rr = new RestartableJenkinsRule();

@Test
public void persistQueueOnCrash() {
rr.thenWithHardShutdown(j -> {
// Speed up the test run by shortening the periodic save interval from 60 seconds to 5
// seconds.
Queue.Saver.DELAY_SECONDS = 5;

scheduleSomeBuild(j);
assertBuildIsScheduled(j);

// Wait for the periodic save to complete.
ExtensionList.lookupSingleton(Queue.Saver.class)
.getNextSave()
.get(30, TimeUnit.SECONDS);

// Ensure the periodic save process saved the queue, since the cleanup process will not
// run on a crash.
assertTrue(new File(j.jenkins.getRootDir(), "queue.xml").exists());
});
rr.then(QueueCrashTest::assertBuildIsScheduled);
}

@Test
public void doNotPersistQueueOnCrashBeforeSave() {
rr.thenWithHardShutdown(j -> {
// Avoid periodic save in order to simulate the scenario of a crash before initial save.
Queue.Saver.DELAY_SECONDS = (int) TimeUnit.DAYS.toSeconds(1);

scheduleSomeBuild(j);
assertBuildIsScheduled(j);

// Ensure the queue has not been saved in order to test that a crash in this scenario
// results in the queue being lost.
assertFalse(new File(j.jenkins.getRootDir(), "queue.xml").exists());
});
rr.then(QueueCrashTest::assertBuildIsNotScheduled);
}

private static void assertBuildIsScheduled(JenkinsRule j) {
j.jenkins.getQueue().maintain();
assertFalse(j.jenkins.getQueue().isEmpty());
}

private static void assertBuildIsNotScheduled(JenkinsRule j) {
j.jenkins.getQueue().maintain();
assertTrue(j.jenkins.getQueue().isEmpty());
}

private static void scheduleSomeBuild(JenkinsRule j) throws IOException {
FreeStyleProject p = j.createFreeStyleProject();
p.setAssignedLabel(Label.get("waitforit"));
p.scheduleBuild2(0);
}
}
83 changes: 41 additions & 42 deletions test/src/test/java/hudson/model/QueueRestartTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,66 +24,65 @@

package hudson.model;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;

import hudson.ExtensionList;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.RestartableJenkinsRule;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule;
import org.jvnet.hudson.test.recipes.LocalData;

public class QueueRestartTest {

@Rule
public RestartableJenkinsRule j = new RestartableJenkinsRule();
@Rule public RealJenkinsRule rr = new RealJenkinsRule();

@LocalData("quietDown")
@Test
public void persistQueueOnRestart() {
j.addStep(new Statement() {
@Override public void evaluate() throws Throwable {
Queue.Saver.DELAY_SECONDS = 24 * 60 * 60; // Avoid period save as we are after the explicit one
scheduleSomeBuild();
assertBuildIsScheduled();
}
});
j.addStep(new Statement() {
@Override public void evaluate() {
assertBuildIsScheduled();
}
});
public void persistQueueOnRestart() throws Throwable {
// Avoid periodic save in order to test that the cleanup process saves the queue.
rr.javaOptions("-Dhudson.model.Queue.Saver.DELAY_SECONDS=" + TimeUnit.DAYS.toSeconds(1));

rr.then(QueueRestartTest::queueBuild);
rr.then(QueueRestartTest::assertBuildFinishes);
}

@LocalData("quietDown")
@Test
public void persistQueueOnCrash() {
j.addStepWithDirtyShutdown(new Statement() {
@Override public void evaluate() throws Throwable {
Queue.Saver.DELAY_SECONDS = 0; // Call Queue#save() on every queue modification simulating time has passed before crash
scheduleSomeBuild();
assertBuildIsScheduled();
public void persistQueueOnConsecutiveRestarts() throws Throwable {
// Avoid periodic save in order to test that the cleanup process saves the queue.
rr.javaOptions("-Dhudson.model.Queue.Saver.DELAY_SECONDS=" + TimeUnit.DAYS.toSeconds(1));

// Save have no delay though is not synchronous
ExtensionList.lookup(Queue.Saver.class).get(0).getNextSave().get(3, TimeUnit.SECONDS);
rr.then(QueueRestartTest::queueBuild);
rr.then(QueueRestartTest::assertBuildIsScheduled);
rr.then(QueueRestartTest::assertBuildFinishes);
}

assertTrue("queue.xml does not exist", j.j.jenkins.getQueue().getXMLQueueFile().exists());
}
});
j.addStep(new Statement() {
@Override public void evaluate() {
assertBuildIsScheduled();
}
});
private static void queueBuild(JenkinsRule j) throws IOException {
FreeStyleProject p = j.createFreeStyleProject("p");
p.scheduleBuild2(0);
assertBuildIsScheduled(j);

// Ensure the queue has not been saved in order to test that the cleanup process saves
// the queue.
assertFalse(new File(j.jenkins.getRootDir(), "queue.xml").exists());
}

private void assertBuildIsScheduled() {
assertEquals(1, j.j.jenkins.getQueue().getItems().length);
private static void assertBuildFinishes(JenkinsRule j) throws Exception {
assertBuildIsScheduled(j);
j.jenkins.doCancelQuietDown();
FreeStyleProject p = j.jenkins.getItemByFullName("p", FreeStyleProject.class);
FreeStyleBuild b;
while ((b = p.getLastBuild()) == null) {
Thread.sleep(100);
}
j.assertBuildStatusSuccess(j.waitForCompletion(b));
}

private void scheduleSomeBuild() throws IOException {
FreeStyleProject p = j.j.createFreeStyleProject();
p.setAssignedLabel(Label.get("waitforit"));
p.scheduleBuild2(0);
private static void assertBuildIsScheduled(JenkinsRule j) {
j.jenkins.getQueue().maintain();
assertFalse(j.jenkins.getQueue().isEmpty());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import jenkins.model.Jenkins

// Start in a state that doesn't do any builds.
Jenkins.get().doQuietDown()