Repository: robustmq/robustmq (language: rust)

Issue:
MINOR: Add validation to the node_list method in GrpcPlacementService and fill in the test case
### What type of enhancement is this?

Refactor

### What does the enhancement do?

Add validation to the node_list method in GrpcPlacementService and fill in the test case. 

Tips:
you can implement the `ValidateExt` trait on `NodeListQuest`, then invoke ` validate_ext ` function to achieve the validation functionality.

- you can locate the ValidateExt trait in the file: src\placement-center\src\server\grpc\validate.rs
- you need to add validation to the node_list method in this file:  src\placement-center\src\server\grpc\service_placement.rs
- you need to fill in the test case in this file: src\grpc-clients\tests\placement_test.rs

References 
- https://github.com/robustmq/robustmq/pull/548)https://github.com/robustmq/robustmq/pull/548

### Implementation challenges

_No response_


Discussion / hints:

Fix patch:
diff --git a/src/placement-center/src/server/grpc/service_inner.rs b/src/placement-center/src/server/grpc/service_inner.rs
index 3bddadbae..e0d3b104c 100644
--- a/src/placement-center/src/server/grpc/service_inner.rs
+++ b/src/placement-center/src/server/grpc/service_inner.rs
@@ -98,6 +98,9 @@ impl PlacementCenterService for GrpcPlacementService {
         request: Request<NodeListRequest>,
     ) -> Result<Response<NodeListReply>, Status> {
         let req = request.into_inner();
+
+        let _ = req.validate_ext()?;
+
         let mut nodes = Vec::new();
 
         for raw in self
diff --git a/src/placement-center/src/server/grpc/validate.rs b/src/placement-center/src/server/grpc/validate.rs
index 49a5c25b5..3139da1be 100644
--- a/src/placement-center/src/server/grpc/validate.rs
+++ b/src/placement-center/src/server/grpc/validate.rs
@@ -16,8 +16,8 @@ use std::net::{IpAddr, SocketAddr};
 
 use common_base::error::common::CommonError;
 use protocol::placement_center::placement_center_inner::{
-    ClusterType, DeleteIdempotentDataRequest, GetResourceConfigRequest, RegisterNodeRequest,
-    SetIdempotentDataRequest, SetResourceConfigRequest, UnRegisterNodeRequest,
+    ClusterType, DeleteIdempotentDataRequest, GetResourceConfigRequest, NodeListRequest,
+    RegisterNodeRequest, SetIdempotentDataRequest, SetResourceConfigRequest, UnRegisterNodeRequest,
 };
 use protocol::placement_center::placement_center_mqtt::GetShareSubLeaderRequest;
 use tonic::Status;
@@ -158,6 +158,13 @@ impl ValidateExt for GetShareSubLeaderRequest {
     }
 }
 
+impl ValidateExt for NodeListRequest {
+    fn validate_ext(&self) -> Result<(), Status> {
+        ensure_param_not_empty("cluster_name", &self.cluster_name)?;
+        Ok(())
+    }
+}
+
 #[cfg(test)]
 mod validate_test {
     use super::*;


Test patch:
diff --git a/src/grpc-clients/tests/placement/mqtt/cluster_test.rs b/src/grpc-clients/tests/placement/mqtt/cluster_test.rs
index 3f43d1c86..6f97c0665 100644
--- a/src/grpc-clients/tests/placement/mqtt/cluster_test.rs
+++ b/src/grpc-clients/tests/placement/mqtt/cluster_test.rs
@@ -17,13 +17,13 @@ mod tests {
     use std::sync::Arc;
 
     use grpc_clients::placement::inner::call::{
-        cluster_status, delete_idempotent_data, get_resource_config, register_node,
+        cluster_status, delete_idempotent_data, get_resource_config, node_list, register_node,
         set_resource_config, unregister_node,
     };
     use grpc_clients::pool::ClientPool;
     use protocol::placement_center::placement_center_inner::{
         ClusterStatusRequest, ClusterType, DeleteIdempotentDataRequest, GetResourceConfigRequest,
-        RegisterNodeRequest, SetResourceConfigRequest, UnRegisterNodeRequest,
+        NodeListRequest, RegisterNodeRequest, SetResourceConfigRequest, UnRegisterNodeRequest,
     };
 
     use crate::common::get_placement_addr;
@@ -126,6 +126,29 @@ mod tests {
         );
     }
 
+    #[tokio::test]
+    async fn node_list_test() {
+        let client_pool: Arc<ClientPool> = Arc::new(ClientPool::new(1));
+        let addrs = vec![get_placement_addr()];
+
+        let request = ClusterStatusRequest::default();
+        assert!(cluster_status(&client_pool, &addrs, request).await.is_ok());
+
+        let cluster_name = "test-cluster-name".to_string();
+
+        let request = NodeListRequest {
+            cluster_name: cluster_name.clone(),
+        };
+        assert!(node_list(&client_pool, &addrs, request).await.is_ok());
+
+        let request_cluster_name_empty = NodeListRequest {
+            cluster_name: "".to_string(),
+        };
+        assert!(node_list(&client_pool, &addrs, request_cluster_name_empty)
+            .await
+            .is_err());
+    }
+
     #[tokio::test]
     async fn delete_idempotent_data_test() {
         let client_pool: Arc<ClientPool> = Arc::new(ClientPool::new(1));