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

yx9o 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 34c8a204 fix: reject updates for missing data sources
34c8a204 is described below

commit 34c8a204b1d317b407330746bdf3f6e3515dcd40
Author: yx9o <[email protected]>
AuthorDate: Sat Jul 25 15:29:10 2026 +0800

    fix: reject updates for missing data sources
---
 .../settings/InMemorySettingsRepository.java       |  5 ++++
 .../studio/settings/SettingsRepository.java        |  2 ++
 .../rocketmq/studio/settings/SettingsService.java  |  6 +++-
 .../settings/InMemorySettingsRepositoryTest.java   | 32 ++++++++++++++++------
 .../studio/settings/SettingsServiceTest.java       | 20 ++++++++++++--
 5 files changed, 53 insertions(+), 12 deletions(-)

diff --git 
a/server/src/main/java/com/rocketmq/studio/settings/InMemorySettingsRepository.java
 
b/server/src/main/java/com/rocketmq/studio/settings/InMemorySettingsRepository.java
index d3c01e43..82cd03c2 100644
--- 
a/server/src/main/java/com/rocketmq/studio/settings/InMemorySettingsRepository.java
+++ 
b/server/src/main/java/com/rocketmq/studio/settings/InMemorySettingsRepository.java
@@ -65,6 +65,11 @@ public class InMemorySettingsRepository implements 
SettingsRepository {
         return dataSource;
     }
 
