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 de05e8c198c741720c8412f9f02c9d545282614e
Author: aias00 <[email protected]>
AuthorDate: Thu Jul 23 22:51:00 2026 -0700

    feat: add LiteTopic backend endpoints (#502)
    
    Add backend stub endpoints for LiteTopic page: list, session details, TTL 
extension, quota, and capability check.
---
 .../instance/topic/LiteTopicCapabilityVO.java      |  29 +++++
 .../studio/instance/topic/LiteTopicController.java |  66 +++++++++++
 .../studio/instance/topic/LiteTopicItemVO.java     |  37 ++++++
 .../studio/instance/topic/LiteTopicQuotaVO.java    |  38 ++++++
 .../studio/instance/topic/LiteTopicService.java    | 122 ++++++++++++++++++++
 .../studio/instance/topic/LiteTopicSessionVO.java  |  55 +++++++++
 .../instance/topic/LiteTopicTTLUpdateDTO.java      |  26 +++++
 .../instance/topic/LiteTopicControllerTest.java    | 127 +++++++++++++++++++++
 .../instance/topic/LiteTopicServiceTest.java       |  66 +++++++++++
 9 files changed, 566 insertions(+)

diff --git 
a/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicCapabilityVO.java
 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicCapabilityVO.java
new file mode 100644
index 00000000..c31ba621
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicCapabilityVO.java
@@ -0,0 +1,29 @@
+/*
+ * 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.instance.topic;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LiteTopicCapabilityVO {
+    private boolean supported;
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicController.java
 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicController.java
new file mode 100644
index 00000000..b4ce5235
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicController.java
@@ -0,0 +1,66 @@
+/*
+ * 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.instance.topic;
+
+import com.rocketmq.studio.common.domain.Result;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/liteTopic")
+@RequiredArgsConstructor
+public class LiteTopicController {
+
+    private final LiteTopicService liteTopicService;
+
+    @GetMapping("/list")
+    public Result<List<LiteTopicItemVO>> listLiteTopics(
+            @RequestParam(required = false) String pattern,
+            @RequestParam(required = false) String namespace) {
+        return Result.ok(liteTopicService.listLiteTopics(pattern, namespace));
+    }
+
+    @GetMapping("/session/{sessionId}")
+    public Result<LiteTopicSessionVO> getSession(@PathVariable String 
sessionId) {
+        return Result.ok(liteTopicService.getSession(sessionId));
+    }
+
+    @PostMapping("/extendTTL")
+    public Result<Void> extendTTL(@RequestBody LiteTopicTTLUpdateDTO request) {
+        liteTopicService.extendTTL(request.getTopicPattern(), 
request.getNewTTL());
+        return Result.ok();
+    }
+
+    @GetMapping("/quota")
+    public Result<LiteTopicQuotaVO> getQuota(@RequestParam(required = false) 
String namespace) {
+        return Result.ok(liteTopicService.getQuota(namespace));
+    }
+
+    @GetMapping("/capability")
+    public Result<LiteTopicCapabilityVO> getCapability() {
+        return Result.ok(liteTopicService.getCapability());
+    }
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicItemVO.java 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicItemVO.java
new file mode 100644
index 00000000..4b156074
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicItemVO.java
@@ -0,0 +1,37 @@
+/*
+ * 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.instance.topic;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class LiteTopicItemVO {
+    private String topicPattern;
+    private String namespace;
+    private Integer topicCount;
+    private Integer consumerCount;
+    private Long totalBacklog;
+    private Long averageTTL;
+    private String ttlStatus;
+    private Long lastActiveTime;
+    private List<String> sessionIds;
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicQuotaVO.java 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicQuotaVO.java
new file mode 100644
index 00000000..976f9d8c
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicQuotaVO.java
@@ -0,0 +1,38 @@
+/*
+ * 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.instance.topic;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class LiteTopicQuotaVO {
+    private Integer currentTopicCount;
+    private Integer maxTopicCount;
+    private Integer currentSessionCount;
+    private Integer maxSessionCount;
+    private Integer currentCreationRate;
+    private Integer maxCreationRate;
+    private Double usageRate;
+    private Double sessionUsageRate;
+    private Long defaultTTL;
+    private Long maxTTL;
+    private Integer remainingQuota;
+    private Double consumerDensity;
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicService.java 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicService.java
new file mode 100644
index 00000000..4e48ff74
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicService.java
@@ -0,0 +1,122 @@
+/*
+ * 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.instance.topic;
+
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Locale;
+
+@Service
+public class LiteTopicService {
+
+    public List<LiteTopicItemVO> listLiteTopics(String pattern, String 
namespace) {
+        return sampleItems().stream()
+                .filter(item -> matches(pattern, item.getTopicPattern()))
+                .filter(item -> matches(namespace, item.getNamespace()))
+                .toList();
+    }
+
+    public LiteTopicSessionVO getSession(String sessionId) {
+        long now = System.currentTimeMillis();
+        return LiteTopicSessionVO.builder()
+                .sessionId(sessionId)
+                .clientId("grpc-client-" + sessionId)
+                .clientAddress("192.168.1.10:8081")
+                .parentTopic("chat/{sessionId}")
+                .consumerGroup("cg-chat-session")
+                .createTime(now - 3_600_000L)
+                .lastActiveTime(now - 30_000L)
+                .ttl(3_600_000L)
+                .ttlRemaining(1_800_000L)
+                .status("ACTIVE")
+                .totalMessages(5_000L)
+                .consumedMessages(4_800L)
+                .pendingMessages(200L)
+                .popProgress(96)
+                .liteTopicCreationCount(2)
+                .liteTopics(List.of(
+                        new LiteTopicSessionVO.SessionLiteTopic("chat/" + 
sessionId, "ACTIVE", 1_800_000L),
+                        new LiteTopicSessionVO.SessionLiteTopic("agent/" + 
sessionId, "ACTIVE", 1_200_000L)))
+                .build();
+    }
+
+    public void extendTTL(String topicPattern, Long newTTL) {
+        if (topicPattern == null || topicPattern.isBlank()) {
+            throw new IllegalArgumentException("topicPattern is required");
+        }
+        if (newTTL == null || newTTL <= 0) {
+            throw new IllegalArgumentException("newTTL must be positive");
+        }
+    }
+
+    public LiteTopicQuotaVO getQuota(String namespace) {
+        return LiteTopicQuotaVO.builder()
+                .currentTopicCount(128)
+                .maxTopicCount(1_000_000)
+                .currentSessionCount(32)
+                .maxSessionCount(100_000)
+                .currentCreationRate(12)
+                .maxCreationRate(1_000)
+                .usageRate(0.000128)
+                .sessionUsageRate(0.00032)
+                .defaultTTL(3_600_000L)
+                .maxTTL(86_400_000L)
+                .remainingQuota(999_872)
+                .consumerDensity(0.25)
+                .build();
+    }
+
+    public LiteTopicCapabilityVO getCapability() {
+        return new LiteTopicCapabilityVO(true);
+    }
+
+    private List<LiteTopicItemVO> sampleItems() {
+        long now = System.currentTimeMillis();
+        return List.of(
+                LiteTopicItemVO.builder()
+                        .topicPattern("chat/{sessionId}")
+                        .namespace("default")
+                        .topicCount(96)
+                        .consumerCount(12)
+                        .totalBacklog(1_200L)
+                        .averageTTL(3_600_000L)
+                        .ttlStatus("ACTIVE")
+                        .lastActiveTime(now - 60_000L)
+                        .sessionIds(List.of("sess-001", "sess-002"))
+                        .build(),
+                LiteTopicItemVO.builder()
+                        .topicPattern("agent/{sessionId}")
+                        .namespace("ai")
+                        .topicCount(32)
+                        .consumerCount(4)
+                        .totalBacklog(180L)
+                        .averageTTL(1_800_000L)
+                        .ttlStatus("EXPIRING_SOON")
+                        .lastActiveTime(now - 120_000L)
+                        .sessionIds(List.of("agent-001"))
+                        .build());
+    }
+
+    private boolean matches(String filter, String value) {
+        if (filter == null || filter.isBlank()) {
+            return true;
+        }
+        return value != null && 
value.toLowerCase(Locale.ROOT).contains(filter.toLowerCase(Locale.ROOT));
+    }
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicSessionVO.java
 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicSessionVO.java
new file mode 100644
index 00000000..ae6aa497
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicSessionVO.java
@@ -0,0 +1,55 @@
+/*
+ * 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.instance.topic;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@Builder
+public class LiteTopicSessionVO {
+    private String sessionId;
+    private String clientId;
+    private String clientAddress;
+    private String parentTopic;
+    private String consumerGroup;
+    private Long createTime;
+    private Long lastActiveTime;
+    private Long ttl;
+    private Long ttlRemaining;
+    private String status;
+    private Long totalMessages;
+    private Long consumedMessages;
+    private Long pendingMessages;
+    private Integer popProgress;
+    private Integer liteTopicCreationCount;
+    private List<SessionLiteTopic> liteTopics;
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class SessionLiteTopic {
+        private String topicName;
+        private String status;
+        private Long ttlRemaining;
+    }
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicTTLUpdateDTO.java
 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicTTLUpdateDTO.java
new file mode 100644
index 00000000..2a445d4d
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/instance/topic/LiteTopicTTLUpdateDTO.java
@@ -0,0 +1,26 @@
+/*
+ * 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.instance.topic;
+
+import lombok.Data;
+
+@Data
+public class LiteTopicTTLUpdateDTO {
+    private String topicPattern;
+    private Long newTTL;
+}
diff --git 
a/server/src/test/java/com/rocketmq/studio/instance/topic/LiteTopicControllerTest.java
 
b/server/src/test/java/com/rocketmq/studio/instance/topic/LiteTopicControllerTest.java
new file mode 100644
index 00000000..9d018193
--- /dev/null
+++ 
b/server/src/test/java/com/rocketmq/studio/instance/topic/LiteTopicControllerTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.instance.topic;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import 
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static 
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static 
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@WebMvcTest(LiteTopicController.class)
+@AutoConfigureMockMvc(addFilters = false)
+class LiteTopicControllerTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private LiteTopicService liteTopicService;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Test
+    void listLiteTopicsShouldPassFilters() throws Exception {
+        LiteTopicItemVO item = LiteTopicItemVO.builder()
+                .topicPattern("chat/{sessionId}")
+                .namespace("default")
+                .topicCount(96)
+                .build();
+
+        when(liteTopicService.listLiteTopics("chat", 
"default")).thenReturn(List.of(item));
+
+        mockMvc.perform(get("/api/liteTopic/list")
+                        .param("pattern", "chat")
+                        .param("namespace", "default"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200))
+                
.andExpect(jsonPath("$.data[0].topicPattern").value("chat/{sessionId}"));
+
+        verify(liteTopicService).listLiteTopics("chat", "default");
+    }
+
+    @Test
+    void getQuotaShouldReturnQuota() throws Exception {
+        LiteTopicQuotaVO quota = LiteTopicQuotaVO.builder()
+                .currentTopicCount(128)
+                .maxTopicCount(1_000_000)
+                .remainingQuota(999_872)
+                .build();
+
+        when(liteTopicService.getQuota("default")).thenReturn(quota);
+
+        mockMvc.perform(get("/api/liteTopic/quota").param("namespace", 
"default"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.data.currentTopicCount").value(128))
+                .andExpect(jsonPath("$.data.remainingQuota").value(999872));
+    }
+
+    @Test
+    void getCapabilityShouldReturnSupportedFlag() throws Exception {
+        when(liteTopicService.getCapability()).thenReturn(new 
LiteTopicCapabilityVO(true));
+
+        mockMvc.perform(get("/api/liteTopic/capability"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.data.supported").value(true));
+    }
+
+    @Test
+    void getSessionShouldReturnSession() throws Exception {
+        LiteTopicSessionVO session = LiteTopicSessionVO.builder()
+                .sessionId("sess-001")
+                .clientId("grpc-client-sess-001")
+                .popProgress(96)
+                .build();
+
+        when(liteTopicService.getSession("sess-001")).thenReturn(session);
+
+        mockMvc.perform(get("/api/liteTopic/session/sess-001"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.data.sessionId").value("sess-001"))
+                .andExpect(jsonPath("$.data.popProgress").value(96));
+    }
+
+    @Test
+    void extendTTLShouldDelegateToService() throws Exception {
+        LiteTopicTTLUpdateDTO request = new LiteTopicTTLUpdateDTO();
+        request.setTopicPattern("chat/{sessionId}");
+        request.setNewTTL(7_200_000L);
+
+        mockMvc.perform(post("/api/liteTopic/extendTTL")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(objectMapper.writeValueAsString(request)))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200));
+
+        verify(liteTopicService).extendTTL(eq("chat/{sessionId}"), 
eq(7_200_000L));
+    }
+}
diff --git 
a/server/src/test/java/com/rocketmq/studio/instance/topic/LiteTopicServiceTest.java
 
b/server/src/test/java/com/rocketmq/studio/instance/topic/LiteTopicServiceTest.java
new file mode 100644
index 00000000..25f5fc99
--- /dev/null
+++ 
b/server/src/test/java/com/rocketmq/studio/instance/topic/LiteTopicServiceTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.instance.topic;
+
+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;
+
+class LiteTopicServiceTest {
+
+    private final LiteTopicService liteTopicService = new LiteTopicService();
+
+    @Test
+    void listLiteTopicsShouldFilterByPatternAndNamespace() {
+        List<LiteTopicItemVO> result = liteTopicService.listLiteTopics("chat", 
"default");
+
+        assertThat(result).hasSize(1);
+        
assertThat(result.get(0).getTopicPattern()).isEqualTo("chat/{sessionId}");
+        assertThat(result.get(0).getNamespace()).isEqualTo("default");
+    }
+
+    @Test
+    void getQuotaShouldReturnDefaultLimits() {
+        LiteTopicQuotaVO quota = liteTopicService.getQuota("default");
+
+        assertThat(quota.getCurrentTopicCount()).isEqualTo(128);
+        assertThat(quota.getMaxTopicCount()).isEqualTo(1_000_000);
+        assertThat(quota.getRemainingQuota()).isEqualTo(999_872);
+    }
+
+    @Test
+    void getSessionShouldReturnRequestedSessionId() {
+        LiteTopicSessionVO session = liteTopicService.getSession("sess-001");
+
+        assertThat(session.getSessionId()).isEqualTo("sess-001");
+        
assertThat(session.getLiteTopics()).extracting("topicName").contains("chat/sess-001");
+    }
+
+    @Test
+    void extendTTLShouldRejectInvalidInput() {
+        assertThatThrownBy(() -> liteTopicService.extendTTL("", 1L))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessage("topicPattern is required");
+        assertThatThrownBy(() -> 
liteTopicService.extendTTL("chat/{sessionId}", 0L))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessage("newTTL must be positive");
+    }
+}

Reply via email to