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

[JENKINS-26398] Use standard JenkinsRule.createSlave plus new InboundAgentRule #219

Merged
merged 3 commits into from
May 3, 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
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
<properties>
<changelist>999999-SNAPSHOT</changelist>
<jenkins.version>2.303.3</jenkins.version>
<jenkins-test-harness.version>1746.v2b_3c5d1983b_e</jenkins-test-harness.version> <!-- TODO until in plugin-pom -->
<useBeta>true</useBeta>
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
<hpi.compatibleSinceVersion>2.40</hpi.compatibleSinceVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,13 @@
import hudson.model.labels.LabelAtom;
import hudson.model.queue.CauseOfBlockage;
import hudson.model.queue.QueueTaskDispatcher;
import hudson.remoting.Launcher;
import hudson.remoting.Which;
import hudson.security.ACL;
import hudson.security.ACLContext;
import hudson.slaves.DumbSlave;
import hudson.slaves.EnvironmentVariablesNodeProperty;
import hudson.slaves.JNLPLauncher;
import hudson.slaves.OfflineCause;
import hudson.slaves.RetentionStrategy;
import hudson.slaves.WorkspaceList;
import hudson.util.StreamCopyThread;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
Expand All @@ -74,8 +70,6 @@
import java.util.stream.Collectors;

import hudson.util.VersionNumber;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import jenkins.model.Jenkins;
import jenkins.security.QueueItemAuthenticator;
import jenkins.security.QueueItemAuthenticatorConfiguration;
Expand All @@ -84,7 +78,6 @@
import net.sf.json.groovy.JsonSlurper;
import org.acegisecurity.Authentication;
import org.apache.commons.io.IOUtils;
import org.apache.tools.ant.util.JavaEnvUtils;
import static org.hamcrest.Matchers.*;
import org.jenkinsci.plugins.durabletask.FileMonitoringTask;
import org.jenkinsci.plugins.workflow.actions.LogAction;
Expand All @@ -104,7 +97,6 @@
import org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep;
import org.jenkinsci.plugins.workflow.steps.durable_task.Messages;
import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep;
import org.junit.After;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
Expand All @@ -118,6 +110,7 @@
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.BuildWatcher;
import org.jvnet.hudson.test.InboundAgentRule;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LoggerRule;
Expand All @@ -133,6 +126,7 @@ public class ExecutorStepTest {

@ClassRule public static BuildWatcher buildWatcher = new BuildWatcher();
@Rule public JenkinsSessionRule sessions = new JenkinsSessionRule();
@Rule public InboundAgentRule inboundAgents = new InboundAgentRule();
@Rule public TemporaryFolder tmp = new TemporaryFolder();
// Currently too noisy due to unrelated warnings; might clear up if test dependencies updated: .record(ExecutorStepExecution.class, Level.FINE)
@Rule public LoggerRule logging = new LoggerRule();
Expand Down Expand Up @@ -217,33 +211,11 @@ public class ExecutorStepTest {
});
}

private Process jnlpProc;
private void startJnlpProc(JenkinsRule r) throws Exception {
killJnlpProc();
ProcessBuilder pb = new ProcessBuilder(JavaEnvUtils.getJreExecutable("java"), "-Djava.awt.headless=true", "-jar", Which.jarFile(Launcher.class).getAbsolutePath(), "-jnlpUrl", r.getURL() + "computer/dumbo/slave-agent.jnlp");
pb.redirectErrorStream(true);
System.err.println("Running: " + pb.command());
jnlpProc = pb.start();
new StreamCopyThread("jnlp", jnlpProc.getInputStream(), System.err).start();
}
@After public void killJnlpProc() {
if (jnlpProc != null) {
jnlpProc.destroyForcibly();
jnlpProc = null;
}
}

