Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit 5d747ce

Browse files
committed
fancy error reporter with whoops fix jooby-project#371
1 parent 51d49ef commit 5d747ce

File tree

26 files changed

+2064
-6
lines changed

26 files changed

+2064
-6
lines changed

coverage-report/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
<source>${project.parent.basedir}/jooby-banner/src/main/java</source>
7373
<source>${project.parent.basedir}/jooby-rxjava-jdbc/src/main/java</source>
7474
<source>${project.parent.basedir}/jooby-reactor/src/main/java</source>
75+
<source>${project.parent.basedir}/jooby-whoops/src/main/java</source>
7576
</sources>
7677
</configuration>
7778
</execution>
@@ -123,6 +124,7 @@
123124
<source>${project.parent.basedir}/jooby-banner/src/test/java</source>
124125
<source>${project.parent.basedir}/jooby-rxjava-jdbc/src/test/java</source>
125126
<source>${project.parent.basedir}/jooby-reactor/src/test/java</source>
127+
<source>${project.parent.basedir}/jooby-whoops/src/test/java</source>
126128
</sources>
127129
</configuration>
128130
</execution>
@@ -146,6 +148,9 @@
146148
<resource>
147149
<directory>${project.parent.basedir}/jooby-hbm/src/test/resources</directory>
148150
</resource>
151+
<resource>
152+
<directory>${project.parent.basedir}/jooby-whoops/src/test/resources</directory>
153+
</resource>
149154
</resources>
150155
</configuration>
151156
</execution>
@@ -361,6 +366,12 @@
361366
<version>${project.version}</version>
362367
</dependency>
363368

