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() {