Skip to content

Commit 5e55921

Browse files
committed
test: expand unit test coverage across core modules
Add comprehensive test suites for common, context, gateway, http, and testing modules. Raise minimum coverage threshold to 0.80 for context and http modules. Add JaCoCo exclusions for compile-time annotation processor code and network-bound classes that are impractical to unit test. Update all gradle lockfiles to reflect build config changes. Modules covered: common, context, gateway, gateway-generator, http, testing Generated with AI-assisted tooling Co-Authored-By: Matthew Nichols <matthew.nichols@mx.com>
1 parent 3c0dc3f commit 5e55921

56 files changed

Lines changed: 4015 additions & 273 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,4 @@ gradle-app.setting
208208

209209
# node
210210
node_modules/
211+
CLAUDE.md

common/gradle.lockfile

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,31 @@
33
# This file is expected to be part of source control.
44
com.github.oowekyala.ooxml:nice-xml-messages:3.1=pmd
55
com.github.rholder:guava-retrying:2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
6-
com.github.spotbugs:spotbugs-annotations:4.9.8=annotationProcessor,compileClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath
7-
com.github.spotbugs:spotbugs:4.9.8=spotbugs
6+
com.github.spotbugs:spotbugs-annotations:4.10.2=compileClasspath,spotbugs,testCompileClasspath
7+
com.github.spotbugs:spotbugs-annotations:4.9.8=annotationProcessor,testAnnotationProcessor
8+
com.github.spotbugs:spotbugs:4.10.2=spotbugs
89
com.github.stephenc.jcip:jcip-annotations:1.0-1=spotbugs
910
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,runtimeClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
10-
com.google.code.gson:gson:2.13.2=pmd,spotbugs
11-
com.google.code.gson:gson:2.14.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
11+
com.google.code.gson:gson:2.13.2=pmd
12+
com.google.code.gson:gson:2.14.0=compileClasspath,runtimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
1213
com.google.errorprone:error_prone_annotations:2.36.0=checkstyle
13-
com.google.errorprone:error_prone_annotations:2.41.0=pmd,spotbugs
14-
com.google.errorprone:error_prone_annotations:2.48.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
14+
com.google.errorprone:error_prone_annotations:2.41.0=pmd
15+
com.google.errorprone:error_prone_annotations:2.48.0=compileClasspath,runtimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
1516
com.google.guava:failureaccess:1.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
1617
com.google.guava:failureaccess:1.0.3=checkstyle
17-
com.google.guava:guava:32.1.3-jre=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
18+
com.google.guava:guava:32.0.1-jre=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
1819
com.google.guava:guava:33.4.8-jre=checkstyle
1920
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=checkstyle,compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
20-
com.google.j2objc:j2objc-annotations:2.8=compileClasspath,testCompileClasspath
21+
com.google.j2objc:j2objc-annotations:2.8=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
2122
com.google.j2objc:j2objc-annotations:3.0.0=checkstyle
2223
com.puppycrawl.tools:checkstyle:10.25.0=checkstyle
2324
commons-beanutils:commons-beanutils:1.11.0=checkstyle
2425
commons-codec:commons-codec:1.15=checkstyle
2526
commons-collections:commons-collections:3.2.2=checkstyle
26-
commons-io:commons-io:2.20.0=spotbugs
27+
commons-io:commons-io:2.21.0=spotbugs
2728
info.picocli:picocli:4.7.7=checkstyle
2829
io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
29-
jaxen:jaxen:2.0.0=spotbugs
30+
jaxen:jaxen:2.0.6=spotbugs
3031
net.bytebuddy:byte-buddy-agent:1.17.7=testCompileClasspath,testRuntimeClasspath
3132
net.bytebuddy:byte-buddy:1.17.7=testCompileClasspath,testRuntimeClasspath
3233
net.sf.saxon:Saxon-HE:12.5=checkstyle
@@ -36,27 +37,25 @@ net.sourceforge.pmd:pmd-core:7.22.0=pmd
3637
net.sourceforge.pmd:pmd-java:7.22.0=pmd
3738
org.antlr:antlr4-runtime:4.13.2=checkstyle
3839
org.antlr:antlr4-runtime:4.9.3=pmd
39-
org.apache.bcel:bcel:6.11.0=spotbugs
40+
org.apache.bcel:bcel:6.12.0=spotbugs
4041
org.apache.commons:commons-lang3:3.18.0=checkstyle
41-
org.apache.commons:commons-lang3:3.19.0=spotbugs
42-
org.apache.commons:commons-lang3:3.20.0=compileClasspath,pmd,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
43-
org.apache.commons:commons-text:1.14.0=spotbugs
44-
org.apache.commons:commons-text:1.15.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
42+
org.apache.commons:commons-lang3:3.20.0=compileClasspath,pmd,runtimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
43+
org.apache.commons:commons-text:1.15.0=compileClasspath,runtimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
4544
org.apache.commons:commons-text:1.3=checkstyle
4645
org.apache.httpcomponents.client5:httpclient5:5.1.3=checkstyle
4746
org.apache.httpcomponents.core5:httpcore5-h2:5.1.3=checkstyle
4847
org.apache.httpcomponents.core5:httpcore5:5.1.3=checkstyle
4948
org.apache.httpcomponents:httpclient:4.5.13=checkstyle
5049
org.apache.httpcomponents:httpcore:4.4.14=checkstyle
51-
org.apache.logging.log4j:log4j-api:2.25.3=spotbugs
52-
org.apache.logging.log4j:log4j-core:2.25.3=spotbugs
50+
org.apache.logging.log4j:log4j-api:2.26.0=spotbugs
51+
org.apache.logging.log4j:log4j-core:2.26.0=spotbugs
5352
org.apache.maven.doxia:doxia-core:1.12.0=checkstyle
5453
org.apache.maven.doxia:doxia-logging-api:1.12.0=checkstyle
5554
org.apache.maven.doxia:doxia-module-xdoc:1.12.0=checkstyle
5655
org.apache.maven.doxia:doxia-sink-api:1.12.0=checkstyle
5756
org.apache.xbean:xbean-reflect:3.7=checkstyle
5857
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
59-
org.checkerframework:checker-qual:3.37.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
58+
org.checkerframework:checker-qual:3.33.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
6059
org.checkerframework:checker-qual:3.49.3=checkstyle
6160
org.checkerframework:checker-qual:3.53.1=pmd
6261
org.codehaus.groovy:groovy:3.0.24=testCompileClasspath,testRuntimeClasspath
@@ -75,25 +74,27 @@ org.jspecify:jspecify:1.0.0=checkstyle
7574
org.junit.jupiter:junit-jupiter-api:5.14.0=testCompileClasspath,testRuntimeClasspath
7675
org.junit.platform:junit-platform-commons:1.14.0=testCompileClasspath,testRuntimeClasspath
7776
org.junit.platform:junit-platform-engine:1.14.0=testCompileClasspath,testRuntimeClasspath
78-
org.junit:junit-bom:5.14.0=annotationProcessor,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
77+
org.junit:junit-bom:5.14.0=annotationProcessor,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
78+
org.junit:junit-bom:6.1.0=spotbugs
7979
org.mockito:mockito-core:5.23.0=testCompileClasspath,testRuntimeClasspath
8080
org.objenesis:objenesis:3.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
8181
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
82-
org.ow2.asm:asm-analysis:9.9=spotbugs
82+
org.ow2.asm:asm-analysis:9.10.1=spotbugs
83+
org.ow2.asm:asm-commons:9.10.1=spotbugs
8384
org.ow2.asm:asm-commons:9.8=jacocoAnt
84-
org.ow2.asm:asm-commons:9.9=spotbugs
85+
org.ow2.asm:asm-tree:9.10.1=spotbugs
8586
org.ow2.asm:asm-tree:9.8=jacocoAnt
86-
org.ow2.asm:asm-tree:9.9=spotbugs
87-
org.ow2.asm:asm-util:9.9=spotbugs
87+
org.ow2.asm:asm-util:9.10.1=spotbugs
88+
org.ow2.asm:asm:9.10.1=spotbugs
8889
org.ow2.asm:asm:9.8=jacocoAnt
89-
org.ow2.asm:asm:9.9=spotbugs
9090
org.ow2.asm:asm:9.9.1=pmd
9191
org.pcollections:pcollections:4.0.2=pmd
9292
org.projectlombok:lombok:1.18.42=annotationProcessor,compileClasspath,lombok,testAnnotationProcessor,testCompileClasspath
9393
org.reflections:reflections:0.10.2=checkstyle
9494
org.slf4j:jul-to-slf4j:1.7.36=pmd
9595
org.slf4j:slf4j-api:1.7.30=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
96-
org.slf4j:slf4j-api:2.0.17=spotbugs,spotbugsSlf4j
96+
org.slf4j:slf4j-api:2.0.17=spotbugsSlf4j
97+
org.slf4j:slf4j-api:2.0.18=spotbugs
9798
org.slf4j:slf4j-simple:2.0.17=spotbugsSlf4j
9899
org.spockframework:spock-bom:2.4-M6-groovy-3.0=testCompileClasspath,testRuntimeClasspath
99100
org.spockframework:spock-core:2.4-M6-groovy-3.0=testCompileClasspath,testRuntimeClasspath

