fix: 修复测试端口分配的 TOCTOU 竞态条件 (#396) #398
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
🔗 相关问题 / Related Issue
Issue 链接 / Issue Link: #396
📋 变更类型 / Type of Change
📝 变更目的 / Purpose of the Change
修复测试框架中端口分配存在的 TOCTOU (Time of Check, Time of Use) 竞态条件。原实现中
TestUtils.getLocalAvailablePort()使用ServerSocket(0)获取可用端口后立即关闭,在 Netty 服务器真正绑定端口前存在时间窗口,可能导致端口被其他进程抢占,引发测试不稳定和端口冲突问题。📋 主要变更 / Brief Changelog
bind(0)机制支持自动端口分配,彻底消除 TOCTOU 竞态条件httpBound和httpsBound标志明确跟踪 HTTP/HTTPS 绑定状态getActualHttpPort()和getActualHttpsPort()接口方法获取实际绑定端口MockMvcListener改为等待服务器启动后动态获取实际端口TestUtils.getLocalAvailablePort()方法HttpClassicServer依赖🧪 验证变更 / Verifying this Change
测试步骤 / Test Steps
mvn clean installmvn test -Dtest=MockMvcListenerTest测试覆盖 / Test Coverage
测试改进:
HttpClassicServer,消除对真实服务器的依赖StubBeans实现返回 mock server📸 截图 / Screenshots
N/A
✅ 贡献者检查清单 / Contributor Checklist
基本要求 / Basic Requirements:
代码质量 / Code Quality:
测试要求 / Testing Requirements:
mvn -B clean package -Dmaven.test.skip=true/ Basic checks passmvn clean install/ Unit tests pass文档和兼容性 / Documentation and Compatibility:
📋 附加信息 / Additional Notes
技术实现细节
端口分配流程:
NettyHttpClassicServer.bind(0)设置端口为 0 并标记httpBound = truestartServer()执行serverBootstrap.bind(0).sync()完成原子绑定channel.localAddress()获取 OS 分配的实际端口MockMvcListener等待server.isStarted()后调用getActualHttpPort()获取端口线程安全保证:
httpPort,httpsPort,httpBound,httpsBound,isStarted)使用volatile修饰bind().sync()确保端口分配在返回前完成MockMvcListener通过轮询isStarted()等待服务器启动,有超时保护设计亮点:
httpBound/httpsBound标志将"是否绑定"与"端口值"分离,避免端口值 0 的语义混淆影响范围
TestUtils.getLocalAvailablePort()方法@EnableMockMvc的测试类现在更加稳定后续计划
本次修复彻底解决了测试端口分配的竞态条件问题,无需后续改进。
审查者注意事项 / Reviewer Notes:
重点关注:
NettyHttpClassicServer中bind(0)后从 Channel 获取实际端口的逻辑MockMvcListener等待服务器启动并获取端口的流程volatile字段和bind().sync()的配合验证建议:
httpBound/httpsBound标志的设计是否合理代码审查结果:
.ai-workspace/context/TASK-20260103-135501/review-final.md🤖 Generated with Claude Code