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 f89e1a0e fix: prevent instance metadata from being orphaned (#1125)
f89e1a0e is described below
commit f89e1a0ef206ad6196b9d4b05920b79fd579f862
Author: aias00 <[email protected]>
AuthorDate: Thu Aug 6 23:47:21 2026 -0700
fix: prevent instance metadata from being orphaned (#1125)
---
.../rocketmq/studio/instance/InstanceService.java | 8 ++++-
.../studio/instance/InstanceControllerTest.java | 19 ++++++++++++
.../studio/instance/InstanceServiceTest.java | 34 ++++++++++++++++++++++
3 files changed, 60 insertions(+), 1 deletion(-)
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
index 95014da8..bb24a94a 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
@@ -204,8 +204,14 @@ public class InstanceService {
throw new BusinessException(400, "InstanceVO ID is required");
}
- instanceRepository.findById(id)
+ InstanceVO existing = instanceRepository.findById(id)
.orElseThrow(() -> new BusinessException(404, "InstanceVO not
found: " + id));
+
+ if (existing.getTopicCount() > 0 || existing.getConsumerGroupCount() >
0) {
+ throw new BusinessException(409, String.format(
+ "Cannot delete instance with managed resources: topics=%d,
consumerGroups=%d",
+ existing.getTopicCount(),
existing.getConsumerGroupCount()));
+ }
instanceRepository.deleteById(id);
}
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceControllerTest.java
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceControllerTest.java
index 8f3ff7e9..3d04b220 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceControllerTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceControllerTest.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.studio.instance;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.rocketmq.studio.common.domain.enums.InstanceType;
+import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@@ -35,6 +36,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@@ -200,6 +202,23 @@ class InstanceControllerTest {
verify(instanceService).deleteInstance("inst-1");
}
+ @Test
+ void deleteInstanceShouldReturnConflictWhenManagedResourcesExist() throws
Exception {
+ doThrow(new BusinessException(409,
+ "Cannot delete instance with managed resources: topics=2,
consumerGroups=1"))
+ .when(instanceService).deleteInstance("inst-1");
+
+ mockMvc.perform(post("/api/instances/delete")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(Map.of("id",
"inst-1"))))
+ .andExpect(status().isConflict())
+ .andExpect(jsonPath("$.code").value(409))
+ .andExpect(jsonPath("$.message")
+ .value("Cannot delete instance with managed resources:
topics=2, consumerGroups=1"));
+
+ verify(instanceService).deleteInstance("inst-1");
+ }
+
@Test
void deleteInstanceShouldRejectBlankId() throws Exception {
mockMvc.perform(post("/api/instances/delete")
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
index b998643e..afc67482 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
@@ -457,6 +457,40 @@ class InstanceServiceTest {
verify(instanceRepository).deleteById("inst-1");
}
+ @Test
+ void deleteInstanceShouldRejectInstanceWithTopics() {
+ InstanceVO existing = InstanceVO.builder()
+ .name("with-topics")
+ .topicCount(2)
+ .build();
+ existing.setId("inst-1");
+
when(instanceRepository.findById("inst-1")).thenReturn(Optional.of(existing));
+
+ assertThatThrownBy(() -> instanceService.deleteInstance("inst-1"))
+ .isInstanceOf(BusinessException.class)
+ .hasMessage("Cannot delete instance with managed resources:
topics=2, consumerGroups=0")
+ .satisfies(ex -> assertThat(((BusinessException)
ex).getCode()).isEqualTo(409));
+
+ verify(instanceRepository, never()).deleteById("inst-1");
+ }
+
+ @Test
+ void deleteInstanceShouldRejectInstanceWithConsumerGroups() {
+ InstanceVO existing = InstanceVO.builder()
+ .name("with-consumer-groups")
+ .consumerGroupCount(3)
+ .build();
+ existing.setId("inst-1");
+
when(instanceRepository.findById("inst-1")).thenReturn(Optional.of(existing));
+
+ assertThatThrownBy(() -> instanceService.deleteInstance("inst-1"))
+ .isInstanceOf(BusinessException.class)
+ .hasMessage("Cannot delete instance with managed resources:
topics=0, consumerGroups=3")
+ .satisfies(ex -> assertThat(((BusinessException)
ex).getCode()).isEqualTo(409));
+
+ verify(instanceRepository, never()).deleteById("inst-1");
+ }
+
@Test
void deleteInstanceShouldThrowWhenIdIsNull() {
assertThatThrownBy(() -> instanceService.deleteInstance(null))