diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/config/mybatis/ActableConfig.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/config/mybatis/ActableConfig.java
index d18e4650..cf6e499f 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/config/mybatis/ActableConfig.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/config/mybatis/ActableConfig.java
@@ -19,19 +19,13 @@
import com.gitee.sunchenbin.mybatis.actable.manager.handler.StartUpHandler;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
@Configuration
@Order(1)
public class ActableConfig {
-
- @Autowired
- private StartUpHandler startUpHandler;
-
- @Bean
- public void generate() {
+ public ActableConfig(@Autowired StartUpHandler startUpHandler) {
startUpHandler.startHandler();
}
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/config/mybatis/RobotConfigMigrate.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/config/mybatis/RobotConfigMigrate.java
new file mode 100644
index 00000000..a183ce74
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/config/mybatis/RobotConfigMigrate.java
@@ -0,0 +1,52 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.config.mybatis;
+
+import lombok.extern.slf4j.Slf4j;
+import org.cloud.sonic.controller.mapper.AlertRobotsMigrateMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @deprecated 保留此类一段时间,在ActableConfig完成之后执行,
+ * 如果发现旧的robot_token配置数据,则自动迁移到新的表结构中,并清空robot_token,
+ * 表结构保留原字段需要暂时保留以免ActableConfig后数据丢失,
+ * 后续完成过渡后可直接删除此类。
+ * 此过程需在ActableConfig完成后才可进行,
+ * Order等注解某些打包方式可能出现不生效问题,通过直接依赖config确保执行顺序
+ */
+@Configuration
+@Slf4j
+@Deprecated
+public class RobotConfigMigrate {
+ public RobotConfigMigrate(
+ @Autowired AlertRobotsMigrateMapper robotsMapper,
+ @Autowired ActableConfig config
+ ) {
+ if (null == config) return;
+ int n;
+ if ((n = robotsMapper.migrateProjectRobot()) > 0) {
+ log.warn("legacy project robot found! migrated to {} alert robots", n);
+ robotsMapper.clearProjectRobot();
+ }
+ if ((n = robotsMapper.migrateAgentRobot()) > 0) {
+ log.warn("legacy project robot found! migrated to {} alert robots", n);
+ robotsMapper.clearAgentRobot();
+ }
+ }
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AgentsController.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AgentsController.java
index 2463d660..23e709b6 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AgentsController.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AgentsController.java
@@ -19,9 +19,6 @@
import com.alibaba.fastjson.JSONObject;
import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.Parameters;
-import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.cloud.sonic.common.config.WebAspect;
import org.cloud.sonic.common.http.RespEnum;
@@ -75,11 +72,12 @@ public RespModel> findAgents() {
@WebAspect
@Operation(summary = "修改agent信息", description = "修改agent信息")
@PutMapping("/update")
- public RespModel update(@RequestBody JSONObject jsonObject) {
- agentsService.update(jsonObject.getInteger("id"),
- jsonObject.getString("name"), jsonObject.getInteger("highTemp"),
- jsonObject.getInteger("highTempTime"), jsonObject.getInteger("robotType"),
- jsonObject.getString("robotToken"), jsonObject.getString("robotSecret"));
+ public RespModel update(@RequestBody AgentsDTO jsonObject) {
+ agentsService.update(jsonObject.getId(),
+ jsonObject.getName(), jsonObject.getHighTemp(),
+ jsonObject.getHighTempTime(), jsonObject.getRobotType(),
+ jsonObject.getRobotToken(), jsonObject.getRobotToken(),
+ jsonObject.getAlertRobotIds());
return new RespModel<>(RespEnum.HANDLE_OK);
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AlertRobotsAdminController.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AlertRobotsAdminController.java
new file mode 100644
index 00000000..61966f2d
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AlertRobotsAdminController.java
@@ -0,0 +1,104 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.cloud.sonic.common.config.WebAspect;
+import org.cloud.sonic.common.config.WhiteUrl;
+import org.cloud.sonic.common.http.RespEnum;
+import org.cloud.sonic.common.http.RespModel;
+import org.cloud.sonic.controller.models.base.CommentPage;
+import org.cloud.sonic.controller.models.domain.AlertRobots;
+import org.cloud.sonic.controller.models.dto.AlertRobotsDTO;
+import org.cloud.sonic.controller.services.AlertRobotsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Tag(name = "告警通知机器人相关")
+@RestController
+@RequestMapping("/alertRobotsAdmin")
+public class AlertRobotsAdminController {
+
+ @Autowired
+ private AlertRobotsService alertRobotsService;
+
+ @WebAspect
+ @Operation(summary = "更新机器人参数", description = "新增或更新对应的机器人")
+ @PutMapping
+ public RespModel save(@Validated @RequestBody AlertRobotsDTO alertRobotsDTO) {
+ alertRobotsService.saveOrUpdate(alertRobotsDTO.convertTo());
+ return new RespModel<>(RespEnum.UPDATE_OK);
+ }
+
+ @WebAspect
+ @Operation(summary = "查找机器人参数", description = "查找所有机器人参数列表")
+ @GetMapping("/list")
+ @Parameters(value = {
+ @Parameter(name = "scene", allowEmptyValue = true, description = "使用场景"),
+ @Parameter(name = "page", description = "页码"),
+ @Parameter(name = "pageSize", description = "页尺寸")
+ })
+ public RespModel> listAll(
+ @RequestParam(name = "scene", required = false) String scene,
+ @RequestParam(name = "page") int page,
+ @RequestParam(name = "pageSize", defaultValue = "20") int pageSize
+ ) {
+ return new RespModel<>(RespEnum.SEARCH_OK, alertRobotsService.findRobots(new Page<>(page, pageSize), null, scene));
+ }
+
+ @WebAspect
+ @Operation(summary = "查找机器人参数", description = "查找所有机器人参数列表")
+ @GetMapping("/listAll")
+ @Parameters(value = {
+ @Parameter(name = "scene", allowEmptyValue = true, description = "使用场景")
+ })
+ public RespModel> listAll(
+ @RequestParam(name = "scene", required = false) String scene
+ ) {
+ return new RespModel<>(RespEnum.SEARCH_OK, alertRobotsService.findAllRobots(null, scene));
+ }
+
+ @WebAspect
+ @Operation(summary = "删除机器人参数", description = "删除对应id的机器人参数")
+ @Parameter(name = "id", description = "id")
+ @DeleteMapping
+ public RespModel delete(@RequestParam(name = "id") int id) {
+ if (alertRobotsService.removeById(id)) {
+ return new RespModel<>(RespEnum.DELETE_OK);
+ } else {
+ return new RespModel<>(RespEnum.DELETE_FAIL);
+ }
+ }
+
+ @WebAspect
+ @Operation(summary = "获取机器人对类型机器人在相应使用场景下的默认模板", description = "获取机器人对类型机器人在相应使用场景下的默认模板")
+ @Parameter(name = "type", description = "type")
+ @Parameter(name = "scene", description = "scene")
+ @GetMapping("/findDefaultTemplate")
+ @WhiteUrl
+ public RespModel getDefaultNoticeTemplate(@RequestParam(name = "type") int type, @RequestParam(name = "scene") String scene) {
+ return new RespModel<>(RespEnum.SEARCH_OK, alertRobotsService.getDefaultNoticeTemplate(type, scene));
+ }
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AlertRobotsController.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AlertRobotsController.java
new file mode 100644
index 00000000..727af057
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/controller/AlertRobotsController.java
@@ -0,0 +1,112 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.cloud.sonic.common.config.WebAspect;
+import org.cloud.sonic.common.config.WhiteUrl;
+import org.cloud.sonic.common.http.RespEnum;
+import org.cloud.sonic.common.http.RespModel;
+import org.cloud.sonic.controller.models.base.CommentPage;
+import org.cloud.sonic.controller.models.domain.AlertRobots;
+import org.cloud.sonic.controller.models.dto.AlertRobotsDTO;
+import org.cloud.sonic.controller.services.AlertRobotsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+@Tag(name = "告警通知机器人相关")
+@RestController
+@RequestMapping("/alertRobots")
+public class AlertRobotsController {
+
+ @Autowired
+ private AlertRobotsService alertRobotsService;
+
+ @WebAspect
+ @Operation(summary = "更新机器人参数", description = "新增或更新对应的机器人")
+ @PutMapping
+ public RespModel save(@Validated @RequestBody AlertRobotsDTO alertRobotsDTO) {
+ alertRobotsService.saveOrUpdate(alertRobotsDTO.convertTo());
+ return new RespModel<>(RespEnum.UPDATE_OK);
+ }
+
+ @WebAspect
+ @Operation(summary = "查找项目机器人参数", description = "查找对应项目id的机器人参数列表")
+ @GetMapping("/list")
+ @Parameters(value = {
+ @Parameter(name = "projectId", description = "项目id"),
+ @Parameter(name = "scene", allowEmptyValue = true, description = "使用场景"),
+ @Parameter(name = "page", description = "页码"),
+ @Parameter(name = "pageSize", description = "页尺寸")
+ })
+ public RespModel> list(
+ @RequestParam(name = "projectId") int projectId,
+ @RequestParam(name = "scene", required = false) String scene,
+ @RequestParam(name = "page") int page,
+ @RequestParam(name = "pageSize", defaultValue = "20") int pageSize
+ ) {
+ return new RespModel<>(RespEnum.SEARCH_OK, alertRobotsService.findRobots(new Page<>(page, pageSize), projectId, scene));
+ }
+
+ @WebAspect
+ @Operation(summary = "查找项目机器人参数", description = "查找对应项目id的机器人参数列表")
+ @GetMapping("/listAll")
+ @Parameters(value = {
+ @Parameter(name = "projectId", allowEmptyValue = true, description = "项目id"),
+ @Parameter(name = "scene", allowEmptyValue = true, description = "使用场景")
+ })
+ public RespModel> listAll(
+ @RequestParam(name = "projectId", required = false, defaultValue = "-1") int projectId,
+ @RequestParam(name = "scene", required = false) String scene
+ ) {
+ return new RespModel<>(RespEnum.SEARCH_OK, alertRobotsService.findAllRobots(projectId, scene));
+ }
+
+ @WebAspect
+ @Operation(summary = "删除机器人参数", description = "删除对应id的机器人参数")
+ @Parameter(name = "id", description = "id")
+ @DeleteMapping
+ public RespModel delete(
+ @Parameter(name = "projectId", description = "项目id") int projectId,
+ @RequestParam(name = "id") int id
+ ) {
+ if (alertRobotsService.removeByMap(Map.of("id", id, "projectId", projectId))) {
+ return new RespModel<>(RespEnum.DELETE_OK);
+ } else {
+ return new RespModel<>(RespEnum.DELETE_FAIL);
+ }
+ }
+
+ @WebAspect
+ @Operation(summary = "获取机器人对类型机器人在相应使用场景下的默认模板", description = "获取机器人对类型机器人在相应使用场景下的默认模板")
+ @Parameter(name = "type", description = "type")
+ @Parameter(name = "scene", description = "scene")
+ @GetMapping("/findDefaultTemplate")
+ @WhiteUrl
+ public RespModel getDefaultNoticeTemplate(@RequestParam(name = "type") int type, @RequestParam(name = "scene") String scene) {
+ return new RespModel<>(RespEnum.SEARCH_OK, alertRobotsService.getDefaultNoticeTemplate(type, scene));
+ }
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/mapper/AlertRobotsMapper.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/mapper/AlertRobotsMapper.java
new file mode 100644
index 00000000..0d6b3b79
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/mapper/AlertRobotsMapper.java
@@ -0,0 +1,84 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.cloud.sonic.controller.models.domain.AlertRobots;
+import org.springframework.lang.Nullable;
+
+import java.util.List;
+
+public interface AlertRobotsMapper extends BaseMapper {
+ @Select("""
+ select ifnull(alert_robot_ids,(select testsuite_alert_robot_ids from projects p where p.id = ts.project_id))
+ as alert_robot_ids from test_suites ts where id = #{suiteId}
+ """)
+ @Nullable String getIdsForTestsuite(@Param("suiteId") int suiteId);
+
+ @Select("""
+
+ """)
+ List listTestsuiteRobotsFromIds(@Param("ids") @Nullable String ids, @Param("suiteId") int suiteId);
+
+ default List computeTestsuiteRobots(int suiteId) {
+ var ids = getIdsForTestsuite(suiteId);
+ if ("".equals(ids)) return List.of();
+ return listTestsuiteRobotsFromIds(ids, suiteId);
+ }
+
+ @Select("select alert_robot_ids from agents where id = #{agentId}")
+ @Nullable String getIdsForAgent(@Param("agentId") int agentId);
+
+ @Select("""
+ """)
+ List listAgentRobotsFromIds(@Param("ids") @Nullable String ids);
+
+ default List computeAgentRobots(int agentId) {
+ String ids = getIdsForAgent(agentId);
+ if ("".equals(ids)) return List.of();
+ return listAgentRobotsFromIds(ids);
+ }
+
+ @Select("""
+ select * from alert_robots r where scene = 'summary'
+ and (
+ r.project_id = ${projectId} or
+ (r.project_id is null and 1 = (select global_robot from projects where id = ${projectId})
+ )
+ """)
+ List computeSummaryRobots(@Param("projectId") int projectId);
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/mapper/AlertRobotsMigrateMapper.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/mapper/AlertRobotsMigrateMapper.java
new file mode 100644
index 00000000..7b42d853
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/mapper/AlertRobotsMigrateMapper.java
@@ -0,0 +1,54 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.mapper;
+
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * @see org.cloud.sonic.controller.config.mybatis.RobotConfigMigrate
+ * @deprecated
+ */
+@Deprecated
+public interface AlertRobotsMigrateMapper {
+
+ @Insert("""
+ INSERT into alert_robots (robot_secret, robot_token, robot_type, project_id, name, scene)
+ SELECT robot_secret, robot_token, robot_type, id, project_name, 'summary'
+ FROM projects
+ WHERE robot_type > 0 and robot_token != ''
+ UNION ALL
+ SELECT robot_secret, robot_token, robot_type, id, project_name, 'testsuite'
+ FROM projects
+ WHERE robot_type > 0 and robot_token != ''
+ """)
+ int migrateProjectRobot();
+ @Update("update projects set robot_type = -robot_type where robot_type > 0")
+ void clearProjectRobot();
+
+ @Insert("""
+ INSERT into alert_robots (robot_secret, robot_token, robot_type, project_id, name, scene)
+ SELECT robot_secret, robot_token, robot_type, null, 'agent', 'agent'
+ FROM agents
+ WHERE robot_type > 0 and robot_token != ''
+ """)
+ int migrateAgentRobot();
+
+ @Update("update agents set robot_type = -robot_type where robot_type > 0")
+ void clearAgentRobot();
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/Agents.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/Agents.java
index ed159a01..4766a6c0 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/Agents.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/Agents.java
@@ -1,12 +1,10 @@
package org.cloud.sonic.controller.models.domain;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.*;
import com.gitee.sunchenbin.mybatis.actable.annotation.*;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlCharsetConstant;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlEngineConstant;
+import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -15,6 +13,7 @@
import lombok.experimental.Accessors;
import org.cloud.sonic.controller.models.base.TypeConverter;
import org.cloud.sonic.controller.models.dto.AgentsDTO;
+import org.cloud.sonic.controller.tools.NullableIntArrayTypeHandler;
import java.io.Serializable;
@@ -28,7 +27,7 @@
@Builder
@NoArgsConstructor
@AllArgsConstructor
-@TableName("agents")
+@TableName(value = "agents", autoResultMap = true)
@TableComment("agents表")
@TableCharset(MySqlCharsetConstant.DEFAULT)
@TableEngine(MySqlEngineConstant.InnoDB)
@@ -78,14 +77,29 @@ public class Agents implements Serializable, TypeConverter {
@Column(value = "high_temp_time", isNull = false, comment = "highTempTime", defaultValue = "15")
private Integer highTempTime;
+ /**
+ * @see org.cloud.sonic.controller.config.mybatis.RobotConfigMigrate
+ * @deprecated
+ */
+ @Deprecated(forRemoval = true)
@TableField
@Column(value = "robot_secret", isNull = false, comment = "机器人秘钥", defaultValue = "")
private String robotSecret;
+ /**
+ * @see org.cloud.sonic.controller.config.mybatis.RobotConfigMigrate
+ * @deprecated
+ */
+ @Deprecated(forRemoval = true)
@TableField
@Column(value = "robot_token", isNull = false, comment = "机器人token", defaultValue = "")
private String robotToken;
+ /**
+ * @see org.cloud.sonic.controller.config.mybatis.RobotConfigMigrate
+ * @deprecated
+ */
+ @Deprecated(forRemoval = true)
@TableField
@Column(value = "robot_type", isNull = false, comment = "机器人类型", defaultValue = "1")
private Integer robotType;
@@ -93,4 +107,8 @@ public class Agents implements Serializable, TypeConverter {
@TableField
@Column(value = "has_hub", isNull = false, comment = "是否使用了Sonic hub", defaultValue = "0")
private Integer hasHub;
+
+ @TableField(typeHandler = NullableIntArrayTypeHandler.class, updateStrategy = FieldStrategy.IGNORED)
+ @Column(value = "alert_robot_ids", type = MySqlTypeConstant.VARCHAR, length = 1024, comment = "逗号分隔通知机器人id串,为null时自动选取所有可用机器人")
+ private int[] alertRobotIds;
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/AlertRobots.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/AlertRobots.java
new file mode 100644
index 00000000..018d0c69
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/AlertRobots.java
@@ -0,0 +1,82 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.models.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.gitee.sunchenbin.mybatis.actable.annotation.*;
+import com.gitee.sunchenbin.mybatis.actable.constants.MySqlCharsetConstant;
+import com.gitee.sunchenbin.mybatis.actable.constants.MySqlEngineConstant;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import org.cloud.sonic.controller.models.base.TypeConverter;
+import org.cloud.sonic.controller.models.dto.AlertRobotsDTO;
+
+import java.io.Serializable;
+
+
+@Schema(name = "AlertRobots对象", description = "")
+@Data
+@Accessors(chain = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("alert_robots")
+@TableComment("alert_robots表")
+@TableCharset(MySqlCharsetConstant.DEFAULT)
+@TableEngine(MySqlEngineConstant.InnoDB)
+public class AlertRobots implements Serializable, TypeConverter {
+
+ @TableId(value = "id", type = IdType.AUTO)
+ @IsAutoIncrement
+ private Integer id;
+
+ @TableField(updateStrategy = FieldStrategy.IGNORED)
+ @Column(value = "project_id", comment = "可用项目id, null为公共机器人")
+ @Index(value = "IDX_PROJECT_ID", columns = {"project_id"})
+ private Integer projectId;
+
+ @TableField
+ @Column(isNull = false, comment = "显示名称")
+ private String name;
+
+ @TableField
+ @Column(value = "robot_secret", comment = "机器人秘钥")
+ private String robotSecret;
+
+ @TableField
+ @Column(value = "robot_token", isNull = false, comment = "机器人token/接口uri")
+ private String robotToken;
+
+ @TableField
+ @Column(value = "robot_type", isNull = false, comment = "机器人类型")
+ private Integer robotType;
+
+ @TableField
+ @Column(value = "scene", isNull = false, comment = "使用场景,可选 agent, testsuite, summary")
+ private String scene;
+
+ @Column(value = "mute_rule", length = 1024, isNull = false, defaultValue = "", comment = "静默规则,SpEL表达式,表达式求值为true时不发送消息,否则正常发送")
+ private String muteRule;
+
+ @Column(value = "template", length = 4096, isNull = false, defaultValue = "", comment = "通知模板,SpEL表达式,表达式为空时机器人类型自动使用默认值")
+ private String template;
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/Projects.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/Projects.java
index 50d44f6d..da6da7dd 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/Projects.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/domain/Projects.java
@@ -14,6 +14,7 @@
import lombok.experimental.Accessors;
import org.cloud.sonic.controller.models.base.TypeConverter;
import org.cloud.sonic.controller.models.dto.ProjectsDTO;
+import org.cloud.sonic.controller.tools.NullableIntArrayTypeHandler;
import java.io.Serializable;
import java.util.Date;
@@ -28,7 +29,7 @@
@Builder
@NoArgsConstructor
@AllArgsConstructor
-@TableName("projects")
+@TableName(value = "projects", autoResultMap = true)
@TableComment("项目表")
@TableCharset(MySqlCharsetConstant.DEFAULT)
@TableEngine(MySqlEngineConstant.InnoDB)
@@ -55,15 +56,38 @@ public class Projects implements Serializable, TypeConverter
@Schema(description = "highTempTime", example = "10")
Integer highTempTime;
+ /**
+ * @see org.cloud.sonic.controller.config.mybatis.RobotConfigMigrate
+ * @deprecated
+ */
+ @Deprecated(forRemoval = true)
@Schema(description = "机器人类型", example = "1")
Integer robotType;
+ /**
+ * @see org.cloud.sonic.controller.config.mybatis.RobotConfigMigrate
+ * @deprecated
+ */
+ @Deprecated(forRemoval = true)
@Schema(description = "机器人token", example = "token")
String robotToken;
+ /**
+ * @see org.cloud.sonic.controller.config.mybatis.RobotConfigMigrate
+ * @deprecated
+ */
+ @Deprecated(forRemoval = true)
@Schema(description = "机器人加签密钥", example = "key")
String robotSecret;
@Schema(description = "是否使用sonic hub", example = "1")
Integer hasHub;
+
+ @Schema(description = "通知机器人id串,为null时自动选取所有可用机器人", example = "[1,2]")
+ int[] alertRobotIds;
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/dto/AlertRobotsDTO.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/dto/AlertRobotsDTO.java
new file mode 100644
index 00000000..95da5ea8
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/dto/AlertRobotsDTO.java
@@ -0,0 +1,57 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.models.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import org.cloud.sonic.controller.models.base.TypeConverter;
+import org.cloud.sonic.controller.models.domain.AlertRobots;
+
+import java.io.Serializable;
+
+@Schema(name = "告警通知机器人DTO 模型")
+@Data
+@Accessors(chain = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AlertRobotsDTO implements Serializable, TypeConverter {
+
+ @Schema(description = "通知机器人id", example = "1")
+ Integer id;
+ @Schema(description = "机器人类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ Integer robotType;
+ @Schema(description = "机器人token", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://dingTalk.com?token=*****")
+ String robotToken;
+ @Schema(description = "机器人加签密钥", example = "qwe***")
+ String robotSecret;
+ @Schema(description = "机器人配置显示名称", example = "1")
+ private String name;
+ @Schema(description = "所属项目id,不属于任何项目的系统级机器人此项为null", example = "1")
+ private Integer projectId;
+ @Schema(description = "通知类型,可选 agent, testsuite, summary", example = "testsuite")
+ private String scene;
+ @Schema(description = "静默规则,SpEL表达式,表达式求值为真时不发送消息", example = "error == 0 && fail == 0")
+ private String muteRule;
+ @Schema(description = "通知模板,SpEL表达式,表达式为null时采用相应 机器人类型 的缺省模板", example = "alert! pass count is #{pass}, error count is #{error}")
+ private String template;
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/dto/ProjectsDTO.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/dto/ProjectsDTO.java
index b4754f88..d8d7903d 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/dto/ProjectsDTO.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/dto/ProjectsDTO.java
@@ -32,12 +32,27 @@ public class ProjectsDTO implements Serializable, TypeConverter devices;
+
+ @Schema(description = "测试套件默认通知机器人id串,为null时取项目配置的默认值", example = "[1,2]")
+ int[] alertRobotIds;
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/interfaces/RobotType.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/interfaces/RobotType.java
index cd2be166..145f00c7 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/interfaces/RobotType.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/models/interfaces/RobotType.java
@@ -8,4 +8,6 @@ public interface RobotType {
int Telegram = 5;
int LineNotify = 6;
int SlackNotify = 7;
+
+ int WebHook = 8;
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/AgentsService.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/AgentsService.java
index 7a6603f2..a3559268 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/AgentsService.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/AgentsService.java
@@ -31,9 +31,7 @@
public interface AgentsService extends IService {
List findAgents();
- void update(int id, String name, int highTemp, int highTempTime, int robotType, String robotToken, String robotSecret);
-
- // todo 删除
+ void update(int id, String name, int highTemp, int highTempTime, int robotType, String robotToken, String robotSecret, int[] alertRobotIds);
boolean offLine(int id);
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/AlertRobotsService.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/AlertRobotsService.java
new file mode 100644
index 00000000..5146f6f8
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/AlertRobotsService.java
@@ -0,0 +1,44 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.services;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.cloud.sonic.controller.models.base.CommentPage;
+import org.cloud.sonic.controller.models.domain.AlertRobots;
+
+import java.util.Date;
+import java.util.List;
+
+public interface AlertRobotsService extends IService {
+ String SCENE_AGENT = "agent";
+ String SCENE_TESTSUITE = "testsuite";
+ String SCENE_SUMMARY = "summary";
+
+ CommentPage findRobots(Page page, Integer projectId, String scene);
+
+ List findAllRobots(Integer projectId, String scene);
+
+ void sendResultFinishReport(int suitId, String suiteName, int pass, int warn, int fail, int projectId, int resultId);
+
+ void sendProjectReportMessage(int projectId, String projectName, Date startDate, Date endDate, boolean isWeekly, int pass, int warn, int fail);
+
+ void sendErrorDevice(int agentId, int errorType, int tem, String udId);
+
+ String getDefaultNoticeTemplate(int type, String scene);
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/AgentsServiceImpl.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/AgentsServiceImpl.java
index e35637b5..1f0d03d8 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/AgentsServiceImpl.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/AgentsServiceImpl.java
@@ -28,7 +28,6 @@
import org.cloud.sonic.controller.services.AgentsService;
import org.cloud.sonic.controller.services.DevicesService;
import org.cloud.sonic.controller.services.impl.base.SonicServiceImpl;
-import org.cloud.sonic.controller.tools.RobotMsgTool;
import org.cloud.sonic.controller.transport.TransportWorker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -44,7 +43,7 @@ public class AgentsServiceImpl extends SonicServiceImpl im
@Autowired
private DevicesService devicesService;
@Autowired
- private RobotMsgTool robotMsgTool;
+ private AlertRobotsServiceImpl alertRobotsService;
@Autowired
private AgentsMapper agentsMapper;
@@ -54,7 +53,7 @@ public List findAgents() {
}
@Override
- public void update(int id, String name, int highTemp, int highTempTime, int robotType, String robotToken, String robotSecret) {
+ public void update(int id, String name, int highTemp, int highTempTime, int robotType, String robotToken, String robotSecret, int[] alertRobotIds) {
if (id == 0) {
Agents agents = new Agents();
agents.setName(name);
@@ -70,6 +69,7 @@ public void update(int id, String name, int highTemp, int highTempTime, int robo
agents.setRobotSecret(robotSecret);
agents.setSecretKey(UUID.randomUUID().toString());
agents.setHasHub(0);
+ agents.setAlertRobotIds(alertRobotIds);
save(agents);
} else {
Agents ag = findById(id);
@@ -80,6 +80,7 @@ public void update(int id, String name, int highTemp, int highTempTime, int robo
ag.setRobotType(robotType);
ag.setRobotToken(robotToken);
ag.setRobotSecret(robotSecret);
+ ag.setAlertRobotIds(alertRobotIds);
save(ag);
JSONObject result = new JSONObject();
result.put("msg", "settings");
@@ -169,9 +170,6 @@ public Agents findBySecretKey(String secretKey) {
@Override
public void errCall(int id, String udId, int tem, int type) {
- Agents agents = findById(id);
- if (agents != null && agents.getRobotType() != 0 && agents.getRobotToken().length() > 0 && agents.getRobotSecret().length() > 0) {
- robotMsgTool.sendErrorDevice(agents.getRobotToken(), agents.getRobotSecret(), agents.getRobotType(), type, tem, udId);
- }
+ alertRobotsService.sendErrorDevice(id, type, tem, udId);
}
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/AlertRobotsServiceImpl.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/AlertRobotsServiceImpl.java
new file mode 100644
index 00000000..bfd16497
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/AlertRobotsServiceImpl.java
@@ -0,0 +1,128 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.services.impl;
+
+import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+import org.cloud.sonic.controller.mapper.AlertRobotsMapper;
+import org.cloud.sonic.controller.models.base.CommentPage;
+import org.cloud.sonic.controller.models.domain.AlertRobots;
+import org.cloud.sonic.controller.services.AlertRobotsService;
+import org.cloud.sonic.controller.services.impl.base.SonicServiceImpl;
+import org.cloud.sonic.controller.tools.robot.Message;
+import org.cloud.sonic.controller.tools.robot.RobotFactory;
+import org.cloud.sonic.controller.tools.robot.message.DeviceMessage;
+import org.cloud.sonic.controller.tools.robot.message.ProjectSummaryMessage;
+import org.cloud.sonic.controller.tools.robot.message.TestSuiteMessage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+import java.util.List;
+
+@Service
+@Slf4j
+public class AlertRobotsServiceImpl extends SonicServiceImpl implements AlertRobotsService {
+
+ @Value("${robot.client.host}")
+ private String clientHost;
+
+ @Autowired
+ private RobotFactory robotFactory;
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Override
+ public CommentPage findRobots(Page page, Integer projectId, String scene) {
+ return CommentPage.convertFrom(findRobots(projectId, scene).page(page));
+ }
+
+ @Override
+ public List findAllRobots(Integer projectId, String scene) {
+ return findRobots(projectId, scene).list();
+ }
+
+ private LambdaQueryChainWrapper findRobots(Integer projectId, String scene) {
+ var query = lambdaQuery();
+ query.eq(null != scene, AlertRobots::getScene, scene);
+ query.and(null != projectId,
+ it -> it.eq(AlertRobots::getProjectId, projectId).or(
+ p -> p.apply("1 = (select global_robot from projects where id = {0})", projectId).isNull(AlertRobots::getProjectId)
+ )
+ );
+ return query;
+ }
+
+ @Override
+ public void sendResultFinishReport(int suitId, String suiteName, int pass, int warn, int fail, int projectId, int resultId) {
+ var robots = baseMapper.computeTestsuiteRobots(suitId);
+ if (robots.isEmpty()) return;
+ var msg = new TestSuiteMessage(suiteName, pass, warn, fail, projectId, resultId, clientHost + "/Home/" + projectId + "/ResultDetail/" + resultId);
+ send(robots, msg);
+ }
+
+ @Override
+ public void sendProjectReportMessage(int projectId, String projectName, Date startDate, Date endDate, boolean isWeekly, int pass, int warn, int fail) {
+ var robots = baseMapper.computeSummaryRobots(projectId);
+ if (robots.isEmpty()) return;
+ var total = pass + warn + fail;
+ var rate = total > 0 ? BigDecimal.valueOf(((float) pass / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0;
+ var url = clientHost + "/Home/" + projectId;
+ var msg = new ProjectSummaryMessage(projectId, projectName, startDate, endDate, pass, warn, fail, rate, total, url, isWeekly);
+ send(robots, msg);
+ }
+
+ @Override
+ public void sendErrorDevice(int agentId, int errorType, int tem, String udId) {
+ var robots = baseMapper.computeAgentRobots(agentId);
+ if (robots.isEmpty()) return;
+ var msg = new DeviceMessage(errorType, tem, udId);
+ send(robots, msg);
+ }
+
+ private void send(List robots, Message message) {
+ for (var robot : robots) {
+ try {
+ var messenger = robotFactory.getRobotMessenger(robot.getRobotType(), robot.getMuteRule());
+ if (messenger == null) continue;
+ var template = robot.getTemplate();
+ messenger.sendMessage(restTemplate, robot.getRobotToken(), robot.getRobotSecret(), template, message);
+ } catch (Exception e) {
+ log.warn("send messaget to robot {} failed, skipping", robot, e);
+ }
+ }
+ }
+
+ @Override
+ public String getDefaultNoticeTemplate(int type, String scene) {
+ var messenger = robotFactory.getRobotMessenger(type);
+ return switch (scene) {
+ case SCENE_AGENT -> messenger.getDefaultDeviceMessageTemplate().getExpressionString();
+ case SCENE_SUMMARY -> messenger.getDefaultProjectSummaryTemplate().getExpressionString();
+ case SCENE_TESTSUITE -> messenger.getDefaultTestSuiteTemplate().getExpressionString();
+ default -> "";
+ };
+ }
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/ResultsServiceImpl.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/ResultsServiceImpl.java
index 46769322..8e5d10c4 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/ResultsServiceImpl.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/services/impl/ResultsServiceImpl.java
@@ -31,7 +31,6 @@
import org.cloud.sonic.controller.models.interfaces.ResultStatus;
import org.cloud.sonic.controller.services.*;
import org.cloud.sonic.controller.services.impl.base.SonicServiceImpl;
-import org.cloud.sonic.controller.tools.RobotMsgTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -61,7 +60,7 @@ public class ResultsServiceImpl extends SonicServiceImpl
@Autowired
private ProjectsService projectsService;
@Autowired
- private RobotMsgTool robotMsgTool;
+ private AlertRobotsService alertRobotsService;
@Autowired
private TestSuitesService testSuitesService;
@Autowired
@@ -239,10 +238,7 @@ public void sendDayReport() {
break;
}
}
- if (projects.getRobotType() != 0 && projects.getRobotToken().length() > 0) {
- robotMsgTool.sendDayReportMessage(projects.getRobotToken(), projects.getRobotSecret(), projects.getId()
- , projects.getProjectName(), sf.format(yesterday), sf.format(today), suc, warn, fail, projects.getRobotType());
- }
+ alertRobotsService.sendProjectReportMessage(projects.getId(), projects.getProjectName(), yesterday, today, false, suc, warn, fail);
}
}
@@ -273,10 +269,7 @@ public void sendWeekReport() {
break;
}
}
- if (projects.getRobotType() != 0 && projects.getRobotToken().length() > 0) {
- robotMsgTool.sendWeekReportMessage(projects.getRobotToken(), projects.getRobotSecret(), projects.getId()
- , projects.getProjectName(), sf.format(lastWeek), sf.format(today), suc, warn, fail, count, projects.getRobotType());
- }
+ alertRobotsService.sendProjectReportMessage(projects.getId(), projects.getProjectName(), lastWeek, today, true, suc, warn, fail);
}
}
@@ -336,11 +329,8 @@ public void setStatus(Results results) {
if (results.getReceiveMsgCount() == results.getSendMsgCount()) {
results.setEndTime(new Date());
save(results);
- Projects projects = projectsService.findById(results.getProjectId());
- if (projects != null && projects.getRobotType() != 0 && projects.getRobotToken().length() > 0) {
- robotMsgTool.sendResultFinishReport(projects.getRobotToken(), projects.getRobotSecret(),
- results.getSuiteName(), sucCount, warnCount, failCount, projects.getId(), results.getId(), projects.getRobotType());
- }
+ alertRobotsService.sendResultFinishReport(results.getSuiteId(),
+ results.getSuiteName(), sucCount, warnCount, failCount, results.getProjectId(), results.getId());
}
}
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/NullableIntArrayTypeHandler.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/NullableIntArrayTypeHandler.java
new file mode 100644
index 00000000..d98ca275
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/NullableIntArrayTypeHandler.java
@@ -0,0 +1,67 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.tools;
+
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+import org.apache.ibatis.type.TypeHandler;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+@MappedTypes(int[].class)
+@MappedJdbcTypes(JdbcType.VARCHAR)
+public class NullableIntArrayTypeHandler implements TypeHandler {
+ @Override
+ public void setParameter(PreparedStatement preparedStatement, int i, int[] param, JdbcType jdbcType) throws SQLException {
+ if (null == param) {
+ preparedStatement.setNull(i, jdbcType.TYPE_CODE);
+ } else {
+ preparedStatement.setString(i, Arrays.stream(param).mapToObj(Integer::toString).collect(Collectors.joining(",")));
+ }
+ }
+
+ @Override
+ public int[] getResult(ResultSet resultSet, String s) throws SQLException {
+ return parseString(resultSet.getString(s));
+ }
+
+ @Override
+ public int[] getResult(ResultSet resultSet, int i) throws SQLException {
+ return parseString(resultSet.getString(i));
+ }
+
+ @Override
+ public int[] getResult(CallableStatement callableStatement, int i) throws SQLException {
+ return parseString(callableStatement.getString(i));
+ }
+
+ private int[] parseString(String ret) {
+ if (ret == null) return null;
+ try {
+ return Arrays.stream(ret.split(",", 0)).mapToInt(Integer::valueOf).toArray();
+ } catch (NumberFormatException e) {
+ return new int[0];
+ }
+ }
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/RobotMsgTool.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/RobotMsgTool.java
deleted file mode 100644
index 55029104..00000000
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/RobotMsgTool.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * sonic-server Sonic Cloud Real Machine Platform.
- * Copyright (C) 2022 SonicCloudOrg
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package org.cloud.sonic.controller.tools;
-
-import org.cloud.sonic.controller.tools.robot.RobotFactory;
-import org.cloud.sonic.controller.tools.robot.RobotMessenger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-
-/**
- * @author ZhouYiXun
- * @des 机器人推送相关工具类
- * @date 2021/8/15 18:20
- */
-@Component
-public class RobotMsgTool {
-
- @Autowired
- private RobotFactory robotFactory;
-
- @Autowired
- private RestTemplate restTemplate;
-
- /**
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param suiteName 套件名称
- * @param pass 通过数量
- * @param warn 警告数量
- * @param fail 失败数量
- * @param projectId 项目id
- * @param resultId 结果id
- * @return void
- * @author ZhouYiXun
- * @des 发送每次测试结果到钉钉
- * @date 2021/8/20 18:29
- */
- public void sendResultFinishReport(String token, String secret, String suiteName, int pass,
- int warn, int fail, int projectId, int resultId, int type) {
- RobotMessenger robotMessenger = robotFactory.getRobotMessenger(type);
- robotMessenger.sendResultFinishReport(restTemplate, token, secret, suiteName, pass, warn, fail, projectId, resultId);
- }
-
- public void sendDayReportMessage(String token, String secret, int projectId, String projectName,
- String yesterday, String today, int passCount, int warnCount, int failCount, int type) {
- RobotMessenger robotMessenger = robotFactory.getRobotMessenger(type);
- robotMessenger.sendDayReportMessage(restTemplate, token, secret, projectId, projectName, yesterday, today, passCount, warnCount, failCount);
- }
-
- public void sendErrorDevice(String token, String secret, int type, int errorType, int tem, String udId) {
- RobotMessenger robotMessenger = robotFactory.getRobotMessenger(type);
- robotMessenger.sendErrorDevice(restTemplate, token, secret, errorType, tem, udId);
- }
-
- public void sendWeekReportMessage(String token, String secret, int projectId, String projectName,
- String yesterday, String today, int passCount, int warnCount, int failCount, int count, int type) {
- RobotMessenger robotMessenger = robotFactory.getRobotMessenger(type);
- robotMessenger.sendWeekReportMessage(restTemplate, token, secret, projectId, projectName, yesterday, today, passCount, warnCount, failCount, count);
- }
-}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/Message.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/Message.java
new file mode 100644
index 00000000..001fb2b7
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/Message.java
@@ -0,0 +1,46 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.tools.robot;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+public abstract class Message {
+ public final Calendar now = Calendar.getInstance();
+ public Object ext = null;
+ public SimpleDateFormat format = null;
+
+ public SimpleDateFormat getFormat(String pattern) {
+ if (null == format) {
+ format = new SimpleDateFormat(pattern);
+ } else {
+ format.applyPattern(pattern);
+ }
+ return format;
+ }
+
+ public SimpleDateFormat getFormat() {
+ if (null == format) {
+ format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ }
+ return format;
+ }
+
+}
+
+
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/RobotFactory.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/RobotFactory.java
index a7699b84..687111b2 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/RobotFactory.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/RobotFactory.java
@@ -53,8 +53,19 @@ public RobotMessenger getRobotMessenger(int robotType) {
case RobotType.Telegram -> robotMessenger = context.getBean(TelegramImpl.class);
case RobotType.LineNotify -> robotMessenger = context.getBean(LineNotifyImpl.class);
case RobotType.SlackNotify -> robotMessenger = context.getBean(SlackNotifyImpl.class);
+ case RobotType.WebHook -> robotMessenger = context.getBean(WebhookImpl.class);
default -> throw new SonicException("Unsupported robot type");
}
return robotMessenger;
}
+
+ public RobotMessenger getRobotMessenger(int robotType, String muteRule) {
+ if (!muteRule.isEmpty()) {
+ var mute = RobotMessenger.parseTemplate(muteRule).getValue(RobotMessenger.ctx, String.class);
+ if ("true".equals(mute)) {
+ return null;
+ }
+ }
+ return getRobotMessenger(robotType);
+ }
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/RobotMessenger.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/RobotMessenger.java
index e289d4a5..e2042b91 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/RobotMessenger.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/RobotMessenger.java
@@ -17,24 +17,53 @@
*/
package org.cloud.sonic.controller.tools.robot;
+import org.cloud.sonic.controller.tools.robot.message.DeviceMessage;
+import org.cloud.sonic.controller.tools.robot.message.ProjectSummaryMessage;
+import org.cloud.sonic.controller.tools.robot.message.TestSuiteMessage;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.ParserContext;
+import org.springframework.expression.common.TemplateParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.web.client.RestTemplate;
-/**
- * @author ayumi760405
- * @des 推送机器人方法介面
- * @date 2022/12/19
- */
+import java.util.WeakHashMap;
+
public interface RobotMessenger {
+ ExpressionParser defaultParser = new SpelExpressionParser();
+ ParserContext templateParserContext = new TemplateParserContext();
+ WeakHashMap expressionCache = new WeakHashMap<>();
+ EvaluationContext ctx = SimpleEvaluationContext.forReadOnlyDataBinding().withInstanceMethods().build();
+
+ static Expression parseTemplate(String template) {
+ return expressionCache.computeIfAbsent(template, it -> defaultParser.parseExpression(it, templateParserContext));
+ }
- void sendResultFinishReport(RestTemplate restTemplate, String token, String secret, String suiteName, int pass,
- int warn, int fail, int projectId, int resultId);
+ default void sendMessage(RestTemplate restTemplate, String token, String secret, String messageTemplate, Message message) {
+ Expression template;
+ if (messageTemplate.isEmpty()) {
+ if (message instanceof TestSuiteMessage) {
+ template = getDefaultTestSuiteTemplate();
+ } else if (message instanceof ProjectSummaryMessage) {
+ template = getDefaultProjectSummaryTemplate();
+ } else if (message instanceof DeviceMessage) {
+ template = getDefaultDeviceMessageTemplate();
+ } else {
+ return;
+ }
+ } else {
+ template = parseTemplate(messageTemplate);
+ }
+ sendMessage(restTemplate, token, secret, template, message);
+ }
- void sendDayReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName,
- String yesterday, String today, int passCount, int warnCount, int failCount);
+ void sendMessage(RestTemplate restTemplate, String token, String secret, Expression messageTemplate, Message message);
- void sendErrorDevice(RestTemplate restTemplate, String token, String secret, int errorType, int tem, String udId);
+ Expression getDefaultTestSuiteTemplate();
- void sendWeekReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName,
- String yesterday, String today, int passCount, int warnCount, int failCount, int count);
+ Expression getDefaultProjectSummaryTemplate();
+ Expression getDefaultDeviceMessageTemplate();
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/DeviceMessage.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/DeviceMessage.java
new file mode 100644
index 00000000..3548db9c
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/DeviceMessage.java
@@ -0,0 +1,28 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.tools.robot.message;
+
+import lombok.AllArgsConstructor;
+import org.cloud.sonic.controller.tools.robot.Message;
+
+@AllArgsConstructor
+public class DeviceMessage extends Message {
+ public int errorType;
+ public int tem;
+ public String udId;
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/ProjectSummaryMessage.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/ProjectSummaryMessage.java
new file mode 100644
index 00000000..e749661a
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/ProjectSummaryMessage.java
@@ -0,0 +1,38 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.tools.robot.message;
+
+import lombok.AllArgsConstructor;
+import org.cloud.sonic.controller.tools.robot.Message;
+
+import java.util.Date;
+
+@AllArgsConstructor
+public class ProjectSummaryMessage extends Message {
+ public int projectId;
+ public String projectName;
+ public Date startDate;
+ public Date endDate;
+ public int pass;
+ public int warn;
+ public int fail;
+ public double rate;
+ public int total;
+ public String url;
+ public boolean isWeekly;
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/TestSuiteMessage.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/TestSuiteMessage.java
new file mode 100644
index 00000000..4907d1cb
--- /dev/null
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/message/TestSuiteMessage.java
@@ -0,0 +1,32 @@
+/*
+ * sonic-server Sonic Cloud Real Machine Platform.
+ * Copyright (C) 2022 SonicCloudOrg
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.cloud.sonic.controller.tools.robot.message;
+
+import lombok.AllArgsConstructor;
+import org.cloud.sonic.controller.tools.robot.Message;
+
+@AllArgsConstructor
+public class TestSuiteMessage extends Message {
+ public String suiteName;
+ public int pass;
+ public int warn;
+ public int fail;
+ public int projectId;
+ public int resultId;
+ public String url;
+}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/DingTalkImpl.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/DingTalkImpl.java
index b2cac109..08eb0a58 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/DingTalkImpl.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/DingTalkImpl.java
@@ -19,19 +19,21 @@
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
+import org.cloud.sonic.controller.tools.robot.Message;
import org.cloud.sonic.controller.tools.robot.RobotMessenger;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.expression.Expression;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
-import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Map;
/**
* @author ayumi760405
@@ -42,10 +44,6 @@
@Service("DingTalkImpl")
public class DingTalkImpl implements RobotMessenger {
- //从配置文件获取前端部署的host
- @Value("${robot.client.host}")
- private String clientHost;
- //成功时的图片url
@Value("${robot.img.success}")
private String successUrl;
//警告时的图片url
@@ -55,6 +53,50 @@ public class DingTalkImpl implements RobotMessenger {
@Value("${robot.img.error}")
private String errorUrl;
+ Expression templateTestSuiteMessage = RobotMessenger.parseTemplate("""
+ #{
+ {
+ msgtype: 'link',
+ link: {
+ title: '测试套件:' + suiteName + '运行完毕!',
+ text: '通过数:'+pass+'
+ 异常数:'+warn+'
+ 失败数:'+fail,
+ messageUrl: url,
+ picUrl: (fail > 0 ? ext.errorUrl : (warn > 0 ? ext.warningUrl : ext.successUrl))
+ }
+ }
+ }""");
+ Expression templateProjectSummaryMessage = RobotMessenger.parseTemplate("""
+ #{
+ {
+ msgtype: 'markdown',
+ markdown: {
+ title: 'Sonic云真机测试平台'+(isWeekly?'周':'日')+'报',
+ text: '### Sonic云真机测试平台'+(isWeekly ? '周': '日')+'报
+ > ###### 项目:'+projectName+'
+ > ###### 时间:'+getFormat().format(startDate)+' ~ '+getFormat().format(endDate)+'
+ > ###### 共测试:'+total+'次
+ > ###### 通过数:'+pass+'
+ > ###### 异常数:'+warn+'
+ > ###### 失败数:'+fail+'
+ > ###### 测试通过率:'+rate+'%
+ > ###### 详细统计:[点击查看]('+url+')'
+ }
+ }
+ }""");
+ Expression templateDeviceMessage = RobotMessenger.parseTemplate("""
+ #{
+ { msgtype: 'markdown',
+ markdown: {
+ title: '设备温度异常通知',
+ text: '### Sonic设备高温'+(errorType == 1 ? '预警' : '超时,已关机!')+'
+ > ###### 设备序列号:'+udId+'
+ > ###### 电池温度:'+tem+' ℃'
+ }
+ }
+ }""");
+
/**
* @param restTemplate RestTemplate
* @param token 机器人token
@@ -64,191 +106,46 @@ public class DingTalkImpl implements RobotMessenger {
* @des 钉钉官方签名方法
* @date 2021/8/20 18:20
*/
- private void signAndSend(RestTemplate restTemplate, String token, String secret, JSONObject jsonObject) {
- clientHost = clientHost.replace(":80/", "/");
+ private void signAndSend(RestTemplate restTemplate, String token, String secret, Map, ?> jsonObject) {
try {
String path = "";
if (!StringUtils.isEmpty(secret)) {
Long timestamp = System.currentTimeMillis();
String stringToSign = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
- mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
- byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
- String sign = URLEncoder.encode(new String(Base64Utils.encode(signData)), "UTF-8");
+ mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
+ byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
+ String sign = URLEncoder.encode(new String(Base64.getEncoder().encode(signData)), StandardCharsets.UTF_8);
path = "×tamp=" + timestamp + "&sign=" + sign;
}
- ResponseEntity responseEntity =
- restTemplate.postForEntity(token + path
- , jsonObject, JSONObject.class);
+ ResponseEntity responseEntity = restTemplate.postForEntity(token + path, jsonObject, JSONObject.class);
log.info("robot result: " + responseEntity.getBody());
} catch (Exception e) {
log.warn("robot send failed, cause: " + e.getMessage());
}
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param suiteName 套件名称
- * @param pass 通过数量
- * @param warn 警告数量
- * @param fail 失败数量
- * @param projectId 项目id
- * @param resultId 结果id
- * @return void
- * @author ZhouYiXun
- * @des 发送每次测试结果到钉钉
- * @date 2021/8/20 18:29
- */
@Override
- public void sendResultFinishReport(RestTemplate restTemplate, String token, String secret, String suiteName, int pass, int warn, int fail, int projectId, int resultId) {
- JSONObject jsonObject = new JSONObject();
- JSONObject link = new JSONObject();
- link.put("text", "通过数:" + pass +
- " \n异常数:" + warn +
- " \n失败数:" + fail);
- link.put("title", "测试套件: " + suiteName + " 运行完毕!");
- link.put("messageUrl", clientHost + "/Home/" + projectId + "/ResultDetail/" + resultId);
- //判断测试结果,来决定显示什么图片
- if (fail > 0) {
- link.put("picUrl", errorUrl);
- } else if (warn > 0) {
- link.put("picUrl", warningUrl);
- } else {
- link.put("picUrl", successUrl);
- }
- jsonObject.put("msgtype", "link");
- jsonObject.put("link", link);
- this.signAndSend(restTemplate, token, secret, jsonObject);
+ public void sendMessage(RestTemplate restTemplate, String token, String secret, Expression messageTemplate, Message msg) {
+ msg.ext = this;
+ Map, ?> content = messageTemplate.getValue(ctx, msg, Map.class);
+ this.signAndSend(restTemplate, token, secret, content);
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param projectId 项目id
- * @param projectName 项目名称
- * @param yesterday 昨天的起始时间
- * @param today 今天的起始时间
- * @return void
- * @author ZhouYiXun
- * @des 发送日报
- * @date 2021/8/20 18:42
- */
@Override
- public void sendDayReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName, String yesterday, String today, int passCount, int warnCount, int failCount) {
- JSONObject jsonObject = new JSONObject();
- int total = passCount + warnCount + failCount;
- JSONObject markdown = new JSONObject();
- //根据三个数量来决定markdown的字体颜色
- String failColorString;
- if (failCount == 0) {
- failColorString = "" + failCount + "";
- } else {
- failColorString = "" + failCount + "";
- }
- String warnColorString;
- if (warnCount == 0) {
- warnColorString = "" + warnCount + "";
- } else {
- warnColorString = "" + warnCount + "";
- }
- markdown.put("text", "### Sonic云真机测试平台日报 \n" +
- "> ###### 项目:" + projectName + " \n" +
- "> ###### 时间:" + yesterday + " ~ " + today + " \n" +
- "> ###### 通过数:" + passCount + " \n" +
- "> ###### 异常数:" + warnColorString + " \n" +
- "> ###### 失败数:" + failColorString + " \n" +
- "> ###### 测试通过率:" + (total > 0 ?
- new BigDecimal(((float) passCount / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0) + "% \n" +
- "> ###### 详细统计:[点击查看](" + clientHost + "/Home/" + projectId + ")");
- markdown.put("title", "Sonic云真机测试平台日报");
- jsonObject.put("msgtype", "markdown");
- jsonObject.put("markdown", markdown);
- this.signAndSend(restTemplate, token, secret, jsonObject);
+ public Expression getDefaultTestSuiteTemplate() {
+ return templateTestSuiteMessage;
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param errorType errorType
- * @param tem 温度
- * @param udId 设备Id
- * @return void
- * @author ZhouYiXun
- * @des 发送设备错误讯息
- * @date 2021/8/20 18:42
- */
@Override
- public void sendErrorDevice(RestTemplate restTemplate, String token, String secret, int errorType, int tem, String udId) {
- JSONObject jsonObject = new JSONObject();
- JSONObject markdown = new JSONObject();
- if (errorType == 1) {
- markdown.put("text", "### Sonic设备高温预警 \n" +
- "> ###### 设备序列号:" + udId + " \n" +
- "> ###### 电池温度:" + (tem / 10) + " ℃");
- } else {
- markdown.put("text", "### Sonic设备高温超时,已关机! \n" +
- "> ###### 设备序列号:" + udId + " \n" +
- "> ###### 电池温度:" + (tem / 10) + " ℃");
- }
- markdown.put("title", "设备温度异常通知");
- jsonObject.put("msgtype", "markdown");
- jsonObject.put("markdown", markdown);
- this.signAndSend(restTemplate, token, secret, jsonObject);
+ public Expression getDefaultProjectSummaryTemplate() {
+ return templateProjectSummaryMessage;
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param projectId 项目id
- * @param projectName 项目名称
- * @param yesterday 昨天的起始时间
- * @param today 今天的起始时间
- * @param passCount 通过数量
- * @param warnCount 警告数量
- * @param failCount 失败数量
- * @param count 测试数量
- * @return void
- * @author ZhouYiXun
- * @des 发送周报
- * @date 2021/8/20 18:42
- */
@Override
- public void sendWeekReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName, String yesterday, String today, int passCount, int warnCount, int failCount, int count) {
- JSONObject jsonObject = new JSONObject();
- int total = passCount + warnCount + failCount;
- JSONObject markdown = new JSONObject();
- //根据三个数量来决定markdown的字体颜色
- String failColorString;
- if (failCount == 0) {
- failColorString = "" + failCount + "";
- } else {
- failColorString = "" + failCount + "";
- }
- String warnColorString;
- if (warnCount == 0) {
- warnColorString = "" + warnCount + "";
- } else {
- warnColorString = "" + warnCount + "";
- }
- markdown.put("text", "### Sonic云真机测试平台周报 \n" +
- "> ###### 项目:" + projectName + " \n" +
- "> ###### 时间:" + yesterday + " ~ " + today + " \n" +
- "> ###### 共测试:" + count + " 次\n" +
- "> ###### 通过数:" + passCount + " \n" +
- "> ###### 异常数:" + warnColorString + " \n" +
- "> ###### 失败数:" + failColorString + " \n" +
- "> ###### 测试通过率:" + (total > 0 ?
- new BigDecimal(((float) passCount / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0) + "% \n" +
- "> ###### 详细统计:[点击查看](" + clientHost + "/Home/" + projectId + ")");
- markdown.put("title", "Sonic云真机测试平台周报");
- jsonObject.put("msgtype", "markdown");
- jsonObject.put("markdown", markdown);
- this.signAndSend(restTemplate, token, secret, jsonObject);
+ public Expression getDefaultDeviceMessageTemplate() {
+ return templateDeviceMessage;
}
+
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/FeiShuImpl.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/FeiShuImpl.java
index 832392c7..15fbc030 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/FeiShuImpl.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/FeiShuImpl.java
@@ -19,20 +19,19 @@
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
+import org.cloud.sonic.controller.tools.robot.Message;
import org.cloud.sonic.controller.tools.robot.RobotMessenger;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.expression.Expression;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
-import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Base64;
import java.util.List;
/**
@@ -44,21 +43,33 @@
@Service("FeiShuImpl")
public class FeiShuImpl implements RobotMessenger {
- //从配置文件获取前端部署的host
- @Value("${robot.client.host}")
- private String clientHost;
+ Expression templateTestSuiteMessage = RobotMessenger.parseTemplate("""
+ **测试套件: ${suiteName} 运行完毕!**
+ 通过数:${pass}
+ 异常数:${warn}
+ 失败数:${fail}
+ 测试报告:[点击查看](${url})""");
+ Expression templateProjectSummaryMessage = RobotMessenger.parseTemplate("""
+ **Sonic云真机测试平台${isWeekly ? '周': '日'}报**
+ 项目:${projectName}
+ 时间:${getFormat().format(startDate)} ~ ${getFormat().format(endDate)}
+ 共测试:${total}次
+ 通过数:${pass}
+ 异常数:${warn}
+ 失败数:${fail}
+ 测试通过率:${rate}%
+ 详细统计:[点击查看](${url})""");
+ Expression templateDeviceMessage = RobotMessenger.parseTemplate("""
+ **Sonic设备高温${errorType == 1 ? '预警' : '超时,已关机!'}**
+ 设备序列号:${udId}
+ 电池温度:${tem}℃""");
/**
* @param restTemplate RestTemplate
* @param token 机器人token
- * @param secret 机器人密钥
* @param jsonObject 通知内容
- * @author ZhouYiXun
- * @des 飞书群机签名方法
- * @date 2021/8/20 18:20
*/
private void signAndSend(RestTemplate restTemplate, String token, String secret, JSONObject jsonObject) {
- clientHost = clientHost.replace(":80/", "/");
try {
if (!StringUtils.isEmpty(secret)) {
String timestamp = String.valueOf(System.currentTimeMillis()).substring(0, 10);
@@ -66,35 +77,20 @@ private void signAndSend(RestTemplate restTemplate, String token, String secret,
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] signData = mac.doFinal(new byte[]{});
- String sign = new String(Base64Utils.encode(signData));
+ String sign = new String(Base64.getEncoder().encode(signData));
jsonObject.put("timestamp", timestamp);
jsonObject.put("sign", sign);
}
- ResponseEntity responseEntity =
- restTemplate.postForEntity(token, jsonObject, JSONObject.class);
+ ResponseEntity responseEntity = restTemplate.postForEntity(token, jsonObject, JSONObject.class);
log.info("robot result: " + responseEntity.getBody());
} catch (Exception e) {
log.warn("robot send failed, cause: " + e.getMessage());
}
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param suiteName 套件名称
- * @param pass 通过数量
- * @param warn 警告数量
- * @param fail 失败数量
- * @param projectId 项目id
- * @param resultId 结果id
- * @return void
- * @author ZhouYiXun
- * @des 发送每次测试结果到飞书群
- * @date 2021/8/20 18:29
- */
@Override
- public void sendResultFinishReport(RestTemplate restTemplate, String token, String secret, String suiteName, int pass, int warn, int fail, int projectId, int resultId) {
+ public void sendMessage(RestTemplate restTemplate, String token, String secret, Expression messageTemplate, Message msg) {
+ String content = messageTemplate.getValue(ctx, msg, String.class);
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg_type", "interactive");
JSONObject card = new JSONObject();
@@ -104,138 +100,26 @@ public void sendResultFinishReport(RestTemplate restTemplate, String token, Stri
JSONObject element = new JSONObject();
element.put("tag", "markdown");
List elementList = new ArrayList<>();
- element.put("content", "**测试套件: " + suiteName + " 运行完毕!**\n" +
- "通过数:" + pass + " \n" +
- "异常数:" + warn + " \n" +
- "失败数:" + fail + "\n" +
- "测试报告:[点击查看](" + clientHost + "/Home/" + projectId + "/ResultDetail/" + resultId + ")");
+ element.put("content", content);
elementList.add(element);
card.put("elements", elementList);
jsonObject.put("card", card);
this.signAndSend(restTemplate, token, secret, jsonObject);
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param projectId 项目id
- * @param projectName 项目名称
- * @param yesterday 昨天的起始时间
- * @param today 今天的起始时间
- * @return void
- * @author ZhouYiXun
- * @des 发送日报
- * @date 2021/8/20 18:42
- */
@Override
- public void sendDayReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName, String yesterday, String today, int passCount, int warnCount, int failCount) {
- JSONObject jsonObject = new JSONObject();
- int total = passCount + warnCount + failCount;
- jsonObject.put("msg_type", "interactive");
- JSONObject card = new JSONObject();
- JSONObject config = new JSONObject();
- config.put("wide_screen_mode", true);
- card.put("config", config);
- JSONObject element = new JSONObject();
- element.put("tag", "markdown");
- List elementList = new ArrayList<>();
- element.put("content", "**Sonic云真机测试平台日报**\n" +
- "项目:" + projectName + " \n" +
- "时间:" + yesterday + " ~ " + today + " \n" +
- "通过数:" + passCount + "\n" +
- "异常数:" + warnCount + " \n" +
- "失败数:" + failCount + " \n" +
- "测试通过率:" + (total > 0 ?
- new BigDecimal(((float) passCount / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0) + "% \n" +
- "详细统计:[点击查看](" + clientHost + "/Home/" + projectId + ")");
- elementList.add(element);
- card.put("elements", elementList);
- jsonObject.put("card", card);
- this.signAndSend(restTemplate, token, secret, jsonObject);
+ public Expression getDefaultTestSuiteTemplate() {
+ return templateTestSuiteMessage;
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param errorType errorType
- * @param tem 温度
- * @param udId 设备Id
- * @return void
- * @author ZhouYiXun
- * @des 发送设备错误讯息
- * @date 2021/8/20 18:42
- */
@Override
- public void sendErrorDevice(RestTemplate restTemplate, String token, String secret, int errorType, int tem, String udId) {
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("msg_type", "interactive");
- JSONObject card = new JSONObject();
- JSONObject config = new JSONObject();
- config.put("wide_screen_mode", true);
- card.put("config", config);
- JSONObject element = new JSONObject();
- element.put("tag", "markdown");
- List elementList = new ArrayList<>();
-
- if (errorType == 1) {
- element.put("content", "**Sonic设备高温预警** \n" +
- "设备序列号:" + udId + " \n" +
- "电池温度:" + (tem / 10) + " ℃");
- } else {
- element.put("content", "**Sonic设备高温超时,已关机!** \n" +
- "设备序列号:" + udId + " \n" +
- "电池温度:" + (tem / 10) + " ℃");
- }
- elementList.add(element);
- card.put("elements", elementList);
- jsonObject.put("card", card);
- this.signAndSend(restTemplate, token, secret, jsonObject);
+ public Expression getDefaultProjectSummaryTemplate() {
+ return templateProjectSummaryMessage;
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param projectId 项目id
- * @param projectName 项目名称
- * @param yesterday 昨天的起始时间
- * @param today 今天的起始时间
- * @param passCount 通过数量
- * @param warnCount 警告数量
- * @param failCount 失败数量
- * @param count 测试数量
- * @return void
- * @author ZhouYiXun
- * @des 发送周报
- * @date 2021/8/20 18:42
- */
@Override
- public void sendWeekReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName, String yesterday, String today, int passCount, int warnCount, int failCount, int count) {
- JSONObject jsonObject = new JSONObject();
- int total = passCount + warnCount + failCount;
- jsonObject.put("msg_type", "interactive");
- JSONObject card = new JSONObject();
- JSONObject config = new JSONObject();
- config.put("wide_screen_mode", true);
- card.put("config", config);
- JSONObject element = new JSONObject();
- element.put("tag", "markdown");
- List elementList = new ArrayList<>();
- element.put("content", "**Sonic云真机测试平台周报**\n" +
- "项目:" + projectName + " \n" +
- "时间:" + yesterday + " ~ " + today + " \n" +
- "共测试:" + count + " 次\n" +
- "通过数:" + passCount + " \n" +
- "异常数:" + warnCount + " \n" +
- "失败数:" + failCount + " \n" +
- "测试通过率:" + (total > 0 ?
- new BigDecimal(((float) passCount / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0) + "% \n" +
- "详细统计:[点击查看](" + clientHost + "/Home/" + projectId + ")");
- elementList.add(element);
- card.put("elements", elementList);
- jsonObject.put("card", card);
- this.signAndSend(restTemplate, token, secret, jsonObject);
+ public Expression getDefaultDeviceMessageTemplate() {
+ return templateDeviceMessage;
}
+
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/LineNotifyImpl.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/LineNotifyImpl.java
index 734ad777..be35f31e 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/LineNotifyImpl.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/LineNotifyImpl.java
@@ -18,8 +18,9 @@
package org.cloud.sonic.controller.tools.robot.vendor;
import lombok.extern.slf4j.Slf4j;
+import org.cloud.sonic.controller.tools.robot.Message;
import org.cloud.sonic.controller.tools.robot.RobotMessenger;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.expression.Expression;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@@ -29,9 +30,6 @@
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
/**
* @author ayumi760405
* @des Line Notify 推送实作类,可以参考 https://notify-bot.line.me/doc/en/
@@ -41,12 +39,34 @@
@Service("LineNotifyImpl")
public class LineNotifyImpl implements RobotMessenger {
- //从配置文件获取前端部署的host
- @Value("${robot.client.host}")
- private String clientHost;
//line notify的host
private static final String LINE_NOTIFY_HOST = "https://notify-api.line.me/api/notify";
+ Expression templateTestSuiteMessage = RobotMessenger.parseTemplate("""
+ *Sonic云真机测试报告*
+ 测试套件: #{suiteName} 运行完毕!
+ 通过数:#{pass}
+ 异常数:#{warn>0?' `'+warn+'`':warn}
+ 失败数:#{fail>0?' `'+fail+'`':fail}
+ 测试报告: #{url}
+ """);
+ Expression templateProjectSummaryMessage = RobotMessenger.parseTemplate("""
+ *Sonic云真机测试平台#{isWeekly ? '周': '日'}报*
+ 项目:#{projectName}
+ 时间:#{getFormat().format(startDate)} ~ #{getFormat().format(endDate)}
+ 共测试:#{total}次
+ 通过数:#{pass}
+ 异常数:#{warn>0?' `'+warn+'`':warn}
+ 失败数:#{fail>0?' `'+fail+'`':fail}
+ 测试通过率:#{rate}%
+ 详细统计:#{url}
+ """);
+ Expression templateDeviceMessage = RobotMessenger.parseTemplate("""
+ *设备温度异常通知*
+ Sonic设备高温#{errorType == 1 ? '预警' : '超时,已关机!'}
+ 设备序列号:#{udId}
+ 电池温度:#{tem}℃""");
+
/**
* @param restTemplate RestTemplate
* @param token 机器人token
@@ -56,7 +76,6 @@ public class LineNotifyImpl implements RobotMessenger {
* @date 2022/12/29
*/
private void signAndSend(RestTemplate restTemplate, String token, String message) {
- clientHost = clientHost.replace(":80/", "/");
try {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + token);
@@ -64,168 +83,32 @@ private void signAndSend(RestTemplate restTemplate, String token, String message
MultiValueMap requestMap = new LinkedMultiValueMap();
requestMap.add("message", message);
HttpEntity> entity = new HttpEntity>(requestMap, headers);
- ResponseEntity responseEntity =
- restTemplate.postForEntity(LINE_NOTIFY_HOST, entity, String.class);
+ ResponseEntity responseEntity = restTemplate.postForEntity(LINE_NOTIFY_HOST, entity, String.class);
log.info("robot result: " + responseEntity.getBody());
} catch (Exception e) {
log.warn("robot send failed, cause: " + e.getMessage());
}
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param suiteName 套件名称
- * @param pass 通过数量
- * @param warnCount 警告数量
- * @param failCount 失败数量
- * @param projectId 项目id
- * @param resultId 结果id
- * @return void
- * @author ayumi760405
- * @des 发送每次测试结果到Line Notify
- * @date 2022/12/29
- */
@Override
- public void sendResultFinishReport(RestTemplate restTemplate, String token, String secret, String suiteName, int pass, int warnCount, int failCount, int projectId, int resultId) {
- String failColorString;
- if (failCount == 0) {
- failColorString = String.valueOf(failCount);
- } else {
- failColorString = " `" + failCount + "`";
- }
- String warnColorString;
- if (warnCount == 0) {
- warnColorString = String.valueOf(warnCount);
- } else {
- warnColorString = " `" + warnCount + "`";
- }
- StringBuilder builder = new StringBuilder();
- builder.append("\n");
- builder.append("*Sonic云真机测试报告*").append("\n");
- builder.append("测试套件: ").append(suiteName).append(" 运行完毕!").append("\n");
- builder.append("通过数:").append(pass).append("\n");
- builder.append("异常数:").append(warnColorString).append("\n");
- builder.append("失败数:").append(failColorString).append("\n");
- builder.append("测试报告:").append(clientHost).append("/Home/").append(projectId).append("/ResultDetail/").append(resultId);
- this.signAndSend(restTemplate, token, builder.toString());
+ public void sendMessage(RestTemplate restTemplate, String token, String secret, Expression messageTemplate, Message msg) {
+ String content = messageTemplate.getValue(ctx, msg, String.class);
+ signAndSend(restTemplate, token, content);
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param projectId 项目id
- * @param projectName 项目名称
- * @param yesterday 昨天的起始时间
- * @param today 今天的起始时间
- * @return void
- * @author ayumi760405
- * @des 发送日报
- * @date 2022/12/29
- */
@Override
- public void sendDayReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName, String yesterday, String today, int passCount, int warnCount, int failCount) {
- int total = passCount + warnCount + failCount;
- String failColorString;
- if (failCount == 0) {
- failColorString = String.valueOf(failCount);
- } else {
- failColorString = " `" + failCount + "`";
- }
- String warnColorString;
- if (warnCount == 0) {
- warnColorString = String.valueOf(warnCount);
- } else {
- warnColorString = " `" + warnCount + "`";
- }
-
- StringBuilder builder = new StringBuilder();
- builder.append("\n");
- builder.append("*Sonic云真机测试平台日报*").append("\n");
- builder.append("项目:").append(projectName).append("\n");
- builder.append("时间:").append(yesterday).append(" ~ ").append(today).append("\n");
- builder.append("通过数:").append(passCount).append("\n");
- builder.append("异常数:").append(warnColorString).append("\n");
- builder.append("失败数:").append(failColorString).append("\n");
- builder.append("测试通过率: ").append((total > 0 ?
- BigDecimal.valueOf(((float) passCount / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0)).append("%").append("\n");
- builder.append("测试报告:").append(clientHost).append("/Home/").append(projectId);
- this.signAndSend(restTemplate, token, builder.toString());
+ public Expression getDefaultTestSuiteTemplate() {
+ return templateTestSuiteMessage;
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param errorType errorType
- * @param tem 温度
- * @param udId 设备Id
- * @return void
- * @author ayumi760405
- * @des 发送设备错误讯息
- * @date 2022/12/29
- */
@Override
- public void sendErrorDevice(RestTemplate restTemplate, String token, String secret, int errorType, int tem, String udId) {
- StringBuilder builder = new StringBuilder();
- builder.append("\n");
- builder.append("*设备温度异常通知*").append("\n");
- if (errorType == 1) {
- builder.append("Sonic设备高温预警").append("\n");
- } else {
- builder.append("Sonic设备高温超时,已关机").append("\n");
- }
- builder.append("设备序列号:").append(udId).append("\n");
- builder.append("电池温度:").append(tem / 10).append(" ℃").append("\n");
- this.signAndSend(restTemplate, token, builder.toString());
+ public Expression getDefaultProjectSummaryTemplate() {
+ return templateProjectSummaryMessage;
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param projectId 项目id
- * @param projectName 项目名称
- * @param yesterday 昨天的起始时间
- * @param today 今天的起始时间
- * @param passCount 通过数量
- * @param warnCount 警告数量
- * @param failCount 失败数量
- * @param count 测试数量
- * @return void
- * @author ayumi760405
- * @des 发送周报
- * @date 2022/12/29
- */
@Override
- public void sendWeekReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName, String yesterday, String today, int passCount, int warnCount, int failCount, int count) {
- int total = passCount + warnCount + failCount;
- String failColorString;
- if (failCount == 0) {
- failColorString = String.valueOf(failCount);
- } else {
- failColorString = " `" + failCount + "`";
- }
- String warnColorString;
- if (warnCount == 0) {
- warnColorString = String.valueOf(warnCount);
- } else {
- warnColorString = " `" + warnCount + "`";
- }
- StringBuilder builder = new StringBuilder();
- builder.append("\n");
- builder.append("*Sonic云真机测试平台周报*").append("\n");
- builder.append("项目:").append(projectName).append("\n");
- builder.append("时间:").append(yesterday).append(" ~ ").append(today).append("\n");
- builder.append("共测试:").append(count).append("次").append("\n");
- builder.append("通过数:").append(passCount).append("\n");
- builder.append("异常数:").append(warnColorString).append("\n");
- builder.append("失败数:").append(failColorString).append("\n");
- builder.append("测试通过率: ").append((total > 0 ?
- BigDecimal.valueOf(((float) passCount / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0)).append("%").append("\n");
- builder.append("测试报告:").append(clientHost).append("/Home/").append(projectId);
- this.signAndSend(restTemplate, token, builder.toString());
+ public Expression getDefaultDeviceMessageTemplate() {
+ return templateDeviceMessage;
}
+
}
diff --git a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/SlackNotifyImpl.java b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/SlackNotifyImpl.java
index 4620a4fd..5343bfab 100644
--- a/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/SlackNotifyImpl.java
+++ b/sonic-server-controller/src/main/java/org/cloud/sonic/controller/tools/robot/vendor/SlackNotifyImpl.java
@@ -17,18 +17,14 @@
*/
package org.cloud.sonic.controller.tools.robot.vendor;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
+import org.cloud.sonic.controller.tools.robot.Message;
import org.cloud.sonic.controller.tools.robot.RobotMessenger;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.expression.Expression;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.LinkedHashMap;
import java.util.Map;
@@ -41,212 +37,99 @@
@Service("SlackNotifyImpl")
public class SlackNotifyImpl implements RobotMessenger {
- //从配置文件获取前端部署的host
- @Value("${robot.client.host}")
- private String clientHost;
+ Expression templateTestSuiteMessage = RobotMessenger.parseTemplate("""
+ #{
+ {
+ text: '测试套件:' + suiteName + '运行完毕!',
+ blocks: {
+ { type: 'section',
+ text: {
+ type: 'mrkdwn',
+ text: '*测试套件:' + suiteName + '运行完毕!*
+ 通过数:'+pass+'
+ 异常数:'+warn+'
+ 失败数:'+fail+'
+ 测试报告:'+url
+ }
+ }
+ }
+ }
+ }""");
+ Expression templateProjectSummaryMessage = RobotMessenger.parseTemplate("""
+ #{
+ {
+ text: 'Sonic云真机测试平台'+(isWeekly?'周':'日')+'报',
+ blocks: {
+ { type: 'section',
+ text: {
+ type: 'mrkdwn',
+ text: '*Sonic云真机测试平台'+(isWeekly ? '周': '日')+'报*
+ 项目:'+projectName+'
+ 时间:'+getFormat().format(startDate)+' ~ '+getFormat().format(endDate)+'
+ 共测试:'+total+'次
+ 通过数:'+pass+'
+ 异常数:'+warn+'
+ 失败数:'+fail+'
+ 测试通过率:'+rate+'%
+ 详细统计:'+url
+ }
+ }
+ }
+ }
+ }""");
+ Expression templateDeviceMessage = RobotMessenger.parseTemplate("""
+ #{
+ {
+ text: '设备温度异常通知',
+ blocks: {
+ { type: 'section',
+ text: {
+ type: 'mrkdwn',
+ text: '*Sonic设备高温'+(errorType == 1 ? '预警' : '超时,已关机!')+'*
+ 设备序列号:'+udId+'
+ 电池温度:'+tem+'℃'
+ }
+ }
+ }
+ }
+ }""");
/**
* @param restTemplate RestTemplate
* @param token 机器人token
* @param secret 机器人密钥
- * @param jsonObject 通知内容
+ * @param content 通知内容
* @author young(stephenwang1011)
* @des SLACK发送测试通知
* @date 2023/2/14
*/
- private void signAndSend(RestTemplate restTemplate, String token, String secret, JSONObject jsonObject) {
- clientHost = clientHost.replace(":80/", "/");
+ private void signAndSend(RestTemplate restTemplate, String token, String secret, Object content) {
try {
- ResponseEntity responseEntity =
- restTemplate.postForEntity(token, jsonObject, JSONObject.class);
+ ResponseEntity responseEntity = restTemplate.postForEntity(token, content, String.class);
log.info("robot result: " + responseEntity.getBody());
} catch (Exception e) {
log.warn("robot send failed, cause: " + e.getMessage());
}
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param suiteName 套件名称
- * @param passCount 通过数量
- * @param warnCount 警告数量
- * @param failCount 失败数量
- * @param projectId 项目id
- * @param resultId 结果id
- * @return void
- * @author young(stephenwang1011)
- * @des 发送每次测试结果到SLACK
- * @date 2023/2/14
- */
@Override
- public void sendResultFinishReport(RestTemplate restTemplate, String token, String secret, String suiteName, int passCount, int warnCount, int failCount, int projectId, int resultId) {
- JSONObject slackObjs = new JSONObject(true);
-
- String reportLink = clientHost + "/Home/" + projectId + "/ResultDetail/" + resultId;
- SlackMessage slackMessage = new SlackMessage();
- slackMessage.setType("mrkdwn");
- slackMessage.setText("*测试套件:" + suiteName + " 运行完毕* \n" +
- "通过数:" + passCount + "\n" +
- "异常数:" + warnCount + "\n" +
- "失败数:" + failCount + "\n" +
- "测试报告:" + reportLink);
-
- this.slackMessage(slackMessage, restTemplate, token, secret, slackObjs, suiteName);
+ public void sendMessage(RestTemplate restTemplate, String token, String secret, Expression messageTemplate, Message msg) {
+ Map, ?> content = messageTemplate.getValue(ctx, msg, Map.class);
+ signAndSend(restTemplate, token, secret, content);
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param projectId 项目id
- * @param projectName 项目名称
- * @param yesterday 昨天的起始时间
- * @param today 今天的起始时间
- * @return void
- * @author young(stephenwang1011)
- * @des 通过slack发送day report
- * @date 2022/12/20
- */
@Override
- public void sendDayReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName, String yesterday, String today, int passCount, int warnCount, int failCount) {
- JSONObject slackObjs = new JSONObject(true);
-
- int total = passCount + warnCount + failCount;
- String reportLink = clientHost + "/Home/" + projectId;
-
- SlackMessage slackMessage = new SlackMessage();
- slackMessage.setType("mrkdwn");
- slackMessage.setText("*Sonic云真机测试平台日报* \n" +
- "项目:" + projectName + "\n" +
- "时间:" + yesterday + " - " + today + "\n" +
- "通过数:" + passCount + "\n" +
- "异常数:" + warnCount + "\n" +
- "失败数:" + failCount + "\n" +
- "测试通过率:" + (total > 0 ?
- new BigDecimal(((float) passCount / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0) + "%\n" +
- "详细统计:" + reportLink);
-
- this.slackMessage(slackMessage, restTemplate, token, secret, slackObjs, projectName);
-
+ public Expression getDefaultTestSuiteTemplate() {
+ return templateTestSuiteMessage;
}
-
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param errorType errorType
- * @param tem 温度
- * @param udId 设备Id
- * @return void
- * @author young(stephenwang1011)
- * @des 向slack发送设备错误讯息
- * @date 2022/12/20
- */
@Override
- public void sendErrorDevice(RestTemplate restTemplate, String token, String secret, int errorType, int tem, String udId) {
-
- JSONObject slackObjs = new JSONObject(true);
- SlackMessage slackMessage = new SlackMessage();
- slackMessage.setType("mrkdwn");
-
- if (errorType == 1) {
- slackMessage.setText("*Sonic设备高温预警* \n" +
- "设备序列号:" + udId + "\n" +
- "电池温度:" + (tem / 10) + "℃");
-
- //这个是slack消息的通知title
- slackObjs.put("text", "Sonic设备:" + udId + "温度过高!");
- } else {
- slackMessage.setText("*Sonic设备高温超时,已关机* \n" +
- "设备序列号:" + udId + "\n" +
- "电池温度:" + (tem / 10) + "℃");
-
- //这个是slack消息的通知title
- slackObjs.put("text", "Sonic设备:" + udId + "高温超时,已关机");
- }
-
- this.slackMessage(slackMessage, restTemplate, token, secret, slackObjs, udId);
+ public Expression getDefaultProjectSummaryTemplate() {
+ return templateProjectSummaryMessage;
}
- /**
- * @param restTemplate RestTemplate
- * @param token 机器人token
- * @param secret 机器人密钥
- * @param projectId 项目id
- * @param projectName 项目名称
- * @param yesterday 昨天的起始时间
- * @param today 今天的起始时间
- * @param passCount 通过数量
- * @param warnCount 警告数量
- * @param failCount 失败数量
- * @param count 测试数量
- * @return void
- * @author young(stephenwang1011)
- * @des 发送周报到slack
- * @date 2022/12/20
- */
@Override
- public void sendWeekReportMessage(RestTemplate restTemplate, String token, String secret, int projectId, String projectName, String yesterday, String today, int passCount, int warnCount, int failCount, int count) {
- JSONObject slackObjs = new JSONObject(true);
- int total = passCount + warnCount + failCount;
- String reportLink = clientHost + "/Home/" + projectId;
-
- SlackMessage slackMessage = new SlackMessage();
- slackMessage.setType("mrkdwn");
- slackMessage.setText("*Sonic云真机测试平台周报* \n" +
- "项目:" + projectName + "\n" +
- "时间:" + yesterday + " - " + today + "\n" +
- "共测试:" + count + "次" + "\n" +
- "通过数:" + passCount + "\n" +
- "异常数:" + warnCount + "\n" +
- "失败数:" + failCount + "\n" +
- "测试通过率:" + (total > 0 ?
- new BigDecimal(((float) passCount / total) * 100).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0) + "%\n" +
- "详细统计:" + reportLink);
-
- this.slackMessage(slackMessage, restTemplate, token, secret, slackObjs, projectName);
+ public Expression getDefaultDeviceMessageTemplate() {
+ return templateDeviceMessage;
}
-
- public void slackMessage(SlackMessage slackMessage, RestTemplate restTemplate, String token, String secret, JSONObject slackObjs, String name) {
-
- Map