Merged
Conversation
**问题描述**: TestUtils.getLocalAvailablePort() 存在 TOCTOU (Time of Check, Time of Use) 竞态条件: ServerSocket 获取可用端口后立即关闭,在 Netty 绑定前可能被其他进程抢占。 **核心改进**: - 使用 Netty bind(0) 自动分配端口,彻底消除 TOCTOU 竞态 - 引入 httpBound/httpsBound 标志明确跟踪绑定状态 - 添加 getActualHttpPort() 和 getActualHttpsPort() 方法 - MockMvcListener 等待服务器启动后动态获取实际端口 - 完善的错误处理和详细的错误消息(区分自动分配和指定端口场景) - 移除 TestUtils.getLocalAvailablePort() 方法 **技术实现**: 1. NettyHttpClassicServer: 支持端口 0,bind().sync() 后从 Channel 获取实际端口 2. HttpClassicServer: 新增接口方法获取实际绑定端口 3. MockMvcListener: 移除端口预分配,改为启动后动态获取 4. DefaultFitTestService: 使用端口 0 和无参构造函数 **测试改进**: - 使用 Mockito mock HttpClassicServer,提升测试隔离性 - 添加 StubBeans 实现返回 mock server - 更新测试断言以匹配新的错误消息 **测试状态**:✅ 所有测试通过 相关 Issue: #396 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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