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

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 99f14ad6 fix: validate operational API requests (#939)
99f14ad6 is described below

commit 99f14ad6a1788aea45e80738ddda09a96a64e460
Author: aias00 <[email protected]>
AuthorDate: Tue Aug 4 03:05:59 2026 -0700

    fix: validate operational API requests (#939)
    
    * [ISSUE #831] Validate proxy address format
    
    * [ISSUE #844] Validate null datasource requests
    
    * [ISSUE #846] Validate null alert rule requests
    
    * [ISSUE #854] Validate null DLQ resend requests
    
    * [ISSUE #856] Validate null system alert acknowledge requests
---
 .../studio/cluster/proxy/ProxyAddressService.java  | 18 +++++++++++++-
 .../studio/instance/dlq/DLQController.java         | 10 +++++++-
 .../studio/ops/alert/AlertRuleController.java      | 16 +++++++++---
 .../rocketmq/studio/ops/alert/AlertService.java    |  8 +++++-
 .../studio/ops/alert/SystemAlertController.java    | 11 +++++++-
 .../studio/settings/SettingsController.java        | 16 +++++++++---
 .../rocketmq/studio/settings/SettingsService.java  |  6 +++++
 .../cluster/proxy/ProxyAddressServiceTest.java     | 29 ++++++++++++++++++++++
 .../studio/instance/dlq/DLQControllerTest.java     | 12 +++++++++
 .../studio/ops/alert/AlertRuleControllerTest.java  | 24 ++++++++++++++++++
 .../studio/ops/alert/AlertServiceTest.java         | 20 +++++++++++++++
 .../ops/alert/SystemAlertControllerTest.java       | 12 +++++++++
 .../studio/settings/SettingsControllerTest.java    | 24 ++++++++++++++++++
 .../studio/settings/SettingsServiceTest.java       | 23 +++++++++++++++++
 14 files changed, 217 insertions(+), 12 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyAddressService.java
 
b/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyAddressService.java
index 5495a573..3b6271d1 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyAddressService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyAddressService.java
@@ -25,11 +25,18 @@ import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 @Slf4j
 @Service
 public class ProxyAddressService {
 
+    private static final Pattern PROXY_ADDR_PATTERN =
+            
Pattern.compile("^(\\[[0-9a-fA-F:.]+]|[A-Za-z0-9._-]+):(\\d{1,5})$");
+    private static final int MIN_PORT = 1;
+    private static final int MAX_PORT = 65535;
+
     private final Set<String> proxyAddrs = new 
LinkedHashSet<>(List.of("127.0.0.1:8081"));
     private String currentProxyAddr = "127.0.0.1:8081";
 
@@ -64,6 +71,15 @@ public class ProxyAddressService {
         if (proxyAddr == null || proxyAddr.trim().isEmpty()) {
             throw new BusinessException(400, fieldName + " is required");
         }
-        return proxyAddr.trim();
+        String normalized = proxyAddr.trim();
+        Matcher matcher = PROXY_ADDR_PATTERN.matcher(normalized);
+        if (!matcher.matches()) {
+            throw new BusinessException(400, fieldName + " must be in 
host:port or [ipv6]:port format");
+        }
+        int port = Integer.parseInt(matcher.group(2));
+        if (port < MIN_PORT || port > MAX_PORT) {
+            throw new BusinessException(400, fieldName + " port must be 
between 1 and 65535");
+        }
+        return normalized;
     }
 }
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQController.java
 
b/server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQController.java
index 4015e1de..5b5517f7 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQController.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQController.java
@@ -17,6 +17,7 @@
 package org.apache.rocketmq.studio.instance.dlq;
 
 import org.apache.rocketmq.studio.common.domain.Result;
+import org.apache.rocketmq.studio.common.exception.BusinessException;
 import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -41,9 +42,16 @@ public class DLQController {
     }
 
     @PostMapping("/resend")
-    public Result<Void> resendMessages(@Valid @RequestBody DLQResendRequestDTO 
request) {
+    public Result<Void> resendMessages(@Valid @RequestBody(required = false) 
DLQResendRequestDTO request) {
+        requireRequest(request);
         dlqService.resendMessages(
                 request.getGroupName(), request.getStartTime(), 
request.getEndTime(), request.getTargetTopic());
         return Result.ok();
     }
+
+    private void requireRequest(DLQResendRequestDTO request) {
+        if (request == null) {
+            throw new BusinessException(400, "DLQ resend request is required");
+        }
+    }
 }
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertRuleController.java
 
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertRuleController.java
index 25a5e9ab..d7613a5f 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertRuleController.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertRuleController.java
@@ -17,6 +17,7 @@
 package org.apache.rocketmq.studio.ops.alert;
 
 import org.apache.rocketmq.studio.common.domain.Result;
+import org.apache.rocketmq.studio.common.exception.BusinessException;
 import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -40,13 +41,13 @@ public class AlertRuleController {
     }
 
     @PostMapping("/create")
-    public Result<AlertRuleVO> createRule(@RequestBody AlertRuleVO rule) {
-        return Result.ok(alertService.createRule(rule));
+    public Result<AlertRuleVO> createRule(@RequestBody(required = false) 
AlertRuleVO rule) {
+        return Result.ok(alertService.createRule(requireAlertRule(rule)));
     }
 
     @PostMapping("/update")
-    public Result<AlertRuleVO> updateRule(@RequestBody AlertRuleVO rule) {
-        return Result.ok(alertService.updateRule(rule));
+    public Result<AlertRuleVO> updateRule(@RequestBody(required = false) 
AlertRuleVO rule) {
+        return Result.ok(alertService.updateRule(requireAlertRule(rule)));
     }
 
     @PostMapping("/toggle")
@@ -59,4 +60,11 @@ public class AlertRuleController {
         alertService.deleteRule(request.getId());
         return Result.ok();
     }
+
+    private AlertRuleVO requireAlertRule(AlertRuleVO rule) {
+        if (rule == null) {
+            throw new BusinessException(400, "Alert rule request is required");
+        }
+        return rule;
+    }
 }
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertService.java 
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertService.java
index cd405ebc..82c67312 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/AlertService.java
@@ -67,6 +67,9 @@ public class AlertService {
 
 
     public AlertRuleVO createRule(AlertRuleVO rule) {
+        if (rule == null) {
+            throw new BusinessException(400, "Alert rule request is required");
+        }
         log.info("Creating alert rule: {}", rule.getName());
         rule.setId(UUID.randomUUID().toString());
         return alertRepository.saveRule(rule);
@@ -74,7 +77,10 @@ public class AlertService {
 
 
     public AlertRuleVO updateRule(AlertRuleVO rule) {
-        String id = rule == null ? null : rule.getId();
+        if (rule == null) {
+            throw new BusinessException(400, "Alert rule request is required");
+        }
+        String id = rule.getId();
         log.info("Updating alert rule: {}", id);
         validateRuleId(id);
         if (!alertRepository.replaceRule(rule)) {
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/SystemAlertController.java
 
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/SystemAlertController.java
index 7dda1bf9..b1ef42a6 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/SystemAlertController.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/SystemAlertController.java
@@ -17,6 +17,7 @@
 package org.apache.rocketmq.studio.ops.alert;
 
 import org.apache.rocketmq.studio.common.domain.Result;
+import org.apache.rocketmq.studio.common.exception.BusinessException;
 import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -43,7 +44,9 @@ public class SystemAlertController {
     }
 
     @PostMapping("/acknowledge")
-    public Result<SystemAlertVO> acknowledgeAlert(@Valid @RequestBody 
AcknowledgeSystemAlertDTO request) {
+    public Result<SystemAlertVO> acknowledgeAlert(
+            @Valid @RequestBody(required = false) AcknowledgeSystemAlertDTO 
request) {
+        requireAcknowledgeRequest(request);
         return Result.ok(alertService.acknowledgeAlert(request.getId()));
     }
 
@@ -52,4 +55,10 @@ public class SystemAlertController {
         int cleared = alertService.clearAcknowledged();
         return Result.ok(Map.of("cleared", cleared));
     }
+
+    private void requireAcknowledgeRequest(AcknowledgeSystemAlertDTO request) {
+        if (request == null) {
+            throw new BusinessException(400, "System alert acknowledge request 
is required");
+        }
+    }
 }
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsController.java
 
b/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsController.java
index 7be4fad3..40d79332 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsController.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsController.java
@@ -17,6 +17,7 @@
 package org.apache.rocketmq.studio.settings;
 
 import org.apache.rocketmq.studio.common.domain.Result;
+import org.apache.rocketmq.studio.common.exception.BusinessException;
 import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -52,13 +53,13 @@ public class SettingsController {
     }
 
     @PostMapping("/datasources/create")
-    public Result<DataSourceVO> createDataSource(@Valid @RequestBody 
DataSourceVO dataSource) {
-        return Result.ok(settingsService.createDataSource(dataSource));
+    public Result<DataSourceVO> createDataSource(@Valid @RequestBody(required 
= false) DataSourceVO dataSource) {
+        return 
Result.ok(settingsService.createDataSource(requireDataSource(dataSource)));
     }
 
     @PostMapping("/datasources/update")
-    public Result<DataSourceVO> updateDataSource(@Valid @RequestBody 
DataSourceVO dataSource) {
-        return Result.ok(settingsService.updateDataSource(dataSource));
+    public Result<DataSourceVO> updateDataSource(@Valid @RequestBody(required 
= false) DataSourceVO dataSource) {
+        return 
Result.ok(settingsService.updateDataSource(requireDataSource(dataSource)));
     }
 
     @PostMapping("/datasources/delete")
@@ -71,4 +72,11 @@ public class SettingsController {
     public Result<DataSourceTestResultVO> testDataSource(@Valid @RequestBody 
DataSourceTestDTO request) {
         return Result.ok(settingsService.testDataSource(request));
     }
+
+    private DataSourceVO requireDataSource(DataSourceVO dataSource) {
+        if (dataSource == null) {
+            throw new BusinessException(400, "Data source request is 
required");
+        }
+        return dataSource;
+    }
 }
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsService.java 
b/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsService.java
index a4bd5068..0d8295dc 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsService.java
@@ -99,6 +99,9 @@ public class SettingsService {
 
 
     public DataSourceVO createDataSource(DataSourceVO dataSource) {
+        if (dataSource == null) {
+            throw new BusinessException(400, "Data source request is 
required");
+        }
         log.info("Creating data source: {}", dataSource.getName());
         dataSource.setKey(UUID.randomUUID().toString());
         return settingsRepository.saveDataSource(dataSource);
@@ -106,6 +109,9 @@ public class SettingsService {
 
 
     public DataSourceVO updateDataSource(DataSourceVO dataSource) {
+        if (dataSource == null) {
+            throw new BusinessException(400, "Data source request is 
required");
+        }
         String key = normalizeDataSourceKey(dataSource.getKey());
         dataSource.setKey(key);
         log.info("Updating data source: {}", key);
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/cluster/proxy/ProxyAddressServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/cluster/proxy/ProxyAddressServiceTest.java
index 81a647b2..82648842 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/cluster/proxy/ProxyAddressServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/cluster/proxy/ProxyAddressServiceTest.java
@@ -20,6 +20,8 @@ package org.apache.rocketmq.studio.cluster.proxy;
 import org.apache.rocketmq.studio.common.exception.BusinessException;
 import org.junit.jupiter.api.Test;
 
+import java.util.List;
+
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
@@ -53,6 +55,33 @@ class ProxyAddressServiceTest {
                 .satisfies(ex -> assertThat(((BusinessException) 
ex).getCode()).isEqualTo(400));
     }
 
+    @Test
+    void addProxyAddrShouldAcceptBracketedIpv6Address() {
+        proxyAddressService.addProxyAddr(" [::1]:8081 ");
+
+        ProxyHomeVO home = proxyAddressService.getHomePage();
+        assertThat(home.getProxyAddrList()).containsExactly("127.0.0.1:8081", 
"[::1]:8081");
+    }
+
+    @Test
+    void addProxyAddrShouldRejectInvalidAddressFormats() {
+        List<String> invalidProxyAddrs = List.of(
+                "10.0.0.1",
+                "10.0.0.1:abc",
+                "10.0.0.1:0",
+                "10.0.0.1:65536",
+                "http://10.0.0.1:8081";,
+                "10.0.0.1:8081/path"
+        );
+
+        for (String invalidProxyAddr : invalidProxyAddrs) {
+            assertThatThrownBy(() -> 
proxyAddressService.addProxyAddr(invalidProxyAddr))
+                    .as("invalid proxy address %s", invalidProxyAddr)
+                    .isInstanceOf(BusinessException.class)
+                    .satisfies(ex -> assertThat(((BusinessException) 
ex).getCode()).isEqualTo(400));
+        }
+    }
+
     @Test
     void removeProxyAddrShouldTrimAndRemoveAddress() {
         proxyAddressService.addProxyAddr("10.0.0.1:8081");
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/instance/dlq/DLQControllerTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/instance/dlq/DLQControllerTest.java
index 6c23be58..2071c348 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/instance/dlq/DLQControllerTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/instance/dlq/DLQControllerTest.java
@@ -124,6 +124,18 @@ class DLQControllerTest {
                 eq("test-group"), isNull(), isNull(), eq("target-topic"));
     }
 
+    @Test
+    void resendMessagesShouldRejectNullRequestBody() throws Exception {
+        mockMvc.perform(post("/api/dlq/resend")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content("null"))
+                .andExpect(status().isBadRequest())
+                .andExpect(jsonPath("$.code").value(400))
+                .andExpect(jsonPath("$.message").value("DLQ resend request is 
required"));
+
+        verifyNoInteractions(dlqService);
+    }
+
     @Test
     void resendMessagesShouldRejectMissingGroupName() throws Exception {
         Map<String, Object> body = Map.of(
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertRuleControllerTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertRuleControllerTest.java
index d8c3aeba..057b04ba 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertRuleControllerTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertRuleControllerTest.java
@@ -91,6 +91,30 @@ class AlertRuleControllerTest {
                 .andExpect(jsonPath("$.data.name").value("High Lag"));
     }
 
+    @Test
+    void createRuleShouldRejectNullRequestBody() throws Exception {
+        mockMvc.perform(post("/api/alert-rules/create")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content("null"))
+                .andExpect(status().isBadRequest())
+                .andExpect(jsonPath("$.code").value(400))
+                .andExpect(jsonPath("$.message").value("Alert rule request is 
required"));
+
+        verifyNoInteractions(alertService);
+    }
+
+    @Test
+    void updateRuleShouldRejectNullRequestBody() throws Exception {
+        mockMvc.perform(post("/api/alert-rules/update")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content("null"))
+                .andExpect(status().isBadRequest())
+                .andExpect(jsonPath("$.code").value(400))
+                .andExpect(jsonPath("$.message").value("Alert rule request is 
required"));
+
+        verifyNoInteractions(alertService);
+    }
+
     @Test
     void toggleRuleShouldPassValidatedRequest() throws Exception {
         AlertRuleVO toggled = AlertRuleVO.builder()
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertServiceTest.java
index 3b11ad02..58209e02 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/AlertServiceTest.java
@@ -250,6 +250,16 @@ class AlertServiceTest {
         assertThat(result1.getId()).isNotEqualTo(result2.getId());
     }
 
+    @Test
+    void createRuleShouldRejectNullRequest() {
+        assertThatThrownBy(() -> alertService.createRule(null))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Alert rule request is required")
+                .satisfies(ex -> assertThat(((BusinessException) 
ex).getCode()).isEqualTo(400));
+
+        verify(alertRepository, never()).saveRule(any());
+    }
+
     @Test
     void updateRuleShouldUpdateExistingRule() {
         AlertRuleVO update = AlertRuleVO.builder().id("rule-1").name("CPU 
Alert").threshold(90.0).build();
@@ -262,6 +272,16 @@ class AlertServiceTest {
         verify(alertRepository).replaceRule(update);
     }
 
+    @Test
+    void updateRuleShouldRejectNullRequest() {
+        assertThatThrownBy(() -> alertService.updateRule(null))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Alert rule request is required")
+                .satisfies(ex -> assertThat(((BusinessException) 
ex).getCode()).isEqualTo(400));
+
+        verify(alertRepository, never()).replaceRule(any());
+    }
+
     @Test
     void updateRuleShouldRejectNullId() {
         AlertRuleVO update = AlertRuleVO.builder().name("CPU Alert").build();
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/SystemAlertControllerTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/SystemAlertControllerTest.java
index ca655a62..2bac8166 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/alert/SystemAlertControllerTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/alert/SystemAlertControllerTest.java
@@ -91,6 +91,18 @@ class SystemAlertControllerTest {
         verify(alertService).acknowledgeAlert("alert-1");
     }
 
+    @Test
+    void acknowledgeAlertShouldRejectNullRequestBody() throws Exception {
+        mockMvc.perform(post("/api/system-alerts/acknowledge")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content("null"))
+                .andExpect(status().isBadRequest())
+                .andExpect(jsonPath("$.code").value(400))
+                .andExpect(jsonPath("$.message").value("System alert 
acknowledge request is required"));
+
+        verifyNoInteractions(alertService);
+    }
+
     @Test
     void acknowledgeAlertShouldRejectBlankId() throws Exception {
         mockMvc.perform(post("/api/system-alerts/acknowledge")
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/settings/SettingsControllerTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/settings/SettingsControllerTest.java
index b6f4f7d7..e56a7495 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/settings/SettingsControllerTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/settings/SettingsControllerTest.java
@@ -222,6 +222,18 @@ class SettingsControllerTest {
         verifyNoInteractions(settingsService);
     }
 
+    @Test
+    void createDataSourceShouldRejectNullRequestBody() throws Exception {
+        mockMvc.perform(post("/api/settings/datasources/create")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content("null"))
+                .andExpect(status().isBadRequest())
+                .andExpect(jsonPath("$.code", is(400)))
+                .andExpect(jsonPath("$.message", is("Data source request is 
required")));
+
+        verifyNoInteractions(settingsService);
+    }
+
     @Test
     void updateDataSourceShouldReturnUpdatedSource() throws Exception {
         DataSourceVO input = DataSourceVO.builder().key("ds-1").name("Updated 
DS").type("rocketmq")
@@ -255,6 +267,18 @@ class SettingsControllerTest {
         verifyNoInteractions(settingsService);
     }
 
+    @Test
+    void updateDataSourceShouldRejectNullRequestBody() throws Exception {
+        mockMvc.perform(post("/api/settings/datasources/update")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content("null"))
+                .andExpect(status().isBadRequest())
+                .andExpect(jsonPath("$.code", is(400)))
+                .andExpect(jsonPath("$.message", is("Data source request is 
required")));
+
+        verifyNoInteractions(settingsService);
+    }
+
     @Test
     void deleteDataSourceShouldReturnSuccess() throws Exception {
         doNothing().when(settingsService).deleteDataSource("ds-1");
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/settings/SettingsServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/settings/SettingsServiceTest.java
index 785f3d5b..5a4de053 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/settings/SettingsServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/settings/SettingsServiceTest.java
@@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
@@ -214,6 +215,17 @@ class SettingsServiceTest {
         verify(settingsRepository).saveDataSource(input);
     }
 
+    @Test
+    void createDataSourceShouldRejectNullRequest() {
+        assertThatThrownBy(() -> settingsService.createDataSource(null))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Data source request is required")
+                .extracting("code")
+                .isEqualTo(400);
+
+        verifyNoInteractions(settingsRepository);
+    }
+
     @Test
     void updateDataSourceShouldDelegateToRepository() {
         DataSourceVO input = DataSourceVO.builder().key("ds-1").name("Updated 
DS").type("rocketmq")
@@ -227,6 +239,17 @@ class SettingsServiceTest {
         verify(settingsRepository).replaceDataSource(input);
     }
 
+    @Test
+    void updateDataSourceShouldRejectNullRequest() {
+        assertThatThrownBy(() -> settingsService.updateDataSource(null))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Data source request is required")
+                .extracting("code")
+                .isEqualTo(400);
+
+        verifyNoInteractions(settingsRepository);
+    }
+
     @Test
     void updateDataSourceShouldRejectUnknownKey() {
         SettingsService service = new SettingsService(settingsRepository, 
RestClient.builder(), new ObjectMapper(), operationAuditService);

Reply via email to