package hudson.util;
import hudson.WebAppMain;
import hudson.model.Hudson;
import hudson.model.listeners.ItemListener;
import static hudson.util.BootFailureTest.makeBootFail;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import jenkins.model.Jenkins;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.HudsonHomeLoader;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestEnvironment;
import org.jvnet.hudson.test.TestExtension;
import org.kohsuke.stapler.WebApp;
/**
*
*
* @author Kohsuke Kawaguchi
*/
public class BootFailureTest {
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder();
static boolean makeBootFail = true;
static WebAppMain wa;
static class CustomRule extends JenkinsRule {
@Override
public void before() throws Throwable {
env = new TestEnvironment(testDescription);
env.pin();
// don't let Jenkins start automatically
}
@Override
public Hudson newHudson() throws Exception {
ServletContext ws = createWebServer();
wa = new WebAppMain() {
@Override
public WebAppMain.FileAndDescription getHomeDir(ServletContextEvent event) {
try {
return new WebAppMain.FileAndDescription(homeLoader.allocate(), "test");
} catch (Exception x) {
throw new AssertionError(x);
}
}
};
wa.contextInitialized(new ServletContextEvent(ws));
wa.joinInit();
Object a = WebApp.get(ws).getApp();
if (a instanceof Hudson) {
return (Hudson) a;
}
return null; // didn't boot
}
}
@Rule
public CustomRule j = new CustomRule();
@After
public void tearDown() {
Jenkins j = Jenkins.getInstanceOrNull();
if (j != null) {
j.cleanUp();
}
}
public static class SeriousError extends Error {}
@TestExtension("runBootFailureScript")
public static class InduceBootFailure extends ItemListener {
@Override
public void onLoaded() {
if (makeBootFail)
throw new SeriousError();
}
}
@Test
public void runBootFailureScript() throws Exception {
final File home = tmpDir.newFolder();
j.with(new HudsonHomeLoader() {
@Override
public File allocate() throws Exception {
return home;
}
});
// creates a script
FileUtils.write(new File(home, "boot-failure.groovy"), "hudson.util.BootFailureTest.problem = exception");
File d = new File(home, "boot-failure.groovy.d");
d.mkdirs();
FileUtils.write(new File(d, "1.groovy"), "hudson.util.BootFailureTest.runRecord << '1'");
FileUtils.write(new File(d, "2.groovy"), "hudson.util.BootFailureTest.runRecord << '2'");
// first failed boot
makeBootFail = true;
assertNull(j.newHudson());
assertEquals(1, bootFailures(home));
// second failed boot
problem = null;
runRecord = new ArrayList<String>();
assertNull(j.newHudson());
assertEquals(2, bootFailures(home));
assertEquals(Arrays.asList("1", "2"), runRecord);
// make sure the script has actually run
assertEquals(SeriousError.class, problem.getCause().getClass());
// if it boots well, the failure record should be gone
makeBootFail = false;
assertNotNull(j.newHudson());
assertFalse(BootFailure.getBootFailureFile(home).exists());
}
private static int bootFailures(File home) throws IOException {
return FileUtils.readLines(BootFailure.getBootFailureFile(home)).size();
}
@Issue("JENKINS-24696")
@Test
public void interruptedStartup() throws Exception {
final File home = tmpDir.newFolder();
j.with(new HudsonHomeLoader() {
@Override
public File allocate() throws Exception {
return home;
}
});
File d = new File(home, "boot-failure.groovy.d");
d.mkdirs();
FileUtils.write(new File(d, "1.groovy"), "hudson.util.BootFailureTest.runRecord << '1'");
j.newHudson();
assertEquals(Collections.singletonList("1"), runRecord);
}
@TestExtension("interruptedStartup")
public static class PauseBoot extends ItemListener {
@Override
public void onLoaded() {
wa.contextDestroyed(null);
}
}
// to be set by the script
public static Exception problem;
public static List<String> runRecord = new ArrayList<String>();
}