Skip to content

Commit 94bee03

Browse files
committed
Merge pull request #758 from tomdcc/clean-stack-traces
Clean up groovy stack traces
2 parents 3c75009 + d551e34 commit 94bee03

File tree

3 files changed

+75
-7
lines changed

3 files changed

+75
-7
lines changed

groovy/src/main/java/cucumber/runtime/groovy/GroovyStepDefinition.java

+12-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import gherkin.formatter.Argument;
99
import gherkin.formatter.model.Step;
1010
import groovy.lang.Closure;
11+
import org.codehaus.groovy.runtime.StackTraceUtils;
1112

1213
import java.lang.reflect.Type;
1314
import java.util.ArrayList;
@@ -63,13 +64,17 @@ private List<ParameterInfo> getParameterInfos() {
6364
}
6465

6566
public void execute(I18n i18n, final Object[] args) throws Throwable {
66-
Timeout.timeout(new Timeout.Callback<Object>() {
67-
@Override
68-
public Object call() throws Throwable {
69-
backend.invoke(body, args);
70-
return null;
71-
}
72-
}, timeoutMillis);
67+
try {
68+
Timeout.timeout(new Timeout.Callback<Object>() {
69+
@Override
70+
public Object call() throws Throwable {
71+
backend.invoke(body, args);
72+
return null;
73+
}
74+
}, timeoutMillis);
75+
} catch(Throwable e) {
76+
throw StackTraceUtils.deepSanitize(e);
77+
}
7378
}
7479

7580
public boolean isDefinedAt(StackTraceElement stackTraceElement) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package cucumber.runtime.groovy
2+
3+
class ExceptionThrowingThing {
4+
def methodMissing(String name, args) {
5+
throw new RuntimeException("Don't have method $name taking $args")
6+
}
7+
8+
RuntimeException returnGroovyException() {
9+
try {
10+
this.foo()
11+
null
12+
} catch(RuntimeException e) {
13+
e
14+
}
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package cucumber.runtime.groovy;
2+
3+
import groovy.lang.Closure;
4+
import org.codehaus.groovy.runtime.MethodClosure;
5+
import org.junit.Before;
6+
import org.junit.Test;
7+
import org.junit.runner.RunWith;
8+
import org.mockito.runners.MockitoJUnitRunner;
9+
10+
import static junit.framework.Assert.assertFalse;
11+
import static org.junit.Assert.fail;
12+
13+
@RunWith(MockitoJUnitRunner.class)
14+
public class GroovyStackTraceTest {
15+
GroovyStepDefinition groovyStepDefinition;
16+
17+
@Before
18+
public void setUp() throws Throwable {
19+
Closure body = new MethodClosure("the owner", "length");
20+
groovyStepDefinition = new GroovyStepDefinition(null, 0, body, null, new ExceptionThrowingBackend());
21+
}
22+
23+
@Test
24+
public void should_sanitize_stacktrace() throws Throwable {
25+
try {
26+
groovyStepDefinition.execute(null, new Object[0]);
27+
fail("step definition didn't throw an exception");
28+
} catch(Throwable thrown) {
29+
for (StackTraceElement stackTraceElement : thrown.getStackTrace()) {
30+
// if there are none of these, pretty good chance it's cleaned up the stack trace
31+
assertFalse("Stack trace has internal groovy callsite elements", stackTraceElement.getClassName().startsWith("org.codehaus.groovy.runtime.callsite"));
32+
}
33+
}
34+
35+
}
36+
37+
private static class ExceptionThrowingBackend extends GroovyBackend {
38+
public ExceptionThrowingBackend() {
39+
super(null);
40+
}
41+
42+
@Override
43+
public void invoke(Closure body, Object[] args) throws Throwable {
44+
throw new ExceptionThrowingThing().returnGroovyException();
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)