Merge branch 'master' into xsj_branch
This commit is contained in:
commit
6fc79a75a4
28
pom.xml
28
pom.xml
|
@ -80,6 +80,11 @@
|
|||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.49.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.3.232</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct</artifactId>
|
||||
|
@ -140,6 +145,16 @@
|
|||
<artifactId>gzs-common-oss</artifactId>
|
||||
<version>0.1.6-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.logstash.logback</groupId>
|
||||
<artifactId>logstash-logback-encoder</artifactId>
|
||||
<version>8.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka-clients</artifactId>
|
||||
<version>3.9.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
@ -176,8 +191,9 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.3.232</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
@ -245,6 +261,14 @@
|
|||
<groupId>com.cmcc.hy</groupId>
|
||||
<artifactId>gzs-common-oss</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.logstash.logback</groupId>
|
||||
<artifactId>logstash-logback-encoder</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka-clients</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
|
|
|
@ -47,9 +47,12 @@ public class CircularQueue<T> {
|
|||
if (isFull()) {
|
||||
dequeue();
|
||||
}
|
||||
data[tail] = element; // 将元素插入尾部
|
||||
tail = (tail + 1) % capacity; // 更新尾指针(循环利用空间)
|
||||
size++; // 增加队列元素数量
|
||||
// 将元素插入尾部
|
||||
data[tail] = element;
|
||||
// 更新尾指针(循环利用空间)
|
||||
tail = (tail + 1) % capacity;
|
||||
// 增加队列元素数量
|
||||
size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,16 @@ public class CommonConfigure {
|
|||
*/
|
||||
public static String PROJECT_PREFIX_URL;
|
||||
|
||||
/**
|
||||
* 本机服务IP地址。
|
||||
*/
|
||||
public static String LOCAL_IP_ADDR;
|
||||
|
||||
/**
|
||||
* 本机服务端口。
|
||||
*/
|
||||
public static Short LOCAL_PORT;
|
||||
|
||||
/**
|
||||
* 服务配置属性。
|
||||
* <p>
|
||||
|
@ -127,10 +137,14 @@ public class CommonConfigure {
|
|||
*
|
||||
* @param prefixUrl 项目上下文路径(Context Path)
|
||||
* @param baseUrl 项目的基础 URL,包括协议、主机地址和端口号
|
||||
* @param ipAddr 本机服务IP地址
|
||||
* @param port 本机服务端口号
|
||||
*/
|
||||
private static void setGlobalVars(String prefixUrl, String baseUrl) {
|
||||
private static void setGlobalVars(String prefixUrl, String baseUrl, String ipAddr, Integer port) {
|
||||
PROJECT_PREFIX_URL = prefixUrl;
|
||||
BASEURL = baseUrl;
|
||||
LOCAL_IP_ADDR = ipAddr;
|
||||
LOCAL_PORT = port.shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,7 +190,9 @@ public class CommonConfigure {
|
|||
log.error("Unable get local ip address: {}", e.getMessage());
|
||||
} finally {
|
||||
setGlobalVars(serverProperties.getServlet().getContextPath(),
|
||||
"http://" + addr + ":" + serverProperties.getPort() + serverProperties.getServlet().getContextPath());
|
||||
"http://" + addr + ":" + serverProperties.getPort() + serverProperties.getServlet().getContextPath(),
|
||||
addr,
|
||||
serverProperties.getPort());
|
||||
log.info("baseUrl: {}", BASEURL);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package com.cmcc.magent.config;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.h2.tools.Server;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* H2 数据库配置类,用于在 Spring Boot 应用中启动 H2 数据库的 TCP 服务器。
|
||||
* 该类通过条件注解 {@code @ConditionalOnProperty} 控制是否启用 H2 数据库服务器。
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-02-27
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(name = "spring.h2.server.enable", havingValue = "true")
|
||||
@Slf4j
|
||||
public class H2DataBaseConfig {
|
||||
/**
|
||||
* 通用配置类,用于获取本地 IP 地址等信息。
|
||||
*/
|
||||
@Resource
|
||||
private CommonConfigure commonConfigure;
|
||||
/**
|
||||
* H2 数据库 TCP 服务器的端口号,通过配置文件 {@code spring.h2.server.port} 注入。
|
||||
*/
|
||||
@Value("${spring.h2.server.port}")
|
||||
private Integer tcpPort;
|
||||
/**
|
||||
* 数据源连接字符串,通过配置文件 {@code spring.datasource.url} 注入。
|
||||
*/
|
||||
@Value("${spring.datasource.url}")
|
||||
private String connectString;
|
||||
|
||||
/**
|
||||
* 启动 H2 数据库 TCP 服务器,并生成远程连接 URL。
|
||||
* 该方法通过 {@code CommandLineRunner} 接口在应用启动后执行。
|
||||
*
|
||||
* @return {@code CommandLineRunner} 实例,用于启动 H2 数据库服务器。
|
||||
*/
|
||||
@Bean
|
||||
public CommandLineRunner startH2DatabaseServer() {
|
||||
return args -> {
|
||||
if (commonConfigure != null) {
|
||||
// 启动 H2 数据库 TCP 服务器
|
||||
Server.createTcpServer("-tcp", "-tcpPort", String.valueOf(tcpPort), "-tcpAllowOthers").start();
|
||||
// 生成远程连接 URL
|
||||
String remoteBase = "jdbc:h2:tcp://" + CommonConfigure.LOCAL_IP_ADDR + ":" + tcpPort;
|
||||
String connStr = connectString.replace("jdbc:h2:file:", remoteBase);
|
||||
// 记录远程连接 URL 到日志
|
||||
log.info("H2 Database server remote connect url [{}]", connStr);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -33,8 +33,8 @@ import java.util.concurrent.TimeoutException;
|
|||
*/
|
||||
@Slf4j
|
||||
public class ExecutingCommand {
|
||||
final static int BASH_SPLIT_LEN = 3;
|
||||
static Map<String, COMMAND_TYPE> osInternalCommand = new HashMap<>(1024);
|
||||
final static int BASH_SPLIT_LEN = 3;
|
||||
final static Map<String, COMMAND_TYPE> OS_INTERNAL_COMMAN = new HashMap<>(1024);
|
||||
|
||||
/**
|
||||
* 私有化构造方法以防止实例化。
|
||||
|
@ -79,7 +79,7 @@ public class ExecutingCommand {
|
|||
for (String line : lines) {
|
||||
String[] value = line.replaceAll("\\s+", " ").trim().split(" ");
|
||||
if (value.length == 2) {
|
||||
osInternalCommand.put(value[1].toUpperCase(), COMMAND_TYPE.TYPE_BASH_LINUX);
|
||||
OS_INTERNAL_COMMAN.put(value[1].toUpperCase(), COMMAND_TYPE.TYPE_BASH_LINUX);
|
||||
log.debug("Bash Command: {} --> {}", value[1], value[0]);
|
||||
}
|
||||
}
|
||||
|
@ -97,12 +97,12 @@ public class ExecutingCommand {
|
|||
*/
|
||||
private static COMMAND_TYPE getCommandTypeOfLinux(String cmdName) {
|
||||
|
||||
if (osInternalCommand.isEmpty()) {
|
||||
if (OS_INTERNAL_COMMAN.isEmpty()) {
|
||||
getAllInternalOfLinux();
|
||||
}
|
||||
|
||||
if (osInternalCommand.containsKey(cmdName.toUpperCase())) {
|
||||
return osInternalCommand.get(cmdName.toUpperCase());
|
||||
if (OS_INTERNAL_COMMAN.containsKey(cmdName.toUpperCase())) {
|
||||
return OS_INTERNAL_COMMAN.get(cmdName.toUpperCase());
|
||||
}
|
||||
|
||||
if (extenAppIsExistsOfLinux(cmdName)) {
|
||||
|
|
|
@ -201,6 +201,7 @@ public class HelperUtils {
|
|||
* @throws NoSuchFieldException 如果指定的字段不存在
|
||||
* @throws IllegalAccessException 如果没有访问权限
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getField(Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = obj.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
|
|
|
@ -8,7 +8,7 @@ import com.mybatisflex.annotation.Table;
|
|||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* MiddlewareData 类表示中间件管理的数据模型。
|
||||
|
@ -68,10 +68,10 @@ public class MiddlewareData {
|
|||
private String uninstall;
|
||||
|
||||
@Schema(description = "中间件记录的创建时间")
|
||||
@Column(value = "created_time", onInsertValue = "DATETIME('now', 'localtime')")
|
||||
private Date createdTime;
|
||||
@Column(value = "created_time", onInsertValue = "CURRENT_TIMESTAMP(6)")
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
@Schema(description = "中间件记录的更新时间")
|
||||
@Column(value = "upgrade_time", onUpdateValue = "DATETIME('now', 'localtime')")
|
||||
private Date upgradeTime;
|
||||
@Column(value = "upgrade_time", onUpdateValue = "CURRENT_TIMESTAMP(6)")
|
||||
private LocalDateTime upgradeTime;
|
||||
}
|
||||
|
|
|
@ -223,8 +223,7 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
|
|||
for (RemoteFileDetails file : configFiles) {
|
||||
try {
|
||||
String saveName = Paths.get(workDir + File.separator + file.getFileName()).toString();
|
||||
// FileDownloader dl = new FileDownloader(file.getUrl(), saveName);
|
||||
// dl.downloadFile();
|
||||
/* Http Download Usage: new FileDownloader(file.getUrl(), saveName).downloadFile(); */
|
||||
OssService service = ossFactory.getOssService();
|
||||
service.download(new URL(file.getUrl()), new File(saveName));
|
||||
|
||||
|
|
|
@ -113,16 +113,13 @@ public class ProtocolSecurityServiceImpl implements ProtocolSecurityService {
|
|||
log.error("AES256 decode message error: {}", base64Decode);
|
||||
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_AES256);
|
||||
}
|
||||
} else if (Objects.equals(proReq.getCryptoType(), ProtoCryptoType.CRYPTO_DES.getValue())) {
|
||||
} else {
|
||||
try {
|
||||
decryptContent = CryptoHelper.desDecryption(base64Decode, protocolConfigure.getCryptoKey());
|
||||
} catch (Exception e) {
|
||||
log.error("DES decode message error: {}", base64Decode);
|
||||
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_3DES);
|
||||
}
|
||||
} else {
|
||||
log.error("Unknown protocol security type: {}, {}", proReq.getCryptoType(), ciphertext);
|
||||
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_UNKNOWN);
|
||||
}
|
||||
|
||||
String decodeMsg = new String(decryptContent, StandardCharsets.UTF_8);
|
||||
|
|
|
@ -5,12 +5,36 @@ server.compression.enabled=true
|
|||
server.compression.mime-types=application/json
|
||||
server.compression.min-response-size=1KB
|
||||
|
||||
#server.port=8443
|
||||
server.ssl.key-store=classpath:mydomain.jks
|
||||
server.ssl.key-store-password=101010
|
||||
server.ssl.key-password=101010
|
||||
server.ssl.key-alias=mydomain
|
||||
|
||||
|
||||
server.undertow.buffer-size=1024
|
||||
server.undertow.max-http-post-size=10MB
|
||||
|
||||
# Spring Web Configuration
|
||||
spring.web.resources.add-mappings=false
|
||||
|
||||
# Spring DataSource Configuration
|
||||
spring.datasource.url=jdbc:sqlite:src/main/resources/db/agent.db
|
||||
spring.datasource.driver-class-name=org.sqlite.JDBC
|
||||
|
||||
spring.datasource.url=jdbc:h2:file:./src/main/resources/db/agent;MODE=MySQL;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=
|
||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
# enable H2 console
|
||||
spring.h2.console.enabled=true
|
||||
spring.h2.console.path=/h2-console
|
||||
# server config
|
||||
spring.h2.server.enable=true
|
||||
spring.h2.server.port=18090
|
||||
# auto init
|
||||
spring.sql.init.mode=always
|
||||
spring.sql.init.schema-locations=classpath:sql/schema.sql
|
||||
|
||||
|
||||
# Mybatis Configuration
|
||||
#mybatis.mapper-locations=classpath:mappers/*.xml
|
||||
|
|
Binary file not shown.
|
@ -6,10 +6,26 @@
|
|||
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder charset="UTF-8">
|
||||
<pattern>[%d{yy-MM-dd HH:mm:ss:SSS}][%-5p][%c{0}][%M\(%L\)][%t]: %m%n</pattern>
|
||||
<pattern>[%d{yy-MM-dd HH:mm:ss:SSS}][%-5p][%C{1}][%M\(%L\)]: %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">
|
||||
<syslogHost>localhost</syslogHost>
|
||||
<facility>LOCAL0</facility>
|
||||
<suffixPattern>[%d{yy-MM-dd HH:mm:ss:SSS}][%-5p][%c{0}][%M\(%L\)][%t]: %msg%n</suffixPattern>
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<pattern>%msg</pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="KAFKA" class="net.logstash.logback.appender.KafkaAppender">
|
||||
<topic>your-topic-name</topic>
|
||||
<deliveryTimeoutMs>5000</deliveryTimeoutMs>
|
||||
<producerConfig>bootstrap.servers=172.21.152.244:9092</producerConfig>
|
||||
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
|
||||
</appender>
|
||||
|
||||
<appender name="BIZ"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_PATH}/biz.log</file>
|
||||
|
@ -29,7 +45,7 @@
|
|||
</fileNamePattern>
|
||||
</rollingPolicy>
|
||||
<encoder charset="UTF-8">
|
||||
<pattern>[%d{yy-MM-dd HH:mm:ss:SSS}][%-5p][%c{0}][%M\(%L\)][%t]: %m%n</pattern>
|
||||
<pattern>[%d{yy-MM-dd HH:mm:ss:SSS}][%-5p][%c][%M\(%L\)][%t]: %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
@ -45,57 +61,20 @@
|
|||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.cmcc.gds.mapper" level="${LOG_LEVEL}" additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.mybatis" level="${LOG_LEVEL}" additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.apache.ibatis" level="${LOG_LEVEL}"
|
||||
additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.mybatis.spring" level="${LOG_LEVEL}"
|
||||
additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.springframework.jdbc" level="${LOG_LEVEL}"
|
||||
additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</logger>
|
||||
<logger name="org.springframework.orm" level="${LOG_LEVEL}"
|
||||
additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
</logger>
|
||||
<logger name="com.mysql" level="${LOG_LEVEL}" additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</logger>
|
||||
<logger name="java.sql" level="${LOG_LEVEL}" additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</logger>
|
||||
|
||||
<logger name="javax.sql" level="${LOG_LEVEL}" additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.springframework.security" level="${LOG_LEVEL}" additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.casbin.jcasbin" level="error" additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</logger>
|
||||
|
||||
<logger name="com.ulisesbocchio.jasyptspringboot" level="error" additivity="false">
|
||||
<appender-ref ref="DATA"/>
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
|
|
Binary file not shown.
|
@ -1,23 +1,21 @@
|
|||
PRAGMA foreign_keys = false;
|
||||
SET REFERENTIAL_INTEGRITY FALSE;
|
||||
|
||||
DROP TABLE IF EXISTS middleware_manager;
|
||||
-- ----------------------------
|
||||
-- Table structure for middleware_manager
|
||||
-- ----------------------------
|
||||
CREATE TABLE IF NOT EXISTS middleware_manager ( -- 部署命令
|
||||
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, -- id
|
||||
"uid" TEXT(48) NOT NULL, -- 部署命令UUID
|
||||
"middleware" TEXT(256) NOT NULL, -- 操作模块
|
||||
"middleware_ver" TEXT(256), -- 操作模块
|
||||
"work_directory" TEXT(4096) NOT NULL, -- 操作类型
|
||||
"deployment" TEXT, -- 部署命令
|
||||
"config" TEXT, -- 配置命令
|
||||
"start" TEXT, -- 启动命令
|
||||
"stop" TEXT, -- 停止命令
|
||||
"restart" TEXT, -- 重启命令
|
||||
"uninstall" TEXT, -- 卸载命令
|
||||
"created_time" DATE DEFAULT (DATETIME('now', 'localtime')), -- 创建时间
|
||||
"upgrade_time" DATE DEFAULT (DATETIME('now', 'localtime')) -- 更新时间
|
||||
CREATE TABLE IF NOT EXISTS middleware_manager (
|
||||
"id" BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'id',
|
||||
"uid" VARCHAR(48) NOT NULL UNIQUE COMMENT '部署命令UUID',
|
||||
"middleware" VARCHAR(256) NOT NULL COMMENT '中间件名称',
|
||||
"middleware_ver" VARCHAR(256) COMMENT '中间件版本',
|
||||
"work_directory" VARCHAR(4096) NOT NULL COMMENT '部署工作目录',
|
||||
"deployment" VARCHAR COMMENT '部署命令',
|
||||
"config" VARCHAR COMMENT '配置命令',
|
||||
"start" VARCHAR COMMENT '启动命令',
|
||||
"stop" VARCHAR COMMENT '停止命令',
|
||||
"restart" VARCHAR COMMENT '重启命令',
|
||||
"uninstall" VARCHAR COMMENT '卸载命令',
|
||||
"created_time" DATE DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
|
||||
"upgrade_time" DATE DEFAULT CURRENT_TIMESTAMP(6) COMMENT '更新时间'
|
||||
);
|
||||
|
||||
PRAGMA foreign_keys = true;
|
||||
SET REFERENTIAL_INTEGRITY TRUE;
|
|
@ -14,6 +14,8 @@ import com.cmcc.magent.crypto.RequestProtocolSecurityTest;
|
|||
import com.cmcc.magent.crypto.arithmetic.CryptoHelperTest;
|
||||
import com.cmcc.magent.exception.CustomExceptionTest;
|
||||
import com.cmcc.magent.interceptor.RequestBodyCacheWrapperTest;
|
||||
import com.cmcc.magent.interceptor.RequestBodyFilterTest;
|
||||
import com.cmcc.magent.interceptor.RestfulLogAspectTest;
|
||||
import com.cmcc.magent.mapper.MiddlewareDataMapperTest;
|
||||
import com.cmcc.magent.misc.ApiContextUtilsTest;
|
||||
import com.cmcc.magent.misc.CircularQueueSerializerTest;
|
||||
|
@ -30,6 +32,7 @@ import com.cmcc.magent.misc.SpringBootBeanUtilsTest;
|
|||
import com.cmcc.magent.pojo.mapper.IObjectConvertImplTest;
|
||||
import com.cmcc.magent.pojo.vo.ProtocolRespTest;
|
||||
import com.cmcc.magent.service.impl.MiddlewareManagerServiceImplTest;
|
||||
import com.cmcc.magent.service.impl.OperationLogServiceImplTest;
|
||||
import com.cmcc.magent.service.impl.PlatformApiServiceImplTest;
|
||||
import com.cmcc.magent.service.impl.ProtocolSecurityServiceImplTest;
|
||||
import com.cmcc.magent.service.impl.ResourceUsageServiceImplTest;
|
||||
|
@ -52,7 +55,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||
* <p>
|
||||
* 测试类包括:
|
||||
* <ul>
|
||||
* <li>{@link CommonFrameworkApiTest}</li>
|
||||
* <li>{@link CommonFrameworkApiTest}, {@link OperationLogServiceImplTest}</li>
|
||||
* <li>{@link EnumCoverTest}</li>
|
||||
* <li>{@link HelperUtilsTest}</li>
|
||||
* <li>{@link PlatformApiServiceImplTest}</li>
|
||||
|
@ -77,8 +80,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||
* <li>{@link ProtocolConfigureTest}</li>
|
||||
* <li>{@link ProtocolRespTest}</li>
|
||||
* <li>{@link ApiContextUtilsTest}</li>
|
||||
* <li>{@link HttpUtilsTest}</li>
|
||||
* <li>{@link JsonUtilsTest}</li>
|
||||
* <li>{@link HttpUtilsTest}, {@link RequestBodyFilterTest}</li>
|
||||
* <li>{@link JsonUtilsTest}, {@link RestfulLogAspectTest}</li>
|
||||
* <li>{@link MessageUtilTest}, {@link MiddlewareManagerApiTest}</li>
|
||||
* <li>{@link IObjectConvertImplTest}, {@link MiddlewareManagerServiceImplTest}</li>
|
||||
* <li>{@link ExecutingCommandTest}, {@link AutoExternStringJsonProcessTest}</li>
|
||||
|
@ -101,7 +104,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||
MessageUtilTest.class, IObjectConvertImplTest.class, ExecutingCommandTest.class, HttpClientUtilsTest.class,
|
||||
FileDownloaderTest.class, CustomLifecycleTest.class, MiddlewareDataMapperTest.class, MiddlewareAgentApplicationTest.class,
|
||||
ValidFixValuesImplTest.class, AutoExternStringJsonProcessTest.class, MiddlewareManagerServiceImplTest.class,
|
||||
MiddlewareManagerApiTest.class})
|
||||
MiddlewareManagerApiTest.class, RestfulLogAspectTest.class, RequestBodyFilterTest.class, OperationLogServiceImplTest.class})
|
||||
@DisplayName("接口集成测试")
|
||||
@Suite
|
||||
@EnableScheduling
|
||||
|
|
|
@ -109,9 +109,6 @@ public class EnumCoverTest {
|
|||
@DisplayName("遍历枚举")
|
||||
void testEnumCover() {
|
||||
for (ErrorCode e : ErrorCode.values()) {
|
||||
// System.out.println(e.getStringValue() + "|" + e.getValue() + "|" + e.getDescription());
|
||||
// System.out.println(e.getValue());
|
||||
// System.out.println(e.getDescription());
|
||||
assertThat(e).isNotNull();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import static org.mockito.Mockito.when;
|
|||
* @since 2025-01-20
|
||||
*/
|
||||
@DisplayName("RequestProtocolSecurity 测试类")
|
||||
@SuppressWarnings("unchecked")
|
||||
public class RequestProtocolSecurityTest {
|
||||
|
||||
@InjectMocks
|
||||
|
@ -190,16 +191,16 @@ public class RequestProtocolSecurityTest {
|
|||
*/
|
||||
@Test
|
||||
@DisplayName("afterBodyRead 应返回相同对象")
|
||||
@SuppressWarnings("unchecked")
|
||||
public void afterBodyRead_ShouldReturnSameObject() {
|
||||
// Arrange
|
||||
Object decryptedObject = new Object();
|
||||
HttpInputMessage httpInputMessage = mock(HttpInputMessage.class);
|
||||
MethodParameter methodParameter = mock(MethodParameter.class);
|
||||
Type type = mock(Type.class);
|
||||
Class<? extends HttpMessageConverter<?>> converterType = aClass;
|
||||
|
||||
// Act
|
||||
Object result = requestProtocolSecurity.afterBodyRead(decryptedObject, httpInputMessage, methodParameter, type, converterType);
|
||||
Object result = requestProtocolSecurity.afterBodyRead(decryptedObject, httpInputMessage, methodParameter, type, aClass);
|
||||
|
||||
// Assert
|
||||
assertEquals(decryptedObject, result, "The method should return the same object that was passed in.");
|
||||
|
|
|
@ -3,22 +3,32 @@ package com.cmcc.magent.interceptor;
|
|||
import jakarta.servlet.ReadListener;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
|
@ -45,9 +55,15 @@ import static org.mockito.Mockito.when;
|
|||
@DisplayName("HTTP请求数据处理")
|
||||
public class RequestBodyCacheWrapperTest {
|
||||
|
||||
private RequestBodyCacheWrapper wrapper;
|
||||
private RequestBodyCacheWrapper requestWrapper;
|
||||
private MockHttpServletRequest mockRequest;
|
||||
@InjectMocks
|
||||
private RequestBodyCacheWrapper requestBodyCacheWrapper;
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest httpRequest;
|
||||
|
||||
private Logger logger;
|
||||
|
||||
private ServletInputStream servletInputStream;
|
||||
|
||||
/**
|
||||
* 初始化方法:在每个测试方法执行之前运行。
|
||||
|
@ -58,9 +74,29 @@ public class RequestBodyCacheWrapperTest {
|
|||
* @throws IOException 如果发生 I/O 异常
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||
ServletInputStream servletInputStream = new ServletInputStream() {
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
logger = mock(Logger.class);
|
||||
|
||||
// 获取 MyService 的 Class 对象
|
||||
Class<?> clazz = RequestBodyCacheWrapper.class;
|
||||
// 获取 log 字段
|
||||
Field logField = clazz.getDeclaredField("log");
|
||||
// 设置字段可访问
|
||||
logField.setAccessible(true);
|
||||
// 获取 Unsafe 实例
|
||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
// 获取 log 字段的偏移量
|
||||
long offset = unsafe.staticFieldOffset(logField);
|
||||
// 获取 log 字段所属的类对象
|
||||
Object base = unsafe.staticFieldBase(logField);
|
||||
|
||||
// 使用 Unsafe 修改 log 字段的值
|
||||
unsafe.putObject(base, offset, logger);
|
||||
|
||||
servletInputStream = new ServletInputStream() {
|
||||
private final InputStream inputStream = new ByteArrayInputStream("testBody".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
@Override
|
||||
|
@ -88,24 +124,18 @@ public class RequestBodyCacheWrapperTest {
|
|||
return inputStream.read();
|
||||
}
|
||||
};
|
||||
when(request.getInputStream()).thenReturn(servletInputStream);
|
||||
wrapper = new RequestBodyCacheWrapper(request);
|
||||
|
||||
mockRequest = new MockHttpServletRequest();
|
||||
requestWrapper = new RequestBodyCacheWrapper(mockRequest);
|
||||
when(httpRequest.getInputStream()).thenReturn(servletInputStream);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws IOException {
|
||||
servletInputStream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试场景:验证从输入流中读取缓存的请求体是否正确。
|
||||
*
|
||||
* <p>预期结果:返回的内容应与原始请求体一致。</p>
|
||||
*
|
||||
* @throws IOException 如果发生 I/O 异常
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("验证从输入流中读取缓存的请求体是否正确")
|
||||
@DisplayName("读取缓存的请求体")
|
||||
public void getInputStream_ReadsCachedBody() throws IOException {
|
||||
ServletInputStream servletInputStream = wrapper.getInputStream();
|
||||
ServletInputStream servletInputStream = requestBodyCacheWrapper.getInputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead = servletInputStream.read(buffer);
|
||||
// 确保 bytesRead 不为负数
|
||||
|
@ -117,55 +147,118 @@ public class RequestBodyCacheWrapperTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试场景:验证输入流的 {@code isFinished()} 方法是否始终返回 false。
|
||||
*
|
||||
* <p>预期结果:方法返回 false。</p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("验证输入流的 isFinished() 方法是否始终返回 false")
|
||||
@DisplayName("isFinished()方法返回false")
|
||||
public void isFinished_AlwaysReturnsFalse() {
|
||||
ServletInputStream servletInputStream = wrapper.getInputStream();
|
||||
ServletInputStream servletInputStream = requestBodyCacheWrapper.getInputStream();
|
||||
assertFalse(servletInputStream.isFinished());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试场景:验证输入流的 {@code isReady()} 方法是否始终返回 false。
|
||||
*
|
||||
* <p>预期结果:方法返回 false。</p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("验证输入流的 isReady() 方法是否始终返回 false")
|
||||
@DisplayName("isReady()方法返回false")
|
||||
public void isReady_AlwaysReturnsFalse() {
|
||||
ServletInputStream servletInputStream = wrapper.getInputStream();
|
||||
ServletInputStream servletInputStream = requestBodyCacheWrapper.getInputStream();
|
||||
assertFalse(servletInputStream.isReady());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试场景:验证设置读取监听器时是否正确执行。
|
||||
*
|
||||
* <p>预期结果:调用 {@code setReadListener()} 方法时不抛出异常。</p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("验证设置读取监听器时是否正确执行")
|
||||
@DisplayName("设置读取监听器")
|
||||
public void setReadListener_DoesNothing() {
|
||||
ServletInputStream servletInputStream = wrapper.getInputStream();
|
||||
ServletInputStream servletInputStream = requestBodyCacheWrapper.getInputStream();
|
||||
servletInputStream.setReadListener(null); // 不应抛出异常
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试场景:验证使用 {@code getReader()} 方法获取请求体内容是否正确。
|
||||
*
|
||||
* <p>预期结果:返回的 {@link BufferedReader} 对象不为空。</p>
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("验证使用 getReader() 方法获取请求体内容是否正确")
|
||||
public void getReader_ShouldReturnCorrectBody() {
|
||||
String requestBody = "{\"key\":\"value\"}";
|
||||
@DisplayName("使用getReader()获取请求体内容")
|
||||
public void getReader_ShouldReturnCorrectBody() throws IOException {
|
||||
String requestBody = "{\"key\":\"value\"}";
|
||||
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
|
||||
RequestBodyCacheWrapper requestWrapper = new RequestBodyCacheWrapper(mockRequest);
|
||||
|
||||
mockRequest.setContent(requestBody.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
BufferedReader reader = requestWrapper.getReader();
|
||||
assertNotNull(reader);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空输入流时读取器行为")
|
||||
public void getReader_EmptyInputStream_ReturnsEmptyString() throws IOException {
|
||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||
ServletInputStream servletInputStream = new ServletInputStream() {
|
||||
private final InputStream inputStream = new ByteArrayInputStream(new byte[0]);
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
try {
|
||||
return inputStream.available() == 0;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
// 不执行任何操作
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return inputStream.read();
|
||||
}
|
||||
};
|
||||
when(request.getInputStream()).thenReturn(servletInputStream);
|
||||
RequestBodyCacheWrapper emptyWrapper = new RequestBodyCacheWrapper(request);
|
||||
|
||||
BufferedReader reader = emptyWrapper.getReader();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
char[] charBuffer = new char[128];
|
||||
int bytesRead;
|
||||
while ((bytesRead = reader.read(charBuffer)) > 0) {
|
||||
stringBuilder.append(charBuffer, 0, bytesRead);
|
||||
}
|
||||
assertEquals("", stringBuilder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("构造函数读写异常")
|
||||
public void requestBodyCacheWrapper_ReadException() throws IOException {
|
||||
when(httpRequest.getInputStream()).thenThrow(new IOException("null"));
|
||||
|
||||
// 验证 log.info 是否被调用,并检查输出内容
|
||||
new RequestBodyCacheWrapper(httpRequest);
|
||||
verify(logger).error(eq("RequestWrapper read error :{}"), eq("null"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("获取请求体JSON内容")
|
||||
public void getReader_Json_ShouldReturnCorrectBody() throws IOException {
|
||||
String requestBody = "{\"key\":\"value\"}";
|
||||
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
|
||||
mockRequest.setContent(requestBody.getBytes(StandardCharsets.UTF_8));
|
||||
// 添加单个请求头
|
||||
mockRequest.addHeader("Authorization", "Bearer token123");
|
||||
// 设置请求头(覆盖已存在的值)
|
||||
mockRequest.addHeader("Content-Type", "application/json");
|
||||
// 添加多个值的请求头
|
||||
mockRequest.addHeader("Accept", "application/json");
|
||||
|
||||
when(httpRequest.getInputStream()).thenReturn(mockRequest.getInputStream());
|
||||
|
||||
RequestBodyCacheWrapper requestWrapper = new RequestBodyCacheWrapper(mockRequest);
|
||||
BufferedReader reader = requestWrapper.getReader();
|
||||
assertNotNull(reader);
|
||||
assertNotNull(requestWrapper.getHeaders());
|
||||
assertEquals(3, requestWrapper.getHeaders().size());
|
||||
assertEquals("Bearer token123", requestWrapper.getHeaders().get("Authorization"));
|
||||
assertEquals("application/json", requestWrapper.getHeaders().get("Content-Type"));
|
||||
assertEquals("application/json", requestWrapper.getHeaders().get("Accept"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
package com.cmcc.magent.interceptor;
|
||||
|
||||
import com.cmcc.magent.config.ObjectMapperProvider;
|
||||
import com.cmcc.magent.misc.MessageUtil;
|
||||
import com.cmcc.magent.misc.ProtocolJsonUtils;
|
||||
import com.cmcc.magent.pojo.vo.DeploymentMiddlewareResp;
|
||||
import com.cmcc.magent.pojo.vo.ProtocolResp;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.FilterConfig;
|
||||
import jakarta.servlet.ReadListener;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* RequestBodyFilter 测试类,用于测试 RequestBodyFilter 过滤器的功能。
|
||||
* 该类通过模拟 HTTP 请求、过滤器链、请求和响应对象,验证过滤器在不同场景下的行为。
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-02-26
|
||||
*/
|
||||
@DisplayName("协议请求JSON拦截")
|
||||
public class RequestBodyFilterTest {
|
||||
@InjectMocks
|
||||
private RequestBodyFilter requestBodyFilter;
|
||||
@Mock
|
||||
private FilterConfig filterConfig;
|
||||
@Mock
|
||||
private FilterChain filterChain;
|
||||
@Mock
|
||||
private ServletRequest servletRequest;
|
||||
@Mock
|
||||
private ServletResponse servletResponse;
|
||||
|
||||
private MockedStatic<ProtocolJsonUtils> mockProtocolJsonUtils;
|
||||
private MockedStatic<ObjectMapperProvider> mockObjectMapperProvider;
|
||||
private MockedStatic<MessageUtil> mockMessageUtil;
|
||||
/**
|
||||
* 在每个测试方法执行前初始化测试环境。
|
||||
* 包括初始化 Mock 对象、模拟静态方法等。
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
mockMessageUtil = mockStatic(MessageUtil.class);
|
||||
mockObjectMapperProvider = mockStatic(ObjectMapperProvider.class);
|
||||
mockProtocolJsonUtils = mockStatic(ProtocolJsonUtils.class);
|
||||
}
|
||||
/**
|
||||
* 在每个测试方法执行后清理测试环境。
|
||||
* 包括关闭模拟的静态方法。
|
||||
*/
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
mockProtocolJsonUtils.close();
|
||||
mockObjectMapperProvider.close();
|
||||
mockMessageUtil.close();
|
||||
}
|
||||
/**
|
||||
* 测试过滤器初始化方法是否不会抛出异常。
|
||||
* 验证在调用 `init()` 方法时,不会抛出任何异常。
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("初始化不抛异常")
|
||||
public void init_ShouldNotThrowException() {
|
||||
assertDoesNotThrow(() -> requestBodyFilter.init(filterConfig));
|
||||
}
|
||||
/**
|
||||
* 测试当请求是 HttpServletRequest 时,过滤器是否对请求进行包装。
|
||||
* 验证在请求是 HttpServletRequest 的情况下,过滤器会包装请求并调用过滤器链。
|
||||
*
|
||||
* @throws Exception 如果测试过程中发生异常
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HttpServletRequest时包装请求")
|
||||
@SuppressWarnings("unchecked")
|
||||
public void doFilter_RequestIsHttpServletRequest_WrapsRequest() throws Exception {
|
||||
HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
|
||||
DeploymentMiddlewareResp resp = DeploymentMiddlewareResp.builder().deploymentId("3dd6175c-ca47-4640-83e0-5231c037c5ac").build();
|
||||
resp.setStatus(0);
|
||||
resp.setMessage(new String[]{"success"});
|
||||
ProtocolResp<DeploymentMiddlewareResp> protocolRespB = new ProtocolResp<>();
|
||||
protocolRespB.setVer(1);
|
||||
protocolRespB.setCryptoType(0);
|
||||
protocolRespB.setTimeStamp(1740564578790L);
|
||||
protocolRespB.setCode(200);
|
||||
protocolRespB.setMsgContent(resp);
|
||||
String requestBody = """
|
||||
{"ver":1,"cryptoType":0,"timeStamp":1740564578790,"code":200,"msgContent":\
|
||||
{"deploymentId":"3dd6175c-ca47-4640-83e0-5231c037c5ac","status":0,"message":["success"]}}
|
||||
""";
|
||||
MockHttpServletRequest mockRequest = new MockHttpServletRequest();
|
||||
mockRequest.setContent(requestBody.getBytes(StandardCharsets.UTF_8));
|
||||
ServletInputStream servletInputStream = new ServletInputStream() {
|
||||
private final InputStream inputStream = new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8));
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
try {
|
||||
return inputStream.available() == 0;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
// 不执行任何操作
|
||||
}
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return inputStream.read();
|
||||
}
|
||||
};
|
||||
when(httpServletRequest.getInputStream()).thenReturn(servletInputStream);
|
||||
mockProtocolJsonUtils.when(() -> ProtocolJsonUtils.jsonGetObject(anyString(), any(Class.class))).thenReturn(protocolRespB);
|
||||
mockMessageUtil.when(() -> MessageUtil.get(anyString(), anyString())).thenReturn("");
|
||||
requestBodyFilter.doFilter(httpServletRequest, servletResponse, filterChain);
|
||||
verify(filterChain).doFilter(any(RequestBodyCacheWrapper.class), eq(servletResponse));
|
||||
}
|
||||
/**
|
||||
* 测试当请求不是 HttpServletRequest 时,过滤器是否直接传递原始请求。
|
||||
* 验证在请求不是 HttpServletRequest 的情况下,过滤器不会包装请求,而是直接传递原始请求。
|
||||
*
|
||||
* @throws IOException 如果测试过程中发生 IO 异常
|
||||
* @throws ServletException 如果测试过程中发生 Servlet 异常
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("非HttpServletRequest时传递原始请求")
|
||||
public void doFilter_RequestIsNotHttpServletRequest_PassesOriginalRequest() throws IOException, ServletException {
|
||||
servletRequest = mock(ServletRequest.class);
|
||||
requestBodyFilter.doFilter(servletRequest, servletResponse, filterChain);
|
||||
verify(filterChain).doFilter(eq(servletRequest), eq(servletResponse));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
package com.cmcc.magent.interceptor;
|
||||
|
||||
import com.cmcc.magent.common.ErrorCode;
|
||||
import com.cmcc.magent.misc.MessageUtil;
|
||||
import com.cmcc.magent.pojo.base.BaseProtocol;
|
||||
import com.cmcc.magent.pojo.po.BaseRespStatus;
|
||||
import com.cmcc.magent.pojo.vo.ProtocolResp;
|
||||
import com.cmcc.magent.service.OperationLogService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.isNull;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* RestfulLogAspect 测试类,用于测试 RestfulLogAspect 切面的功能。
|
||||
* 该类通过模拟 HTTP 请求、请求上下文、日志服务等,验证切面在不同场景下的行为。
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-02-26
|
||||
*/
|
||||
@DisplayName("API接口系统日志注入")
|
||||
public class RestfulLogAspectTest {
|
||||
private MockMvc mockMvc;
|
||||
@Mock
|
||||
private OperationLogService optLogDbService;
|
||||
@InjectMocks
|
||||
private RestfulLogAspect restfulLogAspect;
|
||||
@Mock
|
||||
private JoinPoint joinPoint;
|
||||
@Mock
|
||||
private MethodSignature methodSignature;
|
||||
@Mock
|
||||
private HttpServletRequest request;
|
||||
@Mock
|
||||
private RequestAttributes requestAttributes;
|
||||
private MockedStatic<MessageUtil> mockMessageUtil;
|
||||
private MockedStatic<RequestContextHolder> mockRequestContextHolder;
|
||||
|
||||
/**
|
||||
* 在每个测试方法执行前初始化测试环境。
|
||||
* 包括初始化 Mock 对象、模拟静态方法等。
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
mockMessageUtil = mockStatic(MessageUtil.class);
|
||||
mockRequestContextHolder = mockStatic(RequestContextHolder.class);
|
||||
mockMvc = MockMvcBuilders.standaloneSetup(new Object()).build();
|
||||
when(requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST)).thenReturn(request);
|
||||
when(joinPoint.getSignature()).thenReturn(methodSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在每个测试方法执行后清理测试环境。
|
||||
* 包括关闭模拟的静态方法。
|
||||
*/
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
mockMessageUtil.close();
|
||||
mockRequestContextHolder.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 RestfulLogAspect 切面是否能够拦截控制器方法。
|
||||
* 验证切面在拦截到控制器方法后是否调用了日志服务。
|
||||
*
|
||||
* @throws Exception 如果测试过程中发生异常
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("拦截控制器方法")
|
||||
public void restfulLog_AspectInterceptsControllerMethod() throws Exception {
|
||||
doNothing().when(optLogDbService).systemOperationLog(any(), any(), any(), any(), any(), any(), any());
|
||||
restfulLogAspect.restfulLog();
|
||||
mockMvc.perform(get("/test")).andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当请求上下文为空时,是否不会记录日志。
|
||||
* 验证在请求上下文为空的情况下,日志服务未被调用。
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("请求上下文为空时不记录日志")
|
||||
public void saveOperationLog_RequestAttributesIsNull_NoLogging() {
|
||||
mockRequestContextHolder.when(RequestContextHolder::getRequestAttributes).thenReturn(null);
|
||||
restfulLogAspect.saveOperationLog(joinPoint, new Object());
|
||||
verify(optLogDbService, never()).systemOperationLog(anyString(), any(HttpServletRequest.class), any(), any(), any());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当 HTTP 请求对象为空时,是否不会记录日志。
|
||||
* 验证在 HTTP 请求对象为空的情况下,日志服务未被调用。
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HTTP请求对象为空时不记录日志")
|
||||
public void saveOperationLog_HttpServletRequestIsNull_NoLogging() {
|
||||
mockRequestContextHolder.when(RequestContextHolder::getRequestAttributes).thenReturn(requestAttributes);
|
||||
when(requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST)).thenReturn(null);
|
||||
restfulLogAspect.saveOperationLog(joinPoint, new Object());
|
||||
verify(optLogDbService, never()).systemOperationLog(anyString(), any(HttpServletRequest.class), any(), any(), any());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试在正常请求和响应的情况下,是否能够成功记录日志。
|
||||
* 验证日志服务在正常场景下被正确调用。
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("正常请求和响应时记录日志")
|
||||
public void saveOperationLog_Success() {
|
||||
mockRequestContextHolder.when(RequestContextHolder::getRequestAttributes).thenReturn(requestAttributes);
|
||||
when(requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST)).thenReturn(request);
|
||||
mockMessageUtil.when(() -> MessageUtil.get(anyString(), anyString())).thenReturn("Test");
|
||||
when(methodSignature.getMethod()).thenReturn(new Object() {
|
||||
}.getClass().getEnclosingMethod());
|
||||
ProtocolResp<BaseRespStatus> result = new ProtocolResp<>();
|
||||
result.setMsgContent(new BaseRespStatus(0, new String[] {"Test"}));
|
||||
restfulLogAspect.saveOperationLog(joinPoint, result);
|
||||
verify(optLogDbService).systemOperationLog(anyString(), eq(request), eq(result), isNull(), eq(ErrorCode.ERR_OK));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试当响应对象类型不合法时,是否记录系统异常日志。
|
||||
* 验证在响应对象类型不合法的情况下,日志服务被调用并记录系统异常。
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("响应对象类型不合法时记录系统异常日志")
|
||||
public void saveOperationLog_UnValidProtocolResp_TypeError() {
|
||||
BaseProtocol<String> baseProtocol = new BaseProtocol<>();
|
||||
mockRequestContextHolder.when(RequestContextHolder::getRequestAttributes).thenReturn(requestAttributes);
|
||||
when(requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST)).thenReturn(request);
|
||||
mockMessageUtil.when(() -> MessageUtil.get(anyString(), anyString())).thenReturn("Test");
|
||||
when(methodSignature.getMethod()).thenReturn(new Object() {
|
||||
}.getClass().getEnclosingMethod());
|
||||
restfulLogAspect.saveOperationLog(joinPoint, baseProtocol);
|
||||
verify(optLogDbService).systemOperationLog(anyString(), eq(request), eq(baseProtocol), isNull(), eq(ErrorCode.ERR_SYSTEMEXCEPTION));
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@ import org.mockito.Mockito;
|
|||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -50,7 +49,7 @@ public class ExecutingCommandTest {
|
|||
private static final String[][] TEST_CMD_ARRAY = {{"ping", "-c", "1", "www.baidu.com"}, {"echo", "www.baidu.com"}, {"pwd"}};
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
helperUtils = mockStatic(HelperUtils.class, Mockito.CALLS_REAL_METHODS);
|
||||
}
|
||||
|
|
|
@ -232,10 +232,8 @@ public class HelperUtilsTest {
|
|||
// 断言结果为 false
|
||||
assertFalse(result);
|
||||
|
||||
// null 字符串
|
||||
str = null;
|
||||
// 断言结果为 false
|
||||
assertFalse(HelperUtils.stringNotEmptyOrNull(str));
|
||||
assertFalse(HelperUtils.stringNotEmptyOrNull(null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,9 @@ import org.mockito.MockitoAnnotations;
|
|||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -48,6 +51,7 @@ import static org.mockito.Mockito.when;
|
|||
*/
|
||||
@SpringBootTest
|
||||
@DisplayName("HttpClient 测试类")
|
||||
@SuppressWarnings("unchecked")
|
||||
public class HttpClientUtilsTest {
|
||||
|
||||
private static final String SUCCESS_URL = "https://example.com/success";
|
||||
|
@ -62,6 +66,7 @@ public class HttpClientUtilsTest {
|
|||
private MockedStatic<HttpClientUtils> platformMock;
|
||||
private MockedStatic<HttpClients> httpClientsMock;
|
||||
private MockedStatic<HttpAsyncClients> httpAsyncClientsMock;
|
||||
private MockedStatic<EntityUtils> entityUtilsMock;
|
||||
|
||||
// 创建 Mock 的 HttpClient
|
||||
private CloseableHttpClient mockHttpClient;
|
||||
|
@ -73,6 +78,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
private FutureCallback<SimpleHttpResponse> mockCallback;
|
||||
|
||||
|
||||
/**
|
||||
* 在每个测试前进行设置。
|
||||
* 创建 HttpClient 和响应的 Mock 对象,并初始化 Mockito。
|
||||
|
@ -85,6 +91,7 @@ public class HttpClientUtilsTest {
|
|||
platformMock = mockStatic(HttpClientUtils.class, Mockito.CALLS_REAL_METHODS);
|
||||
httpClientsMock = mockStatic(HttpClients.class, Mockito.CALLS_REAL_METHODS);
|
||||
httpAsyncClientsMock = mockStatic(HttpAsyncClients.class, Mockito.CALLS_REAL_METHODS);
|
||||
entityUtilsMock = mockStatic(EntityUtils.class);
|
||||
|
||||
mockHttpClient = Mockito.mock(CloseableHttpClient.class);
|
||||
mockResponse = Mockito.mock(ClassicHttpResponse.class);
|
||||
|
@ -112,10 +119,10 @@ public class HttpClientUtilsTest {
|
|||
*/
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
|
||||
httpClientsMock.close();
|
||||
platformMock.close();
|
||||
httpAsyncClientsMock.close();
|
||||
entityUtilsMock.close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,7 +147,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("GET 成功")
|
||||
public void get_Success() throws IOException, ParseException {
|
||||
public void get_Success() throws IOException {
|
||||
when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenReturn(SUCCESS_RESPONSE);
|
||||
// 调用 get 方法并验证结果
|
||||
String response = HttpClientUtils.get(SUCCESS_URL, null, null);
|
||||
|
@ -153,9 +160,7 @@ public class HttpClientUtilsTest {
|
|||
Mockito.when(mockResponse.getCode()).thenReturn(404);
|
||||
mockResponse.setEntity(new StringEntity(FAILURE_JSON_RESPONSE, StandardCharsets.UTF_8));
|
||||
// 模拟对于不同的响应处理器返回不同的值
|
||||
Mockito.when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenAnswer(invocation -> {
|
||||
return handleResponse(mockResponse);
|
||||
});
|
||||
Mockito.when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenAnswer(invocation -> handleResponse(mockResponse));
|
||||
// 调用 get 方法并验证结果
|
||||
assertThrows(CommonErrorCodeException.class, () -> HttpClientUtils.get(FAILURE_URL, null, null));
|
||||
}
|
||||
|
@ -172,7 +177,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("GET 带头部成功")
|
||||
public void get_WithHead_Success() throws IOException, ParseException {
|
||||
public void get_WithHead_Success() throws IOException {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Custom-Header", "Value");
|
||||
|
||||
|
@ -183,7 +188,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("GET 带超时成功")
|
||||
public void get_WithTiemout_Success() throws IOException, ParseException {
|
||||
public void get_WithTiemout_Success() throws IOException {
|
||||
when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenReturn(SUCCESS_RESPONSE);
|
||||
String response = HttpClientUtils.get(SUCCESS_URL, null, 10);
|
||||
assertEquals(SUCCESS_RESPONSE, response);
|
||||
|
@ -191,7 +196,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("GET 超时为零或负数成功")
|
||||
public void get_WithTiemoutLessOrEqueleZero_Success() throws IOException, ParseException {
|
||||
public void get_WithTiemoutLessOrEqueleZero_Success() throws IOException {
|
||||
when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenReturn(SUCCESS_RESPONSE);
|
||||
String response = HttpClientUtils.get(SUCCESS_URL, null, 0);
|
||||
assertEquals(SUCCESS_RESPONSE, response);
|
||||
|
@ -202,7 +207,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("POST 成功")
|
||||
public void post_Success() throws IOException, ParseException {
|
||||
public void post_Success() throws IOException {
|
||||
when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenReturn(SUCCESS_RESPONSE);
|
||||
String response = HttpClientUtils.post(SUCCESS_URL, null, null, null);
|
||||
assertEquals(SUCCESS_RESPONSE, response);
|
||||
|
@ -210,7 +215,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("POST 带头部成功")
|
||||
public void post_WithHead_Success() throws IOException, ParseException {
|
||||
public void post_WithHead_Success() throws IOException {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Custom-Header", "Value");
|
||||
|
||||
|
@ -221,7 +226,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("POST 带参数成功")
|
||||
public void post_WithParams_Success() throws IOException, ParseException {
|
||||
public void post_WithParams_Success() throws IOException {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("user", "user");
|
||||
params.put("pwd", "pwd");
|
||||
|
@ -233,7 +238,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("POST 带空参数成功")
|
||||
public void post_WithEmptyParams_Success() throws IOException, ParseException {
|
||||
public void post_WithEmptyParams_Success() throws IOException {
|
||||
Map<String, String> params = new HashMap<>(1);
|
||||
|
||||
when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenReturn(SUCCESS_RESPONSE);
|
||||
|
@ -243,7 +248,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("POST 带超时成功")
|
||||
public void post_WithTiemout_Success() throws IOException, ParseException {
|
||||
public void post_WithTiemout_Success() throws IOException {
|
||||
when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenReturn(SUCCESS_RESPONSE);
|
||||
String response = HttpClientUtils.post(SUCCESS_URL, null, null, 10);
|
||||
assertEquals(SUCCESS_RESPONSE, response);
|
||||
|
@ -251,7 +256,7 @@ public class HttpClientUtilsTest {
|
|||
|
||||
@Test
|
||||
@DisplayName("POST 超时为零或负数成功")
|
||||
public void post_WithTiemoutLessOrEqueleZero_Success() throws IOException, ParseException {
|
||||
public void post_WithTiemoutLessOrEqueleZero_Success() throws IOException {
|
||||
when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenReturn(SUCCESS_RESPONSE);
|
||||
String response = HttpClientUtils.post(SUCCESS_URL, null, null, 0);
|
||||
assertEquals(SUCCESS_RESPONSE, response);
|
||||
|
@ -651,4 +656,70 @@ public class HttpClientUtilsTest {
|
|||
HttpClientUtils.asyncPostForm(FAILURE_URL, null, form, null, mockCallback);
|
||||
mockCallback.failed(exception);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("私有handleResponse调用空Entity")
|
||||
public void get_WithHead_Handle_entityNull() throws IOException {
|
||||
Mockito.when(mockResponse.getCode()).thenReturn(404);
|
||||
mockResponse.setEntity(new StringEntity(FAILURE_JSON_RESPONSE, StandardCharsets.UTF_8));
|
||||
// 模拟对于不同的响应处理器返回不同的值
|
||||
Mockito.when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenAnswer(invocation -> {
|
||||
// 获取私有方法 handleResponse
|
||||
Class<?> clazz = HttpClientUtils.class;
|
||||
// private static String handleResponse(ClassicHttpResponse response)
|
||||
Method method = clazz.getDeclaredMethod("handleResponse", ClassicHttpResponse.class);
|
||||
// 设置方法为可访问
|
||||
method.setAccessible(true);
|
||||
|
||||
// 调用私有方法
|
||||
return method.invoke(null, mockResponse);
|
||||
});
|
||||
// 调用 get 方法并验证结果
|
||||
assertThrows(InvocationTargetException.class, () -> HttpClientUtils.get(FAILURE_URL, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("私有handleResponse返回值200")
|
||||
public void get_WithHead_Handle_isOK() throws IOException {
|
||||
when(mockResponse.getCode()).thenReturn(200);
|
||||
when(mockResponse.getEntity()).thenReturn(new StringEntity(FAILURE_JSON_RESPONSE, StandardCharsets.UTF_8));
|
||||
// mockResponse.setEntity(new StringEntity(FAILURE_JSON_RESPONSE, StandardCharsets.UTF_8));
|
||||
entityUtilsMock.when(() -> EntityUtils.toString(any(HttpEntity.class), any(Charset.class))).thenReturn("message");
|
||||
// 模拟对于不同的响应处理器返回不同的值
|
||||
Mockito.when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenAnswer(invocation -> {
|
||||
// 获取私有方法 handleResponse
|
||||
Class<?> clazz = HttpClientUtils.class;
|
||||
// private static String handleResponse(ClassicHttpResponse response)
|
||||
Method method = clazz.getDeclaredMethod("handleResponse", ClassicHttpResponse.class);
|
||||
// 设置方法为可访问
|
||||
method.setAccessible(true);
|
||||
|
||||
// 调用私有方法
|
||||
return method.invoke(null, mockResponse);
|
||||
});
|
||||
// 调用 get 方法并验证结果
|
||||
assertEquals("message", HttpClientUtils.get(FAILURE_URL, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("私有handleResponse调用非空Entity")
|
||||
public void get_WithHead_Handle_entityNotNull() throws IOException {
|
||||
Mockito.when(mockResponse.getCode()).thenReturn(404);
|
||||
when(mockResponse.getEntity()).thenReturn(new StringEntity(FAILURE_JSON_RESPONSE, StandardCharsets.UTF_8));
|
||||
entityUtilsMock.when(() -> EntityUtils.toString(any(HttpEntity.class), any(Charset.class))).thenReturn("message");
|
||||
// 模拟对于不同的响应处理器返回不同的值
|
||||
Mockito.when(mockHttpClient.execute(any(ClassicHttpRequest.class), any(HttpClientResponseHandler.class))).thenAnswer(invocation -> {
|
||||
// 获取私有方法 handleResponse
|
||||
Class<?> clazz = HttpClientUtils.class;
|
||||
// private static String handleResponse(ClassicHttpResponse response)
|
||||
Method method = clazz.getDeclaredMethod("handleResponse", ClassicHttpResponse.class);
|
||||
// 设置方法为可访问
|
||||
method.setAccessible(true);
|
||||
|
||||
// 调用私有方法
|
||||
return method.invoke(null, mockResponse);
|
||||
});
|
||||
// 调用 get 方法并验证结果
|
||||
assertThrows(InvocationTargetException.class, () -> HttpClientUtils.get(FAILURE_URL, null, null));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.cmcc.magent.misc;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
|
@ -9,16 +10,14 @@ import org.mockito.MockitoAnnotations;
|
|||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 测试 {@link HttpUtils} 工具类的功能。
|
||||
|
@ -44,7 +43,7 @@ public class HttpUtilsTest {
|
|||
assertNotNull(instance);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void testGetHttpRequestHeaders_nullrequest() throws Exception {
|
||||
String result = HttpUtils.getHttpRequestHeaders(null);
|
||||
|
@ -56,5 +55,21 @@ public class HttpUtilsTest {
|
|||
public void testGetHttpRequestSrcIp_nullrequest() throws Exception {
|
||||
String result = HttpUtils.getHttpRequestSrcIp(null);
|
||||
assertEquals("unknown", result);
|
||||
*/
|
||||
|
||||
@Test
|
||||
@DisplayName("参数null测试")
|
||||
public void getHttpRequestHeaders_inputIsNull_returnObject() throws JsonProcessingException, UnknownHostException {
|
||||
assertEquals("{}", HttpUtils.getHttpRequestHeaders(null));
|
||||
assertEquals("unknown", HttpUtils.getHttpRequestSrcIp(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("输入多个IP")
|
||||
public void getHttpRequestSrcIp_returnMutileIpSplit() throws UnknownHostException {
|
||||
String testIp = "172.28.22.21, 172.28.22.22";
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getHeader("x-forwarded-for")).thenReturn(testIp);
|
||||
assertEquals("172.28.22.21", HttpUtils.getHttpRequestSrcIp(request));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
package com.cmcc.magent.misc;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.springframework.context.MessageSource;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -22,8 +34,24 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||
* @since 2025-02-07
|
||||
*/
|
||||
@DisplayName("国际化消息工具测试")
|
||||
@Slf4j
|
||||
public class MessageUtilTest {
|
||||
|
||||
private MockedStatic<SpringBootBeanUtils> mockSpringBootBeanUtils;
|
||||
private MessageSource messageSource;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
messageSource = mock(MessageSource.class);
|
||||
mockSpringBootBeanUtils = mockStatic(SpringBootBeanUtils.class);
|
||||
mockSpringBootBeanUtils.when(() -> SpringBootBeanUtils.getBean(MessageSource.class)).thenReturn(messageSource);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
mockSpringBootBeanUtils.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("禁止类实例化")
|
||||
public void testPrivateConstructor() {
|
||||
|
@ -34,4 +62,40 @@ public class MessageUtilTest {
|
|||
assertNotNull(instance);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("国际化消息为空")
|
||||
public void get_EmptyMessage_returnKey() {
|
||||
MockedStatic<HelperUtils> mockHelpUtils = mockStatic(HelperUtils.class);
|
||||
log.info("message: {}", messageSource);
|
||||
mockHelpUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(false);
|
||||
when(messageSource.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("message");
|
||||
assertEquals("key", MessageUtil.get("key", new Object[0], "zh_CN"));
|
||||
mockHelpUtils.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("指定国际化语言")
|
||||
public void get_Message_returnMessage() {
|
||||
log.info("message: {}", messageSource);
|
||||
when(messageSource.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("message");
|
||||
assertEquals("key", MessageUtil.get("key", new Object[0], "zh_CN"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("国际化语言为空字符串")
|
||||
public void get_EmptyLanguage_returnDefaultLanguage() {
|
||||
log.info("message: {}", messageSource);
|
||||
when(messageSource.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("message");
|
||||
assertEquals("key", MessageUtil.get("key", new Object[0], ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("国际化消息重载方法")
|
||||
public void get_returnDefaultLanguage() {
|
||||
log.info("message: {}", messageSource);
|
||||
when(messageSource.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("message");
|
||||
assertEquals("key", MessageUtil.get("key", "zh_CN"));
|
||||
assertEquals("key", MessageUtil.get("key", ""));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ public class ProtocolJsonUtilsTest {
|
|||
* <p>此方法初始化需要的测试数据。</p>
|
||||
*/
|
||||
@BeforeEach
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setUp() {
|
||||
protocolResp = new ProtocolResp();
|
||||
protocolRespB = new ProtocolResp();
|
||||
|
@ -171,6 +172,7 @@ public class ProtocolJsonUtilsTest {
|
|||
*/
|
||||
@Test
|
||||
@DisplayName("不匹配的 JSON 应返回默认对象")
|
||||
@SuppressWarnings("unchecked")
|
||||
public void jsonGetObject_MismatchedJson() throws JsonProcessingException {
|
||||
String mismatchedJson = "{\"protocolId\":12345,\"protocolName\":true,\"protocolType\":null,\"protocolVersion\":1.0," +
|
||||
"\"protocolStatus\":\"SUCCESS\"}";
|
||||
|
|
|
@ -417,31 +417,4 @@ public class MiddlewareManagerServiceImplTest {
|
|||
|
||||
assertEquals(ErrorCode.ERR_OK, result.getFirstParam());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("异步下载部署脚本异常(部署脚本)")
|
||||
public void executeTaskAsync_downloadConfigFiles_ThrowException() {
|
||||
RemoteFileDetails remoteFileDetails = new RemoteFileDetails();
|
||||
HashMap<MiddlewareManagerCommand, RemoteFileDetails> command = new HashMap<>();
|
||||
List<RemoteFileDetails> configFiles = new ArrayList<>();
|
||||
|
||||
when(ossFactory.getOssService()).thenReturn(service);
|
||||
// 设置 download 方法的行为,不进行真实调用,直接返回
|
||||
doNothing().when(service).download(any(URL.class), any(File.class));
|
||||
when(middlewareDataMapper.insert(any(MiddlewareData.class))).thenReturn(1);
|
||||
when(commonConfigure.isAsyncDeployment()).thenReturn(true);
|
||||
mockCryptoHelper.when(() -> CryptoHelper.md5FileEncryption(anyString())).thenThrow(new NoSuchAlgorithmException());
|
||||
mockHelpUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
|
||||
|
||||
command.put(MiddlewareManagerCommand.COMMAND_DEPLOYMENT,
|
||||
RemoteFileDetails.builder().url("http://test").fileName("").checksum("").build());
|
||||
|
||||
remoteFileDetails.setFileName("test");
|
||||
remoteFileDetails.setUrl("http://test");
|
||||
remoteFileDetails.setChecksum("test");
|
||||
configFiles.add(remoteFileDetails);
|
||||
|
||||
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeTask("Redis", "6.0", command, configFiles);
|
||||
assertEquals(ErrorCode.ERR_OK, result.getFirstParam());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
package com.cmcc.magent.service.impl;
|
||||
|
||||
import com.cmcc.magent.annotation.OperationLogAnnotation;
|
||||
import com.cmcc.magent.common.ErrorCode;
|
||||
import com.cmcc.magent.config.CommonConfigure;
|
||||
import com.cmcc.magent.config.ObjectMapperProvider;
|
||||
import com.cmcc.magent.misc.ApiContextUtils;
|
||||
import com.cmcc.magent.misc.HelperUtils;
|
||||
import com.cmcc.magent.misc.HttpUtils;
|
||||
import com.cmcc.magent.misc.JsonUtils;
|
||||
import com.cmcc.magent.pojo.po.ApiContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* OperationLogServiceImpl 测试类,用于测试 OperationLogServiceImpl 日志服务的功能。
|
||||
* 该类通过模拟 HTTP 请求、API 上下文、工具类等,验证日志服务在不同场景下的行为。
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-02-26
|
||||
*/
|
||||
@DisplayName("操作日志测试")
|
||||
public class OperationLogServiceImplTest {
|
||||
@InjectMocks
|
||||
private OperationLogServiceImpl operationLogService;
|
||||
@Mock
|
||||
private ServerProperties serverProperties;
|
||||
private MockedStatic<HelperUtils> mockHelperUtils;
|
||||
private MockedStatic<HttpUtils> mockHttpUtils;
|
||||
private MockedStatic<JsonUtils> mockJsonUtils;
|
||||
private MockedStatic<ObjectMapperProvider> mockObjectMapperProvider;
|
||||
private MockedStatic<ApiContextUtils> mockApiContextUtils;
|
||||
|
||||
/**
|
||||
* 在每个测试方法执行前初始化测试环境。
|
||||
* 包括初始化 Mock 对象、模拟静态方法等。
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
CommonConfigure.PROJECT_PREFIX_URL = "/api";
|
||||
mockHelperUtils = mockStatic(HelperUtils.class);
|
||||
mockHttpUtils = mockStatic(HttpUtils.class);
|
||||
mockObjectMapperProvider = mockStatic(ObjectMapperProvider.class);
|
||||
mockJsonUtils = mockStatic(JsonUtils.class);
|
||||
mockApiContextUtils = mockStatic(ApiContextUtils.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在每个测试方法执行后清理测试环境。
|
||||
* 包括关闭模拟的静态方法。
|
||||
*/
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
mockHelperUtils.close();
|
||||
mockHttpUtils.close();
|
||||
mockJsonUtils.close();
|
||||
mockObjectMapperProvider.close();
|
||||
mockApiContextUtils.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试日志服务在传入完整参数时是否正常调用。
|
||||
* 验证在传入完整参数的情况下,日志服务是否被正确调用。
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("完整参数调用")
|
||||
public void systemOperationLog_fullParamsCall() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getRequestURI()).thenReturn("/api/error/someError");
|
||||
mockHelperUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
|
||||
operationLogService.systemOperationLog("testCall", request, new Object(), "testModule", "testType", "testDesc", ErrorCode.ERR_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试日志服务在传入简化参数(带注解)时是否正常调用。
|
||||
* 验证在传入简化参数(带注解)的情况下,日志服务是否被正确调用。
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("简单参数调用")
|
||||
public void systemOperationLog_simpleParamsCall() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
OperationLogAnnotation annotation = mock(OperationLogAnnotation.class);
|
||||
when(annotation.OperationModule()).thenReturn("testModule");
|
||||
when(annotation.OperationType()).thenReturn("testType");
|
||||
when(annotation.OperationDesc()).thenReturn("testDesc");
|
||||
when(request.getRequestURI()).thenReturn("/api/error/someError");
|
||||
mockHelperUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
|
||||
operationLogService.systemOperationLog("testCall", request, new Object(), annotation, ErrorCode.ERR_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试日志服务在传入简化参数(注解为空)时是否正常调用。
|
||||
* 验证在传入简化参数(注解为空)的情况下,日志服务是否被正确调用。
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("简单参数调用(注解为空)")
|
||||
public void systemOperationLog_simpleParamsCall_annotationNull() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
mockHelperUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
|
||||
operationLogService.systemOperationLog("testCall", request, new Object(), null, ErrorCode.ERR_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试日志服务在有效请求时是否成功记录日志。
|
||||
* 验证在请求有效的情况下,日志是否被成功记录。
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("有效请求")
|
||||
public void systemOperationLog_ValidRequest_LogsSuccessfully() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getRequestURI()).thenReturn("/api/somePath");
|
||||
when(request.getMethod()).thenReturn("GET");
|
||||
when(request.getHeaderNames()).thenReturn(new java.util.Vector<String>().elements());
|
||||
when(request.getHeader(anyString())).thenReturn("someHeaderValue");
|
||||
ServerProperties.Servlet servlet = mock(ServerProperties.Servlet.class);
|
||||
when(serverProperties.getServlet()).thenReturn(servlet);
|
||||
when(servlet.getContextPath()).thenReturn("/api");
|
||||
ApiContext apiContext = new ApiContext();
|
||||
apiContext.setRequestBody("{\"timeStamp\": 1609459200000}");
|
||||
apiContext.setRequestTime(System.currentTimeMillis());
|
||||
|
||||
mockHttpUtils.when(() -> HttpUtils.getHttpRequestHeaders(any(HttpServletRequest.class))).thenReturn(
|
||||
"{\"someHeader\": \"someHeaderValue\"}");
|
||||
mockHttpUtils.when(() -> HttpUtils.getHttpRequestSrcIp(any(HttpServletRequest.class))).thenReturn("127.0.0.1");
|
||||
mockHelperUtils.when(() -> HelperUtils.truncateString(anyString(), anyInt())).thenReturn("{\"someHeader\": \"someHeaderValue\"}");
|
||||
mockApiContextUtils.when(ApiContextUtils::get).thenReturn(apiContext);
|
||||
mockHelperUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
|
||||
operationLogService.systemOperationLog("testCall", request, new Object(), "testModule", "testType", "testDesc", ErrorCode.ERR_OK);
|
||||
}
|
||||
}
|
|
@ -65,10 +65,9 @@ public class PlatformApiServiceImplTest {
|
|||
* 在每个测试前进行设置。
|
||||
* 创建 HttpClient 和响应的 Mock 对象,并初始化 Mockito。
|
||||
*
|
||||
* @throws IOException 如果在设置过程中发生 IO 异常。
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
platformMock = mockStatic(HttpClientUtils.class, Mockito.CALLS_REAL_METHODS);
|
||||
jsonMock = mockStatic(JsonUtils.class);
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.cmcc.magent.config.ProtocolConfigure;
|
|||
import com.cmcc.magent.crypto.DecryptRequestProtocol;
|
||||
import com.cmcc.magent.crypto.arithmetic.CryptoHelper;
|
||||
import com.cmcc.magent.exception.SecurityProtocolException;
|
||||
import com.cmcc.magent.misc.JsonUtils;
|
||||
import com.cmcc.magent.pojo.dto.ProtocolReq;
|
||||
import com.cmcc.magent.pojo.po.BaseRespStatus;
|
||||
import com.cmcc.magent.pojo.vo.ProtocolResp;
|
||||
|
@ -78,14 +77,8 @@ public class ProtocolSecurityServiceImplTest {
|
|||
@Mock
|
||||
private ProtocolConfigure protocolConfigure;
|
||||
|
||||
@Mock
|
||||
private JsonUtils jsonUtils;
|
||||
|
||||
@Mock
|
||||
private CryptoHelper cryptoHelper;
|
||||
|
||||
@Spy
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
final private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private MockedStatic<CryptoHelper> cryptoHelperMockedStatic;
|
||||
|
||||
|
@ -93,6 +86,7 @@ public class ProtocolSecurityServiceImplTest {
|
|||
public void setUp() {
|
||||
cryptoHelperMockedStatic = Mockito.mockStatic(CryptoHelper.class);
|
||||
when(protocolConfigure.getCryptoKey()).thenReturn("testKey");
|
||||
assertNotNull(objectMapper);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
@ -295,7 +289,17 @@ public class ProtocolSecurityServiceImplTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("AES-256解密:正确解码")
|
||||
@DisplayName("AES-128解密:异常")
|
||||
public void decryptProtocol_CryptoAes128_DecryptsException() throws Exception {
|
||||
String json = "{\"cryptoType\":2,\"msgContent\":\"encryptedData\"}";
|
||||
|
||||
when(CryptoHelper.base64Decryption("encryptedData")).thenReturn("encryptedData".getBytes());
|
||||
when(CryptoHelper.aes128Decryption(any(byte[].class), anyString())).thenThrow(new InvalidKeyException());
|
||||
assertThrows(SecurityProtocolException.class, () -> protocolSecurityService.decryptProtocol(json));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("DES解密:正确解码")
|
||||
public void decryptProtocol_CryptoAes256_DecryptsCorrectly() throws Exception {
|
||||
String json = "{\"cryptoType\":3,\"msgContent\":\"encryptedData\"}";
|
||||
|
||||
|
@ -308,7 +312,18 @@ public class ProtocolSecurityServiceImplTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("DES解密:正确解码")
|
||||
@DisplayName("DES解密:异常")
|
||||
public void decryptProtocol_CryptoAes256_DecryptsException() throws Exception {
|
||||
String json = "{\"cryptoType\":3,\"msgContent\":\"encryptedData\"}";
|
||||
|
||||
when(CryptoHelper.base64Decryption("encryptedData")).thenReturn("encryptedData".getBytes());
|
||||
when(CryptoHelper.desDecryption(any(byte[].class), anyString())).thenThrow(new InvalidKeyException());
|
||||
|
||||
assertThrows(SecurityProtocolException.class, () -> protocolSecurityService.decryptProtocol(json));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("AES-256解密:正确解码")
|
||||
public void decryptProtocol_CryptoDes_DecryptsCorrectly() throws Exception {
|
||||
String json = "{\"cryptoType\":4,\"msgContent\":\"encryptedData\"}";
|
||||
|
||||
|
@ -320,6 +335,17 @@ public class ProtocolSecurityServiceImplTest {
|
|||
assertEquals("{\"cryptoType\":4,\"msgContent\":{\"item\":\"test\"}}", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("AES-256解密:异常")
|
||||
public void decryptProtocol_CryptoDes_DecryptsException() throws Exception {
|
||||
String json = "{\"cryptoType\":4,\"msgContent\":\"encryptedData\"}";
|
||||
|
||||
when(CryptoHelper.base64Decryption("encryptedData")).thenReturn("encryptedData".getBytes());
|
||||
when(CryptoHelper.aes256Decryption(any(byte[].class), anyString())).thenThrow(new InvalidKeyException());
|
||||
|
||||
assertThrows(SecurityProtocolException.class, () -> protocolSecurityService.decryptProtocol(json));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("无效加密类型:抛出异常")
|
||||
public void decryptProtocol_InvalidCryptoType_ThrowsException() {
|
||||
|
|
|
@ -6,7 +6,6 @@ import com.cmcc.magent.pojo.po.MemoryDetails;
|
|||
import com.cmcc.magent.pojo.po.MemoryInfo;
|
||||
import com.cmcc.magent.pojo.po.ResourceUsage;
|
||||
import com.cmcc.magent.service.SystemInfoService;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -67,7 +66,7 @@ public class ResourceUsageServiceImplTest {
|
|||
|
||||
@DisplayName("测试执行任务方法,验证在提供有效数据时能正确入队资源使用率")
|
||||
@Test
|
||||
public void performTask_ValidData_ShouldEnqueueResourceUsage() throws JsonProcessingException {
|
||||
public void performTask_ValidData_ShouldEnqueueResourceUsage() {
|
||||
// 准备
|
||||
MemoryDetails physicalMemory = new MemoryDetails();
|
||||
physicalMemory.setFreeMemory(4096L);
|
||||
|
@ -94,7 +93,7 @@ public class ResourceUsageServiceImplTest {
|
|||
|
||||
@DisplayName("测试执行任务方法,验证在内存使用率为零的情况下能正确处理")
|
||||
@Test
|
||||
public void performTask_ZeroMemoryUsage_ShouldHandleGracefully() throws JsonProcessingException {
|
||||
public void performTask_ZeroMemoryUsage_ShouldHandleGracefully() {
|
||||
// 准备
|
||||
MemoryDetails physicalMemory = new MemoryDetails();
|
||||
physicalMemory.setFreeMemory(0L);
|
||||
|
@ -122,7 +121,7 @@ public class ResourceUsageServiceImplTest {
|
|||
|
||||
@DisplayName("测试执行任务方法,验证在 CPU 使用率为零的情况下能正确处理")
|
||||
@Test
|
||||
public void performTask_ZeroCpuUsage_ShouldHandleGracefully() throws JsonProcessingException {
|
||||
public void performTask_ZeroCpuUsage_ShouldHandleGracefully() {
|
||||
// 准备
|
||||
MemoryDetails physicalMemory = new MemoryDetails();
|
||||
physicalMemory.setFreeMemory(4096L);
|
||||
|
|
|
@ -84,7 +84,7 @@ public class SystemInfoServiceImplTest {
|
|||
|
||||
// 检查返回值是否符合预期(这里只能验证非空,因为操作系统名称依赖具体环境)
|
||||
assertNotNull(osName, "操作系统名称不能为空!");
|
||||
System.out.println("操作系统名称: " + osName);
|
||||
log.info("操作系统名称: {}", osName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,7 +104,7 @@ public class SystemInfoServiceImplTest {
|
|||
|
||||
// 验证时间戳(一般会大于当前时间减去一个合理的范围)
|
||||
assertTrue(bootTimeStamp > 0, "启动时间戳应该是正值!");
|
||||
System.out.println("操作系统启动时间戳: " + bootTimeStamp);
|
||||
log.info("操作系统启动时间戳: {}", bootTimeStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,13 +129,10 @@ public class SystemInfoServiceImplTest {
|
|||
assertTrue(processorInfo.getPhysicalCores() > 0, "处理器核心数量应该大于0!");
|
||||
assertTrue(processorInfo.getLogicalCpu() >= processorInfo.getPhysicalCores(), "线程数量应该不小于核心数量!");
|
||||
assertTrue(processorInfo.getCpuVendorFreq() > 0, "CPU频率应该大于0!");
|
||||
System.out.println("处理器信息: 核心数量 = " +
|
||||
processorInfo.getPhysicalCores() +
|
||||
", 线程数量 = " +
|
||||
processorInfo.getLogicalCpu() +
|
||||
", 主频 = " +
|
||||
processorInfo.getCpuVendorFreq() +
|
||||
" GHz");
|
||||
log.info("处理器信息: 核心数量 = {}, 线程数量 = {}, 主频 = {} Hz",
|
||||
processorInfo.getPhysicalCores(),
|
||||
processorInfo.getLogicalCpu(),
|
||||
processorInfo.getCpuVendorFreq());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,7 +156,7 @@ public class SystemInfoServiceImplTest {
|
|||
SystemInfo si = new SystemInfo();
|
||||
// 转换为 HwInfo 对象并打印 JSON 格式
|
||||
HwInfo hw = IObjectConvert.INSTANCE.toHwInfo(si);
|
||||
System.out.println(JsonUtils.getJson(hw));
|
||||
log.info(JsonUtils.getJson(hw));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,7 +191,7 @@ public class SystemInfoServiceImplTest {
|
|||
// NetworkParams np = si.getOperatingSystem().getNetworkParams();
|
||||
// 转换为 HwInfo 对象并打印 JSON 格式
|
||||
MemoryInfo m = IObjectConvert.INSTANCE.toMemoryInfo(memory);
|
||||
System.out.println(JsonUtils.getJson(m));
|
||||
log.info(JsonUtils.getJson(m));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,9 +208,8 @@ public class SystemInfoServiceImplTest {
|
|||
double d = proc.getSystemCpuLoadBetweenTicks(oldTicks) * 100;
|
||||
oldTicks = proc.getSystemCpuLoadTicks();
|
||||
|
||||
System.out.println(FormatUtil.roundToInt(d) + " %");
|
||||
|
||||
Thread.sleep(1000);
|
||||
log.info("Current {} Cpu load {}%", System.currentTimeMillis(), FormatUtil.roundToInt(d));
|
||||
Thread.sleep(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ import static org.mockito.Mockito.mockStatic;
|
|||
@DisplayName("程序生命周期测试")
|
||||
public class CustomLifecycleTest {
|
||||
@Spy
|
||||
private CommonConfigure commonConfigure = new CommonConfigure();
|
||||
final private CommonConfigure commonConfigure = new CommonConfigure();
|
||||
|
||||
@InjectMocks
|
||||
private CustomLifecycle customLifecycle;
|
||||
|
|
|
@ -2,8 +2,10 @@ package com.cmcc.magent.setup;
|
|||
|
||||
import com.cmcc.magent.MiddlewareAgentApplication;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
@ -15,6 +17,8 @@ import java.lang.reflect.Method;
|
|||
* @since 2025-02-21
|
||||
*/
|
||||
@SpringBootTest(classes = {MiddlewareAgentApplication.class})
|
||||
@DisplayName("应用程序入口测试")
|
||||
@TestPropertySource(properties = "spring.h2.server.enable=true")
|
||||
public class MiddlewareAgentApplicationTest {
|
||||
|
||||
/**
|
||||
|
@ -22,11 +26,12 @@ public class MiddlewareAgentApplicationTest {
|
|||
*
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("测试加载SpringBoot上下文")
|
||||
void contextLoads() {
|
||||
Assertions.assertNotNull(this.getClass());
|
||||
try {
|
||||
Method method = MiddlewareAgentApplication.class.getMethod("main", String[].class);
|
||||
method.invoke(null, (Object) null); // 静态方法调用的 obj 为 null,参数需强转为 Object
|
||||
method.invoke(null, (Object) new String[] {""}); // 静态方法调用的 obj 为 null,参数需强转为 Object
|
||||
} catch (Exception ignored) {
|
||||
// 忽略异常
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ public class ValidFixValuesImplTest {
|
|||
* 在每个测试方法执行前初始化测试环境。
|
||||
*/
|
||||
@BeforeEach
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setUp() {
|
||||
validator = new ValidFixValuesImpl();
|
||||
MockitoAnnotations.openMocks(this);
|
||||
|
|
|
@ -45,6 +45,7 @@ public class ValidPageSizeImplTest {
|
|||
|
||||
@DisplayName("测试初始化方法")
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void initialize_ShouldNotThrowException() {
|
||||
ValidPageSize constraintAnnotation = new ValidPageSize() {
|
||||
@Override
|
||||
|
|
|
@ -70,6 +70,7 @@ public class ValidProtocolTimestampImplTest {
|
|||
* <p>验证 {@link ValidProtocolTimestampImpl#initialize(ValidProtocolTimestamp)} 方法的正常调用。</p>
|
||||
*/
|
||||
@DisplayName("测试初始化方法")
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void initialize_ShouldInvokeSuperInitialize() {
|
||||
ValidProtocolTimestamp constraintAnnotation = new ValidProtocolTimestamp() {
|
||||
|
|
|
@ -6,8 +6,22 @@ server.compression.mime-types=application/json
|
|||
server.compression.min-response-size=1KB
|
||||
|
||||
# Spring DataSource Configuration
|
||||
spring.datasource.url=jdbc:sqlite:src/main/resources/db/agent.db
|
||||
spring.datasource.driver-class-name=org.sqlite.JDBC
|
||||
|
||||
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=
|
||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
# enable H2 console
|
||||
spring.h2.console.enabled=true
|
||||
spring.h2.console.path=/h2-console
|
||||
# server config
|
||||
spring.h2.server.enable=false
|
||||
spring.h2.server.port=18090
|
||||
# auto init
|
||||
spring.sql.init.mode=always
|
||||
spring.sql.init.schema-locations=classpath:sql/schema.sql
|
||||
|
||||
|
||||
# Mybatis Configuration
|
||||
#mybatis.mapper-locations=classpath:mappers/*.xml
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
SET REFERENTIAL_INTEGRITY FALSE;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for middleware_manager
|
||||
-- ----------------------------
|
||||
CREATE TABLE IF NOT EXISTS middleware_manager (
|
||||
"id" BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'id',
|
||||
"uid" VARCHAR(48) NOT NULL UNIQUE COMMENT '部署命令UUID',
|
||||
"middleware" VARCHAR(256) NOT NULL COMMENT '中间件名称',
|
||||
"middleware_ver" VARCHAR(256) COMMENT '中间件版本',
|
||||
"work_directory" VARCHAR(4096) NOT NULL COMMENT '部署工作目录',
|
||||
"deployment" VARCHAR COMMENT '部署命令',
|
||||
"config" VARCHAR COMMENT '配置命令',
|
||||
"start" VARCHAR COMMENT '启动命令',
|
||||
"stop" VARCHAR COMMENT '停止命令',
|
||||
"restart" VARCHAR COMMENT '重启命令',
|
||||
"uninstall" VARCHAR COMMENT '卸载命令',
|
||||
"created_time" DATE DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
|
||||
"upgrade_time" DATE DEFAULT CURRENT_TIMESTAMP(6) COMMENT '更新时间'
|
||||
);
|
||||
SET REFERENTIAL_INTEGRITY TRUE;
|
Loading…
Reference in New Issue