common/src/main/java/com/mx/path/core/common/connect/Request.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ public final void setTimeout(Duration timeout) {
567567
/**
568568
* Called before the request starts. Sets start time. Override to add behavior. Be sure to call {@code super.start()}
569569
*/
570+
@SuppressFBWarnings("USO_UNSAFE_METHOD_SYNCHRONIZATION")
570571
public synchronized void start() {
571572
if (attemptCount < 1) {
572573
attemptCount = 1;
@@ -579,6 +580,7 @@ public synchronized void start() {
579580
/**
580581
* Called before retrying request. Sets start time. Override to add behavior. Be sure to call {@code super.startRetry()}
581582
*/
583+
@SuppressFBWarnings("USO_UNSAFE_METHOD_SYNCHRONIZATION")
582584
public synchronized void startRetry() {
583585
attemptCount++;
584586
startNano = 0;
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
package com.mx.path.core.common.accessor
2+
3+
import spock.lang.Specification
4+
5+
class AccessorExceptionsTest extends Specification {
6+
7+
static class ConcreteSystemException extends AccessorSystemException {
8+
ConcreteSystemException(String message) {
9+
super(message)
10+
}
11+
ConcreteSystemException(String message, Throwable cause) {
12+
super(message, cause)
13+
}
14+
}
15+
16+
static class ConcreteUserException extends AccessorUserException {
17+
ConcreteUserException(String message, PathResponseStatus status) {
18+
super(message, status)
19+
}
20+
ConcreteUserException(String message, PathResponseStatus status, Throwable cause) {
21+
super(message, status, cause)
22+
}
23+
ConcreteUserException(String message, String userMessage, PathResponseStatus status) {
24+
super(message, userMessage, status)
25+
}
26+
ConcreteUserException(String message, String userMessage, PathResponseStatus status, Throwable cause) {
27+
super(message, userMessage, status, cause)
28+
}
29+
}
30+
31+
def "AccessorSystemException sets INTERNAL_ERROR status and shouldReport=true"() {
32+
given:
33+
def ex = new ConcreteSystemException("system error")
34+
35+
expect:
36+
ex.getMessage() == "system error"
37+
ex.getStatus() == PathResponseStatus.INTERNAL_ERROR
38+
ex.shouldReport()
39+
}
40+
41+
def "AccessorSystemException with cause preserves cause"() {
42+
given:
43+
def cause = new RuntimeException("root")
44+
def ex = new ConcreteSystemException("system error", cause)
45+
46+
expect:
47+
ex.getCause().is(cause)
48+
ex.getStatus() == PathResponseStatus.INTERNAL_ERROR
49+
ex.shouldReport()
50+
}
51+
52+
def "AccessorUserException sets status and shouldReport=false"() {
53+
given:
54+
def ex = new ConcreteUserException("user error", PathResponseStatus.NOT_FOUND)
55+
56+
expect:
57+
ex.getMessage() == "user error"
58+
ex.getStatus() == PathResponseStatus.NOT_FOUND
59+
!ex.shouldReport()
60+
}
61+
62+
def "AccessorUserException with cause"() {
63+
given:
64+
def cause = new RuntimeException("root")
65+
def ex = new ConcreteUserException("user error", PathResponseStatus.BAD_REQUEST, cause)
66+
67+
expect:
68+
ex.getCause().is(cause)
69+
!ex.shouldReport()
70+
}
71+
72+
def "AccessorUserException with userMessage"() {
73+
given:
74+
def ex = new ConcreteUserException("internal msg", "user msg", PathResponseStatus.UNAUTHORIZED)
75+
76+
expect:
77+
ex.getMessage() == "internal msg"
78+
ex.getUserMessage() == "user msg"
79+
ex.getStatus() == PathResponseStatus.UNAUTHORIZED
80+
}
81+
82+
def "AccessorUserException with userMessage and cause"() {
83+
given:
84+
def cause = new RuntimeException("root")
85+
def ex = new ConcreteUserException("internal msg", "user msg", PathResponseStatus.UNAUTHORIZED, cause)
86+
87+
expect:
88+
ex.getCause().is(cause)
89+
ex.getUserMessage() == "user msg"
90+
}
91+
92+
def "ResourceNotFoundException message constructor"() {
93+
given:
94+
def ex = new ResourceNotFoundException("not found")
95+
96+
expect:
97+
ex.getStatus() == PathResponseStatus.NOT_FOUND
98+
ex.getMessage() == "not found"
99+
}
100+
101+
def "ResourceNotFoundException message+cause constructor"() {
102+
given:
103+
def cause = new RuntimeException("root")
104+
def ex = new ResourceNotFoundException("not found", cause)
105+
106+
expect:
107+
ex.getCause().is(cause)
108+
ex.getStatus() == PathResponseStatus.NOT_FOUND
109+
}
110+
111+
def "UnauthorizedException constructors"() {
112+
given:
113+
def ex = new UnauthorizedException("unauthorized", "please log in")
114+
115+
expect:
116+
ex.getStatus() == PathResponseStatus.UNAUTHORIZED
117+
ex.getUserMessage() == "please log in"
118+
}
119+
120+
def "UnauthorizedException with cause"() {
121+
given:
122+
def cause = new RuntimeException("root")
123+
def ex = new UnauthorizedException("unauthorized", "please log in", cause)
124+
125+
expect:
126+
ex.getCause().is(cause)
127+
ex.getStatus() == PathResponseStatus.UNAUTHORIZED
128+
}
129+
130+
def "BadRequestException sets BAD_REQUEST status"() {
131+
given:
132+
def ex = new BadRequestException("bad input")
133+
134+
expect:
135+
ex.getStatus() == PathResponseStatus.BAD_REQUEST
136+
}
137+
138+
def "UpstreamResponseError single-arg constructor"() {
139+
given:
140+
def ex = new UpstreamResponseError("upstream error")
141+
142+
expect:
143+
ex.getMessage() == "upstream error"
144+
ex.shouldReport()
145+
}
146+
147+
def "UpstreamResponseError with cause"() {
148+
given:
149+
def cause = new RuntimeException("root")
150+
def ex = new UpstreamResponseError("upstream error", cause)
151+
152+
expect:
153+
ex.getCause().is(cause)
154+
}
155+
156+
def "RequestValidationException with message"() {
157+
given:
158+
def ex = new RequestValidationException("validation failed")
159+
160+
expect:
161+
ex.getMessage() == "validation failed"
162+
ex.getStatus() == PathResponseStatus.USER_ERROR
163+
}
164+
165+
def "RequestValidationException with message and userMessage"() {
166+
given:
167+
def ex = new RequestValidationException("validation failed", "please fix input")
168+
169+
expect:
170+
ex.getUserMessage() == "please fix input"
171+
}
172+
173+
def "RequestPayloadException sets shouldReport=true and isInternal=true"() {
174+
given:
175+
def ex = new RequestPayloadException("payload error")
176+
177+
expect:
178+
ex.getMessage() == "payload error"
179+
ex.shouldReport()
180+
ex.isInternal()
181+
}
182+
183+
def "ResponsePayloadException sets shouldReport=true and isInternal=true"() {
184+
given:
185+
def ex = new ResponsePayloadException("response error")
186+
187+
expect:
188+
ex.getMessage() == "response error"
189+
ex.shouldReport()
190+
ex.isInternal()
191+
}
192+
193+
def "UpstreamResponseProcessingException constructors"() {
194+
given:
195+
def cause = new RuntimeException("root")
196+
197+
expect:
198+
new UpstreamResponseProcessingException("processing error").getMessage() == "processing error"
199+
new UpstreamResponseProcessingException("processing error", cause).getCause().is(cause)
200+
}
201+
202+
def "UpstreamResponseValidationException constructors"() {
203+
given:
204+
def cause = new RuntimeException("root")
205+
206+
expect:
207+
new UpstreamResponseValidationException("validation error").getMessage() == "validation error"
208+
new UpstreamResponseValidationException("validation error", cause).getCause().is(cause)
209+
}
210+
211+
def "UpstreamSystemUnavailable constructors"() {
212+
given:
213+
def cause = new RuntimeException("root")
214+
215+
expect:
216+
new UpstreamSystemUnavailable("unavailable").getMessage() == "unavailable"
217+
new UpstreamSystemUnavailable("unavailable", cause).getCause().is(cause)
218+
new UpstreamSystemUnavailable("unavailable", "user msg").getUserMessage() == "user msg"
219+
new UpstreamSystemUnavailable("unavailable", "user msg", cause).getCause().is(cause)
220+
}
221+
222+
def "UpstreamSystemMaintenance sets errorTitle"() {
223+
given:
224+
def ex = new UpstreamSystemMaintenance("maintenance")
225+
226+
expect:
227+
ex.getMessage() == "maintenance"
228+
ex.getErrorTitle() == "System under maintenance"
229+
}
230+
231+
def "UpstreamSystemMaintenance with cause"() {
232+
given:
233+
def cause = new RuntimeException("root")
234+
def ex = new UpstreamSystemMaintenance("maintenance", cause)
235+
236+
expect:
237+
ex.getCause().is(cause)
238+
ex.getErrorTitle() == "System under maintenance"
239+
}
240+
}

0 commit comments

Comments
 (0)