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 fd2fa6c3f fix(settings): consolidate persistence and LLM consistency 
(#2963)
fd2fa6c3f is described below

commit fd2fa6c3f17ce69db27378f12b6b37acd271e059
Author: aias00 <[email protected]>
AuthorDate: Wed Sep 2 15:10:42 2026 +0800

    fix(settings): consolidate persistence and LLM consistency (#2963)
    
    General settings are a singleton configuration surface, but concurrent 
first writes could create competing rows and partial Settings saves could drop 
LLM-only fields. Persist settings behind an explicit business key, recover 
concurrent singleton creation, and remove the in-memory LLM override path so 
reads always reflect persisted state.
    
    Constraint: preserve current WRITE_ONLY API key behavior while allowing 
explicit blank persistence for key clearing.
    
    Rejected: keep runtime LLM overrides | it keeps process memory and database 
state divergent after General Settings saves.
    
    Tested: JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn 
-Dtest=MybatisPlusSettingsRepositoryTest,LlmConfigServiceTest,SettingsServiceTest,SettingsControllerTest,DemoDataSqlCompatibilityTest
 test
    
    Tested: JAVA_HOME=$(/usr/libexec/java_home -v 21) mvn -DskipTests package
    
    Scope-risk: moderate
    
    Confidence: high
    
    Signed-off-by: liuhy <[email protected]>
---
 deploy/mysql/upgrade-settings-singleton-key.sql    | 42 +++++++++++++++++++
 .../rocketmq/studio/ops/ai/LlmConfigService.java   | 11 +----
 .../persistence/MybatisPlusSettingsRepository.java | 29 ++++++++-----
 .../studio/persistence/entity/RmqSettings.java     |  2 +
 .../rocketmq/studio/settings/SettingsService.java  |  9 ++++
 server/src/main/resources/db/schema.sql            |  4 +-
 .../studio/ops/ai/LlmConfigServiceTest.java        | 48 ++++++++++++++++++++++
 .../persistence/DemoDataSqlCompatibilityTest.java  | 18 ++++++++
 .../MybatisPlusSettingsRepositoryTest.java         | 36 ++++++++++++++++
 .../studio/settings/SettingsServiceTest.java       |  6 +++
 10 files changed, 184 insertions(+), 21 deletions(-)

diff --git a/deploy/mysql/upgrade-settings-singleton-key.sql 
b/deploy/mysql/upgrade-settings-singleton-key.sql
new file mode 100644
index 000000000..4cbe50d7e
--- /dev/null
+++ b/deploy/mysql/upgrade-settings-singleton-key.sql
@@ -0,0 +1,42 @@
+-- deploy/mysql/upgrade-settings-singleton-key.sql
+-- Existing MySQL volumes: enforce the rmq_settings singleton invariant.
+-- Fresh volumes receive settings_key and uk_settings_key from schema.sql.
+--
+-- This migration preserves the row the application historically selected (the 
lowest id)
+-- and removes any additional rows that violate the singleton invariant. Back 
up first.
+--
+-- Run once on existing deployments:
+--   docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq < 
upgrade-settings-singleton-key.sql
+
+SET NAMES utf8mb4;
+
+SET @column_exists := (
+  SELECT COUNT(*) FROM information_schema.columns
+   WHERE table_schema = DATABASE()
+     AND table_name = 'rmq_settings'
+     AND column_name = 'settings_key'
+);
+SET @column_sql := IF(@column_exists = 0,
+    'ALTER TABLE rmq_settings ADD COLUMN settings_key VARCHAR(32) NOT NULL 
DEFAULT ''general'' COMMENT ''Settings singleton business key'' AFTER 
gmt_modified',
+    'SELECT ''settings_key already exists'' AS msg');
+PREPARE stmt FROM @column_sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+DELETE duplicate_settings FROM rmq_settings duplicate_settings
+JOIN rmq_settings retained_settings
+  ON duplicate_settings.settings_key = retained_settings.settings_key
+ AND duplicate_settings.id > retained_settings.id;
+
+SET @index_exists := (
+  SELECT COUNT(*) FROM information_schema.statistics
+   WHERE table_schema = DATABASE()
+     AND table_name = 'rmq_settings'
+     AND index_name = 'uk_settings_key'
+);
+SET @index_sql := IF(@index_exists = 0,
+    'ALTER TABLE rmq_settings ADD UNIQUE KEY uk_settings_key (settings_key)',
+    'SELECT ''uk_settings_key already exists'' AS msg');
+PREPARE stmt FROM @index_sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
index ee76bfefc..9266e09de 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
@@ -90,12 +90,9 @@ public class LlmConfigService {
     private final OpenAiCompatibleLlmClient llmClient;
     private final AgentProviderRegistry agentProviders;
     private final LlmProperties llmProperties;
-    private LlmConfigVO overrides;
 
     public synchronized LlmConfigVO getConfig() {
-        LlmConfigVO config = overrides != null
-                ? copy(overrides)
-                : fromGeneralSettings(settingsService.getGeneralSettings());
+        LlmConfigVO config = 
fromGeneralSettings(settingsService.getGeneralSettings());
         String token = envToken();
         if (StringUtils.hasText(token)) {
             config.setApiKey(token.trim());
@@ -133,9 +130,7 @@ public class LlmConfigService {
                 .maxTokens(normalized.getMaxTokens())
                 .temperature(normalized.getTemperature())
                 .build();
-        LlmConfigVO nextOverrides = copy(normalized);
         settingsService.saveGeneralSettings(updated);
-        overrides = nextOverrides;
     }
 
     public LlmOperationResultVO testConfig(LlmConfigVO config) {
@@ -297,10 +292,6 @@ public class LlmConfigService {
                 .build();
     }
 
-    private LlmConfigVO copy(LlmConfigVO config) {
-        return normalize(config);
-    }
-
     private LlmConfigVO normalizeWithStoredApiKey(LlmConfigVO config) {
         LlmConfigVO normalized = normalize(config);
         if (normalized.isClearApiKey()) {
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/persistence/MybatisPlusSettingsRepository.java
 
b/server/src/main/java/org/apache/rocketmq/studio/persistence/MybatisPlusSettingsRepository.java
index 74b7ff502..9338b16c9 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/persistence/MybatisPlusSettingsRepository.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/persistence/MybatisPlusSettingsRepository.java
@@ -30,6 +30,7 @@ import org.apache.rocketmq.studio.common.domain.PageResult;
 import org.apache.rocketmq.studio.settings.DataSourceVO;
 import org.apache.rocketmq.studio.settings.GeneralSettingsVO;
 import org.apache.rocketmq.studio.settings.SettingsRepository;
+import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -42,6 +43,8 @@ import java.util.stream.Collectors;
 @Repository
 public class MybatisPlusSettingsRepository implements SettingsRepository {
 
+    private static final String GENERAL_SETTINGS_KEY = "general";
+
     private final RmqSettingsMapper settingsMapper;
     private final RmqDataSourceMapper dataSourceMapper;
     private final ObjectMapper objectMapper;
@@ -54,12 +57,9 @@ public class MybatisPlusSettingsRepository implements 
SettingsRepository {
         this.objectMapper = objectMapper;
     }
 
-    /**
-     * The settings table holds a single row; load it regardless of its 
auto-increment id.
-     */
     private RmqSettings findSingletonSettings() {
         return settingsMapper.selectOne(new QueryWrapper<RmqSettings>()
-                .orderByAsc("id")
+                .eq("settings_key", GENERAL_SETTINGS_KEY)
                 .last("LIMIT 1"));
     }
 
@@ -98,11 +98,9 @@ public class MybatisPlusSettingsRepository implements 
SettingsRepository {
         try {
             com.fasterxml.jackson.databind.node.ObjectNode node =
                     (com.fasterxml.jackson.databind.node.ObjectNode) 
objectMapper.valueToTree(settings);
-            if 
(org.springframework.util.StringUtils.hasText(settings.getApiKey())) {
-                // apiKey is WRITE_ONLY (hidden from API responses), so plain 
serialization
-                // drops it; re-add it here or the configured LLM token is 
lost on restart.
-                node.put("apiKey", settings.getApiKey());
-            }
+            // apiKey is WRITE_ONLY (hidden from API responses), but it must 
be serialized even
+            // when blank so the LLM configuration endpoint can explicitly 
clear a stored key.
+            node.put("apiKey", settings.getApiKey() == null ? "" : 
settings.getApiKey());
             if 
(org.springframework.util.StringUtils.hasText(settings.getDingtalkSigningSecret()))
 {
                 // The signing secret is also WRITE_ONLY and must be retained 
in persisted settings.
                 node.put("dingtalkSigningSecret", 
settings.getDingtalkSigningSecret());
@@ -111,10 +109,21 @@ public class MybatisPlusSettingsRepository implements 
SettingsRepository {
             RmqSettings entity = findSingletonSettings();
             if (entity == null) {
                 entity = new RmqSettings();
+                entity.setSettingsKey(GENERAL_SETTINGS_KEY);
                 entity.setJson(json);
                 entity.setGmtCreate(LocalDateTime.now());
                 entity.setGmtModified(LocalDateTime.now());
-                settingsMapper.insert(entity);
+                try {
+                    settingsMapper.insert(entity);
+                } catch (DuplicateKeyException duplicateKey) {
+                    RmqSettings concurrent = findSingletonSettings();
+                    if (concurrent == null) {
+                        throw duplicateKey;
+                    }
+                    concurrent.setJson(json);
+                    concurrent.setGmtModified(LocalDateTime.now());
+                    settingsMapper.updateById(concurrent);
+                }
             } else {
                 entity.setJson(json);
                 entity.setGmtModified(LocalDateTime.now());
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/persistence/entity/RmqSettings.java
 
b/server/src/main/java/org/apache/rocketmq/studio/persistence/entity/RmqSettings.java
index 8d17be91d..3617a5bc1 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/persistence/entity/RmqSettings.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/persistence/entity/RmqSettings.java
@@ -31,6 +31,8 @@ public class RmqSettings {
     @TableId(type = IdType.AUTO)
     private Long id;
 
+    private String settingsKey;
+
     @ToString.Exclude
     private String json;
 
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 807408dfa..4b9177c50 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
@@ -138,6 +138,9 @@ public class SettingsService {
             
settings.setDingtalkSigningSecret(currentSettings.getDingtalkSigningSecret());
         }
         if (currentSettings != null) {
+            if (!StringUtils.hasText(settings.getLlmEngine())) {
+                settings.setLlmEngine(currentSettings.getLlmEngine());
+            }
             if (!StringUtils.hasText(settings.getDeploymentName())) {
                 
settings.setDeploymentName(currentSettings.getDeploymentName());
             }
@@ -147,6 +150,12 @@ public class SettingsService {
             if (!StringUtils.hasText(settings.getAwsRegion())) {
                 settings.setAwsRegion(currentSettings.getAwsRegion());
             }
+            if (settings.getMaxTokens() == null) {
+                settings.setMaxTokens(currentSettings.getMaxTokens());
+            }
+            if (settings.getTemperature() == null) {
+                settings.setTemperature(currentSettings.getTemperature());
+            }
         }
         settings.setClearApiKey(false);
         settings.setClearDingtalkSigningSecret(false);
diff --git a/server/src/main/resources/db/schema.sql 
b/server/src/main/resources/db/schema.sql
index 4cd62aa9c..7c3fbb30d 100644
--- a/server/src/main/resources/db/schema.sql
+++ b/server/src/main/resources/db/schema.sql
@@ -193,8 +193,10 @@ CREATE TABLE IF NOT EXISTS rmq_settings (
   `id`           bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
   `gmt_create`   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP COMMENT '修改时间',
+  settings_key VARCHAR(32) NOT NULL DEFAULT 'general' COMMENT '设置单例业务键',
   json TEXT NOT NULL COMMENT 'GeneralSettingsVO JSON',
-  PRIMARY KEY (`id`)
+  PRIMARY KEY (`id`),
+  UNIQUE KEY uk_settings_key (settings_key)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
 -- 10. 数据源配置
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmConfigServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmConfigServiceTest.java
index d30d3ca51..a927c1516 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmConfigServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmConfigServiceTest.java
@@ -29,10 +29,12 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 
 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.doAnswer;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -187,6 +189,7 @@ class LlmConfigServiceTest {
         
assertThat(saved.getBaseUrl()).isEqualTo("https://api.deepseek.com/v1";);
         assertThat(saved.getMaxTokens()).isEqualTo(8192);
         assertThat(saved.getTemperature()).isEqualTo(0.2);
+        when(settingsService.getGeneralSettings()).thenReturn(saved);
         
assertThat(llmConfigService.getConfig().getProvider()).isEqualTo("deepseek");
         
assertThat(llmConfigService.getConfig().getMaxTokens()).isEqualTo(8192);
         
assertThat(llmConfigService.getConfig().getTemperature()).isEqualTo(0.2);
@@ -242,6 +245,36 @@ class LlmConfigServiceTest {
         
assertThat(llmConfigService.getConfig().getModel()).isEqualTo("gpt-4o");
     }
 
+    @Test
+    void getConfigShouldReflectGeneralSettingsSavedAfterLlmConfigurationTest() 
{
+        llmConfigService.saveConfig(LlmConfigVO.builder()
+                .provider("deepseek")
+                .apiKey("sk-deepseek")
+                .apiBase("https://api.deepseek.com/v1";)
+                .model("deepseek-chat")
+                .maxTokens(8192)
+                .temperature(0.2)
+                .enabled(true)
+                .build());
+        
when(settingsService.getGeneralSettings()).thenReturn(GeneralSettingsVO.builder()
+                .llmProvider("ollama")
+                .llmEngine("http")
+                .apiKey("")
+                .model("llama3")
+                .baseUrl("http://localhost:11434/v1";)
+                .maxTokens(4096)
+                .temperature(0.7)
+                .build());
+
+        LlmConfigVO config = llmConfigService.getConfig();
+
+        assertThat(config.getProvider()).isEqualTo("ollama");
+        assertThat(config.getEngine()).isEqualTo("http");
+        assertThat(config.getModel()).isEqualTo("llama3");
+        assertThat(config.getMaxTokens()).isEqualTo(4096);
+        assertThat(config.getTemperature()).isEqualTo(0.7);
+    }
+
     @Test
     void saveConfigShouldPreserveStoredApiKeyWhenApiKeyIsOmitted() {
         LlmConfigVO config = LlmConfigVO.builder()
@@ -275,6 +308,7 @@ class LlmConfigServiceTest {
         ArgumentCaptor<GeneralSettingsVO> captor = 
ArgumentCaptor.forClass(GeneralSettingsVO.class);
         verify(settingsService).saveGeneralSettings(captor.capture());
         assertThat(captor.getValue().getApiKey()).isBlank();
+        
when(settingsService.getGeneralSettings()).thenReturn(captor.getValue());
         assertThat(llmConfigService.getConfig().getApiKey()).isBlank();
         
assertThat(llmConfigService.getConfig().isApiKeyConfigured()).isFalse();
     }
@@ -550,6 +584,13 @@ class LlmConfigServiceTest {
 
     @Test
     void listModelsShouldUseSavedProvider() {
+        AtomicReference<GeneralSettingsVO> persisted = new 
AtomicReference<>(settingsService.getGeneralSettings());
+        when(settingsService.getGeneralSettings()).thenAnswer(invocation -> 
persisted.get());
+        doAnswer(invocation -> {
+            persisted.set(invocation.getArgument(0));
+            return null;
+        
}).when(settingsService).saveGeneralSettings(any(GeneralSettingsVO.class));
+
         llmConfigService.saveConfig(LlmConfigVO.builder()
                 .provider("tongyi")
                 .apiKey("dashscope-key")
@@ -599,6 +640,13 @@ class LlmConfigServiceTest {
 
     @Test
     void listModelsShouldNotBlockConcurrentConfigReadsOrWrites() throws 
Exception {
+        AtomicReference<GeneralSettingsVO> persisted = new 
AtomicReference<>(settingsService.getGeneralSettings());
+        when(settingsService.getGeneralSettings()).thenAnswer(invocation -> 
persisted.get());
+        doAnswer(invocation -> {
+            persisted.set(invocation.getArgument(0));
+            return null;
+        
}).when(settingsService).saveGeneralSettings(any(GeneralSettingsVO.class));
+
         CountDownLatch listingStarted = new CountDownLatch(1);
         CountDownLatch releaseListing = new CountDownLatch(1);
         when(llmClient.supports(any())).thenReturn(true);
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/persistence/DemoDataSqlCompatibilityTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/persistence/DemoDataSqlCompatibilityTest.java
index 293024751..d70a307e0 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/persistence/DemoDataSqlCompatibilityTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/persistence/DemoDataSqlCompatibilityTest.java
@@ -32,6 +32,7 @@ import java.sql.SQLException;
 import java.sql.Statement;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 class DemoDataSqlCompatibilityTest {
 
@@ -85,6 +86,23 @@ class DemoDataSqlCompatibilityTest {
         }
     }
 
+    @Test
+    void schemaShouldEnforceSingletonSettingsKeyTest() throws Exception {
+        try (Connection connection = DriverManager.getConnection(
+                
"jdbc:h2:mem:settings-schema-sql;MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1",
 "sa", "")) {
+            ScriptUtils.executeSqlScript(connection, new 
ClassPathResource("db/schema.sql"));
+
+            try (Statement statement = connection.createStatement()) {
+                statement.executeUpdate("INSERT INTO rmq_settings (json) 
VALUES ('{}')");
+
+                assertThatThrownBy(() -> statement.executeUpdate("INSERT INTO 
rmq_settings (json) VALUES ('{}')"))
+                        .isInstanceOf(SQLException.class);
+            }
+
+            assertThat(hasColumn(connection, "rmq_settings", 
"settings_key")).isTrue();
+        }
+    }
+
     private static void executeDeployScript(Connection connection, String 
filename) throws IOException {
         String script = Files.readString(resolveDeployScript(filename), 
StandardCharsets.UTF_8)
                 .replace("SET NAMES utf8mb4;", "");
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/persistence/MybatisPlusSettingsRepositoryTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/persistence/MybatisPlusSettingsRepositoryTest.java
index 1a1ad1d57..eac09c5b9 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/persistence/MybatisPlusSettingsRepositoryTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/persistence/MybatisPlusSettingsRepositoryTest.java
@@ -16,11 +16,16 @@ import org.apache.rocketmq.studio.settings.DataSourceVO;
 import org.apache.rocketmq.studio.settings.GeneralSettingsVO;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.springframework.dao.DuplicateKeyException;
 
 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.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 class MybatisPlusSettingsRepositoryTest {
@@ -85,6 +90,37 @@ class MybatisPlusSettingsRepositoryTest {
         assertThat(loaded.isRequireLogin()).isTrue();
     }
 
+    @Test
+    void shouldUpdateSingletonSettingsWhenConcurrentCreationWinsTest() {
+        RmqSettings concurrent = new RmqSettings();
+        concurrent.setId(7L);
+        concurrent.setSettingsKey("general");
+        when(settingsMapper.selectOne(any())).thenReturn(null, concurrent);
+        doThrow(new DuplicateKeyException("uk_settings_key"))
+                .when(settingsMapper).insert(any(RmqSettings.class));
+
+        
repository.saveGeneralSettings(GeneralSettingsVO.builder().theme("dark").build());
+
+        verify(settingsMapper).insert(argThat((RmqSettings entity) -> 
"general".equals(entity.getSettingsKey())));
+        verify(settingsMapper).updateById(argThat((RmqSettings entity) -> 
entity == concurrent
+                && entity.getJson().contains("\"theme\":\"dark\"")));
+    }
+
+    @Test
+    void shouldPersistBlankApiKeyForExplicitLlmClearTest() throws Exception {
+        when(settingsMapper.selectOne(any())).thenReturn(null);
+
+        repository.saveGeneralSettings(GeneralSettingsVO.builder()
+                .theme("dark")
+                .apiKey("")
+                .build());
+
+        ArgumentCaptor<RmqSettings> captor = 
ArgumentCaptor.forClass(RmqSettings.class);
+        verify(settingsMapper).insert(captor.capture());
+        GeneralSettingsVO persisted = new 
ObjectMapper().readValue(captor.getValue().getJson(), GeneralSettingsVO.class);
+        assertThat(persisted.getApiKey()).isEmpty();
+    }
+
     @Test
     void shouldRejectNullPersistedDataSource() {
         RmqDataSource dataSource = new RmqDataSource();
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 521ebf168..60fd940e2 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
@@ -165,6 +165,9 @@ class SettingsServiceTest {
                 .deploymentName("production-gpt")
                 .apiVersion("2024-06-01")
                 .awsRegion("eu-west-1")
+                .llmEngine("http")
+                .maxTokens(8192)
+                .temperature(0.2)
                 .build();
         GeneralSettingsVO update = GeneralSettingsVO.builder()
                 .theme("light")
@@ -176,6 +179,9 @@ class SettingsServiceTest {
         assertThat(update.getDeploymentName()).isEqualTo("production-gpt");
         assertThat(update.getApiVersion()).isEqualTo("2024-06-01");
         assertThat(update.getAwsRegion()).isEqualTo("eu-west-1");
+        assertThat(update.getLlmEngine()).isEqualTo("http");
+        assertThat(update.getMaxTokens()).isEqualTo(8192);
+        assertThat(update.getTemperature()).isEqualTo(0.2);
     }
 
     @Test

Reply via email to