You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@inlong.apache.org by do...@apache.org on 2022/07/01 06:17:07 UTC

[inlong] branch master updated: [INLONG-4761][Manager] Optimize DataNode related business and write some unit tests (#4768)

This is an automated email from the ASF dual-hosted git repository.

dockerzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/inlong.git


The following commit(s) were added to refs/heads/master by this push:
     new a51323438 [INLONG-4761][Manager] Optimize DataNode related business and write some unit tests (#4768)
a51323438 is described below

commit a51323438e540f93552adce61cfb9f3b7f6cfca1
Author: leosanqing <st...@qq.com>
AuthorDate: Fri Jul 1 14:17:02 2022 +0800

    [INLONG-4761][Manager] Optimize DataNode related business and write some unit tests (#4768)
---
 .../manager/common/pojo/common/SaveReqValid.java}  |  17 ++-
 .../common/pojo/common/UpdateReqValid.java}        |  22 +++-
 .../manager/common/pojo/node/DataNodeRequest.java  |  12 +-
 .../service/core/impl/DataNodeServiceImpl.java     |  15 +--
 .../manager-test/src/main/resources/h2/data.sql    |   7 +-
 .../manager/web/controller/DataNodeController.java |  11 +-
 .../org/apache/inlong/manager/web/WebBaseTest.java |  97 +++++++++++++++-
 .../manager/web/controller/AnnoControllerTest.java |  27 ++---
 .../web/controller/DataNodeControllerTest.java     | 122 +++++++++++++++++++++
 9 files changed, 283 insertions(+), 47 deletions(-)

diff --git a/inlong-manager/manager-test/src/main/resources/h2/data.sql b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/common/SaveReqValid.java
similarity index 71%
copy from inlong-manager/manager-test/src/main/resources/h2/data.sql
copy to inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/common/SaveReqValid.java
index 1ab768789..78a263eb3 100644
--- a/inlong-manager/manager-test/src/main/resources/h2/data.sql
+++ b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/common/SaveReqValid.java
@@ -14,7 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-INSERT INTO `user` (`id`, `name`, `password`, `account_type`, `due_date`, `create_time`,
-                    `update_time`, `create_by`, `update_by`)
-VALUES (1, 'admin', '628ed559bff5ae36bd2184d4216973cf', 0, '2099-12-31 23:59:59', '2022-06-05 08:58:06',
-        '2022-06-05 08:58:06', 'inlong_init', 'inlong_init');
\ No newline at end of file
+
+package org.apache.inlong.manager.common.pojo.common;
+
+import javax.validation.groups.Default;
+
+/**
+ * Used for validate add request fields group
+ *
+ * @see UpdateReqValid
+ */
+public interface SaveReqValid extends Default {
+
+}
diff --git a/inlong-manager/manager-test/src/main/resources/h2/data.sql b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/common/UpdateReqValid.java
similarity index 58%
copy from inlong-manager/manager-test/src/main/resources/h2/data.sql
copy to inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/common/UpdateReqValid.java
index 1ab768789..bf7a07b08 100644
--- a/inlong-manager/manager-test/src/main/resources/h2/data.sql
+++ b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/common/UpdateReqValid.java
@@ -14,7 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-INSERT INTO `user` (`id`, `name`, `password`, `account_type`, `due_date`, `create_time`,
-                    `update_time`, `create_by`, `update_by`)
-VALUES (1, 'admin', '628ed559bff5ae36bd2184d4216973cf', 0, '2099-12-31 23:59:59', '2022-06-05 08:58:06',
-        '2022-06-05 08:58:06', 'inlong_init', 'inlong_init');
\ No newline at end of file
+
+package org.apache.inlong.manager.common.pojo.common;
+
+import javax.validation.groups.Default;
+
+/**
+ * Used for validate update request fields group
+ *
+ * In general, the request body of save and update can be shared,
+ * but we need to verify the parameters of the two requests separately
+ *
+ * For example, the request body save and update only have the difference in id,
+ * and this id must be carried when updating, we can use it like this
+ * {@link org.apache.inlong.manager.common.pojo.node.DataNodeRequest}
+ */
+public interface UpdateReqValid extends Default {
+
+}
diff --git a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/node/DataNodeRequest.java b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/node/DataNodeRequest.java
index 6e203a0b1..362d1757c 100644
--- a/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/node/DataNodeRequest.java
+++ b/inlong-manager/manager-common/src/main/java/org/apache/inlong/manager/common/pojo/node/DataNodeRequest.java
@@ -19,17 +19,26 @@ package org.apache.inlong.manager.common.pojo.node;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.inlong.manager.common.pojo.common.UpdateReqValid;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 
 /**
  * Data node request
  */
 @Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 @ApiModel("Data node  request")
 public class DataNodeRequest {
 
+    @NotNull(groups = UpdateReqValid.class)
     @ApiModelProperty(value = "Primary key")
     private Integer id;
 
@@ -53,7 +62,8 @@ public class DataNodeRequest {
     @ApiModelProperty(value = "Extended params")
     private String extParams;
 
-    @ApiModelProperty(value = "Name of responsible person, separated by commas")
+    @NotBlank
+    @ApiModelProperty(value = "Name of responsible person, separated by commas", required = true)
     private String inCharges;
 
 }
diff --git a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/impl/DataNodeServiceImpl.java b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/impl/DataNodeServiceImpl.java
index b394732f3..6d78f1ebe 100644
--- a/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/impl/DataNodeServiceImpl.java
+++ b/inlong-manager/manager-service/src/main/java/org/apache/inlong/manager/service/core/impl/DataNodeServiceImpl.java
@@ -55,12 +55,8 @@ public class DataNodeServiceImpl implements DataNodeService {
 
     @Override
     public Integer save(DataNodeRequest request, String operator) {
-        // check request
-        Preconditions.checkNotNull(request, "data node info cannot be empty");
         String name = request.getName();
         String type = request.getType();
-        Preconditions.checkNotEmpty(name, "data node name cannot be empty");
-        Preconditions.checkNotEmpty(type, "data node type cannot be empty");
 
         // check if data node already exist
         DataNodeEntity exist = dataNodeMapper.selectByNameAndType(name, type);
@@ -84,7 +80,6 @@ public class DataNodeServiceImpl implements DataNodeService {
 
     @Override
     public DataNodeResponse get(Integer id) {
-        Preconditions.checkNotNull(id, "data node id cannot be empty");
         DataNodeEntity entity = dataNodeMapper.selectById(id);
         if (entity == null) {
             LOGGER.error("data node not found by id={}", id);
@@ -101,22 +96,17 @@ public class DataNodeServiceImpl implements DataNodeService {
         Page<DataNodeEntity> entityPage = (Page<DataNodeEntity>) dataNodeMapper.selectByCondition(request);
         List<DataNodeResponse> responseList = CommonBeanUtils.copyListProperties(entityPage, DataNodeResponse::new);
         PageInfo<DataNodeResponse> page = new PageInfo<>(responseList);
-        page.setTotal(responseList.size());
+        page.setTotal(entityPage.getTotal());
         LOGGER.debug("success to list data node by {}", request);
         return page;
     }
 
     @Override
     public Boolean update(DataNodeRequest request, String operator) {
-        // check request
-        Preconditions.checkNotNull(request, "data node info cannot be empty");
         String name = request.getName();
         String type = request.getType();
-        Preconditions.checkNotEmpty(name, "data node name cannot be empty");
-        Preconditions.checkNotEmpty(type, "data node type cannot be empty");
 
         Integer id = request.getId();
-        Preconditions.checkNotNull(id, "data node id is empty");
         DataNodeEntity exist = dataNodeMapper.selectByNameAndType(name, type);
         if (exist != null && !Objects.equals(id, exist.getId())) {
             String errMsg = String.format("data node already exist for name=%s type=%s", name, type);
@@ -139,7 +129,6 @@ public class DataNodeServiceImpl implements DataNodeService {
 
     @Override
     public Boolean delete(Integer id, String operator) {
-        Preconditions.checkNotNull(id, "data node id cannot be empty");
         DataNodeEntity entity = dataNodeMapper.selectById(id);
         if (entity == null || entity.getIsDeleted() > InlongConstants.UN_DELETED) {
             LOGGER.error("data node not found or was already deleted for id={}", id);
@@ -156,9 +145,7 @@ public class DataNodeServiceImpl implements DataNodeService {
     @Override
     public Boolean testConnection(DataNodeRequest request) {
         LOGGER.info("begin test connection for: {}", request);
-        Preconditions.checkNotNull(request, "Connection request cannot be empty");
         String type = request.getType();
-        Preconditions.checkNotNull(type, "Connection type cannot be empty");
 
         Boolean result = false;
         if (DataNodeType.HIVE.toString().equals(type)) {
diff --git a/inlong-manager/manager-test/src/main/resources/h2/data.sql b/inlong-manager/manager-test/src/main/resources/h2/data.sql
index 1ab768789..1a4944c9a 100644
--- a/inlong-manager/manager-test/src/main/resources/h2/data.sql
+++ b/inlong-manager/manager-test/src/main/resources/h2/data.sql
@@ -17,4 +17,9 @@
 INSERT INTO `user` (`id`, `name`, `password`, `account_type`, `due_date`, `create_time`,
                     `update_time`, `create_by`, `update_by`)
 VALUES (1, 'admin', '628ed559bff5ae36bd2184d4216973cf', 0, '2099-12-31 23:59:59', '2022-06-05 08:58:06',
-        '2022-06-05 08:58:06', 'inlong_init', 'inlong_init');
\ No newline at end of file
+        '2022-06-05 08:58:06', 'inlong_init', 'inlong_init');
+
+INSERT INTO `user` (`id`, `name`, `password`, `account_type`, `due_date`, `create_time`,
+                    `update_time`, `create_by`, `update_by`)
+VALUES (2, 'operator', '628ed559bff5ae36bd2184d4216973cf', 1, '2099-12-31 23:59:59', '2022-06-05 08:58:06',
+        '2022-06-05 08:58:06', 'inlong_init', 'inlong_init');
diff --git a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/controller/DataNodeController.java b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/controller/DataNodeController.java
index 7f6e89b34..72aa9d2d2 100644
--- a/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/controller/DataNodeController.java
+++ b/inlong-manager/manager-web/src/main/java/org/apache/inlong/manager/web/controller/DataNodeController.java
@@ -23,6 +23,7 @@ import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiOperation;
 import org.apache.inlong.manager.common.beans.Response;
 import org.apache.inlong.manager.common.enums.OperationType;
+import org.apache.inlong.manager.common.pojo.common.UpdateReqValid;
 import org.apache.inlong.manager.common.pojo.node.DataNodePageRequest;
 import org.apache.inlong.manager.common.pojo.node.DataNodeRequest;
 import org.apache.inlong.manager.common.pojo.node.DataNodeResponse;
@@ -32,13 +33,13 @@ import org.apache.inlong.manager.service.core.DataNodeService;
 import org.apache.inlong.manager.service.core.operationlog.OperationLog;
 import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.DeleteMapping;
 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.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
 /**
@@ -56,7 +57,7 @@ public class DataNodeController {
     @ApiOperation(value = "Save node")
     @OperationLog(operation = OperationType.CREATE)
     @RequiresRoles(value = UserRoleCode.ADMIN)
-    public Response<Integer> save(@RequestBody DataNodeRequest request) {
+    public Response<Integer> save(@Validated @RequestBody DataNodeRequest request) {
         String currentUser = LoginUserUtils.getLoginUserDetail().getUsername();
         return Response.success(dataNodeService.save(request, currentUser));
     }
@@ -77,7 +78,7 @@ public class DataNodeController {
     @PostMapping(value = "/update")
     @OperationLog(operation = OperationType.UPDATE)
     @ApiOperation(value = "Update data node")
-    public Response<Boolean> update(@RequestBody DataNodeRequest request) {
+    public Response<Boolean> update(@Validated(UpdateReqValid.class) @RequestBody DataNodeRequest request) {
         String username = LoginUserUtils.getLoginUserDetail().getUsername();
         return Response.success(dataNodeService.update(request, username));
     }
@@ -91,9 +92,9 @@ public class DataNodeController {
         return Response.success(dataNodeService.delete(id, LoginUserUtils.getLoginUserDetail().getUsername()));
     }
 
-    @RequestMapping(value = "/testConnection", method = RequestMethod.POST)
+    @PostMapping("/testConnection")
     @ApiOperation(value = "Test connection for data node")
-    public Response<Boolean> testConnection(@RequestBody DataNodeRequest request) {
+    public Response<Boolean> testConnection(@Validated @RequestBody DataNodeRequest request) {
         return Response.success(dataNodeService.testConnection(request));
     }
 
diff --git a/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/WebBaseTest.java b/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/WebBaseTest.java
index 9b87dcb18..6a9d3b45c 100644
--- a/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/WebBaseTest.java
+++ b/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/WebBaseTest.java
@@ -19,18 +19,24 @@ package org.apache.inlong.manager.web;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.SneakyThrows;
 import org.apache.inlong.manager.common.beans.Response;
+import org.apache.inlong.manager.common.pojo.user.LoginUser;
+import org.apache.inlong.manager.common.util.JsonUtils;
 import org.apache.inlong.manager.test.BaseTest;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.mgt.SecurityManager;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.TestInstance.Lifecycle;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.MvcResult;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.context.WebApplicationContext;
 
 import javax.annotation.Resource;
@@ -39,8 +45,13 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+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.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
+@Transactional
 @TestInstance(Lifecycle.PER_CLASS)
 @SpringBootTest(classes = InLongWebApplication.class)
 public abstract class WebBaseTest extends BaseTest {
@@ -53,7 +64,7 @@ public abstract class WebBaseTest extends BaseTest {
     ObjectMapper objectMapper;
 
     @BeforeAll
-    void setup() {
+    void baseSetup() {
         SecurityUtils.setSecurityManager(context.getBean(SecurityManager.class));
 
         mockMvc = MockMvcBuilders
@@ -62,6 +73,90 @@ public abstract class WebBaseTest extends BaseTest {
                 .build();
     }
 
+    @BeforeEach
+    void baseBeforeEach() throws Exception {
+        logout();
+        adminLogin();
+    }
+
+    protected void logout() {
+        SecurityUtils.getSubject().logout();
+    }
+
+    protected void adminLogin() throws Exception {
+        LoginUser loginUser = new LoginUser();
+        loginUser.setUsername("admin");
+        loginUser.setPassword("inlong");
+
+        MvcResult mvcResult = mockMvc.perform(
+                        post("/anno/login")
+                                .content(JsonUtils.toJsonString(loginUser))
+                                .contentType(MediaType.APPLICATION_JSON_UTF8)
+                                .accept(MediaType.APPLICATION_JSON)
+                )
+                .andExpect(status().isOk())
+                .andReturn();
+
+        String resBodyObj = getResBodyObj(mvcResult, String.class);
+        Assertions.assertNotNull(resBodyObj);
+
+        Assertions.assertTrue(SecurityUtils.getSubject().isAuthenticated());
+    }
+
+    @SneakyThrows
+    protected MvcResult postForSuccessMvcResult(String url, Object body) {
+        return mockMvc.perform(
+                        post(url)
+                                .content(JsonUtils.toJsonString(body))
+                                .contentType(MediaType.APPLICATION_JSON_UTF8)
+                                .accept(MediaType.APPLICATION_JSON)
+                )
+                .andExpect(status().isOk())
+                .andReturn();
+    }
+
+    @SneakyThrows
+    protected MvcResult getForSuccessMvcResult(String url, Object... pathVariable) {
+        return mockMvc.perform(
+                        get(url, pathVariable)
+                                .contentType(MediaType.APPLICATION_JSON_UTF8)
+                                .accept(MediaType.APPLICATION_JSON)
+                )
+                .andExpect(status().isOk())
+                .andReturn();
+    }
+
+    @SneakyThrows
+    protected MvcResult deleteForSuccessMvcResult(String url, Object... pathVariable) {
+        return mockMvc.perform(
+                        delete(url, pathVariable)
+                                .contentType(MediaType.APPLICATION_JSON_UTF8)
+                                .accept(MediaType.APPLICATION_JSON)
+                )
+                .andExpect(status().isOk())
+                .andReturn();
+    }
+
+    protected void operatorLogin() throws Exception {
+        LoginUser loginUser = new LoginUser();
+        loginUser.setUsername("operator");
+        loginUser.setPassword("inlong");
+
+        MvcResult mvcResult = mockMvc.perform(
+                        post("/anno/login")
+                                .content(JsonUtils.toJsonString(loginUser))
+                                .contentType(MediaType.APPLICATION_JSON_UTF8)
+                                .accept(MediaType.APPLICATION_JSON)
+                )
+                .andExpect(status().isOk())
+                .andReturn();
+
+        String resBodyObj = getResBodyObj(mvcResult, String.class);
+        Assertions.assertNotNull(resBodyObj);
+
+        Assertions.assertTrue(SecurityUtils.getSubject().isAuthenticated());
+    }
+
     public <T> Response<T> getResBody(MvcResult mvcResult, Class<T> t) throws Exception {
         return objectMapper
                 .readValue(
diff --git a/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/controller/AnnoControllerTest.java b/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/controller/AnnoControllerTest.java
index fd91352ea..4983fd76b 100644
--- a/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/controller/AnnoControllerTest.java
+++ b/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/controller/AnnoControllerTest.java
@@ -25,7 +25,10 @@ import org.apache.inlong.manager.common.util.JsonUtils;
 import org.apache.inlong.manager.web.WebBaseTest;
 import org.apache.shiro.SecurityUtils;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
 import org.springframework.http.MediaType;
 import org.springframework.test.web.servlet.MvcResult;
 
@@ -33,30 +36,20 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
+@TestInstance(Lifecycle.PER_CLASS)
 class AnnoControllerTest extends WebBaseTest {
 
     // Password contains uppercase and lowercase numeric special characters
     private static final String TEST_PWD = "test_#$%%Y@UI$123";
 
+    @BeforeAll
+    void setup() {
+        logout();
+    }
+
     @Test
     void testLogin() throws Exception {
-        LoginUser loginUser = new LoginUser();
-        loginUser.setUsername("admin");
-        loginUser.setPassword("inlong");
-
-        MvcResult mvcResult = mockMvc.perform(
-                        post("/anno/login")
-                                .content(JsonUtils.toJsonString(loginUser))
-                                .contentType(MediaType.APPLICATION_JSON_UTF8)
-                                .accept(MediaType.APPLICATION_JSON)
-                )
-                .andExpect(status().isOk())
-                .andReturn();
-
-        String resBodyObj = getResBodyObj(mvcResult, String.class);
-        Assertions.assertNotNull(resBodyObj);
-
-        Assertions.assertTrue(SecurityUtils.getSubject().isAuthenticated());
+        adminLogin();
     }
 
     @Test
diff --git a/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/controller/DataNodeControllerTest.java b/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/controller/DataNodeControllerTest.java
new file mode 100644
index 000000000..f47659b1d
--- /dev/null
+++ b/inlong-manager/manager-web/src/test/java/org/apache/inlong/manager/web/controller/DataNodeControllerTest.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 org.apache.inlong.manager.web.controller;
+
+import org.apache.inlong.manager.common.beans.Response;
+import org.apache.inlong.manager.common.pojo.node.DataNodeRequest;
+import org.apache.inlong.manager.common.pojo.node.DataNodeResponse;
+import org.apache.inlong.manager.dao.entity.DataNodeEntity;
+import org.apache.inlong.manager.dao.mapper.DataNodeEntityMapper;
+import org.apache.inlong.manager.web.WebBaseTest;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.web.servlet.MvcResult;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+class DataNodeControllerTest extends WebBaseTest {
+
+    @Resource
+    DataNodeEntityMapper dataNodeEntityMapper;
+
+    DataNodeRequest getDataNodeRequest() {
+        return DataNodeRequest.builder()
+                .name("hiveNode1")
+                .type("HIVE")
+                .url("127.0.0.1:8080")
+                .username("admin")
+                .token("123")
+                .inCharges("admin")
+                .build();
+    }
+
+    @Test
+    void testSaveFailByNoPermission() throws Exception {
+        logout();
+        operatorLogin();
+
+        MvcResult mvcResult = postForSuccessMvcResult("/node/save", getDataNodeRequest());
+
+        Response<Integer> response = getResBody(mvcResult, Integer.class);
+        Assertions.assertEquals("Current user [operator] has no permission to access URL", response.getErrMsg());
+    }
+
+    @Test
+    void testSaveAndGetAndDelete() throws Exception {
+        // save
+        MvcResult mvcResult = postForSuccessMvcResult("/node/save", getDataNodeRequest());
+
+        Integer dataNodeId = getResBodyObj(mvcResult, Integer.class);
+        Assertions.assertNotNull(dataNodeId);
+
+        // get
+        MvcResult getResult = getForSuccessMvcResult("/node/get/{id}", dataNodeId);
+
+        DataNodeResponse dataNode = getResBodyObj(getResult, DataNodeResponse.class);
+        Assertions.assertNotNull(dataNode);
+        Assertions.assertEquals(getDataNodeRequest().getName(), dataNode.getName());
+
+        // delete
+        MvcResult deleteResult = deleteForSuccessMvcResult("/node/delete/{id}", dataNodeId);
+
+        Boolean success = getResBodyObj(deleteResult, Boolean.class);
+        Assertions.assertTrue(success);
+
+        DataNodeEntity dataNodeEntity = dataNodeEntityMapper.selectById(dataNodeId);
+        Assertions.assertEquals(dataNodeEntity.getId(), dataNodeEntity.getIsDeleted());
+    }
+
+    @Test
+    void testUpdate() throws Exception {
+        // insert the test data
+        DataNodeEntity nodeEntity = new DataNodeEntity();
+        nodeEntity.setName("test");
+        nodeEntity.setType("MYSQL");
+        nodeEntity.setIsDeleted(0);
+        nodeEntity.setModifier("test");
+        nodeEntity.setCreator("test");
+        nodeEntity.setCreateTime(new Date());
+        nodeEntity.setModifyTime(new Date());
+        nodeEntity.setInCharges("test");
+
+        dataNodeEntityMapper.insert(nodeEntity);
+
+        DataNodeRequest request = getDataNodeRequest();
+        request.setId(nodeEntity.getId());
+        request.setName("test447777");
+
+        MvcResult mvcResult = postForSuccessMvcResult("/node/update", request);
+
+        Boolean success = getResBodyObj(mvcResult, Boolean.class);
+        Assertions.assertTrue(success);
+
+        DataNodeEntity dataNodeEntity = dataNodeEntityMapper.selectById(request.getId());
+        Assertions.assertEquals(request.getName(), dataNodeEntity.getName());
+    }
+
+    @Test
+    void testUpdateFailByNoId() throws Exception {
+        MvcResult mvcResult = postForSuccessMvcResult("/node/update", getDataNodeRequest());
+
+        Response<Boolean> response = getResBody(mvcResult, Boolean.class);
+        Assertions.assertFalse(response.isSuccess());
+        Assertions.assertEquals("id: must not be null\n", response.getErrMsg());
+    }
+
+}