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
commit 6c03e140dc4fd38ccfc4253b45fbe38a4543f64a Author: wizcraft_kris <[email protected]> AuthorDate: Fri Jul 24 13:43:09 2026 +0800 fix: generate data source keys on creation (#509) Fix ConcurrentHashMap NPE when creating data sources with null key by auto-generating UUID in service layer. --- .../rocketmq/studio/settings/SettingsService.java | 2 + .../settings/InMemorySettingsRepositoryTest.java | 54 ++++++++++++++++++++++ .../studio/settings/SettingsServiceTest.java | 22 ++++++--- 3 files changed, 72 insertions(+), 6 deletions(-) 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 1f128769..5505d27f 100644 --- a/server/src/main/java/com/rocketmq/studio/settings/SettingsService.java +++ b/server/src/main/java/com/rocketmq/studio/settings/SettingsService.java @@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.List; +import java.util.UUID; @Slf4j @Service @@ -50,6 +51,7 @@ public class SettingsService { public DataSourceVO createDataSource(DataSourceVO dataSource) { log.info("Creating data source: {}", dataSource.getName()); + dataSource.setKey(UUID.randomUUID().toString()); return settingsRepository.saveDataSource(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 new file mode 100644 index 00000000..d1d06f60 --- /dev/null +++ b/server/src/test/java/com/rocketmq/studio/settings/InMemorySettingsRepositoryTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rocketmq.studio.settings; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class InMemorySettingsRepositoryTest { + + private final InMemorySettingsRepository repository = new InMemorySettingsRepository(); + + @Test + void saveDataSourceShouldSupportCreateUpdateAndDeleteByKey() { + DataSourceVO dataSource = DataSourceVO.builder() + .key("source-1") + .name("Prometheus") + .type("Prometheus") + .url("http://localhost:9090") + .build(); + + repository.saveDataSource(dataSource); + + 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(); + } +} 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 331197e3..430021af 100644 --- a/server/src/test/java/com/rocketmq/studio/settings/SettingsServiceTest.java +++ b/server/src/test/java/com/rocketmq/studio/settings/SettingsServiceTest.java @@ -108,18 +108,28 @@ class SettingsServiceTest { } @Test - void createDataSourceShouldDelegateToRepository() { + void createDataSourceShouldAssignKeyBeforeSaving() { DataSourceVO input = DataSourceVO.builder().name("New DS").type("rocketmq") .url("new-host:9876").build(); - DataSourceVO saved = DataSourceVO.builder().key("ds-new").name("New DS").type("rocketmq") - .url("new-host:9876").status("connected").build(); - when(settingsRepository.saveDataSource(any(DataSourceVO.class))).thenReturn(saved); + when(settingsRepository.saveDataSource(any(DataSourceVO.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); DataSourceVO result = settingsService.createDataSource(input); - assertThat(result.getKey()).isEqualTo("ds-new"); + assertThat(result.getKey()).isNotBlank(); assertThat(result.getName()).isEqualTo("New DS"); - assertThat(result.getStatus()).isEqualTo("connected"); + verify(settingsRepository).saveDataSource(input); + } + + @Test + void createDataSourceShouldReplaceClientProvidedKey() { + DataSourceVO input = DataSourceVO.builder().key("existing-key").name("New DS").build(); + when(settingsRepository.saveDataSource(any(DataSourceVO.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + DataSourceVO result = settingsService.createDataSource(input); + + assertThat(result.getKey()).isNotBlank().isNotEqualTo("existing-key"); verify(settingsRepository).saveDataSource(input); }
