This is an automated email from the ASF dual-hosted git repository.

dengliming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d5392d286   fix: prevent NPE when fetching data with stale discovery 
handler (#7054)
4d5392d286 is described below

commit 4d5392d28627202a990ee36de9d7ec2e694296d0
Author: Southern <[email protected]>
AuthorDate: Thu Sep 17 15:36:57 2026 +0800

      fix: prevent NPE when fetching data with stale discovery handler (#7054)
    
    Guard against missing discovery handler and discovery records before 
accessing them in
      ProxySelectorServiceImpl.fetchData. Add unit tests for valid fetching, 
missing records, and handlers without bound
      selectors.
    
    Co-authored-by: moremind <[email protected]>
    Co-authored-by: Liming Deng <[email protected]>
---
 .../service/impl/ProxySelectorServiceImpl.java     |  6 ++
 .../admin/service/ProxySelectorServiceTest.java    | 64 ++++++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
index 5760608411..ef71339450 100644
--- 
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
+++ 
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ProxySelectorServiceImpl.java
@@ -398,7 +398,13 @@ public class ProxySelectorServiceImpl implements 
ProxySelectorService {
     @Override
     public void fetchData(final String discoveryHandlerId) {
         DiscoveryHandlerDO discoveryHandlerDO = 
discoveryHandlerMapper.selectById(discoveryHandlerId);
+        if (Objects.isNull(discoveryHandlerDO)) {
+            return;
+        }
         DiscoveryDO discoveryDO = 
discoveryMapper.selectById(discoveryHandlerDO.getDiscoveryId());
+        if (Objects.isNull(discoveryDO)) {
+            return;
+        }
         ProxySelectorDO proxySelectorDO = 
proxySelectorMapper.selectByHandlerId(discoveryHandlerId);
         DiscoveryHandlerDTO discoveryHandlerDTO = 
DiscoveryTransfer.INSTANCE.mapToDTO(discoveryHandlerDO);
         if (Objects.nonNull(proxySelectorDO)) {
diff --git 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
index d38951ec98..0751ee66c9 100644
--- 
a/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
+++ 
b/shenyu-admin/src/test/java/org/apache/shenyu/admin/service/ProxySelectorServiceTest.java
@@ -52,6 +52,7 @@ import java.util.Collections;
 import java.util.List;
 
 import static 
org.apache.shenyu.common.constant.Constants.SYS_DEFAULT_NAMESPACE_ID;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
@@ -156,6 +157,69 @@ class ProxySelectorServiceTest {
         verify(discoveryUpstreamMapper, 
never()).deleteByDiscoveryHandlerId(any());
     }
 
+    @Test
+    void testFetchDataWithProxySelector() {
+        DiscoveryHandlerDO discoveryHandlerDO = new DiscoveryHandlerDO();
+        discoveryHandlerDO.setId("handler-1");
+        discoveryHandlerDO.setDiscoveryId("discovery-1");
+        
given(discoveryHandlerMapper.selectById("handler-1")).willReturn(discoveryHandlerDO);
+
+        DiscoveryDO discoveryDO = new DiscoveryDO();
+        discoveryDO.setDiscoveryType("local");
+        
given(discoveryMapper.selectById("discovery-1")).willReturn(discoveryDO);
+
+        ProxySelectorDO proxySelectorDO = buildProxySelectorDO();
+        
given(proxySelectorMapper.selectByHandlerId("handler-1")).willReturn(proxySelectorDO);
+        DiscoveryProcessor discoveryProcessor = mock(DiscoveryProcessor.class);
+        
given(discoveryProcessorHolder.chooseProcessor("local")).willReturn(discoveryProcessor);
+
+        proxySelectorService.fetchData("handler-1");
+
+        verify(discoveryProcessor).fetchAll(any(), any());
+    }
+
+    @Test
+    void testFetchDataWithMissingDiscoveryHandler() {
+        
given(discoveryHandlerMapper.selectById("missing-handler")).willReturn(null);
+
+        assertDoesNotThrow(() -> 
proxySelectorService.fetchData("missing-handler"));
+
+        verify(discoveryMapper, never()).selectById(any());
+        verify(proxySelectorMapper, never()).selectByHandlerId(any());
+        verify(selectorMapper, never()).selectByDiscoveryHandlerId(any());
+        verify(discoveryProcessorHolder, never()).chooseProcessor(any());
+    }
+
+    @Test
+    void testFetchDataWithMissingDiscovery() {
+        DiscoveryHandlerDO discoveryHandlerDO = new DiscoveryHandlerDO();
+        discoveryHandlerDO.setDiscoveryId("missing-discovery");
+        
given(discoveryHandlerMapper.selectById("handler-1")).willReturn(discoveryHandlerDO);
+        
given(discoveryMapper.selectById("missing-discovery")).willReturn(null);
+
+        assertDoesNotThrow(() -> proxySelectorService.fetchData("handler-1"));
+
+        verify(proxySelectorMapper, never()).selectByHandlerId(any());
+        verify(selectorMapper, never()).selectByDiscoveryHandlerId(any());
+        verify(discoveryProcessorHolder, never()).chooseProcessor(any());
+    }
+
+    @Test
+    void testFetchDataWithoutBoundSelector() {
+        DiscoveryHandlerDO discoveryHandlerDO = new DiscoveryHandlerDO();
+        discoveryHandlerDO.setId("handler-1");
+        discoveryHandlerDO.setDiscoveryId("discovery-1");
+        
given(discoveryHandlerMapper.selectById("handler-1")).willReturn(discoveryHandlerDO);
+
+        DiscoveryDO discoveryDO = new DiscoveryDO();
+        discoveryDO.setDiscoveryType("local");
+        
given(discoveryMapper.selectById("discovery-1")).willReturn(discoveryDO);
+
+        assertDoesNotThrow(() -> proxySelectorService.fetchData("handler-1"));
+
+        verify(discoveryProcessorHolder, never()).chooseProcessor(any());
+    }
+
     @Test
     void testDelete() {
 

Reply via email to