From 7c6165ae01d3d05a7addfedd88e815478871d6c0 Mon Sep 17 00:00:00 2001 From: Devin Nusbaum Date: Thu, 16 May 2024 16:22:34 -0400 Subject: [PATCH 01/10] Fix origin identification for unserializable exceptions --- .../plugins/workflow/actions/ErrorAction.java | 17 +++++++++++------ .../workflow/actions/ErrorActionTest.java | 13 +++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java index a6853bff..b32a92c0 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java @@ -42,7 +42,7 @@ import org.jenkinsci.plugins.workflow.flow.FlowExecution; import org.jenkinsci.plugins.workflow.graph.AtomNode; import org.jenkinsci.plugins.workflow.graph.BlockEndNode; -import org.jenkinsci.plugins.workflow.graphanalysis.ForkScanner; +import org.jenkinsci.plugins.workflow.graphanalysis.DepthFirstScanner; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.Beta; @@ -56,20 +56,25 @@ public class ErrorAction implements PersistentAction { private final @NonNull Throwable error; public ErrorAction(@NonNull Throwable error) { + Throwable errorForAction = error; if (isUnserializableException(error, new HashSet<>())) { - error = new ProxyException(error); + errorForAction = new ProxyException(error); } else if (error != null) { try { Jenkins.XSTREAM2.toXMLUTF8(error, new NullOutputStream()); } catch (Exception x) { // Typically SecurityException from ClassFilter. - error = new ProxyException(error); + errorForAction = new ProxyException(error); } } - this.error = error; + this.error = errorForAction; String id = findId(error, new HashSet<>()); if (id == null && error != null) { - error.addSuppressed(new ErrorId()); + errorForAction.addSuppressed(new ErrorId()); + if (error != errorForAction) { + // Make sure the original exception has the error ID, not just the copy here. + error.addSuppressed(new ErrorId()); + } } } @@ -140,7 +145,7 @@ public String getUrlName() { */ public static @CheckForNull FlowNode findOrigin(@NonNull Throwable error, @NonNull FlowExecution execution) { FlowNode candidate = null; - for (FlowNode n : new ForkScanner().allNodes(execution)) { + for (FlowNode n : new DepthFirstScanner().allNodes(execution)) { ErrorAction errorAction = n.getPersistentAction(ErrorAction.class); if (errorAction != null && equals(error, errorAction.getError())) { candidate = n; // continue search for earlier one diff --git a/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java b/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java index 53d4dd1b..64bc1dc6 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java @@ -52,6 +52,8 @@ import hudson.model.Result; import hudson.remoting.ProxyException; import org.codehaus.groovy.runtime.NullObject; +import org.jenkinsci.plugins.workflow.graph.StepNode; +import static org.hamcrest.Matchers.equalTo; /** * Tests for {@link ErrorAction} @@ -245,4 +247,15 @@ public static class X extends Exception { assertNotNull(new ErrorAction(unserializable)); assertNotNull(new ErrorAction(cyclic)); } + + @Test public void findOriginOfRethrownUnserializableException() throws Throwable { + rr.then(r -> { + WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); + p.setDefinition(new CpsFlowDefinition( + "stage('test') { withEnv([]) { throw new " + X.class.getCanonicalName() + "() } }", false /* for "new org.jenkinsci.plugins.workflow.actions.ErrorActionTest$X" */)); + WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); + FlowNode originNode = ErrorAction.findOrigin(b.getExecution().getCauseOfFailure(), b.getExecution()); + assertThat(((StepNode) originNode).getDescriptor().getFunctionName(), equalTo("withEnv")); + }); + } } From d816bebadcaa84e14a76c21cc7db2710ae43c68e Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 17:45:45 -0400 Subject: [PATCH 02/10] `ErrorActionTest.findOriginFromBodyExecutionCallback` --- pom.xml | 2 +- .../plugins/workflow/actions/ErrorAction.java | 6 + .../workflow/actions/ErrorActionTest.java | 104 ++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3c420334..da483158 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ io.jenkins.tools.bom bom-2.426.x - 2555.v3190a_8a_c60c6 + 2745.vc7b_fe4c876fa_ import pom diff --git a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java index a6853bff..662b640a 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java @@ -37,6 +37,8 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; import jenkins.model.Jenkins; import org.apache.commons.io.output.NullOutputStream; import org.jenkinsci.plugins.workflow.flow.FlowExecution; @@ -53,15 +55,19 @@ */ public class ErrorAction implements PersistentAction { + private static final Logger LOGGER = Logger.getLogger(ErrorAction.class.getName()); + private final @NonNull Throwable error; public ErrorAction(@NonNull Throwable error) { if (isUnserializableException(error, new HashSet<>())) { + LOGGER.log(Level.FINE, "sanitizing unserializable error", error); error = new ProxyException(error); } else if (error != null) { try { Jenkins.XSTREAM2.toXMLUTF8(error, new NullOutputStream()); } catch (Exception x) { + LOGGER.log(Level.FINE, "unable to serialize to XML", x); // Typically SecurityException from ClassFilter. error = new ProxyException(error); } diff --git a/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java b/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java index 6165330e..6ec2ac99 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java @@ -47,21 +47,44 @@ import org.jvnet.hudson.test.JenkinsSessionRule; import groovy.lang.MissingMethodException; +import hudson.FilePath; import hudson.Functions; import hudson.model.Result; +import hudson.model.TaskListener; import hudson.remoting.ProxyException; +import hudson.remoting.VirtualChannel; +import java.io.File; +import java.io.IOException; +import java.util.Set; +import java.util.logging.Level; +import jenkins.MasterToSlaveFileCallable; import org.codehaus.groovy.runtime.NullObject; +import org.jenkinsci.plugins.workflow.steps.BodyExecutionCallback; +import org.jenkinsci.plugins.workflow.steps.Step; +import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.jenkinsci.plugins.workflow.steps.StepDescriptor; +import org.jenkinsci.plugins.workflow.steps.StepExecution; +import org.jenkinsci.plugins.workflow.steps.StepExecutions; +import org.jvnet.hudson.test.InboundAgentRule; +import org.jvnet.hudson.test.LoggerRule; +import org.jvnet.hudson.test.TestExtension; +import org.kohsuke.stapler.DataBoundConstructor; /** * Tests for {@link ErrorAction} */ public class ErrorActionTest { + @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); @Rule public JenkinsSessionRule rr = new JenkinsSessionRule(); + @Rule public InboundAgentRule agents = new InboundAgentRule(); + + @Rule public LoggerRule logging = new LoggerRule().record(ErrorAction.class, Level.FINE); + private List extractErrorActions(FlowExecution exec) { List ret = new ArrayList<>(); @@ -228,6 +251,87 @@ public static class X extends Exception { }); } + @Test public void findOriginFromBodyExecutionCallback() throws Throwable { + rr.then(r -> { + agents.createAgent(r, "remote"); + var p = r.createProject(WorkflowJob.class); + p.setDefinition(new CpsFlowDefinition("callsFindOrigin {node('remote') {fails()}}", true)); + var b = p.scheduleBuild2(0).waitForStart(); + r.waitForMessage("Acting slowly in ", b); + agents.stop("remote"); + r.assertBuildStatus(Result.FAILURE, r.waitForCompletion(b)); + r.assertLogContains("Found in: fails", b); + }); + } + public static final class WrapperStep extends Step { + @DataBoundConstructor public WrapperStep() {} + @Override public StepExecution start(StepContext context) throws Exception { + return new ExecutionImpl(context); + } + private static final class ExecutionImpl extends StepExecution { + ExecutionImpl(StepContext context) { + super(context); + } + @Override public boolean start() throws Exception { + getContext().newBodyInvoker().withCallback(new Callback()).start(); + return false; + } + } + private static class Callback extends BodyExecutionCallback { + @Override public void onSuccess(StepContext context, Object result) { + context.onSuccess(result); + } + @Override + public void onFailure(StepContext context, Throwable t) { + try { + var l = context.get(TaskListener.class); + Functions.printStackTrace(t, l.error("Original failure:")); + l.getLogger().println("Found in: " + ErrorAction.findOrigin(t, context.get(FlowExecution.class)).getDisplayFunctionName()); + } catch (Exception x) { + assert false : x; + } + context.onFailure(t); + } + } + @TestExtension("findOriginFromBodyExecutionCallback") public static final class DescriptorImpl extends StepDescriptor { + @Override public String getFunctionName() { + return "callsFindOrigin"; + } + @Override public Set> getRequiredContext() { + return Set.of(); + } + @Override public boolean takesImplicitBlockArgument() { + return true; + } + } + } + public static final class FailingStep extends Step { + @DataBoundConstructor public FailingStep() {} + @Override public StepExecution start(StepContext context) throws Exception { + return StepExecutions.synchronousNonBlockingVoid(context, c -> c.get(FilePath.class).act(new Sleep(c.get(TaskListener.class)))); + } + private static final class Sleep extends MasterToSlaveFileCallable { + private final TaskListener l; + Sleep(TaskListener l) { + this.l = l; + } + @Override public Void invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { + l.getLogger().println("Acting slowly in " + f); + l.getLogger().flush(); + Thread.sleep(Long.MAX_VALUE); + return null; + } + } + @TestExtension("findOriginFromBodyExecutionCallback") public static final class DescriptorImpl extends StepDescriptor { + @Override public String getFunctionName() { + return "fails"; + } + @Override public Set> getRequiredContext() { + return Set.of(FilePath.class); + } + } + } + @Test public void cyclicErrorsAreSupported() throws Throwable { Exception cyclic1 = new Exception(); Exception cyclic2 = new Exception(cyclic1); From 9c0a25a0fc22bc7f71d4584acab918aa6985ac0c Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 18:06:41 -0400 Subject: [PATCH 03/10] Logging in `equals` --- .../plugins/workflow/actions/ErrorAction.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java index 93d20a1b..cf8edf72 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java @@ -181,28 +181,42 @@ public String getUrlName() { @Restricted(Beta.class) public static boolean equals(Throwable t1, Throwable t2) { if (t1 == t2) { + LOGGER.fine(() -> "Same object: " + t1); return true; } else if (t1.getClass() != t2.getClass()) { + LOGGER.fine(() -> "Different types: " + t1.getClass() + " vs. " + t2.getClass()); return false; } else if (!Objects.equals(t1.getMessage(), t2.getMessage())) { + LOGGER.fine(() -> "Different messages: " + t1.getMessage() + " vs. " + t2.getMessage()); return false; } else { String id1 = findId(t1, new HashSet<>()); if (id1 != null) { - return id1.equals(findId(t2, new HashSet<>())); + String id2 = findId(t2, new HashSet<>()); + LOGGER.fine(() -> "ErrorId comparisons: " + id1 + " vs. " + id2); + return id1.equals(id2); } // No ErrorId, use a best-effort approach that doesn't work across restarts for exceptions thrown // synchronously from the CPS VM thread. // Check that stack traces match, but specifically avoid checking suppressed exceptions, which are often // modified after ErrorAction is written to disk when steps like parallel are involved. - while (t1 != null && t2 != null) { - if (!Arrays.equals(t1.getStackTrace(), t2.getStackTrace())) { + var _t1 = t1; + var _t2 = t2; + while (_t1 != null && _t2 != null) { + if (!Arrays.equals(_t1.getStackTrace(), _t2.getStackTrace())) { + LOGGER.fine(() -> "Different stack traces between " + t1 + " vs. " + t2); // not showing details return false; } - t1 = t1.getCause(); - t2 = t2.getCause(); + _t1 = _t1.getCause(); + _t2 = _t2.getCause(); + } + if ((_t1 == null) == (_t2 == null)) { + LOGGER.fine(() -> "Same stack traces in " + t1 + " vs. " + t2); + return true; + } else { + LOGGER.fine(() -> "Different cause depths between " + t1 + " vs. " + t2); + return false; } - return (t1 == null) == (t2 == null); } } From 23d9662a2a81e2ac581bd554c1aa2682c1bc719f Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 18:17:46 -0400 Subject: [PATCH 04/10] Do not do a null check on `error` when it is `@NonNull` --- .../org/jenkinsci/plugins/workflow/actions/ErrorAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java index cf8edf72..cb17bb08 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java @@ -75,7 +75,7 @@ public ErrorAction(@NonNull Throwable error) { } this.error = errorForAction; String id = findId(error, new HashSet<>()); - if (id == null && error != null) { + if (id == null) { errorForAction.addSuppressed(new ErrorId()); if (error != errorForAction) { // Make sure the original exception has the error ID, not just the copy here. From 352dc46d0227ff205dbc07810492f91269bbd444 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 18:18:59 -0400 Subject: [PATCH 05/10] Doing an id check first does not suffice; the `ProxyException` lacks an id initially, and later gets a distinct one --- .../plugins/workflow/actions/ErrorAction.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java index cb17bb08..3e3e745c 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java @@ -183,19 +183,25 @@ public static boolean equals(Throwable t1, Throwable t2) { if (t1 == t2) { LOGGER.fine(() -> "Same object: " + t1); return true; - } else if (t1.getClass() != t2.getClass()) { + } + String id1 = findId(t1, new HashSet<>()); + if (id1 != null) { + String id2 = findId(t2, new HashSet<>()); + if (id1.equals(id2)) { + LOGGER.fine(() -> "ErrorId matches: " + id1); + return true; + } + LOGGER.fine(() -> "ErrorId mismatch: " + t1 + " " + id1 + " vs. " + t2 + " " + id2); + } else { + LOGGER.fine(() -> "No ErrorId on " + t1); + } + if (t1.getClass() != t2.getClass()) { LOGGER.fine(() -> "Different types: " + t1.getClass() + " vs. " + t2.getClass()); return false; } else if (!Objects.equals(t1.getMessage(), t2.getMessage())) { LOGGER.fine(() -> "Different messages: " + t1.getMessage() + " vs. " + t2.getMessage()); return false; } else { - String id1 = findId(t1, new HashSet<>()); - if (id1 != null) { - String id2 = findId(t2, new HashSet<>()); - LOGGER.fine(() -> "ErrorId comparisons: " + id1 + " vs. " + id2); - return id1.equals(id2); - } // No ErrorId, use a best-effort approach that doesn't work across restarts for exceptions thrown // synchronously from the CPS VM thread. // Check that stack traces match, but specifically avoid checking suppressed exceptions, which are often From b33d4594a46e2e862f7bb27329bd66ee4cac041d Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 18:24:17 -0400 Subject: [PATCH 06/10] Back to `ForkScanner` https://github.com/jenkinsci/workflow-api-plugin/pull/327/commits/28d0acd535d3008120412de33819115953edf710 https://github.com/jenkinsci/workflow-api-plugin/pull/327#discussion_r1604122340 --- .../org/jenkinsci/plugins/workflow/actions/ErrorAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java index 3e3e745c..3c9de2c7 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java @@ -44,7 +44,7 @@ import org.jenkinsci.plugins.workflow.flow.FlowExecution; import org.jenkinsci.plugins.workflow.graph.AtomNode; import org.jenkinsci.plugins.workflow.graph.BlockEndNode; -import org.jenkinsci.plugins.workflow.graphanalysis.DepthFirstScanner; +import org.jenkinsci.plugins.workflow.graphanalysis.ForkScanner; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.Beta; @@ -151,7 +151,7 @@ public String getUrlName() { */ public static @CheckForNull FlowNode findOrigin(@NonNull Throwable error, @NonNull FlowExecution execution) { FlowNode candidate = null; - for (FlowNode n : new DepthFirstScanner().allNodes(execution)) { + for (FlowNode n : new ForkScanner().allNodes(execution)) { ErrorAction errorAction = n.getPersistentAction(ErrorAction.class); if (errorAction != null && equals(error, errorAction.getError())) { candidate = n; // continue search for earlier one From 15024e3bc079c4fcc9de6c20758acaaa17fb8575 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 18:29:45 -0400 Subject: [PATCH 07/10] We need to use the same id --- .../org/jenkinsci/plugins/workflow/actions/ErrorAction.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java index 3c9de2c7..9a934388 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java @@ -76,10 +76,11 @@ public ErrorAction(@NonNull Throwable error) { this.error = errorForAction; String id = findId(error, new HashSet<>()); if (id == null) { - errorForAction.addSuppressed(new ErrorId()); + var errorId = new ErrorId(); + errorForAction.addSuppressed(errorId); if (error != errorForAction) { // Make sure the original exception has the error ID, not just the copy here. - error.addSuppressed(new ErrorId()); + error.addSuppressed(errorId); } } } From fd9832948eb3ad216d41b43c4f114d0765a206ed Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 18:43:56 -0400 Subject: [PATCH 08/10] Optimization along the lines of c27b80bcdfb3d416e66ae24f2e2cac65b12f6222 --- .../plugins/workflow/actions/ErrorAction.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java index 9a934388..f8d58295 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/actions/ErrorAction.java @@ -185,24 +185,25 @@ public static boolean equals(Throwable t1, Throwable t2) { LOGGER.fine(() -> "Same object: " + t1); return true; } - String id1 = findId(t1, new HashSet<>()); - if (id1 != null) { - String id2 = findId(t2, new HashSet<>()); - if (id1.equals(id2)) { - LOGGER.fine(() -> "ErrorId matches: " + id1); - return true; - } - LOGGER.fine(() -> "ErrorId mismatch: " + t1 + " " + id1 + " vs. " + t2 + " " + id2); - } else { - LOGGER.fine(() -> "No ErrorId on " + t1); - } - if (t1.getClass() != t2.getClass()) { + boolean noProxy = t1.getClass() != ProxyException.class && t2.getClass() != ProxyException.class; + if (noProxy && t1.getClass() != t2.getClass()) { LOGGER.fine(() -> "Different types: " + t1.getClass() + " vs. " + t2.getClass()); return false; - } else if (!Objects.equals(t1.getMessage(), t2.getMessage())) { + } else if (noProxy && !Objects.equals(t1.getMessage(), t2.getMessage())) { LOGGER.fine(() -> "Different messages: " + t1.getMessage() + " vs. " + t2.getMessage()); return false; } else { + String id1 = findId(t1, new HashSet<>()); + if (id1 != null) { + String id2 = findId(t2, new HashSet<>()); + if (id1.equals(id2)) { + LOGGER.fine(() -> "ErrorId matches: " + id1); + return true; + } else { + LOGGER.fine(() -> "ErrorId mismatch: " + t1 + " " + id1 + " vs. " + t2 + " " + id2); + return false; + } + } // No ErrorId, use a best-effort approach that doesn't work across restarts for exceptions thrown // synchronously from the CPS VM thread. // Check that stack traces match, but specifically avoid checking suppressed exceptions, which are often From 401e35efd6902787fe0d6a1d36cb2c74c428a18e Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 18:48:30 -0400 Subject: [PATCH 09/10] Removing earlier test case Co-authored-by: Devin Nusbaum --- .../plugins/workflow/actions/ErrorActionTest.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java b/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java index 4c38eaa4..0b4c27c6 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java @@ -349,15 +349,4 @@ private static final class Sleep extends MasterToSlaveFileCallable { assertNotNull(new ErrorAction(unserializable)); assertNotNull(new ErrorAction(cyclic)); } - - @Test public void findOriginOfRethrownUnserializableException() throws Throwable { - rr.then(r -> { - WorkflowJob p = r.jenkins.createProject(WorkflowJob.class, "p"); - p.setDefinition(new CpsFlowDefinition( - "stage('test') { withEnv([]) { throw new " + X.class.getCanonicalName() + "() } }", false /* for "new org.jenkinsci.plugins.workflow.actions.ErrorActionTest$X" */)); - WorkflowRun b = r.buildAndAssertStatus(Result.FAILURE, p); - FlowNode originNode = ErrorAction.findOrigin(b.getExecution().getCauseOfFailure(), b.getExecution()); - assertThat(((StepNode) originNode).getDescriptor().getFunctionName(), equalTo("withEnv")); - }); - } } From c952156139b00f82e7f86aa60a90f2fd9729ccfe Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 May 2024 18:49:02 -0400 Subject: [PATCH 10/10] Cleaning imports (maybe time to enable Spotless) --- .../org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java b/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java index 0b4c27c6..6ec2ac99 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/actions/ErrorActionTest.java @@ -69,8 +69,6 @@ import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.TestExtension; import org.kohsuke.stapler.DataBoundConstructor; -import org.jenkinsci.plugins.workflow.graph.StepNode; -import static org.hamcrest.Matchers.equalTo; /** * Tests for {@link ErrorAction}