369+
<dependency>
370+
<groupId>org.jooby</groupId>
371+
<artifactId>jooby-whoops</artifactId>
372+
<version>${project.version}</version>
373+
</dependency>
374+
364375
<!-- H2 database -->
365376
<dependency>
366377
<groupId>com.h2database</groupId>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package org.jooby.issues;
2+
3+
import static org.junit.Assert.assertTrue;
4+
5+
import org.jooby.test.ServerFeature;
6+
import org.jooby.whoops.Whoops;
7+
import org.junit.Test;
8+
9+
public class Issue371 extends ServerFeature {
10+
11+
{
12+
use(new Whoops());
13+
14+
get("/whoops/direct-ex", req -> {
15+
req.session().set("foo", "bar");
16+
17+
throw new IllegalStateException("Something broken!");
18+
});
19+
20+
get("/whoops/session-atrr", req -> {
21+
req.session().set("foo", "bar");
22+
23+
throw new IllegalStateException("Something broken!");
24+
});
25+
26+
get("/whoops/wrap-ex", req -> {
27+
try {
28+
return doSomething();
29+
} catch (Exception ex) {
30+
throw new IllegalStateException("Wrap wrap", ex);
31+
}
32+
});
33+
34+
get("/whoops/json", req -> {
35+
throw new IllegalStateException("def handler");
36+
});
37+
}
38+
39+
private Object doSomething() {
40+
throw new IllegalArgumentException("Xxx");
41+
}
42+
43+
@Test
44+
public void shouldHandleDirectEx() throws Exception {
45+
request()
46+
.get("/whoops/direct-ex")
47+
.expect(s -> {
48+
assertTrue(
49+
s.contains(
50+
"<span id=\"plain-exception\">java.lang.IllegalStateException: Something broken!"));
51+
});
52+
}
53+
54+
@Test
55+
public void shouldDumpSessionAttr() throws Exception {
56+
request()
57+
.get("/whoops/direct-ex")
58+
.expect(s -> {
59+
assertTrue(s.contains("foo"));
60+
assertTrue(s.contains("bar"));
61+
});
62+
}
63+
64+
@Test
65+
public void shouldHandleWrapEx() throws Exception {
66+
request()
67+
.get("/whoops/wrap-ex")
68+
.expect(s -> {
69+
assertTrue(
70+
s.contains(
71+
"<span id=\"plain-exception\">java.lang.IllegalStateException: Wrap wrap"));
72+
assertTrue(s.contains("java.lang.IllegalArgumentException: Xxx"));
73+
});
74+
}
75+
76+
@Test
77+
public void shouldIgnoreNonHtmlRequest() throws Exception {
78+
request()
79+
.get("/whoops/json")
80+
.header("Accept", "application/json")
81+
.expect(s -> assertTrue(s.contains("message=def handler")));
82+
}
83+
84+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.jooby.issues;
2+
3+
import org.jooby.test.ServerFeature;
4+
import org.jooby.whoops.Whoops;
5+
import org.junit.Test;
6+
7+
import com.typesafe.config.ConfigFactory;
8+
import com.typesafe.config.ConfigValueFactory;
9+
10+
public class Issue371b extends ServerFeature {
11+
12+
{
13+
use(ConfigFactory.empty().withValue("application.env", ConfigValueFactory.fromAnyRef("prod")));
14+
15+
use(new Whoops());
16+
17+
get("/no-whoops", req -> {
18+
throw new IllegalStateException("Something broken!");
19+
});
20+
21+
}
22+
23+
@Test
24+
public void shouldIgnoreWhoopsOnNonDevEnv() throws Exception {
25+
request()
26+
.get("/no-whoops")
27+
.expect("<!doctype html>\n" +
28+
"<html>\n" +
29+
"<head>\n" +
30+
"<meta charset=\"UTF-8\">\n" +
31+
"<style>\n" +
32+
"body {font-family: \"open sans\",sans-serif; margin-left: 20px;}\n" +
33+
"h1 {font-weight: 300; line-height: 44px; margin: 25px 0 0 0;}\n" +
34+
"h2 {font-size: 16px;font-weight: 300; line-height: 44px; margin: 0;}\n" +
35+
"footer {font-weight: 300; line-height: 44px; margin-top: 10px;}\n" +
36+
"hr {background-color: #f7f7f9;}\n" +
37+
"div.trace {border:1px solid #e1e1e8; background-color: #f7f7f9;}\n" +
38+
"p {padding-left: 20px;}\n" +
39+
"p.tab {padding-left: 40px;}\n" +
40+
"</style>\n" +
41+
"<title>\n" +
42+
"500 Server Error\n" +
43+
"</title>\n" +
44+
"<body>\n" +
45+
"<h1>Server Error</h1>\n" +
46+
"<hr><h2>message: Something broken!</h2>\n" +
47+
"<h2>status: 500</h2>\n" +
48+
"</body>\n" +
49+
"</html>\n" +
50+
"");
51+
}
52+
53+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.jooby.issues;
2+
3+
import static org.junit.Assert.assertNotEquals;
4+
5+
import org.jooby.test.ServerFeature;
6+
import org.jooby.whoops.Whoops;
7+
import org.junit.Test;
8+
9+
import com.typesafe.config.ConfigFactory;
10+
import com.typesafe.config.ConfigValueFactory;
11+
12+
public class Issue371c extends ServerFeature {
13+
14+
{
15+
use(ConfigFactory.empty()
16+
.withValue("application.env", ConfigValueFactory.fromAnyRef("prod"))
17+
.withValue("whoops", ConfigValueFactory.fromAnyRef(true)));
18+
19+
use(new Whoops());
20+
21+
get("/force-whoops", req -> {
22+
throw new IllegalStateException("Something broken!");
23+
});
24+
25+
}
26+
27+
@Test
28+
public void shouldForceWhoopsInNonEnvDev() throws Exception {
29+
request()
30+
.get("/no-whoops")
31+
.expect(s -> assertNotEquals("<!doctype html>\n" +
32+
"<html>\n" +
33+
"<head>\n" +
34+
"<meta charset=\"UTF-8\">\n" +
35+
"<style>\n" +
36+
"body {font-family: \"open sans\",sans-serif; margin-left: 20px;}\n" +
37+
"h1 {font-weight: 300; line-height: 44px; margin: 25px 0 0 0;}\n" +
38+
"h2 {font-size: 16px;font-weight: 300; line-height: 44px; margin: 0;}\n" +
39+
"footer {font-weight: 300; line-height: 44px; margin-top: 10px;}\n" +
40+
"hr {background-color: #f7f7f9;}\n" +
41+
"div.trace {border:1px solid #e1e1e8; background-color: #f7f7f9;}\n" +
42+
"p {padding-left: 20px;}\n" +
43+
"p.tab {padding-left: 40px;}\n" +
44+
"</style>\n" +
45+
"<title>\n" +
46+
"500 Server Error\n" +
47+
"</title>\n" +
48+
"<body>\n" +
49+
"<h1>Server Error</h1>\n" +
50+
"<hr><h2>message: Something broken!</h2>\n" +
51+
"<h2>status: 500</h2>\n" +
52+
"</body>\n" +
53+
"</html>\n" +
54+
"", s));
55+
}
56+
57+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package org.jooby.whoops;
2+
3+
import static org.junit.Assert.assertArrayEquals;
4+
import static org.junit.Assert.assertEquals;
5+
import static org.junit.Assert.assertFalse;
6+
import static org.junit.Assert.assertNotNull;
7+
import static org.junit.Assert.assertTrue;
8+
9+
import java.io.IOException;
10+
11+
import org.jooby.whoops.SourceLocator.Source;
12+
import org.junit.Test;
13+
14+
public class SourceLocatorTest {
15+
16+
@Test
17+
public void findJava() throws IOException {
18+
SourceLocator locator = SourceLocator.local();
19+
Source source = locator.source(WhoopsApp.class.getName());
20+
assertNotNull(source);
21+
assertTrue(source.getPath().toFile().exists());
22+
assertTrue(source.getLines().size() > 0);
23+
assertEquals("public class WhoopsApp extends Jooby {", source.source(5, 6));
24+
assertEquals(source.getPath().toString(), source.toString());
25+
}
26+
27+
@Test
28+
public void range() throws IOException {
29+
SourceLocator locator = SourceLocator.local();
30+
Source source = locator.source(WhoopsApp.class.getName());
31+
assertNotNull(source);
32+
assertArrayEquals(new int[]{0, 20}, source.range(1, 10));
33+
assertArrayEquals(new int[]{5, 25}, source.range(15, 10));
34+
assertArrayEquals(new int[]{15, 35}, source.range(33, 10));
35+
}
36+
37+
@Test
38+
public void emptyLinesShouldBeOneSpace() throws IOException {
39+
SourceLocator locator = SourceLocator.local();
40+
Source source = locator.source(WhoopsApp.class.getName());
41+
assertNotNull(source);
42+
assertEquals(" ", source.source(1, 2));
43+
assertEquals("", source.source(-1, 2));
44+
assertEquals("", source.source(10, Integer.MAX_VALUE));
45+
}
46+
47+
@Test
48+
public void findFile() throws IOException {
49+
SourceLocator locator = SourceLocator.local();
50+
SourceLocator.Source source = locator.source("whoops.js");
51+
assertNotNull(source);
52+
assertTrue(source.getPath().toFile().exists());
53+
assertTrue(source.getLines().size() > 0);
54+
assertEquals(" console.log('hey')", source.source(1, 2));
55+
56+
assertEquals("})(jQuery);", source.source(2, 3));
57+
}
58+
59+
@Test
60+
public void missingFile() throws IOException {
61+
SourceLocator locator = SourceLocator.local();
62+
Source source = locator.source("missing.js");
63+
assertNotNull(source);
64+
assertFalse(source.getPath().toFile().exists());
65+
assertTrue(source.getLines().size() == 0);
66+
assertEquals("", source.source(2, 1));
67+
}
68+
69+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.jooby.whoops;
2+
3+
import org.jooby.Jooby;
4+
import org.jooby.Request;
5+
6+
public class WhoopsApp extends Jooby {
7+
8+
{
9+
use(new Whoops());
10+
11+
get("/", req -> {
12+
try {
13+
return doSomething(req);
14+
} catch (Exception ex) {
15+
throw new IllegalStateException("Xxx", ex);
16+
}
17+
});
18+
}
19+
20+
public static void main(final String[] args) throws Throwable {
21+
run(WhoopsApp::new, args);
22+
}
23+
24+
private Object doSomething(final Request req) {
25+
try {
26+
return dx();
27+
} catch(Exception ex) {
28+
throw new IllegalStateException(ex);
29+
}
30+
}
31+
32+
private Object dx() {
33+
throw new UnsupportedOperationException("Something broken!");
34+
}
35+
}

0 commit comments

Comments
 (0)