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

wangyang pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 6aa6e114a5 [Improvement][Alert] Add a test send feature when creating 
an alert instance (#15163)
6aa6e114a5 is described below

commit 6aa6e114a531cc43675e198799b14eb6fdcd9fa5
Author: 旺阳 <[email protected]>
AuthorDate: Mon Nov 20 10:03:37 2023 +0800

    [Improvement][Alert] Add a test send feature when creating an alert 
instance (#15163)
    
    * add alert test send feature
    
    * update doc
    
    * add alarm instance test send ui
    
    * update
    
    * fix mvn
    
    * fix test
    
    * update
    
    * update
    
    * change to rpc
    
    * fix ut
    
    * fix ut
    
    * update
    
    * update
    
    * change result
    
    * update
    
    * Update docs/docs/en/guide/alert/alert_plugin_user_guide.md
    
    Co-authored-by: Aaron Wang <[email protected]>
    
    ---------
    
    Co-authored-by: Aaron Wang <[email protected]>
---
 .../docs/en/guide/alert/alert_plugin_user_guide.md |   2 +
 .../docs/zh/guide/alert/alert_plugin_user_guide.md |   2 +
 docs/img/new_ui/dev/alert/alert_instance01.png     | Bin 70279 -> 110602 bytes
 docs/img/new_ui/dev/alert/alert_instance02.png     | Bin 102718 -> 148594 bytes
 docs/img/new_ui/dev/alert/alert_instance03.png     | Bin 104143 -> 153641 bytes
 .../dolphinscheduler/alert/api/AlertConstants.java |   2 +
 .../alert/rpc/AlertOperatorImpl.java               |  11 ++++
 .../alert/service/AlertBootstrapService.java       |  58 +++++++++++++++++-
 .../alert/service/ListenerEventPostService.java    |   1 -
 .../alert/runner/AlertBootstrapServiceTest.java    |  61 +++++++++++++------
 dolphinscheduler-api/pom.xml                       |   4 ++
 .../controller/AlertPluginInstanceController.java  |  14 +++++
 .../apache/dolphinscheduler/api/enums/Status.java  |   5 +-
 .../api/service/AlertPluginInstanceService.java    |   2 +
 .../impl/AlertPluginInstanceServiceImpl.java       |  56 +++++++++++++++++
 .../AlertPluginInstanceControllerTest.java         |  28 +++++++++
 .../service/AlertPluginInstanceServiceTest.java    |  29 +++++++++
 .../extract/alert/IAlertOperator.java              |   4 ++
 .../AlertTestSendRequest.java}                     |  19 +++---
 .../dolphinscheduler-registry-api/pom.xml          |   4 ++
 .../registry/api/RegistryClient.java               |   1 -
 dolphinscheduler-ui/src/locales/en_US/security.ts  |   4 +-
 dolphinscheduler-ui/src/locales/zh_CN/security.ts  |   1 +
 .../src/service/modules/alert-plugin/index.ts      |  11 +++-
 .../src/service/modules/alert-plugin/types.ts      |   8 ++-
 .../security/alarm-instance-manage/detail.tsx      |  66 ++++++++++++++-------
 .../security/alarm-instance-manage/use-detail.ts   |  27 ++++++++-
 27 files changed, 364 insertions(+), 56 deletions(-)

diff --git a/docs/docs/en/guide/alert/alert_plugin_user_guide.md 
b/docs/docs/en/guide/alert/alert_plugin_user_guide.md
index 330a7e3f7f..0445b32c5a 100644
--- a/docs/docs/en/guide/alert/alert_plugin_user_guide.md
+++ b/docs/docs/en/guide/alert/alert_plugin_user_guide.md
@@ -13,6 +13,8 @@ Steps to be used are as follows:
 - Select the corresponding alarm plug-in and fill in the relevant alarm 
parameters.
 - Select `Alarm Group Management`, create an alarm group, and choose the 
corresponding alarm instance.
 
+> You can click `Test Send` button to test whether the alarm instance is 
configured correctly.
+
 ![alert-instance01](../../../../img/new_ui/dev/alert/alert_instance01.png)
 
 ![alert-instance02](../../../../img/new_ui/dev/alert/alert_instance02.png)
diff --git a/docs/docs/zh/guide/alert/alert_plugin_user_guide.md 
b/docs/docs/zh/guide/alert/alert_plugin_user_guide.md
index dbea97b961..5af6b17508 100644
--- a/docs/docs/zh/guide/alert/alert_plugin_user_guide.md
+++ b/docs/docs/zh/guide/alert/alert_plugin_user_guide.md
@@ -10,6 +10,8 @@
 
 然后选择告警组管理,创建告警组,选择相应的告警实例即可。
 
+> 可以使用`测试发送`功能来验证配置的告警实例是否正确。
+
 ![alert-instance01](../../../../img/new_ui/dev/alert/alert_instance01.png)
 ![alert-instance02](../../../../img/new_ui/dev/alert/alert_instance02.png)
 ![alert-instance03](../../../../img/new_ui/dev/alert/alert_instance03.png)
diff --git a/docs/img/new_ui/dev/alert/alert_instance01.png 
b/docs/img/new_ui/dev/alert/alert_instance01.png
index c5a515254f..3ebe89d010 100644
Binary files a/docs/img/new_ui/dev/alert/alert_instance01.png and 
b/docs/img/new_ui/dev/alert/alert_instance01.png differ
diff --git a/docs/img/new_ui/dev/alert/alert_instance02.png 
b/docs/img/new_ui/dev/alert/alert_instance02.png
index 37be6dd859..6ee6867146 100644
Binary files a/docs/img/new_ui/dev/alert/alert_instance02.png and 
b/docs/img/new_ui/dev/alert/alert_instance02.png differ
diff --git a/docs/img/new_ui/dev/alert/alert_instance03.png 
b/docs/img/new_ui/dev/alert/alert_instance03.png
index 094c38b65f..8260fdcc3d 100644
Binary files a/docs/img/new_ui/dev/alert/alert_instance03.png and 
b/docs/img/new_ui/dev/alert/alert_instance03.png differ
diff --git 
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-api/src/main/java/org/apache/dolphinscheduler/alert/api/AlertConstants.java
 
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-api/src/main/java/org/apache/dolphinscheduler/alert/api/AlertConstants.java
index a94a31a8a9..cf6f071dfb 100644
--- 
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-api/src/main/java/org/apache/dolphinscheduler/alert/api/AlertConstants.java
+++ 
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-api/src/main/java/org/apache/dolphinscheduler/alert/api/AlertConstants.java
@@ -31,6 +31,8 @@ public final class AlertConstants {
     public static final String WARNING_TYPE = "warningType";
 
     public static final String NAME_WARNING_TYPE = "WarningType";
+    public static final String TEST_TITLE = "DolphinScheduler test alert";
+    public static final String TEST_CONTENT = "[{\"message\":\" This is a test 
alert message form DolphinScheduler\"}]";
 
     private AlertConstants() {
         throw new UnsupportedOperationException("This is a utility class and 
cannot be instantiated");
diff --git 
a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/rpc/AlertOperatorImpl.java
 
b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/rpc/AlertOperatorImpl.java
index 36c0a5556d..9f11fa6c2e 100644
--- 
a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/rpc/AlertOperatorImpl.java
+++ 
b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/rpc/AlertOperatorImpl.java
@@ -20,6 +20,7 @@ import 
org.apache.dolphinscheduler.alert.service.AlertBootstrapService;
 import org.apache.dolphinscheduler.extract.alert.IAlertOperator;
 import org.apache.dolphinscheduler.extract.alert.request.AlertSendRequest;
 import org.apache.dolphinscheduler.extract.alert.request.AlertSendResponse;
+import org.apache.dolphinscheduler.extract.alert.request.AlertTestSendRequest;
 
 import lombok.extern.slf4j.Slf4j;
 
@@ -44,4 +45,14 @@ public class AlertOperatorImpl implements IAlertOperator {
         log.info("Handle AlertSendRequest finish: {}", alertSendResponse);
         return alertSendResponse;
     }
+
+    @Override
+    public AlertSendResponse sendTestAlert(AlertTestSendRequest 
alertSendRequest) {
+        log.info("Received AlertTestSendRequest : {}", alertSendRequest);
+        AlertSendResponse alertSendResponse = 
alertBootstrapService.syncTestSend(
+                alertSendRequest.getPluginDefineId(),
+                alertSendRequest.getPluginInstanceParams());
+        log.info("Handle AlertTestSendRequest finish: {}", alertSendResponse);
+        return alertSendResponse;
+    }
 }
diff --git 
a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/service/AlertBootstrapService.java
 
b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/service/AlertBootstrapService.java
index 57ef75d6d6..77e62a65a0 100644
--- 
a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/service/AlertBootstrapService.java
+++ 
b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/service/AlertBootstrapService.java
@@ -38,6 +38,7 @@ import org.apache.dolphinscheduler.dao.entity.Alert;
 import org.apache.dolphinscheduler.dao.entity.AlertPluginInstance;
 import org.apache.dolphinscheduler.dao.entity.AlertSendStatus;
 import org.apache.dolphinscheduler.extract.alert.request.AlertSendResponse;
+import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer;
 
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
@@ -192,7 +193,7 @@ public final class AlertBootstrapService extends 
BaseDaemonThread implements Aut
             if (alertResult != null) {
                 AlertSendResponse.AlertSendResponseResult 
alertSendResponseResult =
                         new AlertSendResponse.AlertSendResponseResult(
-                                
Boolean.parseBoolean(String.valueOf(alertResult.getStatus())),
+                                Boolean.parseBoolean(alertResult.getStatus()),
                                 alertResult.getMessage());
                 sendResponseStatus = sendResponseStatus && 
alertSendResponseResult.isSuccess();
                 sendResponseResults.add(alertSendResponseResult);
@@ -302,6 +303,61 @@ public final class AlertBootstrapService extends 
BaseDaemonThread implements Aut
         }
     }
 
+    public AlertSendResponse syncTestSend(int pluginDefineId, String 
pluginInstanceParams) {
+
+        boolean sendResponseStatus = true;
+        List<AlertSendResponse.AlertSendResponseResult> sendResponseResults = 
new ArrayList<>();
+
+        Optional<AlertChannel> alertChannelOptional = 
alertPluginManager.getAlertChannel(pluginDefineId);
+        if (!alertChannelOptional.isPresent()) {
+            String message = String.format("Test send alert error: the channel 
doesn't exist, pluginDefineId: %s",
+                    pluginDefineId);
+            AlertSendResponse.AlertSendResponseResult alertSendResponseResult =
+                    new AlertSendResponse.AlertSendResponseResult();
+            alertSendResponseResult.setSuccess(false);
+            alertSendResponseResult.setMessage(message);
+            sendResponseResults.add(alertSendResponseResult);
+            log.error("Test send alert error : not found plugin {}", 
pluginDefineId);
+            return new AlertSendResponse(false, sendResponseResults);
+        }
+        AlertChannel alertChannel = alertChannelOptional.get();
+
+        Map<String, String> paramsMap = 
PluginParamsTransfer.getPluginParamsMap(pluginInstanceParams);
+
+        AlertData alertData = AlertData.builder()
+                .title(AlertConstants.TEST_TITLE)
+                .content(AlertConstants.TEST_CONTENT)
+                .warnType(WarningType.ALL.getCode())
+                .build();
+
+        AlertInfo alertInfo = AlertInfo.builder()
+                .alertData(alertData)
+                .alertParams(paramsMap)
+                .build();
+
+        try {
+            AlertResult alertResult = alertChannel.process(alertInfo);
+            if (alertResult != null) {
+                AlertSendResponse.AlertSendResponseResult 
alertSendResponseResult =
+                        new AlertSendResponse.AlertSendResponseResult(
+                                Boolean.parseBoolean(alertResult.getStatus()),
+                                alertResult.getMessage());
+                sendResponseStatus = alertSendResponseResult.isSuccess();
+                sendResponseResults.add(alertSendResponseResult);
+            }
+        } catch (Exception e) {
+            log.error("Test send alert error", e);
+            AlertSendResponse.AlertSendResponseResult alertSendResponseResult =
+                    new AlertSendResponse.AlertSendResponseResult();
+            alertSendResponseResult.setSuccess(false);
+            alertSendResponseResult.setMessage(e.getMessage());
+            sendResponseResults.add(alertSendResponseResult);
+            return new AlertSendResponse(false, sendResponseResults);
+        }
+
+        return new AlertSendResponse(sendResponseStatus, sendResponseResults);
+    }
+
     @Override
     public void close() {
         log.info("Closed AlertBootstrapService...");
diff --git 
a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/service/ListenerEventPostService.java
 
b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/service/ListenerEventPostService.java
index e3a1bdefee..b57562c711 100644
--- 
a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/service/ListenerEventPostService.java
+++ 
b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/service/ListenerEventPostService.java
@@ -259,5 +259,4 @@ public final class ListenerEventPostService extends 
BaseDaemonThread implements
     public void close() {
         log.info("Closed ListenerEventPostService...");
     }
-
 }
diff --git 
a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/test/java/org/apache/dolphinscheduler/alert/runner/AlertBootstrapServiceTest.java
 
b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/test/java/org/apache/dolphinscheduler/alert/runner/AlertBootstrapServiceTest.java
index 3819200690..eafba16585 100644
--- 
a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/test/java/org/apache/dolphinscheduler/alert/runner/AlertBootstrapServiceTest.java
+++ 
b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/test/java/org/apache/dolphinscheduler/alert/runner/AlertBootstrapServiceTest.java
@@ -26,15 +26,19 @@ import org.apache.dolphinscheduler.alert.config.AlertConfig;
 import org.apache.dolphinscheduler.alert.plugin.AlertPluginManager;
 import org.apache.dolphinscheduler.alert.service.AlertBootstrapService;
 import org.apache.dolphinscheduler.common.enums.WarningType;
+import org.apache.dolphinscheduler.common.utils.JSONUtils;
 import org.apache.dolphinscheduler.dao.AlertDao;
 import org.apache.dolphinscheduler.dao.PluginDao;
 import org.apache.dolphinscheduler.dao.entity.Alert;
 import org.apache.dolphinscheduler.dao.entity.AlertPluginInstance;
+import org.apache.dolphinscheduler.dao.entity.ListenerEvent;
 import org.apache.dolphinscheduler.dao.entity.PluginDefine;
 import org.apache.dolphinscheduler.extract.alert.request.AlertSendResponse;
+import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 import org.junit.jupiter.api.Assertions;
@@ -42,6 +46,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.slf4j.Logger;
@@ -63,6 +68,18 @@ public class AlertBootstrapServiceTest {
     @InjectMocks
     private AlertBootstrapService alertBootstrapService;
 
+    private static final String PLUGIN_INSTANCE_PARAMS =
+            
"{\"User\":\"xx\",\"receivers\":\"xx\",\"sender\":\"xx\",\"smtpSslTrust\":\"*\",\"enableSmtpAuth\":\"true\",\"receiverCcs\":null,\"showType\":\"table\",\"starttlsEnable\":\"false\",\"serverPort\":\"25\",\"serverHost\":\"xx\",\"Password\":\"xx\",\"sslEnable\":\"false\"}";
+
+    private static final String PLUGIN_INSTANCE_NAME = "alert-instance-mail";
+    private static final String TITLE = "alert mail test TITLE";
+    private static final String CONTENT = "alert mail test CONTENT";
+    private static final List<ListenerEvent> EVENTS = new ArrayList<>();
+
+    private static final int PLUGIN_DEFINE_ID = 1;
+
+    private static final int ALERT_GROUP_ID = 1;
+
     @BeforeEach
     public void before() {
         MockitoAnnotations.initMocks(this);
@@ -70,17 +87,12 @@ public class AlertBootstrapServiceTest {
 
     @Test
     public void testSyncHandler() {
-
-        int alertGroupId = 1;
-        String title = "alert mail test title";
-        String content = "alert mail test content";
-
         // 1.alert instance does not exist
-        
when(alertDao.listInstanceByAlertGroupId(alertGroupId)).thenReturn(null);
+        
when(alertDao.listInstanceByAlertGroupId(ALERT_GROUP_ID)).thenReturn(null);
         when(alertConfig.getWaitTimeout()).thenReturn(0);
 
         AlertSendResponse alertSendResponse =
-                alertBootstrapService.syncHandler(alertGroupId, title, 
content, WarningType.ALL.getCode());
+                alertBootstrapService.syncHandler(ALERT_GROUP_ID, TITLE, 
CONTENT, WarningType.ALL.getCode());
         Assertions.assertFalse(alertSendResponse.isSuccess());
         alertSendResponse.getResResults().forEach(result -> logger
                 .info("alert send response result, status:{}, message:{}", 
result.isSuccess(), result.getMessage()));
@@ -101,7 +113,7 @@ public class AlertBootstrapServiceTest {
         
when(pluginDao.getPluginDefineById(pluginDefineId)).thenReturn(pluginDefine);
 
         alertSendResponse =
-                alertBootstrapService.syncHandler(alertGroupId, title, 
content, WarningType.ALL.getCode());
+                alertBootstrapService.syncHandler(ALERT_GROUP_ID, TITLE, 
CONTENT, WarningType.ALL.getCode());
         Assertions.assertFalse(alertSendResponse.isSuccess());
         alertSendResponse.getResResults().forEach(result -> logger
                 .info("alert send response result, status:{}, message:{}", 
result.isSuccess(), result.getMessage()));
@@ -113,7 +125,7 @@ public class AlertBootstrapServiceTest {
         when(alertConfig.getWaitTimeout()).thenReturn(0);
 
         alertSendResponse =
-                alertBootstrapService.syncHandler(alertGroupId, title, 
content, WarningType.ALL.getCode());
+                alertBootstrapService.syncHandler(ALERT_GROUP_ID, TITLE, 
CONTENT, WarningType.ALL.getCode());
         Assertions.assertFalse(alertSendResponse.isSuccess());
         alertSendResponse.getResResults().forEach(result -> logger
                 .info("alert send response result, status:{}, message:{}", 
result.isSuccess(), result.getMessage()));
@@ -126,7 +138,7 @@ public class AlertBootstrapServiceTest {
         
when(alertPluginManager.getAlertChannel(1)).thenReturn(Optional.of(alertChannelMock));
 
         alertSendResponse =
-                alertBootstrapService.syncHandler(alertGroupId, title, 
content, WarningType.ALL.getCode());
+                alertBootstrapService.syncHandler(ALERT_GROUP_ID, TITLE, 
CONTENT, WarningType.ALL.getCode());
         Assertions.assertFalse(alertSendResponse.isSuccess());
         alertSendResponse.getResResults().forEach(result -> logger
                 .info("alert send response result, status:{}, message:{}", 
result.isSuccess(), result.getMessage()));
@@ -140,7 +152,7 @@ public class AlertBootstrapServiceTest {
         when(alertConfig.getWaitTimeout()).thenReturn(5000);
 
         alertSendResponse =
-                alertBootstrapService.syncHandler(alertGroupId, title, 
content, WarningType.ALL.getCode());
+                alertBootstrapService.syncHandler(ALERT_GROUP_ID, TITLE, 
CONTENT, WarningType.ALL.getCode());
         Assertions.assertTrue(alertSendResponse.isSuccess());
         alertSendResponse.getResResults().forEach(result -> logger
                 .info("alert send response result, status:{}, message:{}", 
result.isSuccess(), result.getMessage()));
@@ -149,15 +161,12 @@ public class AlertBootstrapServiceTest {
 
     @Test
     public void testRun() {
-        int alertGroupId = 1;
-        String title = "alert mail test title";
-        String content = "alert mail test content";
         List<Alert> alertList = new ArrayList<>();
         Alert alert = new Alert();
         alert.setId(1);
-        alert.setAlertGroupId(alertGroupId);
-        alert.setTitle(title);
-        alert.setContent(content);
+        alert.setAlertGroupId(ALERT_GROUP_ID);
+        alert.setTitle(TITLE);
+        alert.setContent(CONTENT);
         alert.setWarningType(WarningType.FAILURE);
         alertList.add(alert);
 
@@ -170,7 +179,7 @@ public class AlertBootstrapServiceTest {
         AlertPluginInstance alertPluginInstance = new AlertPluginInstance(
                 pluginDefineId, pluginInstanceParams, pluginInstanceName);
         alertInstanceList.add(alertPluginInstance);
-        
when(alertDao.listInstanceByAlertGroupId(alertGroupId)).thenReturn(alertInstanceList);
+        
when(alertDao.listInstanceByAlertGroupId(ALERT_GROUP_ID)).thenReturn(alertInstanceList);
 
         String pluginName = "alert-plugin-mail";
         PluginDefine pluginDefine = new PluginDefine(pluginName, "1", null);
@@ -186,4 +195,20 @@ public class AlertBootstrapServiceTest {
         when(alertDao.listInstanceByAlertGroupId(1)).thenReturn(new 
ArrayList<>());
         alertBootstrapService.send(alertList);
     }
+
+    @Test
+    public void testSendAlert() {
+        AlertResult sendResult = new AlertResult();
+        sendResult.setStatus(String.valueOf(true));
+        sendResult.setMessage(String.format("Alert Plugin %s send success", 
PLUGIN_INSTANCE_NAME));
+        AlertChannel alertChannelMock = mock(AlertChannel.class);
+        when(alertChannelMock.process(Mockito.any())).thenReturn(sendResult);
+        
when(alertPluginManager.getAlertChannel(1)).thenReturn(Optional.of(alertChannelMock));
+        Map<String, String> paramsMap = 
JSONUtils.toMap(PLUGIN_INSTANCE_PARAMS);
+        MockedStatic<PluginParamsTransfer> pluginParamsTransferMockedStatic =
+                Mockito.mockStatic(PluginParamsTransfer.class);
+        pluginParamsTransferMockedStatic.when(() -> 
PluginParamsTransfer.getPluginParamsMap(PLUGIN_INSTANCE_PARAMS))
+                .thenReturn(paramsMap);
+        alertBootstrapService.syncTestSend(PLUGIN_DEFINE_ID, 
PLUGIN_INSTANCE_PARAMS);
+    }
 }
diff --git a/dolphinscheduler-api/pom.xml b/dolphinscheduler-api/pom.xml
index 40fe41c190..681a85318a 100644
--- a/dolphinscheduler-api/pom.xml
+++ b/dolphinscheduler-api/pom.xml
@@ -228,6 +228,10 @@
             <groupId>com.azure.resourcemanager</groupId>
             <artifactId>azure-resourcemanager-datafactory</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.dolphinscheduler</groupId>
+            <artifactId>dolphinscheduler-extract-alert</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <testResources>
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/AlertPluginInstanceController.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/AlertPluginInstanceController.java
index 688f2c594c..a676bf283f 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/AlertPluginInstanceController.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/AlertPluginInstanceController.java
@@ -22,6 +22,7 @@ import static 
org.apache.dolphinscheduler.api.enums.Status.DELETE_ALERT_PLUGIN_I
 import static 
org.apache.dolphinscheduler.api.enums.Status.GET_ALERT_PLUGIN_INSTANCE_ERROR;
 import static 
org.apache.dolphinscheduler.api.enums.Status.LIST_PAGING_ALERT_PLUGIN_INSTANCE_ERROR;
 import static 
org.apache.dolphinscheduler.api.enums.Status.QUERY_ALL_ALERT_PLUGIN_INSTANCE_ERROR;
+import static 
org.apache.dolphinscheduler.api.enums.Status.SEND_TEST_ALERT_PLUGIN_INSTANCE_ERROR;
 import static 
org.apache.dolphinscheduler.api.enums.Status.UPDATE_ALERT_PLUGIN_INSTANCE_ERROR;
 
 import org.apache.dolphinscheduler.api.enums.Status;
@@ -99,6 +100,19 @@ public class AlertPluginInstanceController extends 
BaseController {
         return returnDataList(result);
     }
 
+    @Operation(summary = "testSendAlertPluginInstance", description = 
"TEST_SEND_ALERT_PLUGIN_INSTANCE")
+    @Parameters({
+            @Parameter(name = "pluginDefineId", description = 
"ALERT_PLUGIN_DEFINE_ID", required = true, schema = @Schema(implementation = 
int.class, example = "100")),
+            @Parameter(name = "pluginInstanceParams", description = 
"ALERT_PLUGIN_INSTANCE_PARAMS", required = true, schema = 
@Schema(implementation = String.class, example = 
"ALERT_PLUGIN_INSTANCE_PARAMS"))
+    })
+    @PostMapping(value = "/test-send")
+    @ResponseStatus(HttpStatus.OK)
+    @ApiException(SEND_TEST_ALERT_PLUGIN_INSTANCE_ERROR)
+    public Result testSendAlertPluginInstance(@RequestParam(value = 
"pluginDefineId") int pluginDefineId,
+                                              @RequestParam(value = 
"pluginInstanceParams") String pluginInstanceParams) {
+        return alertPluginInstanceService.testSend(pluginDefineId, 
pluginInstanceParams);
+    }
+
     /**
      * updateAlertPluginInstance
      *
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
index e37eca0f3f..44f2de8604 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
@@ -472,7 +472,10 @@ public enum Status {
             "failed to delete the alert instance, there is an alarm group 
associated with this alert instance",
             "删除告警实例失败,存在与此告警实例关联的警报组"),
     PROCESS_DEFINITION_VERSION_IS_USED(110013, "this process definition 
version is used", "此工作流定义版本被使用"),
-
+    ALERT_TEST_SENDING_FAILED(110014, "Alert test sending failed, [{0}]", 
"alert测试发送失败,[{0}]"),
+    ALERT_CHANNEL_NOT_EXIST(110015, "Alert channel not exist", "alert 
channel不存在"),
+    SEND_TEST_ALERT_PLUGIN_INSTANCE_ERROR(110016, "send test alert plugin 
instance error", "发送测试告警错误"),
+    ALERT_SERVER_NOT_EXIST(110017, "Alert server does not exist", "Alert 
server不存在"),
     CREATE_ENVIRONMENT_ERROR(120001, "create environment error", "创建环境失败"),
     ENVIRONMENT_NAME_EXISTS(120002, "this environment name [{0}] already 
exists", "环境名称[{0}]已经存在"),
     ENVIRONMENT_NAME_IS_NULL(120003, "this environment name shouldn't be 
empty.", "环境名称不能为空"),
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/AlertPluginInstanceService.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/AlertPluginInstanceService.java
index 156531f160..e8679c27af 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/AlertPluginInstanceService.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/AlertPluginInstanceService.java
@@ -94,4 +94,6 @@ public interface AlertPluginInstanceService {
      * @return plugins
      */
     Result listPaging(User loginUser, String searchVal, int pageNo, int 
pageSize);
+
+    Result<Void> testSend(int pluginDefineId, String pluginInstanceParams);
 }
diff --git 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AlertPluginInstanceServiceImpl.java
 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AlertPluginInstanceServiceImpl.java
index fffb95fbcf..65ba0c0334 100644
--- 
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AlertPluginInstanceServiceImpl.java
+++ 
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/AlertPluginInstanceServiceImpl.java
@@ -31,6 +31,7 @@ import org.apache.dolphinscheduler.common.constants.Constants;
 import org.apache.dolphinscheduler.common.enums.AlertPluginInstanceType;
 import org.apache.dolphinscheduler.common.enums.AuthorizationType;
 import org.apache.dolphinscheduler.common.enums.WarningType;
+import org.apache.dolphinscheduler.common.model.Server;
 import org.apache.dolphinscheduler.common.utils.JSONUtils;
 import org.apache.dolphinscheduler.dao.entity.AlertGroup;
 import org.apache.dolphinscheduler.dao.entity.AlertPluginInstance;
@@ -39,6 +40,13 @@ import org.apache.dolphinscheduler.dao.entity.User;
 import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper;
 import org.apache.dolphinscheduler.dao.mapper.AlertPluginInstanceMapper;
 import org.apache.dolphinscheduler.dao.mapper.PluginDefineMapper;
+import org.apache.dolphinscheduler.extract.alert.IAlertOperator;
+import org.apache.dolphinscheduler.extract.alert.request.AlertSendResponse;
+import org.apache.dolphinscheduler.extract.alert.request.AlertTestSendRequest;
+import 
org.apache.dolphinscheduler.extract.base.client.SingletonJdkDynamicRpcClientProxyFactory;
+import org.apache.dolphinscheduler.extract.base.utils.Host;
+import org.apache.dolphinscheduler.registry.api.RegistryClient;
+import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
 import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer;
 
 import org.apache.commons.collections4.CollectionUtils;
@@ -82,6 +90,9 @@ public class AlertPluginInstanceServiceImpl extends 
BaseServiceImpl implements A
 
     private final Integer GLOBAL_ALERT_GROUP_ID = 2;
 
+    @Autowired
+    private RegistryClient registryClient;
+
     /**
      * creat alert plugin instance
      *
@@ -352,4 +363,49 @@ public class AlertPluginInstanceServiceImpl extends 
BaseServiceImpl implements A
         return first.isPresent();
     }
 
+    public Optional<Host> getAlertServerAddress() {
+        List<Server> serverList = 
registryClient.getServerList(RegistryNodeType.ALERT_SERVER);
+        if (CollectionUtils.isEmpty(serverList)) {
+            return Optional.empty();
+        }
+        Server server = serverList.get(0);
+        return Optional.of(new Host(server.getHost(), server.getPort()));
+    }
+
+    @Override
+    public Result<Void> testSend(int pluginDefineId, String 
pluginInstanceParams) {
+        Result<Void> result = new Result<>();
+        Optional<Host> alertServerAddressOptional = getAlertServerAddress();
+        if (!alertServerAddressOptional.isPresent()) {
+            log.error("Cannot get alert server address, please check the alert 
server is running");
+            putMsg(result, Status.ALERT_SERVER_NOT_EXIST);
+            return result;
+        }
+
+        Host alertServerAddress = alertServerAddressOptional.get();
+        AlertTestSendRequest alertTestSendRequest = new AlertTestSendRequest(
+                pluginDefineId,
+                pluginInstanceParams);
+
+        AlertSendResponse alertSendResponse;
+
+        try {
+            IAlertOperator alertOperator = 
SingletonJdkDynamicRpcClientProxyFactory
+                    .getProxyClient(alertServerAddress.getAddress(), 
IAlertOperator.class);
+            alertSendResponse = 
alertOperator.sendTestAlert(alertTestSendRequest);
+            log.info("Send alert to: {} successfully, response: {}", 
alertServerAddress, alertSendResponse);
+        } catch (Exception e) {
+            log.error("Send alert: {} to: {} failed", alertTestSendRequest, 
alertServerAddress, e);
+            putMsg(result, Status.ALERT_TEST_SENDING_FAILED, e.getMessage());
+            return result;
+        }
+
+        if (alertSendResponse.isSuccess()) {
+            putMsg(result, Status.SUCCESS);
+        } else {
+            putMsg(result, Status.ALERT_TEST_SENDING_FAILED, 
alertSendResponse.getResResults().get(0).getMessage());
+        }
+
+        return result;
+    }
 }
diff --git 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/AlertPluginInstanceControllerTest.java
 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/AlertPluginInstanceControllerTest.java
index 870fb1f82b..b2ffbe2b2f 100644
--- 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/AlertPluginInstanceControllerTest.java
+++ 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/controller/AlertPluginInstanceControllerTest.java
@@ -92,6 +92,34 @@ public class AlertPluginInstanceControllerTest extends 
AbstractControllerTest {
         
assertThat(actualResponseContent.toString()).isEqualTo(expectResponseContent.toString());
     }
 
+    @Test
+    public void testSendAlertPluginInstance() throws Exception {
+        // Given
+        Result result = JSONUtils.parseObject(
+                "{\"code\":0,\"msg\":\"success\",\"data\":\"Test 
Data\",\"success\":true,\"failed\":false}",
+                Result.class);
+
+        final MultiValueMap<String, String> paramsMap = new 
LinkedMultiValueMap<>();
+        paramsMap.add("pluginDefineId", String.valueOf(pluginDefineId));
+        paramsMap.add("pluginInstanceParams", pluginInstanceParams);
+
+        when(alertPluginInstanceService.testSend(eq(pluginDefineId), 
eq(pluginInstanceParams)))
+                .thenReturn(result);
+
+        // When
+        final MvcResult mvcResult = 
mockMvc.perform(post("/alert-plugin-instances/test-send")
+                .header(SESSION_ID, sessionId)
+                .params(paramsMap))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
+                .andReturn();
+
+        // Then
+        final Result actualResponseContent =
+                
JSONUtils.parseObject(mvcResult.getResponse().getContentAsString(), 
Result.class);
+        
assertThat(actualResponseContent.toString()).isEqualTo(expectResponseContent.toString());
+    }
+
     @Test
     public void testUpdateAlertPluginInstance() throws Exception {
         // Given
diff --git 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AlertPluginInstanceServiceTest.java
 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AlertPluginInstanceServiceTest.java
index a91d2da37f..8072c72e3b 100644
--- 
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AlertPluginInstanceServiceTest.java
+++ 
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/AlertPluginInstanceServiceTest.java
@@ -25,11 +25,13 @@ import org.apache.dolphinscheduler.api.enums.Status;
 import 
org.apache.dolphinscheduler.api.permission.ResourcePermissionCheckService;
 import 
org.apache.dolphinscheduler.api.service.impl.AlertPluginInstanceServiceImpl;
 import org.apache.dolphinscheduler.api.service.impl.BaseServiceImpl;
+import org.apache.dolphinscheduler.api.utils.Result;
 import org.apache.dolphinscheduler.common.constants.Constants;
 import org.apache.dolphinscheduler.common.enums.AlertPluginInstanceType;
 import org.apache.dolphinscheduler.common.enums.AuthorizationType;
 import org.apache.dolphinscheduler.common.enums.UserType;
 import org.apache.dolphinscheduler.common.enums.WarningType;
+import org.apache.dolphinscheduler.common.model.Server;
 import org.apache.dolphinscheduler.dao.entity.AlertGroup;
 import org.apache.dolphinscheduler.dao.entity.AlertPluginInstance;
 import org.apache.dolphinscheduler.dao.entity.PluginDefine;
@@ -37,6 +39,10 @@ import org.apache.dolphinscheduler.dao.entity.User;
 import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper;
 import org.apache.dolphinscheduler.dao.mapper.AlertPluginInstanceMapper;
 import org.apache.dolphinscheduler.dao.mapper.PluginDefineMapper;
+import org.apache.dolphinscheduler.extract.alert.request.AlertSendResponse;
+import org.apache.dolphinscheduler.extract.alert.request.AlertTestSendRequest;
+import org.apache.dolphinscheduler.registry.api.RegistryClient;
+import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -78,6 +84,9 @@ public class AlertPluginInstanceServiceTest {
     @Mock
     private AlertGroupMapper alertGroupMapper;
 
+    @Mock
+    private RegistryClient registryClient;
+
     private List<AlertPluginInstance> alertPluginInstances;
 
     private User user;
@@ -190,6 +199,26 @@ public class AlertPluginInstanceServiceTest {
         Assertions.assertNotNull(result.get(Constants.DATA_LIST));
     }
 
+    @Test
+    public void testSendAlert() {
+        Result<Void> result;
+        
Mockito.when(registryClient.getServerList(RegistryNodeType.ALERT_SERVER)).thenReturn(new
 ArrayList<>());
+        result = alertPluginInstanceService.testSend(1, uiParams);
+        Assertions.assertEquals(Status.ALERT_SERVER_NOT_EXIST.getCode(), 
result.getCode());
+        AlertSendResponse.AlertSendResponseResult alertResult = new 
AlertSendResponse.AlertSendResponseResult();
+        alertResult.setSuccess(true);
+        AlertTestSendRequest alertTestSendRequest = new AlertTestSendRequest(
+                1,
+                uiParams);
+        Server server = new Server();
+        server.setPort(50052);
+        server.setHost("127.0.0.1");
+        
Mockito.when(registryClient.getServerList(RegistryNodeType.ALERT_SERVER))
+                .thenReturn(Collections.singletonList(server));
+        result = alertPluginInstanceService.testSend(1, uiParams);
+        Assertions.assertEquals(Status.ALERT_TEST_SENDING_FAILED.getCode(), 
result.getCode());
+    }
+
     @Test
     public void testDelete() {
         List<String> ids = Arrays.asList("11,2,3", "5,96", null, "98,1");
diff --git 
a/dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/IAlertOperator.java
 
b/dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/IAlertOperator.java
index 295bd3bd62..44823c34a1 100644
--- 
a/dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/IAlertOperator.java
+++ 
b/dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/IAlertOperator.java
@@ -19,6 +19,7 @@ package org.apache.dolphinscheduler.extract.alert;
 
 import org.apache.dolphinscheduler.extract.alert.request.AlertSendRequest;
 import org.apache.dolphinscheduler.extract.alert.request.AlertSendResponse;
+import org.apache.dolphinscheduler.extract.alert.request.AlertTestSendRequest;
 import org.apache.dolphinscheduler.extract.base.RpcMethod;
 import org.apache.dolphinscheduler.extract.base.RpcService;
 
@@ -28,4 +29,7 @@ public interface IAlertOperator {
     @RpcMethod
     AlertSendResponse sendAlert(AlertSendRequest alertSendRequest);
 
+    @RpcMethod
+    AlertSendResponse sendTestAlert(AlertTestSendRequest alertSendRequest);
+
 }
diff --git 
a/dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/IAlertOperator.java
 
b/dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/request/AlertTestSendRequest.java
similarity index 64%
copy from 
dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/IAlertOperator.java
copy to 
dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/request/AlertTestSendRequest.java
index 295bd3bd62..887bc2b48f 100644
--- 
a/dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/IAlertOperator.java
+++ 
b/dolphinscheduler-extract/dolphinscheduler-extract-alert/src/main/java/org/apache/dolphinscheduler/extract/alert/request/AlertTestSendRequest.java
@@ -15,17 +15,18 @@
  * limitations under the License.
  */
 
-package org.apache.dolphinscheduler.extract.alert;
+package org.apache.dolphinscheduler.extract.alert.request;
 
-import org.apache.dolphinscheduler.extract.alert.request.AlertSendRequest;
-import org.apache.dolphinscheduler.extract.alert.request.AlertSendResponse;
-import org.apache.dolphinscheduler.extract.base.RpcMethod;
-import org.apache.dolphinscheduler.extract.base.RpcService;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 
-@RpcService
-public interface IAlertOperator {
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class AlertTestSendRequest {
 
-    @RpcMethod
-    AlertSendResponse sendAlert(AlertSendRequest alertSendRequest);
+    private int pluginDefineId;
 
+    private String pluginInstanceParams;
 }
diff --git a/dolphinscheduler-registry/dolphinscheduler-registry-api/pom.xml 
b/dolphinscheduler-registry/dolphinscheduler-registry-api/pom.xml
index 8ee7b8f6f8..5e51f68b49 100644
--- a/dolphinscheduler-registry/dolphinscheduler-registry-api/pom.xml
+++ b/dolphinscheduler-registry/dolphinscheduler-registry-api/pom.xml
@@ -33,5 +33,9 @@
             <groupId>org.apache.dolphinscheduler</groupId>
             <artifactId>dolphinscheduler-common</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.dolphinscheduler</groupId>
+            <artifactId>dolphinscheduler-extract-base</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git 
a/dolphinscheduler-registry/dolphinscheduler-registry-api/src/main/java/org/apache/dolphinscheduler/registry/api/RegistryClient.java
 
b/dolphinscheduler-registry/dolphinscheduler-registry-api/src/main/java/org/apache/dolphinscheduler/registry/api/RegistryClient.java
index f690b6800f..3193614d0d 100644
--- 
a/dolphinscheduler-registry/dolphinscheduler-registry-api/src/main/java/org/apache/dolphinscheduler/registry/api/RegistryClient.java
+++ 
b/dolphinscheduler-registry/dolphinscheduler-registry-api/src/main/java/org/apache/dolphinscheduler/registry/api/RegistryClient.java
@@ -238,5 +238,4 @@ public class RegistryClient {
     private Collection<String> getServerNodes(RegistryNodeType nodeType) {
         return getChildrenKeys(nodeType.getRegistryPath());
     }
-
 }
diff --git a/dolphinscheduler-ui/src/locales/en_US/security.ts 
b/dolphinscheduler-ui/src/locales/en_US/security.ts
index 578047fd14..b9bb18966c 100644
--- a/dolphinscheduler-ui/src/locales/en_US/security.ts
+++ b/dolphinscheduler-ui/src/locales/en_US/security.ts
@@ -168,7 +168,8 @@ export default {
     user_password: 'Password',
     user_password_tips:
       'Please enter a password containing letters and numbers with a length 
between 6 and 20',
-    confirm_password_tips: 'The both of password and confirm password are not 
same.',
+    confirm_password_tips:
+      'The both of password and confirm password are not same.',
     user_type: 'User Type',
     ordinary_user: 'Ordinary users',
     administrator: 'Administrator',
@@ -216,6 +217,7 @@ export default {
     confirm: 'Confirm',
     cancel: 'Cancel',
     submit: 'Submit',
+    test_send: 'Test Send',
     create_alarm_instance: 'Create Alarm Instance',
     select_plugin: 'Select plugin',
     select_plugin_tips: 'Select Alarm plugin',
diff --git a/dolphinscheduler-ui/src/locales/zh_CN/security.ts 
b/dolphinscheduler-ui/src/locales/zh_CN/security.ts
index 30f25e5953..b16624885b 100644
--- a/dolphinscheduler-ui/src/locales/zh_CN/security.ts
+++ b/dolphinscheduler-ui/src/locales/zh_CN/security.ts
@@ -213,6 +213,7 @@ export default {
     confirm: '确定',
     cancel: '取消',
     submit: '提交',
+    test_send: '测试发送',
     create_alarm_instance: '创建告警实例',
     select_plugin: '选择插件',
     select_plugin_tips: '请选择告警插件',
diff --git a/dolphinscheduler-ui/src/service/modules/alert-plugin/index.ts 
b/dolphinscheduler-ui/src/service/modules/alert-plugin/index.ts
index 7081438a18..4f92f7d9d6 100644
--- a/dolphinscheduler-ui/src/service/modules/alert-plugin/index.ts
+++ b/dolphinscheduler-ui/src/service/modules/alert-plugin/index.ts
@@ -21,7 +21,8 @@ import {
   PluginInstanceReq,
   InstanceNameReq,
   IdReq,
-  UpdatePluginInstanceReq
+  UpdatePluginInstanceReq,
+  TestPluginInstanceReq
 } from './types'
 
 export function queryAlertPluginInstanceListPaging(params: ListReq): any {
@@ -40,6 +41,14 @@ export function createAlertPluginInstance(data: 
PluginInstanceReq): any {
   })
 }
 
+export function testAlertPluginInstance(data: TestPluginInstanceReq): any {
+  return axios({
+    url: '/alert-plugin-instances/test-send',
+    method: 'post',
+    data
+  })
+}
+
 export function verifyAlertInstanceName(params: InstanceNameReq): any {
   return axios({
     url: '/alert-plugin-instances/verify-name',
diff --git a/dolphinscheduler-ui/src/service/modules/alert-plugin/types.ts 
b/dolphinscheduler-ui/src/service/modules/alert-plugin/types.ts
index ff977af5ab..8551c027de 100644
--- a/dolphinscheduler-ui/src/service/modules/alert-plugin/types.ts
+++ b/dolphinscheduler-ui/src/service/modules/alert-plugin/types.ts
@@ -29,6 +29,11 @@ interface PluginInstanceReq {
   pluginInstanceParams: string
 }
 
+interface TestPluginInstanceReq {
+  pluginDefineId: number
+  pluginInstanceParams: string
+}
+
 interface InstanceNameReq {
   alertInstanceName: string
 }
@@ -58,5 +63,6 @@ export {
   InstanceNameReq,
   IdReq,
   UpdatePluginInstanceReq,
-  AlertPluginItem
+  AlertPluginItem,
+  TestPluginInstanceReq
 }
diff --git 
a/dolphinscheduler-ui/src/views/security/alarm-instance-manage/detail.tsx 
b/dolphinscheduler-ui/src/views/security/alarm-instance-manage/detail.tsx
index 86e39a27f2..893b443cf9 100644
--- a/dolphinscheduler-ui/src/views/security/alarm-instance-manage/detail.tsx
+++ b/dolphinscheduler-ui/src/views/security/alarm-instance-manage/detail.tsx
@@ -23,7 +23,15 @@ import {
   ref,
   getCurrentInstance
 } from 'vue'
-import { NSelect, NInput, NSwitch, NRadioGroup, NSpace, NRadio } from 
'naive-ui'
+import {
+  NSelect,
+  NInput,
+  NSwitch,
+  NRadioGroup,
+  NSpace,
+  NRadio,
+  NButton
+} from 'naive-ui'
 import { isFunction } from 'lodash'
 import { useI18n } from 'vue-i18n'
 import { useForm } from './use-form'
@@ -69,7 +77,7 @@ const DetailModal = defineComponent({
       changePlugin
     } = useForm()
 
-    const { status, createOrUpdate } = useDetail(getFormValues)
+    const { status, createOrUpdate, testSend } = useDetail(getFormValues)
 
     const onCancel = () => {
       resetForm()
@@ -86,6 +94,11 @@ const DetailModal = defineComponent({
         ctx.emit('update')
       }
     }
+    const onTest = async () => {
+      await state.detailFormRef.validate()
+      testSend(state.json)
+    }
+
     const onChangePlugin = changePlugin
 
     const trim = getCurrentInstance()?.appContext.config.globalProperties.trim
@@ -98,7 +111,9 @@ const DetailModal = defineComponent({
     )
     watch(
       () => state.detailForm.instanceType,
-      () => warningTypeSpan.value = state.detailForm.instanceType === 'GLOBAL' 
? 0 : 24
+      () =>
+        (warningTypeSpan.value =
+          state.detailForm.instanceType === 'GLOBAL' ? 0 : 24)
     )
     watch(
       () => state.json,
@@ -131,6 +146,7 @@ const DetailModal = defineComponent({
       elements,
       onChangePlugin,
       onSubmit,
+      onTest,
       onCancel,
       trim
     }
@@ -150,7 +166,9 @@ const DetailModal = defineComponent({
       saving,
       onChangePlugin,
       onCancel,
-      onSubmit
+      onSubmit,
+      onTest,
+      testing
     } = this
     const { currentRecord } = props
     return (
@@ -195,11 +213,11 @@ const DetailModal = defineComponent({
                     label: t('security.alarm_instance.is_global_instance'),
                     widget: (
                       <NSwitch
-                      checkedValue={'GLOBAL'}
-                      uncheckedValue={'NORMAL'}
-                      disabled={!!currentRecord?.id}
-                      v-model:value={detailForm.instanceType}
-                    />
+                        checkedValue={'GLOBAL'}
+                        uncheckedValue={'NORMAL'}
+                        disabled={!!currentRecord?.id}
+                        v-model:value={detailForm.instanceType}
+                      />
                     )
                   },
                   {
@@ -208,18 +226,12 @@ const DetailModal = defineComponent({
                     span: warningTypeSpan,
                     widget: (
                       <NRadioGroup v-model:value={detailForm.warningType}>
-                      <NSpace>
-                        <NRadio value={'SUCCESS'}>
-                          {"success"}
-                        </NRadio>
-                        <NRadio value={'FAILURE'} >
-                          {"failure"}
-                        </NRadio>
-                        <NRadio value={'ALL'} >
-                          {"all"}
-                        </NRadio>
-                      </NSpace>
-                    </NRadioGroup>
+                        <NSpace>
+                          <NRadio value={'SUCCESS'}>{'success'}</NRadio>
+                          <NRadio value={'FAILURE'}>{'failure'}</NRadio>
+                          <NRadio value={'ALL'}>{'all'}</NRadio>
+                        </NSpace>
+                      </NRadioGroup>
                     )
                   },
                   {
@@ -244,6 +256,18 @@ const DetailModal = defineComponent({
                 cols: 24
               }}
             />
+          ),
+
+          'btn-middle': () => (
+            <NButton
+              class='btn-test-send'
+              type='primary'
+              size='small'
+              onClick={onTest}
+              loading={testing || loading}
+            >
+              {t('security.alarm_instance.test_send')}
+            </NButton>
           )
         }}
       </Modal>
diff --git 
a/dolphinscheduler-ui/src/views/security/alarm-instance-manage/use-detail.ts 
b/dolphinscheduler-ui/src/views/security/alarm-instance-manage/use-detail.ts
index c6ac01a528..eb208e0e96 100644
--- a/dolphinscheduler-ui/src/views/security/alarm-instance-manage/use-detail.ts
+++ b/dolphinscheduler-ui/src/views/security/alarm-instance-manage/use-detail.ts
@@ -19,14 +19,19 @@ import { reactive } from 'vue'
 import { isFunction } from 'lodash'
 import {
   createAlertPluginInstance,
+  testAlertPluginInstance,
   updateAlertPluginInstance,
   verifyAlertInstanceName
 } from '@/service/modules/alert-plugin'
 import type { IJsonItem, IRecord } from './types'
+import { useI18n } from 'vue-i18n'
 
 export function useDetail(getFormValues: Function) {
+  const { t } = useI18n()
+
   const status = reactive({
     saving: false,
+    testing: false,
     loading: false
   })
 
@@ -41,6 +46,26 @@ export function useDetail(getFormValues: Function) {
     return JSON.stringify(json)
   }
 
+  const testSend = async (json?: IJsonItem[]) => {
+    const values = getFormValues()
+
+    if (status.testing) return
+    status.testing = true
+    try {
+      const res = await testAlertPluginInstance({
+        pluginDefineId: values.pluginDefineId,
+        pluginInstanceParams: formatParams(json, values)
+      })
+      window.$message.success(
+        res
+          ? res.msg
+          : `${t('security.alarm_instance.test_send')} ${t('home.success')}`
+      )
+    } finally {
+      status.testing = false
+    }
+  }
+
   const createOrUpdate = async (currentRecord: IRecord, json?: IJsonItem[]) => 
{
     const values = getFormValues()
     if (status.saving) return false
@@ -79,5 +104,5 @@ export function useDetail(getFormValues: Function) {
     }
   }
 
-  return { status, createOrUpdate }
+  return { status, createOrUpdate, testSend }
 }

Reply via email to