diff --git a/pom.xml b/pom.xml
index 6bebbe8e..87d4c0d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
org.jenkins-ci.plugins
plugin
- 3.24
+ 3.33
org.jenkins-ci.plugins.workflow
diff --git a/src/main/java/org/jenkinsci/plugins/workflow/steps/durable_task/DurableTaskStep.java b/src/main/java/org/jenkinsci/plugins/workflow/steps/durable_task/DurableTaskStep.java
index 43276590..13d3f46b 100644
--- a/src/main/java/org/jenkinsci/plugins/workflow/steps/durable_task/DurableTaskStep.java
+++ b/src/main/java/org/jenkinsci/plugins/workflow/steps/durable_task/DurableTaskStep.java
@@ -31,7 +31,6 @@
import hudson.FilePath;
import hudson.Functions;
import hudson.Launcher;
-import hudson.Main;
import hudson.Util;
import hudson.init.Terminator;
import hudson.model.Node;
@@ -196,7 +195,7 @@ interface ExecutionRemotable {
/** If set to false, disables {@link Execution#watching} mode. */
@SuppressFBWarnings(value = "MS_SHOULD_BE_FINAL", justification = "public & mutable only for tests")
@Restricted(NoExternalUse.class)
- public static boolean USE_WATCHING = Boolean.parseBoolean(System.getProperty(DurableTaskStep.class.getName() + ".USE_WATCHING", Main.isUnitTest ? "true" : /* JENKINS-52165 turn back on by default */ "false"));
+ public static boolean USE_WATCHING = Boolean.getBoolean(DurableTaskStep.class.getName() + ".USE_WATCHING"); // JENKINS-52165: turn back on by default
private static ScheduledThreadPoolExecutor threadPool;
private static synchronized ScheduledThreadPoolExecutor threadPool() {
diff --git a/src/test/java/org/jenkinsci/plugins/workflow/steps/durable_task/ShellStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/steps/durable_task/ShellStepTest.java
index 4c380e30..3d12da26 100644
--- a/src/test/java/org/jenkinsci/plugins/workflow/steps/durable_task/ShellStepTest.java
+++ b/src/test/java/org/jenkinsci/plugins/workflow/steps/durable_task/ShellStepTest.java
@@ -25,7 +25,6 @@
import hudson.remoting.Channel;
import hudson.model.Slave;
import hudson.model.TaskListener;
-import hudson.remoting.Command;
import hudson.slaves.DumbSlave;
import hudson.slaves.EnvironmentVariablesNodeProperty;
import hudson.tasks.BatchFile;
@@ -45,12 +44,10 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import javax.annotation.CheckForNull;
import jenkins.util.JenkinsJVM;
-import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import static org.hamcrest.Matchers.*;
@@ -85,7 +82,6 @@
import org.junit.Assume;
import static org.junit.Assume.assumeFalse;
import org.junit.ClassRule;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -367,6 +363,8 @@ public DescriptorImpl() {
@Issue("JENKINS-38381")
@Test public void remoteLogger() throws Exception {
+ DurableTaskStep.USE_WATCHING = true;
+ try {
assumeFalse(Functions.isWindows()); // TODO create Windows equivalent
final String credentialsId = "creds";
final String username = "bob";
@@ -393,6 +391,9 @@ public DescriptorImpl() {
j.assertLogNotContains(password, b);
j.assertLogNotContains(password.toUpperCase(Locale.ENGLISH), b);
j.assertLogContains("CURL -U **** HTTP://SERVER/ [master → remote]", b);
+ } finally {
+ DurableTaskStep.USE_WATCHING = false;
+ }
}
@TestExtension("remoteLogger") public static class LogFile implements LogStorageFactory {
@Override public LogStorage forBuild(FlowExecutionOwner b) {
@@ -463,114 +464,10 @@ private Object writeReplace() {
}
}
- @Ignore("TODO too flaky to run in CI")
- @Issue("JENKINS-38381")
- @Test public void remoteVoluminousLogger() throws Exception {
- assumeFalse(Functions.isWindows()); // TODO create Windows equivalent
- DumbSlave remote = j.createSlave("remote", null, null);
- WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p");
- p.setDefinition(new CpsFlowDefinition(
- "node('remote') {\n" +
- " sh 'echo one; sleep 1; echo two'\n" +
- "}", true));
- // Priming builds:
- j.assertBuildStatusSuccess(p.scheduleBuild2(0));
- try {
- DurableTaskStep.USE_WATCHING = false;
- j.assertBuildStatusSuccess(p.scheduleBuild2(0));
- } finally {
- DurableTaskStep.USE_WATCHING = true;
- }
- // Now check Remoting usage:
- Thread.sleep(1000); // TODO waiting for GC?
- p.setDefinition(new CpsFlowDefinition(
- "node('remote') {\n" +
- " sh 'set +x; for i in 0 1 2 3 4 5 6 7 8 9; do for j in 0 1 2 3 4 5 6 7 8 9; do for k in 0 1 2 3 4 5 6 7 8 9; do echo ijk=$i$j$k; sleep .01; done; done; done'\n" +
- "}", true));
- AtomicInteger cnt = new AtomicInteger();
- ((Channel) remote.getChannel()).addListener(new Channel.Listener() {
- @Override public void onRead(Channel channel, Command cmd, long blockSize) {
- cnt.incrementAndGet();
- }
- @Override public void onWrite(Channel channel, Command cmd, long blockSize) {
- cnt.incrementAndGet();
- }
- });
- WorkflowRun b = j.assertBuildStatusSuccess(p.scheduleBuild2(0));
- j.assertLogNotContains("ijk=567", b);
- assertThat(FileUtils.readFileToString(new File(b.getRootDir(), "log-remote")), containsString("ijk=567"));
- Thread.sleep(1000); // ditto
- int watchCount = cnt.getAndSet(0);
- try {
- DurableTaskStep.USE_WATCHING = false;
- b = j.assertBuildStatusSuccess(p.scheduleBuild2(0));
- j.assertLogContains("ijk=567", b);
- } finally {
- DurableTaskStep.USE_WATCHING = true;
- }
- int oldCount = cnt.getAndSet(0);
- System.out.println("Using watching: " + watchCount + " packets sent/received");
- System.out.println("Not using watching: " + oldCount + " packets sent/received");
- assertThat("at least 2× reduction in Remoting traffic by packet count", 1.0 * oldCount / watchCount, greaterThan(2.0));
- }
- @TestExtension("remoteVoluminousLogger") public static class ExternalLogFile implements LogStorageFactory {
- @Override public LogStorage forBuild(FlowExecutionOwner b) {
- final LogStorage base;
- final File mainLog;
- try {
- mainLog = new File(b.getRootDir(), "log");
- base = FileLogStorage.forFile(mainLog);
- } catch (IOException x) {
- return new BrokenLogStorage(x);
- }
- return new LogStorage() {
- @Override public BuildListener overallListener() throws IOException, InterruptedException {
- return new ExternalBuildListener(mainLog, null);
- }
- @Override public TaskListener nodeListener(FlowNode node) throws IOException, InterruptedException {
- return new ExternalBuildListener(mainLog, node.getId());
- }
- @Override public AnnotatedLargeText overallLog(FlowExecutionOwner.Executable build, boolean complete) {
- return base.overallLog(build, complete);
- }
- @Override public AnnotatedLargeText stepLog(FlowNode node, boolean complete) {
- return base.stepLog(node, complete);
- }
- };
- }
- }
- private static class ExternalBuildListener implements BuildListener {
- private static final long serialVersionUID = 1;
- private final File log;
- private final String node;
- private transient PrintStream logger;
- ExternalBuildListener(File log, String node) {
- this.log = log;
- this.node = node;
- }
- @Override public PrintStream getLogger() {
- if (logger == null) {
- LogStorage storage = FileLogStorage.forFile(log);
- TaskListener listener;
- try {
- listener = node == null ? storage.overallListener() : storage.nodeListener(new FlowNode(null, node) {
- @Override protected String getTypeDisplayName() {return null;}
- });
- } catch (Exception x) {
- throw new RuntimeException(x);
- }
- logger = listener.getLogger();
- }
- return logger;
- }
- private Object writeReplace() {
- String name = Channel.current().getName();
- return new ExternalBuildListener(new File(log + "-" + name), node);
- }
- }
-
@Issue("JENKINS-54133")
@Test public void remoteConsoleNotes() throws Exception {
+ DurableTaskStep.USE_WATCHING = true;
+ try {
assumeFalse(Functions.isWindows()); // TODO create Windows equivalent
j.createSlave("remote", null, null);
WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p");
@@ -596,6 +493,9 @@ private Object writeReplace() {
assertThat("a ConsoleNote created in the master is trusted", w.toString(), containsString("hello from master"));
assertThat("but this one was created in the agent and is discarded", w.toString(), containsString("hello from agent"));
assertThat("however we can pass it from the master to agent", w.toString(), containsString("hello from halfway in between"));
+ } finally {
+ DurableTaskStep.USE_WATCHING = false;
+ }
}
public static final class MarkUpStep extends Step {
@DataBoundSetter public boolean smart;
diff --git a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepTest.java b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepTest.java
index 892e38f8..3a7bd444 100644
--- a/src/test/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepTest.java
+++ b/src/test/java/org/jenkinsci/plugins/workflow/support/steps/ExecutorStepTest.java
@@ -79,7 +79,6 @@
import java.util.regex.Pattern;
import javax.annotation.Nullable;
-import hudson.util.VersionNumber;
import jenkins.model.Jenkins;
import jenkins.security.QueueItemAuthenticator;
import jenkins.security.QueueItemAuthenticatorConfiguration;
@@ -293,9 +292,11 @@ private void startJnlpProc() throws Exception {
@Issue("JENKINS-52165")
@Test public void shellOutputAcrossRestart() throws Exception {
Assume.assumeFalse("TODO not sure how to write a corresponding batch script", Functions.isWindows());
- Assume.assumeThat("TODO no longer asserts anything, just informational. There is no way for FileMonitoringTask.Watcher to know when content has been written through to the sink other than by periodically flushing output and declining to write lastLocation until after this completes. This applies both to buffered on-master logs, and to typical cloud sinks.", System.getenv("JENKINS_URL"), nullValue());
+ // TODO does not assert anything in watch mode, just informational.
+ // There is no way for FileMonitoringTask.Watcher to know when content has been written through to the sink
+ // other than by periodically flushing output and declining to write lastLocation until after this completes.
+ // This applies both to buffered on-master logs, and to typical cloud sinks.
logging.record(DurableTaskStep.class, Level.FINE).record(FileMonitoringTask.class, Level.FINE);
- // for comparison: DurableTaskStep.USE_WATCHING = false;
int count = 3_000;
story.then(r -> {
DumbSlave s = new DumbSlave("dumbo", tmp.getRoot().getAbsolutePath(), new JNLPLauncher(true));
@@ -336,9 +337,6 @@ private void startJnlpProc() throws Exception {
story.addStep(new Statement() {
@SuppressWarnings("SleepWhileInLoop")
@Override public void evaluate() throws Throwable {
- long origWatchingRecurrencePeriod = DurableTaskStep.WATCHING_RECURRENCE_PERIOD;
- DurableTaskStep.WATCHING_RECURRENCE_PERIOD = /* 5s */5_000;
- try {
logging.record(DurableTaskStep.class, Level.FINE).record(FileMonitoringTask.class, Level.FINE);
DumbSlave s = new DumbSlave("dumbo", "dummy", tmp.getRoot().getAbsolutePath(), "1", Node.Mode.NORMAL, "", new JNLPLauncher(), RetentionStrategy.NOOP, Collections.>emptyList());
story.j.jenkins.addNode(s);
@@ -376,9 +374,6 @@ private void startJnlpProc() throws Exception {
story.j.assertLogContains("finished waiting", b); // TODO sometimes is not printed to log, despite f2 having been removed
story.j.assertLogContains("OK, done", b);
killJnlpProc();
- } finally {
- DurableTaskStep.WATCHING_RECURRENCE_PERIOD = origWatchingRecurrencePeriod;
- }
}
});
}