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 c3b2300e fix: validate cluster operation requests (#633)
c3b2300e is described below
commit c3b2300e5146926e5983a7380d6c382e466332d3
Author: aias00 <[email protected]>
AuthorDate: Tue Jul 28 07:07:11 2026 -0700
fix: validate cluster operation requests (#633)
---
.../studio/cluster/broker/ClusterController.java | 3 +-
.../studio/cluster/config/UpdateConfigDTO.java | 3 +
.../cluster/nameserver/CreateNameServerDTO.java | 5 +
.../cluster/nameserver/DeleteNameServerDTO.java | 4 +
.../cluster/nameserver/NameServerController.java | 11 +-
.../cluster/nameserver/RestartNameServerDTO.java | 4 +
.../cluster/nameserver/UpdateNameServerDTO.java | 5 +
.../cluster/nameserver/UpgradeNameServerDTO.java | 6 +
.../studio/cluster/proxy/ProxyController.java | 3 +-
.../studio/cluster/proxy/RestartProxyDTO.java | 4 +
.../nameserver/NameServerControllerTest.java | 159 +++++++++++++++++++++
.../cluster/broker/ClusterControllerTest.java | 35 +++++
.../studio/cluster/proxy/ProxyControllerTest.java | 100 +++++++++++++
13 files changed, 335 insertions(+), 7 deletions(-)
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/ClusterController.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/ClusterController.java
index c3b68403..1cd53c2c 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/ClusterController.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/ClusterController.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.studio.cluster.broker;
import org.apache.rocketmq.studio.cluster.config.UpdateConfigDTO;
import org.apache.rocketmq.studio.common.domain.Result;
+import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -48,7 +49,7 @@ public class ClusterController {
}
@PostMapping("/config/update")
- public Result<ClusterVO> updateClusterConfig(@RequestBody UpdateConfigDTO
command) {
+ public Result<ClusterVO> updateClusterConfig(@Valid @RequestBody
UpdateConfigDTO command) {
return Result.ok(clusterService.updateClusterConfig(command));
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/config/UpdateConfigDTO.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/config/UpdateConfigDTO.java
index 1413be21..229653c1 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/config/UpdateConfigDTO.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/config/UpdateConfigDTO.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.cluster.config;
+import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -26,7 +27,9 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class UpdateConfigDTO {
+ @NotBlank(message = "id is required")
private String id;
+
private String flushDiskType;
private Boolean autoCreateTopicEnable;
private Boolean autoCreateSubscriptionGroup;
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/CreateNameServerDTO.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/CreateNameServerDTO.java
index 30054716..fd63cc95 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/CreateNameServerDTO.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/CreateNameServerDTO.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.cluster.nameserver;
+import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -26,7 +27,11 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class CreateNameServerDTO {
+ @NotBlank(message = "clusterId is required")
private String clusterId;
+
+ @NotBlank(message = "addr is required")
private String addr;
+
private String version;
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/DeleteNameServerDTO.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/DeleteNameServerDTO.java
index 55f67554..acc02515 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/DeleteNameServerDTO.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/DeleteNameServerDTO.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.cluster.nameserver;
+import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -26,6 +27,9 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class DeleteNameServerDTO {
+ @NotBlank(message = "clusterId is required")
private String clusterId;
+
+ @NotBlank(message = "addr is required")
private String addr;
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/NameServerController.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/NameServerController.java
index d775baf3..0e1b8cc2 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/NameServerController.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/NameServerController.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.studio.cluster.nameserver;
import org.apache.rocketmq.studio.cluster.broker.ClusterService;
import org.apache.rocketmq.studio.common.domain.Result;
+import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -35,30 +36,30 @@ public class NameServerController {
private final ClusterService clusterService;
@PostMapping("/create")
- public Result<NameServerVO> createNameServer(@RequestBody
CreateNameServerDTO command) {
+ public Result<NameServerVO> createNameServer(@Valid @RequestBody
CreateNameServerDTO command) {
return Result.ok(clusterService.createNameServer(command));
}
@PostMapping("/update")
- public Result<Void> updateNameServer(@RequestBody UpdateNameServerDTO
command) {
+ public Result<Void> updateNameServer(@Valid @RequestBody
UpdateNameServerDTO command) {
clusterService.updateNameServer(command);
return Result.ok();
}
@PostMapping("/restart")
- public Result<Map<String, Boolean>> restartNameServer(@RequestBody
RestartNameServerDTO command) {
+ public Result<Map<String, Boolean>> restartNameServer(@Valid @RequestBody
RestartNameServerDTO command) {
boolean success = clusterService.restartNameServer(command);
return Result.ok(Map.of("success", success));
}
@PostMapping("/upgrade")
- public Result<Map<String, Boolean>> upgradeNameServer(@RequestBody
UpgradeNameServerDTO command) {
+ public Result<Map<String, Boolean>> upgradeNameServer(@Valid @RequestBody
UpgradeNameServerDTO command) {
boolean success = clusterService.upgradeNameServer(command);
return Result.ok(Map.of("success", success));
}
@PostMapping("/delete")
- public Result<Map<String, Boolean>> deleteNameServer(@RequestBody
DeleteNameServerDTO command) {
+ public Result<Map<String, Boolean>> deleteNameServer(@Valid @RequestBody
DeleteNameServerDTO command) {
boolean success = clusterService.deleteNameServer(command);
return Result.ok(Map.of("success", success));
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/RestartNameServerDTO.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/RestartNameServerDTO.java
index a9ca0c1b..91ae1841 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/RestartNameServerDTO.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/RestartNameServerDTO.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.cluster.nameserver;
+import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -26,6 +27,9 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class RestartNameServerDTO {
+ @NotBlank(message = "clusterId is required")
private String clusterId;
+
+ @NotBlank(message = "addr is required")
private String addr;
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/UpdateNameServerDTO.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/UpdateNameServerDTO.java
index c0d3803d..8b2c1b47 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/UpdateNameServerDTO.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/UpdateNameServerDTO.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.cluster.nameserver;
+import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -26,7 +27,11 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class UpdateNameServerDTO {
+ @NotBlank(message = "clusterId is required")
private String clusterId;
+
+ @NotBlank(message = "addr is required")
private String addr;
+
private String version;
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/UpgradeNameServerDTO.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/UpgradeNameServerDTO.java
index adbd944a..8fab9568 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/UpgradeNameServerDTO.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/nameserver/UpgradeNameServerDTO.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.cluster.nameserver;
+import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -26,7 +27,12 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class UpgradeNameServerDTO {
+ @NotBlank(message = "clusterId is required")
private String clusterId;
+
+ @NotBlank(message = "addr is required")
private String addr;
+
+ @NotBlank(message = "targetVersion is required")
private String targetVersion;
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyController.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyController.java
index 12487096..fa90b888 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyController.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/ProxyController.java
@@ -18,6 +18,7 @@ package org.apache.rocketmq.studio.cluster.proxy;
import org.apache.rocketmq.studio.cluster.broker.ClusterService;
import org.apache.rocketmq.studio.common.domain.Result;
+import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -34,7 +35,7 @@ public class ProxyController {
private final ClusterService clusterService;
@PostMapping("/restart")
- public Result<Map<String, Boolean>> restartProxy(@RequestBody
RestartProxyDTO command) {
+ public Result<Map<String, Boolean>> restartProxy(@Valid @RequestBody
RestartProxyDTO command) {
boolean success = clusterService.restartProxy(command);
return Result.ok(Map.of("success", success));
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/RestartProxyDTO.java
b/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/RestartProxyDTO.java
index e393f6f0..5c80e89e 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/RestartProxyDTO.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/cluster/proxy/RestartProxyDTO.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.cluster.proxy;
+import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -26,6 +27,9 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class RestartProxyDTO {
+ @NotBlank(message = "clusterId is required")
private String clusterId;
+
+ @NotBlank(message = "addr is required")
private String addr;
}
diff --git
a/server/src/test/java/com/rocketmq/studio/cluster/nameserver/NameServerControllerTest.java
b/server/src/test/java/com/rocketmq/studio/cluster/nameserver/NameServerControllerTest.java
new file mode 100644
index 00000000..eb4de252
--- /dev/null
+++
b/server/src/test/java/com/rocketmq/studio/cluster/nameserver/NameServerControllerTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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 org.apache.rocketmq.studio.cluster.nameserver;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.rocketmq.studio.cluster.broker.ClusterService;
+import org.apache.rocketmq.studio.common.domain.enums.ClusterStatus;
+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 static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+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(NameServerController.class)
+@AutoConfigureMockMvc(addFilters = false)
+class NameServerControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @MockBean
+ private ClusterService clusterService;
+
+ @Test
+ void createNameServerShouldPassValidatedRequest() throws Exception {
+ CreateNameServerDTO request = CreateNameServerDTO.builder()
+ .clusterId("cluster-1")
+ .addr("127.0.0.1:9876")
+ .version("5.3.2")
+ .build();
+ NameServerVO created = NameServerVO.builder()
+ .addr("127.0.0.1:9876")
+ .status(ClusterStatus.healthy)
+ .build();
+
when(clusterService.createNameServer(any(CreateNameServerDTO.class))).thenReturn(created);
+
+ mockMvc.perform(post("/api/nameservers/create")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.code").value(200))
+ .andExpect(jsonPath("$.data.addr").value("127.0.0.1:9876"));
+
+
verify(clusterService).createNameServer(any(CreateNameServerDTO.class));
+ }
+
+ @Test
+ void updateNameServerShouldRejectBlankAddr() throws Exception {
+ UpdateNameServerDTO request = UpdateNameServerDTO.builder()
+ .clusterId("cluster-1")
+ .addr(" ")
+ .build();
+
+ mockMvc.perform(post("/api/nameservers/update")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.code").value(400))
+ .andExpect(jsonPath("$.message").value("addr is required"));
+
+ verifyNoInteractions(clusterService);
+ }
+
+ @Test
+ void restartNameServerShouldPassValidatedRequest() throws Exception {
+ RestartNameServerDTO request = RestartNameServerDTO.builder()
+ .clusterId("cluster-1")
+ .addr("127.0.0.1:9876")
+ .build();
+
when(clusterService.restartNameServer(any(RestartNameServerDTO.class))).thenReturn(true);
+
+ mockMvc.perform(post("/api/nameservers/restart")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.code").value(200))
+ .andExpect(jsonPath("$.data.success").value(true));
+
+
verify(clusterService).restartNameServer(any(RestartNameServerDTO.class));
+ }
+
+ @Test
+ void restartNameServerShouldRejectMissingClusterId() throws Exception {
+ RestartNameServerDTO request = RestartNameServerDTO.builder()
+ .addr("127.0.0.1:9876")
+ .build();
+
+ mockMvc.perform(post("/api/nameservers/restart")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.code").value(400))
+ .andExpect(jsonPath("$.message").value("clusterId is
required"));
+
+ verifyNoInteractions(clusterService);
+ }
+
+ @Test
+ void upgradeNameServerShouldRejectMissingTargetVersion() throws Exception {
+ UpgradeNameServerDTO request = UpgradeNameServerDTO.builder()
+ .clusterId("cluster-1")
+ .addr("127.0.0.1:9876")
+ .build();
+
+ mockMvc.perform(post("/api/nameservers/upgrade")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.code").value(400))
+ .andExpect(jsonPath("$.message").value("targetVersion is
required"));
+
+ verifyNoInteractions(clusterService);
+ }
+
+ @Test
+ void deleteNameServerShouldPassValidatedRequest() throws Exception {
+ DeleteNameServerDTO request = DeleteNameServerDTO.builder()
+ .clusterId("cluster-1")
+ .addr("127.0.0.1:9876")
+ .build();
+
when(clusterService.deleteNameServer(any(DeleteNameServerDTO.class))).thenReturn(true);
+
+ mockMvc.perform(post("/api/nameservers/delete")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.code").value(200))
+ .andExpect(jsonPath("$.data.success").value(true));
+
+
verify(clusterService).deleteNameServer(any(DeleteNameServerDTO.class));
+ }
+}
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/ClusterControllerTest.java
b/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/ClusterControllerTest.java
index 6c3356c5..5279f617 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/ClusterControllerTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/ClusterControllerTest.java
@@ -35,6 +35,7 @@ import java.util.Arrays;
import java.util.Collections;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verifyNoInteractions;
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;
@@ -135,6 +136,40 @@ class ClusterControllerTest {
.andExpect(jsonPath("$.data.config.readQueueNums").value(16));
}
+ @Test
+ void updateConfigShouldRejectMissingId() throws Exception {
+ UpdateConfigDTO command = UpdateConfigDTO.builder()
+ .flushDiskType("SYNC_FLUSH")
+ .writeQueueNums(16)
+ .build();
+
+ mockMvc.perform(post("/api/clusters/config/update")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(command)))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.code").value(400))
+ .andExpect(jsonPath("$.message").value("id is required"));
+
+ verifyNoInteractions(clusterService);
+ }
+
+ @Test
+ void updateConfigShouldRejectBlankId() throws Exception {
+ UpdateConfigDTO command = UpdateConfigDTO.builder()
+ .id(" ")
+ .flushDiskType("SYNC_FLUSH")
+ .build();
+
+ mockMvc.perform(post("/api/clusters/config/update")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(command)))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.code").value(400))
+ .andExpect(jsonPath("$.message").value("id is required"));
+
+ verifyNoInteractions(clusterService);
+ }
+
@Test
void restartBrokerShouldReturnSuccess() throws Exception {
when(clusterService.restartBroker("cluster-1",
"broker-0")).thenReturn(true);
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/cluster/proxy/ProxyControllerTest.java
b/server/src/test/java/org/apache/rocketmq/studio/cluster/proxy/ProxyControllerTest.java
new file mode 100644
index 00000000..3f5d0d5d
--- /dev/null
+++
b/server/src/test/java/org/apache/rocketmq/studio/cluster/proxy/ProxyControllerTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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 org.apache.rocketmq.studio.cluster.proxy;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.rocketmq.studio.cluster.broker.ClusterService;
+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 static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+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(ProxyController.class)
+@AutoConfigureMockMvc(addFilters = false)
+class ProxyControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @MockBean
+ private ClusterService clusterService;
+
+ @Test
+ void restartProxyShouldPassValidatedRequest() throws Exception {
+ RestartProxyDTO request = RestartProxyDTO.builder()
+ .clusterId("cluster-1")
+ .addr("127.0.0.1:8081")
+ .build();
+
when(clusterService.restartProxy(any(RestartProxyDTO.class))).thenReturn(true);
+
+ mockMvc.perform(post("/api/proxies/restart")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.code").value(200))
+ .andExpect(jsonPath("$.data.success").value(true));
+
+ verify(clusterService).restartProxy(any(RestartProxyDTO.class));
+ }
+
+ @Test
+ void restartProxyShouldRejectMissingClusterId() throws Exception {
+ RestartProxyDTO request = RestartProxyDTO.builder()
+ .addr("127.0.0.1:8081")
+ .build();
+
+ mockMvc.perform(post("/api/proxies/restart")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.code").value(400))
+ .andExpect(jsonPath("$.message").value("clusterId is
required"));
+
+ verifyNoInteractions(clusterService);
+ }
+
+ @Test
+ void restartProxyShouldRejectBlankAddr() throws Exception {
+ RestartProxyDTO request = RestartProxyDTO.builder()
+ .clusterId("cluster-1")
+ .addr(" ")
+ .build();
+
+ mockMvc.perform(post("/api/proxies/restart")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(request)))
+ .andExpect(status().isBadRequest())
+ .andExpect(jsonPath("$.code").value(400))
+ .andExpect(jsonPath("$.message").value("addr is required"));
+
+ verifyNoInteractions(clusterService);
+ }
+}