Skip to content

For #13400, Fix naming subscriber get appName is - problem. #13464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 4, 2025

Conversation

KomachiSion
Copy link
Collaborator

Please do not create a Pull Request without creating an issue first.

What is the purpose of the change

Fix #13400

Brief changelog

XX

Verifying this change

XXXX

Follow this checklist to help us incorporate your contribution quickly and easily:

  • Make sure there is a Github issue filed for the change (usually before you start working on it). Trivial changes like typos do not require a Github issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue.
  • Format the pull request title like [ISSUE #123] Fix UnknownException when host config not exist. Each commit in the pull request should have a meaningful subject line and body.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Write necessary unit-test to verify your logic correction, more mock a little better when cross module dependency exist. If the new feature or significant change is committed, please remember to add integration-test in test module.
  • Run mvn -B clean package apache-rat:check findbugs:findbugs -Dmaven.test.skip=true to make sure basic checks pass. Run mvn clean install -DskipITs to make sure unit-test pass. Run mvn clean test-compile failsafe:integration-test to make sure integration-test pass.

@KomachiSion KomachiSion added this to the 3.0.2 milestone Jun 4, 2025
@KomachiSion KomachiSion added the kind/bug Category issues or prs related to bug. label Jun 4, 2025
Copy link

github-actions bot commented Jun 4, 2025

Thanks for your this PR. 🙏
Please check again for your PR changes whether contains any usage/api/configuration change such as Add new API , Add new configuration, Change default value of configuration.
If so, please add or update documents(markdown type) in docs/next/ for repository nacos-group/nacos-group.github.io


感谢您提交的PR。 🙏
请再次查看您的PR内容,确认是否包含任何使用方式/API/配置参数的变更,如:新增API新增配置参数修改默认配置等操作。
如果是,请确保在提交之前,在仓库nacos-group/nacos-group.github.io中的docs/next/目录下添加或更新文档(markdown格式)。

Copy link

lingma-agents bot commented Jun 4, 2025

修复appName默认值导致获取异常问题并补充测试用例

变更文件

文件路径 变更说明
core/​src/​main/​java/​com/​alibaba/​nacos/​core/​remote/​grpc/​GrpcRequestAcceptor.java 添加`private static final String DEFAULT_APP_NAME = "-"`常量,修改应用名判断逻辑为当连接元数据中的appName为空或等于默认值时,从请求头`HttpHeaderConsts.APP_FILED`获取应用名(默认"unknown")。
core/​src/​test/​java/​com/​alibaba/​nacos/​core/​remote/​grpc/​GrpcRequestAcceptorTest.java 新增`@AfterEach`清理上下文的`tearDown`方法,新增`testHandleRequestSuccessWithAppName`和`testHandleRequestSuccessWithAppNameInHeader`两个测试用例,分别验证连接元数据和请求头中应用名的正确性。

时序图

sequenceDiagram
    participant Client as GRPC客户端
    participant Acceptor as GrpcRequestAcceptor
    participant Context as 请求上下文
    Client->>Acceptor: 发送请求
    Acceptor->>Acceptor: prepareRequestContext()
    Acceptor->>Connection: 获取连接元数据appName
    alt appName无效(空或"-")
        Acceptor->>Request: 读取请求头APP_FILED
        Acceptor->>Context: 设置app为请求头值
    else appName有效
        Acceptor->>Context: 直接使用连接appName
    end
    Context-->>Acceptor: 完成上下文构建
Loading

💡 小贴士

与 lingma-agents 交流的方式

📜 直接回复评论
直接回复本条评论,lingma-agents 将自动处理您的请求。例如:

  • 在当前代码中添加详细的注释说明。

  • 请详细介绍一下你说的 LRU 改造方案,并使用伪代码加以说明。

📜 在代码行处标记
在文件的特定位置创建评论并 @lingma-agents。例如:

  • @Lingma-Agent 分析这个方法的性能瓶颈并提供优化建议。

  • @Lingma-Agent 对这个方法生成优化代码。

📜 在讨论中提问
在任何讨论中 @lingma-agents 来获取帮助。例如:

  • @Lingma-Agent 请总结上述讨论并提出解决方案。

  • @Lingma-Agent 请根据讨论内容生成优化代码。

Copy link

@lingma-agents lingma-agents bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 代码评审报告

🎯 评审意见概览

严重度 数量 说明
🔴 Blocker 0 阻断性问题,需立即修复。例如:系统崩溃、关键功能不可用或严重安全漏洞。
🟠 Critical 0 严重问题,高优先级修复。例如:核心功能异常或性能瓶颈影响用户体验。
🟡 Major 0 主要问题,建议修复。例如:非核心功能缺陷或代码维护性较差。
🟢 Minor 2 次要问题,酌情优化。例如:代码格式不规范或注释缺失。

总计: 2 个问题


📋 评审意见详情

💡 单文件建议

以下是文件级别的代码建议,聚焦于代码的可读性、可维护性和潜在问题。
☕ core/src/test/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptorTest.java (2 💬)

🚀 跨文件建议

以下是对代码架构和设计的综合分析,聚焦于跨文件交互、系统一致性和潜在优化空间。
🔍 1. 默认应用名称处理逻辑存在架构不一致性风险

新增的DEFAULT_APP_NAME常量在GrpcRequestAcceptor.java中被定义为"-", 但未在其他相关模块中统一使用。当前仅在GrpcRequestAcceptor的prepareRequestContext方法中处理了该默认值逻辑,可能导致以下问题: 1. 其他模块可能仍直接使用"-"字符串进行硬编码,导致维护困难 2. 不同组件对默认应用名称的处理逻辑可能出现不一致 3. 未建立统一的应用名称解析机制,存在重复实现风险 建议将默认应用名称配置集中管理,并建立统一的应用名称解析服务

📌 关键代码:

private static final String DEFAULT_APP_NAME = "-";

⚠️ 潜在风险: 若其他模块未遵循统一规则,可能导致应用名称解析结果不一致,引发业务逻辑错误或数据污染

🔍 2. 应用名称优先级逻辑未在系统层面明确

当connection的appName为默认值时,当前逻辑会从请求头获取应用名称,但未在架构层面定义以下关键规则: 1. 当connection和请求头同时存在有效值时的优先级规则 2. 不同通信协议(如HTTP/REST)间应用名称处理的统一性 3. 客户端/服务端对应用名称格式的契约约定 建议在系统设计文档中明确应用名称的获取策略和优先级规则,并确保各组件实现一致

📌 关键代码:

if (StringUtils.isBlank(app) || StringUtils.equals(DEFAULT_APP_NAME, app)) {
    app = request.getHeader(HttpHeaderConsts.APP_FILED, "unknown");
}

⚠️ 潜在风险: 不同组件可能采用不同优先级规则,导致系统行为不可预测,增加排查问题的复杂度

🔍 3. 测试覆盖未包含关键边界条件

新增的测试用例未覆盖以下重要场景: 1. connection的appName为默认值且请求头也为空时的处理(当前默认返回"unknown") 2. connection的appName非空且非默认值,但请求头包含有效值时的优先级验证 3. 请求头应用名称字段名称与系统约定不一致时的容错处理 建议补充上述场景的测试用例,并建立参数化测试框架统一验证各种组合情况

📌 关键代码:

// 新增测试用例的实现代码
assertEquals("appNameInConnection", RequestContextHolder.getContext().getBasicContext().getApp());

⚠️ 潜在风险: 未覆盖的边界条件可能导致线上环境出现未预见的应用名称解析错误


💡 小贴士

与 lingma-agents 交流的方式

📜 直接回复评论
直接回复本条评论,lingma-agents 将自动处理您的请求。例如:

  • 在当前代码中添加详细的注释说明。

  • 请详细介绍一下你说的 LRU 改造方案,并使用伪代码加以说明。

📜 在代码行处标记
在文件的特定位置创建评论并 @lingma-agents。例如:

  • @Lingma-Agent 分析这个方法的性能瓶颈并提供优化建议。

  • @Lingma-Agent 对这个方法生成优化代码。

📜 在讨论中提问
在任何讨论中 @lingma-agents 来获取帮助。例如:

  • @Lingma-Agent 请总结上述讨论并提出解决方案。

  • @Lingma-Agent 请根据讨论内容生成优化代码。

Comment on lines +376 to +414
@Test
void testHandleRequestSuccessWithAppName() {
ApplicationUtils.setStarted(true);
Mockito.when(requestHandlerRegistry.getByRequestType(Mockito.anyString())).thenReturn(mockHandler);
Mockito.when(connectionManager.checkValid(Mockito.any())).thenReturn(true);
String ip = "1.1.1.1";
ConnectionMeta connectionMeta = new ConnectionMeta(connectId, ip, ip, 8888, 9848, "GRPC", "", "appNameInConnection", new HashMap<>());
Connection connection = new GrpcConnection(connectionMeta, null, null);
Mockito.when(connectionManager.getConnection(Mockito.any())).thenReturn(connection);

RequestMeta metadata = new RequestMeta();
metadata.setClientIp("127.0.0.1");
metadata.setConnectionId(connectId);
HealthCheckRequest mockRequest = new HealthCheckRequest();
Payload payload = GrpcUtils.convert(mockRequest, metadata);

StreamObserver<Payload> streamObserver = new StreamObserver<Payload>() {
@Override
public void onNext(Payload payload) {
System.out.println("Receive data from server: " + payload);
Object res = GrpcUtils.parse(payload);
assertTrue(res instanceof HealthCheckResponse);
assertEquals("appNameInConnection", RequestContextHolder.getContext().getBasicContext().getApp());
}

@Override
public void onError(Throwable throwable) {
fail(throwable.getMessage());
}

@Override
public void onCompleted() {
System.out.println("complete");
}
};

streamStub.request(payload, streamObserver);
ApplicationUtils.setStarted(false);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

减少测试用例中的重复代码,提取公共方法以提高可维护性

🟢 Minor | 🧹 Code Smells

📋 问题详情

测试方法testHandleRequestSuccessWithAppName和testHandleRequestSuccessWithAppNameInHeader存在大量重复代码,包括mock配置、连接和元数据的初始化。重复代码增加了维护成本,当需要修改公共逻辑时需要同时修改多个地方,容易引入错误。

💡 解决方案

将重复的mock配置、连接创建和元数据初始化提取到公共方法中:

+private void setupCommonMocks() {
+    ApplicationUtils.setStarted(true);
+    Mockito.when(requestHandlerRegistry.getByRequestType(Mockito.anyString())).thenReturn(mockHandler);
+    Mockito.when(connectionManager.checkValid(Mockito.any())).thenReturn(true);
+}
+
+private Connection createConnection(String appName) {
+    String ip = "1.1.1.1";
+    ConnectionMeta connectionMeta = new ConnectionMeta(connectId, ip, ip, 8888, 9848, "GRPC", "", appName, new HashMap<>());
+    return new GrpcConnection(connectionMeta, null, null);
+}
+
+private RequestMeta createMetadata() {
+    RequestMeta metadata = new RequestMeta();
+    metadata.setClientIp("127.0.0.1");
+    metadata.setConnectionId(connectId);
+    return metadata;
+}

@Test
void testHandleRequestSuccessWithAppName() {
+    setupCommonMocks();
+    Connection connection = createConnection("appNameInConnection");
+    Mockito.when(connectionManager.getConnection(Mockito.any())).thenReturn(connection);
+    
+    RequestMeta metadata = createMetadata();
+    HealthCheckRequest mockRequest = new HealthCheckRequest();
+    Payload payload = GrpcUtils.convert(mockRequest, metadata);
+    
+    // 流观察者逻辑保持不变
}

@Test
void testHandleRequestSuccessWithAppNameInHeader() {
+    setupCommonMocks();
+    Connection connection = createConnection("-");
+    Mockito.when(connectionManager.getConnection(Mockito.any())).thenReturn(connection);
+    
+    RequestMeta metadata = createMetadata();
+    HealthCheckRequest mockRequest = new HealthCheckRequest();
+    mockRequest.putHeader(HttpHeaderConsts.APP_FILED, "appNameInHeader");
+    Payload payload = GrpcUtils.convert(mockRequest, metadata);
+    
+    // 流观察者逻辑保持不变
}

您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)

有用意见👍无用意见👎错误意见❌

Comment on lines +376 to +414
@Test
void testHandleRequestSuccessWithAppName() {
ApplicationUtils.setStarted(true);
Mockito.when(requestHandlerRegistry.getByRequestType(Mockito.anyString())).thenReturn(mockHandler);
Mockito.when(connectionManager.checkValid(Mockito.any())).thenReturn(true);
String ip = "1.1.1.1";
ConnectionMeta connectionMeta = new ConnectionMeta(connectId, ip, ip, 8888, 9848, "GRPC", "", "appNameInConnection", new HashMap<>());
Connection connection = new GrpcConnection(connectionMeta, null, null);
Mockito.when(connectionManager.getConnection(Mockito.any())).thenReturn(connection);

RequestMeta metadata = new RequestMeta();
metadata.setClientIp("127.0.0.1");
metadata.setConnectionId(connectId);
HealthCheckRequest mockRequest = new HealthCheckRequest();
Payload payload = GrpcUtils.convert(mockRequest, metadata);

StreamObserver<Payload> streamObserver = new StreamObserver<Payload>() {
@Override
public void onNext(Payload payload) {
System.out.println("Receive data from server: " + payload);
Object res = GrpcUtils.parse(payload);
assertTrue(res instanceof HealthCheckResponse);
assertEquals("appNameInConnection", RequestContextHolder.getContext().getBasicContext().getApp());
}

@Override
public void onError(Throwable throwable) {
fail(throwable.getMessage());
}

@Override
public void onCompleted() {
System.out.println("complete");
}
};

streamStub.request(payload, streamObserver);
ApplicationUtils.setStarted(false);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

补充测试用例覆盖appName为默认值且请求头缺失的情况

🟢 Minor | 🧹 Code Smells

📋 问题详情

当前测试未覆盖当connection的appName为-且请求头未设置APP_FILED时的逻辑。根据代码逻辑,此时应使用默认值unknown,但缺少对应的测试验证。

💡 解决方案

添加新测试用例验证默认情况:

+@Test
+void testHandleRequestWithDefaultAppNameAndMissingHeader() {
+    setupCommonMocks();
+    Connection connection = createConnection("-");
+    Mockito.when(connectionManager.getConnection(Mockito.any())).thenReturn(connection);
+    
+    RequestMeta metadata = createMetadata();
+    HealthCheckRequest mockRequest = new HealthCheckRequest();
+    Payload payload = GrpcUtils.convert(mockRequest, metadata);
+    
+    StreamObserver<Payload> streamObserver = new StreamObserver<Payload>() {
+        @Override
+        public void onNext(Payload payload) {
+            assertEquals("unknown", RequestContextHolder.getContext().getBasicContext().getApp());
+        }
+    };
+    streamStub.request(payload, streamObserver);
+    ApplicationUtils.setStarted(false);
+}

您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)

有用意见👍无用意见👎错误意见❌

@codecov-commenter
Copy link

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 70.51%. Comparing base (c5aebb0) to head (054e9e5).

Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##             develop   #13464      +/-   ##
=============================================
- Coverage      70.52%   70.51%   -0.02%     
+ Complexity     11912    11911       -1     
=============================================
  Files           1621     1621              
  Lines          51826    51826              
  Branches        5210     5210              
=============================================
- Hits           36552    36545       -7     
- Misses         12826    12831       +5     
- Partials        2448     2450       +2     
Files with missing lines Coverage Δ
...ba/nacos/core/remote/grpc/GrpcRequestAcceptor.java 75.36% <100.00%> (+0.72%) ⬆️

... and 3 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c5aebb0...054e9e5. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@KomachiSion KomachiSion merged commit bd7a1dd into alibaba:develop Jun 4, 2025
5 checks passed
KomachiSion added a commit to KomachiSion/nacos that referenced this pull request Jun 4, 2025
@KomachiSion KomachiSion deleted the develop#13400 branch June 4, 2025 07:46
@wuyfee
Copy link

wuyfee commented Jun 4, 2025

$\color{red}{FAILURE}$
DETAILS
✅ - docker: success
❌ - deploy (standalone & cluster & standalone_auth): failure
❌ - e2e-java-test (standalone & cluster & standalone_auth): skipped
❌ - e2e-go-test (standalone & cluster): skipped
❌ - e2e-cpp-test (standalone & cluster): skipped
❌ - e2e-csharp-test (standalone & cluster): skipped
❌ - e2e-nodejs-test (standalone & cluster): skipped
❌ - e2e-python-test (standalone & cluster): skipped
✅ - clean (standalone & cluster & standalone_auth): success

KomachiSion added a commit that referenced this pull request Jun 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Category issues or prs related to bug.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug] Naming module subscriber can't get right appName
3 participants