Skip to content

Commit 065792c

Browse files
CodeCasterXclaude
andauthored
fix: 修复 MockMvcListener 无限等待导致测试卡死问题 (#397)
为 MockMvcListener.beforeTestClass() 添加超时机制(默认 30 秒), 确保在服务器启动失败时能快速失败,并提供详细的故障排查建议。 关键改进: - 添加可配置的超时机制,支持 1秒至10分钟范围 - 超时抛出详细异常,包含端口号、可能原因及排查命令 - 增加 MockMvcListenerTest 单元测试,覆盖各种超时及边界场景 - 优化测试桩设计,确保在无网络环境下的测试稳定性 Fixes #395 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.5 <[email protected]>
1 parent 07648a9 commit 065792c

File tree

2 files changed

+512
-2
lines changed

2 files changed

+512
-2
lines changed

framework/fit/java/fit-test/fit-test-framework/src/main/java/modelengine/fitframework/test/domain/listener/MockMvcListener.java

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
public class MockMvcListener implements TestListener {
3939
private static final Set<String> DEFAULT_SCAN_PACKAGES =
4040
new HashSet<>(Arrays.asList("modelengine.fit.server", "modelengine.fit.http"));
41+
private static final String TIMEOUT_PROPERTY_KEY = "fit.test.mockmvc.startup.timeout";
42+
private static final long DEFAULT_STARTUP_TIMEOUT = 30_000L;
43+
private static final long MIN_STARTUP_TIMEOUT = 1_000L;
44+
private static final long MAX_STARTUP_TIMEOUT = 600_000L;
4145

4246
private final int port;
4347

@@ -71,14 +75,60 @@ public void beforeTestClass(TestContext context) {
7175
}
7276
MockMvc mockMvc = new MockMvc(this.port);
7377
context.plugin().container().registry().register(mockMvc);
78+
long timeout = this.getStartupTimeout();
79+
long startTime = System.currentTimeMillis();
7480
boolean started = this.isStarted(mockMvc);
7581
while (!started) {
82+
long elapsed = System.currentTimeMillis() - startTime;
83+
if (elapsed > timeout) {
84+
throw new IllegalStateException(this.buildTimeoutErrorMessage(elapsed, this.port));
85+
}
7686
ThreadUtils.sleep(100);
7787
started = this.isStarted(mockMvc);
7888
}
7989
}
8090

81-
private boolean isStarted(MockMvc mockMvc) {
91+
private long getStartupTimeout() {
92+
String timeoutStr = System.getProperty(TIMEOUT_PROPERTY_KEY);
93+
if (StringUtils.isNotBlank(timeoutStr)) {
94+
try {
95+
long timeout = Long.parseLong(timeoutStr);
96+
if (timeout < MIN_STARTUP_TIMEOUT) {
97+
return DEFAULT_STARTUP_TIMEOUT;
98+
}
99+
if (timeout > MAX_STARTUP_TIMEOUT) {
100+
return MAX_STARTUP_TIMEOUT;
101+
}
102+
return timeout;
103+
} catch (NumberFormatException e) {
104+
return DEFAULT_STARTUP_TIMEOUT;
105+
}
106+
}
107+
return DEFAULT_STARTUP_TIMEOUT;
108+
}
109+
110+
private String buildTimeoutErrorMessage(long elapsed, int port) {
111+
return StringUtils.format("""
112+
Mock MVC server failed to start within {0}ms. [port={1}]
113+
114+
Possible causes:
115+
1. Port {1} is already in use by another process
116+
2. Network configuration issues
117+
3. Server startup is slower than expected in this environment
118+
119+
Troubleshooting steps:
120+
- Check if port {1} is in use:
121+
* macOS/Linux: lsof -i :{1}
122+
* Windows: netstat -ano | findstr :{1}
123+
- Check server logs for detailed error messages
124+
- If running in a slow environment, increase timeout:
125+
mvn test -D{2}=60000""",
126+
elapsed,
127+
port,
128+
TIMEOUT_PROPERTY_KEY);
129+
}
130+
131+
protected boolean isStarted(MockMvc mockMvc) {
82132
MockRequestBuilder builder = MockMvcRequestBuilders.get(MockController.PATH).responseType(String.class);
83133
try (HttpClassicClientResponse<String> response = mockMvc.perform(builder)) {
84134
String content = response.textEntity()
@@ -91,4 +141,4 @@ private boolean isStarted(MockMvc mockMvc) {
91141
return false;
92142
}
93143
}
94-
}
144+
}

0 commit comments

Comments
 (0)