+    @Override
+    public boolean replaceDataSource(DataSourceVO dataSource) {
+        return dataSources.replace(dataSource.getKey(), dataSource) != null;
+    }
+
     @Override
     public void deleteDataSource(String key) {
         dataSources.remove(key);
diff --git 
a/server/src/main/java/com/rocketmq/studio/settings/SettingsRepository.java 
b/server/src/main/java/com/rocketmq/studio/settings/SettingsRepository.java
index 70e08a71..49b3e8ee 100644
--- a/server/src/main/java/com/rocketmq/studio/settings/SettingsRepository.java
+++ b/server/src/main/java/com/rocketmq/studio/settings/SettingsRepository.java
@@ -30,6 +30,8 @@ public interface SettingsRepository {
 
     DataSourceVO saveDataSource(DataSourceVO dataSource);
 
+    boolean replaceDataSource(DataSourceVO dataSource);
+
     void deleteDataSource(String key);
 
     Optional<DataSourceVO> findDataSourceByKey(String key);
diff --git 
a/server/src/main/java/com/rocketmq/studio/settings/SettingsService.java 
b/server/src/main/java/com/rocketmq/studio/settings/SettingsService.java
index 2c2db875..3dce8aff 100644
--- a/server/src/main/java/com/rocketmq/studio/settings/SettingsService.java
+++ b/server/src/main/java/com/rocketmq/studio/settings/SettingsService.java
@@ -16,6 +16,7 @@
  */
 package com.rocketmq.studio.settings;
 
+import com.rocketmq.studio.common.exception.BusinessException;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -66,7 +67,10 @@ public class SettingsService {
 
     public DataSourceVO updateDataSource(DataSourceVO dataSource) {
         log.info("Updating data source: {}", dataSource.getKey());
-        return settingsRepository.saveDataSource(dataSource);
+        if (!settingsRepository.replaceDataSource(dataSource)) {
+            throw new BusinessException(404, "Data source not found: " + 
dataSource.getKey());
+        }
+        return dataSource;
     }
 
 
diff --git 
a/server/src/test/java/com/rocketmq/studio/settings/InMemorySettingsRepositoryTest.java
 
b/server/src/test/java/com/rocketmq/studio/settings/InMemorySettingsRepositoryTest.java
index d1d06f60..c811eff7 100644
--- 
a/server/src/test/java/com/rocketmq/studio/settings/InMemorySettingsRepositoryTest.java
+++ 
b/server/src/test/java/com/rocketmq/studio/settings/InMemorySettingsRepositoryTest.java
@@ -25,7 +25,7 @@ class InMemorySettingsRepositoryTest {
     private final InMemorySettingsRepository repository = new 
InMemorySettingsRepository();
 
     @Test
-    void saveDataSourceShouldSupportCreateUpdateAndDeleteByKey() {
+    void saveDataSourceShouldSupportCreateAndDeleteByKey() {
         DataSourceVO dataSource = DataSourceVO.builder()
                 .key("source-1")
                 .name("Prometheus")
@@ -38,17 +38,31 @@ class InMemorySettingsRepositoryTest {
         
assertThat(repository.findDataSourceByKey("source-1")).containsSame(dataSource);
         
assertThat(repository.findAllDataSources()).containsExactly(dataSource);
 
-        dataSource.setName("Updated Prometheus");
-        repository.saveDataSource(dataSource);
-
-        assertThat(repository.findDataSourceByKey("source-1"))
-                .get()
-                .extracting(DataSourceVO::getName)
-                .isEqualTo("Updated Prometheus");
-
         repository.deleteDataSource("source-1");
 
         assertThat(repository.findDataSourceByKey("source-1")).isEmpty();
         assertThat(repository.findAllDataSources()).isEmpty();
     }
+
+    @Test
+    void replaceDataSourceShouldUpdateExistingEntry() {
+        DataSourceVO existing = 
DataSourceVO.builder().key("source-1").name("Prometheus").build();
+        DataSourceVO replacement = 
DataSourceVO.builder().key("source-1").name("Updated Prometheus").build();
+        repository.saveDataSource(existing);
+
+        boolean replaced = repository.replaceDataSource(replacement);
+
+        assertThat(replaced).isTrue();
+        
assertThat(repository.findAllDataSources()).containsExactly(replacement);
+    }
+
+    @Test
+    void replaceDataSourceShouldNotInsertUnknownEntry() {
+        DataSourceVO replacement = 
DataSourceVO.builder().key("missing").name("Unexpected DS").build();
+
+        boolean replaced = repository.replaceDataSource(replacement);
+
+        assertThat(replaced).isFalse();
+        assertThat(repository.findAllDataSources()).isEmpty();
+    }
 }
diff --git 
a/server/src/test/java/com/rocketmq/studio/settings/SettingsServiceTest.java 
b/server/src/test/java/com/rocketmq/studio/settings/SettingsServiceTest.java
index 024a9a75..af2d8de8 100644
--- a/server/src/test/java/com/rocketmq/studio/settings/SettingsServiceTest.java
+++ b/server/src/test/java/com/rocketmq/studio/settings/SettingsServiceTest.java
@@ -16,6 +16,7 @@
  */
 package com.rocketmq.studio.settings;
 
+import com.rocketmq.studio.common.exception.BusinessException;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
@@ -27,6 +28,7 @@ import java.util.Collections;
 import java.util.List;
 
 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.doNothing;
 import static org.mockito.Mockito.verify;
@@ -188,13 +190,27 @@ class SettingsServiceTest {
     void updateDataSourceShouldDelegateToRepository() {
         DataSourceVO input = DataSourceVO.builder().key("ds-1").name("Updated 
DS").type("rocketmq")
                 .url("updated-host:9876").build();
-        
when(settingsRepository.saveDataSource(any(DataSourceVO.class))).thenReturn(input);
+        when(settingsRepository.replaceDataSource(input)).thenReturn(true);
 
         DataSourceVO result = settingsService.updateDataSource(input);
 
         assertThat(result.getKey()).isEqualTo("ds-1");
         assertThat(result.getName()).isEqualTo("Updated DS");
-        verify(settingsRepository).saveDataSource(input);
+        verify(settingsRepository).replaceDataSource(input);
+    }
+
+    @Test
+    void updateDataSourceShouldRejectUnknownKey() {
+        SettingsService service = new SettingsService(new 
InMemorySettingsRepository());
+        DataSourceVO input = 
DataSourceVO.builder().key("missing").name("Unexpected DS").type("rocketmq")
+                .url("unexpected-host:9876").build();
+
+        assertThatThrownBy(() -> service.updateDataSource(input))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Data source not found: missing")
+                .extracting("code")
+                .isEqualTo(404);
+        assertThat(service.listDataSources()).isEmpty();
     }
 
     @Test

Reply via email to