@Test public void buildShellScriptAcrossRestart() throws Throwable {
Assume.assumeFalse("TODO not sure how to write a corresponding batch script", Functions.isWindows());
sessions.then(r -> {
logging.record(DurableTaskStep.class, Level.FINE).record(FileMonitoringTask.class, Level.FINE);
// Cannot use regular JenkinsRule.createSlave due to JENKINS-26398.
// Nor can we can use JenkinsRule.createComputerLauncher, since spawned commands are killed by CommandLauncher somehow (it is not clear how; apparently before its onClosed kills them off).
DumbSlave s = new DumbSlave("dumbo", tmp.getRoot().getAbsolutePath(), new JNLPLauncher(true));
s.setNumExecutors(1);
s.setRetentionStrategy(RetentionStrategy.NOOP);
r.jenkins.addNode(s);
startJnlpProc(r);
DumbSlave s = r.createSlave("dumbo", null, null);
WorkflowJob p = r.createProject(WorkflowJob.class, "demo");
File f1 = new File(r.jenkins.getRootDir(), "f1");
File f2 = new File(r.jenkins.getRootDir(), "f2");
Expand All @@ -259,13 +231,11 @@ private void startJnlpProc(JenkinsRule r) throws Exception {
}
r.waitForMessage("waiting", b);
assertTrue(b.isBuilding());
killJnlpProc();
});
sessions.then(r -> {
WorkflowJob p = (WorkflowJob) r.jenkins.getItem("demo");
WorkflowRun b = p.getLastBuild();
assertTrue(b.isBuilding()); // TODO occasionally fails; log ends with: ‘Running: Allocate node : Body : Start’ (no shell step in sight)
startJnlpProc(r); // Have to relaunch JNLP agent, since the Jenkins port has changed, and we cannot force JenkinsRule to reuse the same port as before.
File f1 = new File(r.jenkins.getRootDir(), "f1");
File f2 = new File(r.jenkins.getRootDir(), "f2");
assertTrue(f2.isFile());
Expand All @@ -276,7 +246,6 @@ private void startJnlpProc(JenkinsRule r) throws Exception {
r.assertBuildStatusSuccess(r.waitForCompletion(b));
r.assertLogContains("finished waiting", b);
r.assertLogContains("OK, done", b);
killJnlpProc();
});
}

Expand All @@ -290,9 +259,7 @@ private void startJnlpProc(JenkinsRule r) throws Exception {
logging.record(DurableTaskStep.class, Level.FINE).record(FileMonitoringTask.class, Level.FINE);
int count = 3_000;
sessions.then(r -> {
DumbSlave s = new DumbSlave("dumbo", tmp.getRoot().getAbsolutePath(), new JNLPLauncher(true));
r.jenkins.addNode(s);
startJnlpProc(r);
DumbSlave s = r.createSlave("dumbo", null, null);
WorkflowJob p = r.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("node('dumbo') {sh 'set +x; i=0; while [ $i -lt " + count + " ]; do echo \"<<<$i>>>\"; sleep .01; i=`expr $i + 1`; done'}", true));
WorkflowRun b = p.scheduleBuild2(0).waitForStart();
Expand All @@ -301,7 +268,6 @@ private void startJnlpProc(JenkinsRule r) throws Exception {
});
sessions.then(r -> {
WorkflowRun b = r.jenkins.getItemByFullName("p", WorkflowJob.class).getBuildByNumber(1);
startJnlpProc(r);
r.assertBuildStatusSuccess(r.waitForCompletion(b));
// Paying attention to the per-node log rather than whole-build log to exclude issues with copyLogs prior to JEP-210:
FlowNode shNode = new DepthFirstScanner().findFirstMatch(b.getExecution(), new NodeStepTypePredicate("sh"));
Expand All @@ -319,19 +285,14 @@ private void startJnlpProc(JenkinsRule r) throws Exception {
}
System.out.printf("Lost content: %.02f%%%n", lost * 100.0 / count);
System.out.printf("Duplicated content: %.02f%%%n", (seen - count) * 100.0 / count);
killJnlpProc();
});
}

@Test public void buildShellScriptAcrossDisconnect() throws Throwable {
Assume.assumeFalse("TODO not sure how to write a corresponding batch script", Functions.isWindows());
sessions.then(r -> {
logging.record(DurableTaskStep.class, Level.FINE).record(FileMonitoringTask.class, Level.FINE);
DumbSlave s = new DumbSlave("dumbo", tmp.getRoot().getAbsolutePath(), new JNLPLauncher(true));
s.setNumExecutors(1);
s.setRetentionStrategy(RetentionStrategy.NOOP);
r.jenkins.addNode(s);
startJnlpProc(r);
Slave s = inboundAgents.createAgent(r, "dumbo");
WorkflowJob p = r.createProject(WorkflowJob.class, "demo");
File f1 = new File(r.jenkins.getRootDir(), "f1");
File f2 = new File(r.jenkins.getRootDir(), "f2");
Expand All @@ -349,11 +310,11 @@ private void startJnlpProc(JenkinsRule r) throws Exception {
assertTrue(b.isBuilding());
Computer c = s.toComputer();
assertNotNull(c);
killJnlpProc();
inboundAgents.stop("dumbo");
while (c.isOnline()) {
Thread.sleep(100);
}
startJnlpProc(r);
inboundAgents.start(r, "dumbo");
while (c.isOffline()) {
Thread.sleep(100);
}
Expand All @@ -365,7 +326,6 @@ private void startJnlpProc(JenkinsRule r) throws Exception {
r.assertBuildStatusSuccess(r.waitForCompletion(b));
r.assertLogContains("finished waiting", b); // TODO sometimes is not printed to log, despite f2 having been removed
r.assertLogContains("OK, done", b);
killJnlpProc();
});
}

Expand All @@ -377,11 +337,7 @@ public void contextualizeFreshFilePathAfterAgentReconnection() throws Throwable
logging.record(DurableTaskStep.class, Level.FINE).
record(FilePathDynamicContext.class, Level.FINE).
record(WorkspaceList.class, Level.FINE);
DumbSlave s = new DumbSlave("dumbo", tmp.getRoot().getAbsolutePath(), new JNLPLauncher(true));
s.setNumExecutors(1);
s.setRetentionStrategy(RetentionStrategy.NOOP);
r.jenkins.addNode(s);
startJnlpProc(r);
Slave s = inboundAgents.createAgent(r, "dumbo");
WorkflowJob p = r.createProject(WorkflowJob.class, "demo");
File f1 = new File(r.jenkins.getRootDir(), "f1");
File f2 = new File(r.jenkins.getRootDir(), "f2");
Expand Down Expand Up @@ -414,18 +370,17 @@ public void contextualizeFreshFilePathAfterAgentReconnection() throws Throwable
String workspacePath = actions.get(0).getWorkspace().getRemote();
assertWorkspaceLocked(computer, workspacePath);
LOGGER.info("killing agent");
jnlpProc.destroyForcibly();
inboundAgents.stop("dumbo");
long lastMessageMillis = System.currentTimeMillis();
while (computer.isOnline()) {
if (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - lastMessageMillis) > 30) {
LOGGER.info(() -> "Waiting for " + computer.getNode() + " to go offline. JNLP Process is " + (jnlpProc.isAlive() ? "alive" : "not alive"));
LOGGER.info(() -> "Waiting for " + computer.getNode() + " to go offline. JNLP Process is " + (inboundAgents.isAlive("dumbo") ? "alive" : "not alive"));
lastMessageMillis = System.currentTimeMillis();
}
Thread.sleep(100);
}
jnlpProc = null;
LOGGER.info("restarting agent");
startJnlpProc(r);
inboundAgents.start(r, "dumbo");
while (computer.isOffline()) {
Thread.sleep(100);
}
Expand All @@ -441,7 +396,6 @@ public void contextualizeFreshFilePathAfterAgentReconnection() throws Throwable
r.assertLogContains("finished waiting", b);
r.assertLogContains("Back again", b);
r.assertLogContains("OK, done", b);
killJnlpProc();
});
}

Expand Down