Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #189 from olivergondza/JENKINS-46140
[FIXED JENKINS-46140] Improve presentation of remote exception
  • Loading branch information
oleg-nenashev committed Sep 9, 2017
2 parents c9d858a + ef7e916 commit 4f8e9da
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 9 deletions.
18 changes: 9 additions & 9 deletions src/main/java/hudson/remoting/Channel.java
Expand Up @@ -1644,16 +1644,16 @@ public void checkRoles(RoleChecker checker) throws SecurityException {
* Decorates the stack elements of the given {@link Throwable} by adding the call site information.
*/
/*package*/ void attachCallSiteStackTrace(Throwable t) {
Exception e = new Exception();
StackTraceElement[] callSite = e.getStackTrace();
StackTraceElement[] original = t.getStackTrace();

StackTraceElement[] combined = new StackTraceElement[original.length+1+callSite.length];
System.arraycopy(original,0,combined,0,original.length); // original stack trace at the top
combined[original.length] = new StackTraceElement(".....","remote call to "+name,null,-2);
System.arraycopy(callSite,0,combined,original.length+1,callSite.length);
t.addSuppressed(new CallSiteStackTrace(name));
}

t.setStackTrace(combined);
/**
* Dummy exception indicating the stacktrace on calling side of channel for remote exception for ease of debugging.
*/
private static final class CallSiteStackTrace extends Exception {
public CallSiteStackTrace(String message) {
super("Remote call to " + message);
}
}

public String getName() {
Expand Down
35 changes: 35 additions & 0 deletions src/test/java/hudson/remoting/ChannelTest.java
Expand Up @@ -17,6 +17,8 @@
import javax.annotation.Nonnull;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;

import org.jenkinsci.remoting.RoleChecker;

/**
Expand Down Expand Up @@ -183,6 +185,39 @@ public void testDiagnostics() throws Exception {
assertTrue(sw.toString().contains("Commands sent=0"));
assertTrue(sw.toString().contains("Commands received=0"));
}

public void testCallSiteStacktrace() throws Exception {
try {
failRemotelyToBeWrappedLocally();
fail();
} catch (Exception e) {
assertEquals("Local Nested", e.getMessage());
assertEquals(Exception.class, e.getClass());
Throwable cause = e.getCause();
assertEquals("Node Nested", cause.getMessage());
assertEquals(IOException.class, cause.getClass());
Throwable rootCause = cause.getCause();
assertEquals("Node says hello!", rootCause.getMessage());
assertEquals(RuntimeException.class, rootCause.getClass());
Throwable callSite = cause.getSuppressed()[0];
assertEquals("Remote call to north", callSite.getMessage());
assertEquals("hudson.remoting.Channel$CallSiteStackTrace", callSite.getClass().getName());
}
}

private void failRemotelyToBeWrappedLocally() throws Exception {
try {
channel.call(new ThrowingCallable());
} catch (IOException e) {
throw new Exception("Local Nested", e);
}
}

private static class ThrowingCallable extends CallableBase<Void, IOException> {
@Override public Void call() throws IOException {
throw new IOException("Node Nested", new RuntimeException("Node says hello!"));
}
}

/**
* Checks if {@link UserRequest}s can be executed during the pending close operation.
Expand Down

0 comments on commit 4f8e9da

Please sign in to comment.