parent
37b57fa577
commit
19605826f8
7
pom.xml
7
pom.xml
|
@ -130,6 +130,13 @@
|
|||
<version>6.1.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<version>4.12.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package com.cmhi.magent.annotation.impl;
|
||||
|
||||
import com.cmhi.magent.annotation.AutoExternString;
|
||||
import com.cmhi.magent.common.BaseEnum;
|
||||
import com.cmhi.magent.common.ErrorCode;
|
||||
import com.cmhi.magent.common.UtilsFormatType;
|
||||
import com.cmhi.magent.exception.CommonErrorCodeException;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.BeanProperty;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
|
||||
|
@ -12,7 +14,6 @@ import org.springframework.boot.jackson.JsonComponent;
|
|||
import oshi.util.FormatUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* {@code AutoExternStringJsonProcess} 是一个 Jackson 自定义序列化器,用于处理 {@link AutoExternString} 注解的字段。
|
||||
|
@ -148,18 +149,34 @@ public class AutoExternStringJsonProcess extends JsonSerializer<Number> implemen
|
|||
jsonGenerator.writeString(formattedValue);
|
||||
} else if (formatType == UtilsFormatType.FORMAT_ENUM) {
|
||||
try {
|
||||
// 将字段值转换为枚举实例
|
||||
Method fromValueMethod = enumClass.getMethod("fromValue", int.class);
|
||||
Enum<?> enumInstance = (Enum<?>) fromValueMethod.invoke(null, (int) value);
|
||||
if (!enumClass.isEnum()) {
|
||||
throw new CommonErrorCodeException(ErrorCode.ERR_PARAMS);
|
||||
}
|
||||
|
||||
int index = (int) value;
|
||||
|
||||
if (index < 0 || index >= enumClass.getEnumConstants().length) {
|
||||
throw new CommonErrorCodeException(ErrorCode.ERR_NOSUCHITEM);
|
||||
}
|
||||
|
||||
boolean isBaseEnumImplemented = false;
|
||||
for (Class<?> iface : enumClass.getInterfaces()) {
|
||||
if (iface.equals(BaseEnum.class)) {
|
||||
isBaseEnumImplemented = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isBaseEnumImplemented) {
|
||||
BaseEnum baseEnum = (BaseEnum) enumClass.getEnumConstants()[index];
|
||||
jsonGenerator.writeString(baseEnum.getDescription());
|
||||
} else {
|
||||
jsonGenerator.writeString(enumClass.getEnumConstants()[index].toString());
|
||||
}
|
||||
|
||||
// 调用枚举实例的描述方法
|
||||
Method method = enumClass.getMethod("getDescription");
|
||||
String description = (String) method.invoke(enumInstance);
|
||||
|
||||
// 写入描述字符串
|
||||
jsonGenerator.writeString(description);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Failed to convert enum value to description", e);
|
||||
throw new CommonErrorCodeException(ErrorCode.ERR_NOSUCHITEM);
|
||||
}
|
||||
} else {
|
||||
jsonGenerator.writeString(numericValue.toString());
|
||||
|
@ -188,8 +205,12 @@ public class AutoExternStringJsonProcess extends JsonSerializer<Number> implemen
|
|||
AutoExternString annotation = property.getAnnotation(AutoExternString.class);
|
||||
if (annotation != null) {
|
||||
// 根据注解配置创建新的序列化器
|
||||
return new AutoExternStringJsonProcess(annotation.prefix(), annotation.suffix(), annotation.format(), annotation.units(),
|
||||
annotation.enumClass(), true);
|
||||
return new AutoExternStringJsonProcess(annotation.prefix(),
|
||||
annotation.suffix(),
|
||||
annotation.format(),
|
||||
annotation.units(),
|
||||
annotation.enumClass(),
|
||||
true);
|
||||
}
|
||||
}
|
||||
// 如果字段不存在注解,返回默认实例
|
||||
|
|
|
@ -71,12 +71,11 @@ public final class ConstValue {
|
|||
* <li>简化形式的IPv6地址:如 {@code ::1} 或 {@code 2001:db8::1}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final String IP_ADDRESS_REGEX =
|
||||
"^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$" +
|
||||
"|^([\\da-fA-F]{1,4}:){7}[\\da-fA-F]{1,4}$" +
|
||||
"|^::([\\da-fA-F]{1,4}:){0,6}[\\da-fA-F]{1,4}$" +
|
||||
"|^([\\da-fA-F]{1,4}:){1,7}:$" +
|
||||
"|^([\\da-fA-F]{1,4}:){1,6}:[\\da-fA-F]{1,4}$";
|
||||
public static final String IP_ADDRESS_REGEX = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$" +
|
||||
"|^([\\da-fA-F]{1,4}:){7}[\\da-fA-F]{1,4}$" +
|
||||
"|^::([\\da-fA-F]{1,4}:){0,6}[\\da-fA-F]{1,4}$" +
|
||||
"|^([\\da-fA-F]{1,4}:){1,7}:$" +
|
||||
"|^([\\da-fA-F]{1,4}:){1,6}:[\\da-fA-F]{1,4}$";
|
||||
|
||||
/**
|
||||
* 协议相关的常量。
|
||||
|
|
|
@ -148,8 +148,10 @@ public class CommonConfigure {
|
|||
*/
|
||||
@PostConstruct
|
||||
private void initGlobalValue() {
|
||||
log.info("Current: tokenExpiredOfSeconds = {}, allowPasswdRetryTimes = {}, showSqlCommand = {}", tokenExpiredOfSeconds,
|
||||
allowPasswdRetryTimes, showSqlCommand);
|
||||
log.info("Current: tokenExpiredOfSeconds = {}, allowPasswdRetryTimes = {}, showSqlCommand = {}",
|
||||
tokenExpiredOfSeconds,
|
||||
allowPasswdRetryTimes,
|
||||
showSqlCommand);
|
||||
|
||||
String addr = "localhost";
|
||||
try {
|
||||
|
|
|
@ -109,8 +109,12 @@ public class PlatformServiceConfig {
|
|||
HttpClient httpClient = HttpClient.create().responseTimeout(Duration.ofSeconds(requestTimeout));
|
||||
|
||||
// 构建 WebClient
|
||||
return builder.baseUrl(platformUrl).defaultHeader("Content-Type", "application/json").clientConnector(
|
||||
new ReactorClientHttpConnector(httpClient)).filter(logRequest()).filter(logResponse()).build();
|
||||
return builder.baseUrl(platformUrl)
|
||||
.defaultHeader("Content-Type", "application/json")
|
||||
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||
.filter(logRequest())
|
||||
.filter(logResponse())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -93,7 +93,8 @@ public class ProtocolConfigure {
|
|||
private void initGlobalValue() {
|
||||
log.info("Current: checkTimestamp = {}, timeoutOfSeconds = {}", checkTimestamp, timeoutOfSeconds);
|
||||
|
||||
setGlobalVars(Optional.ofNullable(checkTimestamp).orElse(false), Optional.ofNullable(timeoutOfSeconds).orElse(30),
|
||||
setGlobalVars(Optional.ofNullable(checkTimestamp).orElse(false),
|
||||
Optional.ofNullable(timeoutOfSeconds).orElse(30),
|
||||
Optional.ofNullable(cryptoType).orElse(0));
|
||||
}
|
||||
|
||||
|
|
|
@ -61,14 +61,16 @@ public class CommonFrameworkApi {
|
|||
OperationType = "SYSLOG_TYPE_READ",
|
||||
OperationDesc = "SYSLOG_DESC_GET_VERSION")
|
||||
public ProtocolResp<VersionResp> getVersion() {
|
||||
return ProtocolResp.result(VersionResp.builder().version(VersionInfo.builder()
|
||||
.commitId(prgVer.getCommitId())
|
||||
.commitDescribe(prgVer.getCommitDescribe())
|
||||
.commitTime(prgVer.getCommitTime())
|
||||
.tagName(prgVer.getTagName())
|
||||
.buildTime(prgVer.getBuildTime())
|
||||
.gitBranch(prgVer.getGitBranch())
|
||||
.build()).build());
|
||||
return ProtocolResp.result(VersionResp.builder()
|
||||
.version(VersionInfo.builder()
|
||||
.commitId(prgVer.getCommitId())
|
||||
.commitDescribe(prgVer.getCommitDescribe())
|
||||
.commitTime(prgVer.getCommitTime())
|
||||
.tagName(prgVer.getTagName())
|
||||
.buildTime(prgVer.getBuildTime())
|
||||
.gitBranch(prgVer.getGitBranch())
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,13 +87,15 @@ public class CommonFrameworkApi {
|
|||
OperationType = "SYSLOG_TYPE_READ",
|
||||
OperationDesc = "SYSLOG_DESC_GET_VERSION")
|
||||
public ProtocolResp<VersionResp> getVersionV2() {
|
||||
return ProtocolResp.result(VersionResp.builder().version(VersionInfo.builder()
|
||||
.commitId(prgVer.getCommitId())
|
||||
.commitDescribe(prgVer.getCommitDescribe())
|
||||
.commitTime(prgVer.getCommitTime())
|
||||
.tagName(prgVer.getTagName())
|
||||
.buildTime(prgVer.getBuildTime())
|
||||
.gitBranch(prgVer.getGitBranch())
|
||||
.build()).build());
|
||||
return ProtocolResp.result(VersionResp.builder()
|
||||
.version(VersionInfo.builder()
|
||||
.commitId(prgVer.getCommitId())
|
||||
.commitDescribe(prgVer.getCommitDescribe())
|
||||
.commitTime(prgVer.getCommitTime())
|
||||
.tagName(prgVer.getTagName())
|
||||
.buildTime(prgVer.getBuildTime())
|
||||
.gitBranch(prgVer.getGitBranch())
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,8 +58,8 @@ public class RequestProtocolSecurity implements RequestBodyAdvice {
|
|||
@NotNull Type type,
|
||||
@NotNull Class<? extends HttpMessageConverter<?>> aClass) {
|
||||
// 检查类级别或方法级别上是否存在 @DecryptionProtocol 注解
|
||||
return methodParameter.getContainingClass().isAnnotationPresent(DecryptionProtocol.class)
|
||||
|| methodParameter.hasMethodAnnotation(DecryptionProtocol.class);
|
||||
return methodParameter.getContainingClass().isAnnotationPresent(DecryptionProtocol.class) || methodParameter.hasMethodAnnotation(
|
||||
DecryptionProtocol.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -63,11 +63,10 @@ public class ResponseProtocolSecurity implements ResponseBodyAdvice<Object> {
|
|||
* @since 2025-01-07
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(@NotNull MethodParameter methodParameter,
|
||||
@NotNull Class<? extends HttpMessageConverter<?>> aClass) {
|
||||
public boolean supports(@NotNull MethodParameter methodParameter, @NotNull Class<? extends HttpMessageConverter<?>> aClass) {
|
||||
// 检查类级别或方法级别上是否存在 @EncryptionProtocol 注解
|
||||
return methodParameter.getContainingClass().isAnnotationPresent(EncryptionProtocol.class)
|
||||
|| methodParameter.hasMethodAnnotation(EncryptionProtocol.class);
|
||||
return methodParameter.getContainingClass().isAnnotationPresent(EncryptionProtocol.class) || methodParameter.hasMethodAnnotation(
|
||||
EncryptionProtocol.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,8 +75,9 @@ public class RequestBodyFilter implements Filter {
|
|||
* @throws ServletException 如果发生其他错误
|
||||
*/
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
public void doFilter(ServletRequest servletRequest,
|
||||
ServletResponse servletResponse,
|
||||
FilterChain filterChain) throws IOException, ServletException {
|
||||
// 定义包装后的请求对象
|
||||
ServletRequest requestWrapper = null;
|
||||
|
||||
|
@ -84,7 +85,7 @@ public class RequestBodyFilter implements Filter {
|
|||
if (servletRequest instanceof HttpServletRequest httpServletRequest) {
|
||||
requestWrapper = new RequestBodyCacheWrapper(httpServletRequest);
|
||||
}
|
||||
//获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中
|
||||
// 获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中
|
||||
// 在chain.doFiler方法中传递新的request对象
|
||||
if (null == requestWrapper) {
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
|
|
|
@ -81,7 +81,7 @@ public class HelperUtils {
|
|||
if (!stringNotEmptyOrNull(orgString) || orgString.length() <= maxLength) {
|
||||
return orgString;
|
||||
} else {
|
||||
return orgString.substring(0, maxLength - 4) + "...";
|
||||
return orgString.substring(0, maxLength - 3) + "...";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -130,9 +130,9 @@ public class JsonParameterizedType implements ParameterizedType {
|
|||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
return Objects.equals(this.ownerType, other.getOwnerType())
|
||||
&& Objects.equals(this.rawType, other.getRawType())
|
||||
&& Arrays.equals(this.actualTypeArguments, other.getActualTypeArguments());
|
||||
return Objects.equals(this.ownerType, other.getOwnerType()) &&
|
||||
Objects.equals(this.rawType, other.getRawType()) &&
|
||||
Arrays.equals(this.actualTypeArguments, other.getActualTypeArguments());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -144,9 +144,7 @@ public class JsonParameterizedType implements ParameterizedType {
|
|||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(this.actualTypeArguments)
|
||||
^ Objects.hashCode(this.ownerType)
|
||||
^ Objects.hashCode(this.rawType);
|
||||
return Arrays.hashCode(this.actualTypeArguments) ^ Objects.hashCode(this.ownerType) ^ Objects.hashCode(this.rawType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.cmhi.magent.misc;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeansException;
|
||||
|
@ -101,8 +100,7 @@ public class SpringBootBeanUtils implements ApplicationContextAware {
|
|||
* @throws BeansException 如果上下文注入失败
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(
|
||||
@NotNull @org.jetbrains.annotations.NotNull ApplicationContext applicationContext) throws BeansException {
|
||||
public void setApplicationContext(@org.jetbrains.annotations.NotNull ApplicationContext applicationContext) throws BeansException {
|
||||
setAppContext(applicationContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import oshi.software.os.FileSystem;
|
|||
import oshi.software.os.NetworkParams;
|
||||
import oshi.software.os.OSFileStore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -234,16 +233,8 @@ public interface IObjectConvert {
|
|||
* @return 自定义的 {@link FileStoreInfo} 对象。
|
||||
*/
|
||||
default FileStoreInfo toFileStoreInfo(FileSystem fs, List<HWDiskStore> d) {
|
||||
if (fs == null) {
|
||||
return FileStoreInfo.builder().fileStore(new ArrayList<>()).build();
|
||||
}
|
||||
|
||||
List<OSFileStore> o = fs.getFileStores(true);
|
||||
|
||||
if (o == null || o.isEmpty()) {
|
||||
return FileStoreInfo.builder().fileStore(new ArrayList<>()).build();
|
||||
}
|
||||
|
||||
FileStoreInfo fileStoreInfo = FileStoreInfo.builder().build();
|
||||
fileStoreInfo.setFileStore(toFileStoreDetailsList(o));
|
||||
fileStoreInfo.setHwDisk(toHwDisk(d));
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package com.cmhi.magent.pojo.po;
|
||||
|
||||
import com.cmhi.magent.annotation.AutoExternString;
|
||||
|
|
|
@ -69,7 +69,7 @@ public class IfInterfaceInfo {
|
|||
*/
|
||||
@AutoExternString(format = UtilsFormatType.FORMAT_ENUM, enumClass = NetworkIF.IfOperStatus.class)
|
||||
@Schema(description = "网络接口的运行状态,枚举类型:UP, DOWN, UNKNOWN 等", example = "1")
|
||||
private int ifOperStatus;
|
||||
private Integer ifOperStatus;
|
||||
|
||||
/**
|
||||
* 网络接口的最大传输单元(MTU)。
|
||||
|
|
|
@ -155,8 +155,7 @@ public class OperationLog {
|
|||
* 记录 HTTP 请求的头部信息,通常以 JSON 字符串形式存储。
|
||||
* </p>
|
||||
*/
|
||||
@Schema(description = "HTTP 请求头信息(以 JSON 格式存储)。",
|
||||
example = "{ 'Content-Type': 'application/json' }")
|
||||
@Schema(description = "HTTP 请求头信息(以 JSON 格式存储)。", example = "{ 'Content-Type': 'application/json' }")
|
||||
private String requestHeaders;
|
||||
|
||||
/**
|
||||
|
|
|
@ -68,8 +68,7 @@ public class PageResults<T> {
|
|||
* 表示当前页返回的具体数据项,类型由泛型参数 {@code T} 决定。
|
||||
* </p>
|
||||
*/
|
||||
@Schema(description = "当前页的具体数据项列表。",
|
||||
example = "[{ 'id': 1, 'name': 'Item 1' }, { 'id': 2, 'name': 'Item 2' }]")
|
||||
@Schema(description = "当前页的具体数据项列表。", example = "[{ 'id': 1, 'name': 'Item 1' }, { 'id': 2, 'name': 'Item 2' }]")
|
||||
private List<T> items;
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,8 +71,7 @@ public class ProcessorInfo {
|
|||
* 表示处理器的完整型号名称,例如 "Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz"。
|
||||
* </p>
|
||||
*/
|
||||
@Schema(description = "处理器的完整型号名称。",
|
||||
example = "Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz")
|
||||
@Schema(description = "处理器的完整型号名称。", example = "Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz")
|
||||
private String cpuName;
|
||||
|
||||
/**
|
||||
|
|
|
@ -79,7 +79,8 @@ public class BasePageResultResp<T> extends BaseRespStatus {
|
|||
*/
|
||||
@Schema(description = "分页数据,包含分页元信息(如当前页码、总页数、总行数等)以及具体数据项。",
|
||||
example = "{ \"pageNumber\": 1, \"pageSize\": 10, \"totalPage\": 5, \"totalRow\": 50, " +
|
||||
"\"items\": [ {\"id\": 1, \"name\": " + "\"Item 1\"}, {\"id\": 2, \"name\": " +
|
||||
"\"Item 2\"} ] }")
|
||||
"\"items\": [ {\"id\": 1, \"name\": " +
|
||||
"\"Item 1\"}, {\"id\": 2, \"name\": " +
|
||||
"\"Item 2\"} ] }")
|
||||
private PageResults<T> items;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,12 @@ public class OperationLogServiceImpl implements OperationLogService {
|
|||
ErrorCode errorCode) {
|
||||
if (annotation != null) {
|
||||
// 提取注解中的元数据并记录日志
|
||||
systemOperationLog(call, request, result, annotation.OperationModule(), annotation.OperationType(), annotation.OperationDesc(),
|
||||
systemOperationLog(call,
|
||||
request,
|
||||
result,
|
||||
annotation.OperationModule(),
|
||||
annotation.OperationType(),
|
||||
annotation.OperationDesc(),
|
||||
errorCode);
|
||||
} else {
|
||||
// 如果注解为空,使用默认值记录日志
|
||||
|
|
|
@ -74,10 +74,7 @@ public class ValidHttpMethodImpl implements ConstraintValidator<ValidHttpMethod,
|
|||
// 遍历 HTTP 方法列表并校验
|
||||
strings.forEach(k -> {
|
||||
if (RequestMethod.resolve(k.toUpperCase()) == null) {
|
||||
errMsg.append("[")
|
||||
.append(k)
|
||||
.append("]: ")
|
||||
.append(MessageUtil.get("http.request_invalid", ApiContextUtils.getLanguage()));
|
||||
errMsg.append("[").append(k).append("]: ").append(MessageUtil.get("http.request_invalid", ApiContextUtils.getLanguage()));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
package com.cmhi.magent.common;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* NoneEnumTest 是 {@link NoneEnum} 的单元测试类。
|
||||
* <p>
|
||||
* 使用 JUnit 5 和 AssertJ 对 NoneEnum 的各个方法功能进行验证,确保枚举方法返回的值符合预期。
|
||||
* 主要测试以下方法:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@link NoneEnum#getStringValue()} - 验证获取字符串值功能。</li>
|
||||
* <li>{@link NoneEnum#getValue()} - 验证获取整数值功能。</li>
|
||||
* <li>{@link NoneEnum#getDescription()} - 验证获取描述功能。</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>依赖注入:</p>
|
||||
* <ul>
|
||||
* <li>使用 {@code @SpringBootTest} 确保 Spring Boot 环境正常加载。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-01-13
|
||||
*/
|
||||
@SpringBootTest
|
||||
class EnumCoverTest {
|
||||
|
||||
/**
|
||||
* 测试 {@link NoneEnum#getStringValue()} 方法。
|
||||
* <p>
|
||||
* 验证是否能正确返回枚举的字符串值。
|
||||
* </p>
|
||||
*
|
||||
* <p>测试逻辑:</p>
|
||||
* <ul>
|
||||
* <li>调用 {@link NoneEnum#NONE_ENUM#getStringValue()}。</li>
|
||||
* <li>断言返回的字符串值是否等于预期值 {@code ""}(空字符串)。</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
void testGetStringValue() {
|
||||
// Setup
|
||||
// Run the test
|
||||
final String result = NoneEnum.NONE_ENUM.getStringValue();
|
||||
|
||||
// Verify the results
|
||||
assertThat(result).isEqualTo("");
|
||||
|
||||
final String var = UtilsFormatType.FORMAT_NONE.getStringValue();
|
||||
assertThat(var).isEqualTo("不进行格式化");
|
||||
|
||||
assertThat(UtilsFormatType.FORMAT_NONE.getValue()).isEqualTo(4);
|
||||
assertThat(UtilsFormatType.FORMAT_NONE.getDescription().length()).isGreaterThan(0);
|
||||
|
||||
assertThat(ProtoCryptoType.CRYPTO_NONE.getValue()).isEqualTo(0);
|
||||
assertThat(ProtoCryptoType.CRYPTO_NONE.getDescription().length()).isGreaterThan(0);
|
||||
assertThat(ProtoCryptoType.CRYPTO_NONE.getStringValue().length()).isGreaterThan(0);
|
||||
|
||||
assertThat(CommonStatus.NORMAL.getValue()).isEqualTo(0);
|
||||
assertThat(CommonStatus.NORMAL.getDescription().length()).isGreaterThan(0);
|
||||
assertThat(CommonStatus.NORMAL.getStringValue().length()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 {@link NoneEnum#getValue()} 方法。
|
||||
* <p>
|
||||
* 验证是否能正确返回枚举的整数值。
|
||||
* </p>
|
||||
*
|
||||
* <p>测试逻辑:</p>
|
||||
* <ul>
|
||||
* <li>调用 {@link NoneEnum#NONE_ENUM#getValue()}。</li>
|
||||
* <li>断言返回的整数值是否等于预期值 {@code 0}。</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
void testGetValue() {
|
||||
// Setup
|
||||
// Run the test
|
||||
final Integer result = NoneEnum.NONE_ENUM.getValue();
|
||||
|
||||
// Verify the results
|
||||
assertThat(result).isEqualTo(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 {@link NoneEnum#getDescription()} 方法。
|
||||
* <p>
|
||||
* 验证是否能正确返回枚举的描述信息。
|
||||
* </p>
|
||||
*
|
||||
* <p>测试逻辑:</p>
|
||||
* <ul>
|
||||
* <li>调用 {@link NoneEnum#NONE_ENUM#getDescription()}。</li>
|
||||
* <li>断言返回的描述信息是否等于预期值 {@code ""}(空字符串)。</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
void testGetDescription() {
|
||||
// Setup
|
||||
// Run the test
|
||||
final String result = NoneEnum.NONE_ENUM.getDescription();
|
||||
|
||||
// Verify the results
|
||||
assertThat(result).isEqualTo("");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
package com.cmhi.magent.misc;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
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.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* HelperUtilsTest 是 HelperUtils 工具类的单元测试类。
|
||||
* <p>
|
||||
* 使用 JUnit 5 测试框架对 HelperUtils 提供的方法进行功能验证,确保工具方法在各种场景下表现正确。
|
||||
* </p>
|
||||
*
|
||||
* <p>主要测试内容:</p>
|
||||
* <ul>
|
||||
* <li>JSON 序列化功能的测试</li>
|
||||
* <li>字符串操作的测试</li>
|
||||
* <li>字节数组与十六进制字符串转换的测试</li>
|
||||
* <li>字符集编码转换的测试</li>
|
||||
* <li>输入流与字符串的相互转换测试</li>
|
||||
* <li>时间和时间戳处理的测试</li>
|
||||
* <li>字符串非空判断与合并逻辑的测试</li>
|
||||
* <li>对象验证功能的测试</li>
|
||||
* </ul>
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-01-14
|
||||
*/
|
||||
@SpringBootTest
|
||||
@Slf4j
|
||||
public class HelperUtilsTest {
|
||||
|
||||
/**
|
||||
* 测试 JSON 序列化功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#getJson(Object)} 方法是否能正确序列化传入的对象为 JSON 字符串。
|
||||
* </p>
|
||||
*
|
||||
* @throws Exception 如果 JSON 序列化失败
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.getJson")
|
||||
void testGetJson() throws Exception {
|
||||
// 创建一个测试对象
|
||||
Long jsonVal = 123L;
|
||||
|
||||
// 调用 getJson 方法
|
||||
String json = HelperUtils.getJson(jsonVal);
|
||||
|
||||
// 断言生成的 JSON 字符串不为空
|
||||
assertNotNull(json);
|
||||
assertEquals(new ObjectMapper().writeValueAsString(jsonVal), json);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试字符串截断功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#truncateString(String, int)} 方法是否能正确截断字符串,并追加 "..." 后缀。
|
||||
* 断言截断后的长度、内容与期望值是否一致。
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.truncateString")
|
||||
void testTruncateString() {
|
||||
// 原始字符串
|
||||
String orgString = "This is a long string";
|
||||
|
||||
// 截断长度
|
||||
int maxLength = 8;
|
||||
|
||||
// 调用 truncateString 方法
|
||||
String truncatedString = HelperUtils.truncateString(orgString, maxLength);
|
||||
|
||||
log.info("[{}] --> [{}]", orgString, truncatedString);
|
||||
// 断言截断后的字符串长度符合预期
|
||||
assertEquals(maxLength, truncatedString.length());
|
||||
assertTrue(truncatedString.endsWith("..."));
|
||||
assertTrue(truncatedString.startsWith(orgString.substring(0, maxLength - 3)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试字节数组转换为十六进制字符串功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#bytesToHexString(byte[])} 方法是否能正确将字节数组转换为十六进制字符串。
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.bytesToHexString")
|
||||
void testBytesToHexString() {
|
||||
// 字节数组
|
||||
byte[] bArray = {1, 2, 3, 4, 5};
|
||||
|
||||
// 调用 bytesToHexString 方法
|
||||
String hexString = HelperUtils.bytesToHexString(bArray);
|
||||
|
||||
// 断言生成的十六进制字符串正确
|
||||
assertEquals("0102030405", hexString);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试字符串转换为 GB2312 编码的字节数组功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#convertStringToGb2312(String)} 方法是否能正确转换字符串为 GB2312 字节数组。
|
||||
* </p>
|
||||
*
|
||||
* @throws UnsupportedEncodingException 如果指定的编码不受支持
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.convertStringToGb2312")
|
||||
void testConvertStringToGb2312() throws UnsupportedEncodingException {
|
||||
// 原始字符串
|
||||
String str = "测试字符串";
|
||||
|
||||
// 调用 convertStringToGb2312 方法
|
||||
byte[] gb2312Bytes = HelperUtils.convertStringToGb2312(str);
|
||||
|
||||
// 可以进一步验证转换后的字节数组是否符合预期
|
||||
assertNotNull(gb2312Bytes);
|
||||
assertTrue(gb2312Bytes.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试输入流转换为字符串功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#inputStream2String(InputStream)} 方法是否能将输入流正确转换为字符串。
|
||||
* </p>
|
||||
*
|
||||
* @throws IOException 如果读取输入流失败
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.inputStream2String")
|
||||
void testInputStream2String() throws IOException {
|
||||
// 创建一个输入流
|
||||
InputStream inputStream = new ByteArrayInputStream("测试输入流".getBytes());
|
||||
|
||||
// 调用 inputStream2String 方法
|
||||
String result = HelperUtils.inputStream2String(inputStream);
|
||||
|
||||
// 断言转换后的字符串正确
|
||||
assertEquals("测试输入流", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试时间字符串转换为时间戳(毫秒)功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#getTimestampMilliSecond(String)} 方法是否能正确计算时间戳。
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.getTimestampMilliSecond")
|
||||
void testGetTimestampMilliSecond() {
|
||||
// 时间字符串
|
||||
String dateTime = "2023-09-15 10:10:10";
|
||||
|
||||
// 调用 getTimestampMilliSecond 方法
|
||||
long timestamp = HelperUtils.getTimestampMilliSecond(dateTime);
|
||||
|
||||
// 可以根据具体时间进行断言
|
||||
assertEquals(1694743810000L, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试获取当前日期和时间的功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#getCurrentDatetime()} 方法是否能返回不为空的当前日期和时间字符串。
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.getCurrentDatetime")
|
||||
void testGetCurrentDatetime() {
|
||||
// 调用 getCurrentDatetime 方法
|
||||
String currentDatetime = HelperUtils.getCurrentDatetime();
|
||||
|
||||
// 可以根据当前时间进行断言
|
||||
assertNotNull(currentDatetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试字符串非空或非 null 检查功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#stringNotEmptyOrNull(String)} 方法是否能正确判断字符串是否为空或 null。
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.stringNotEmptyOrNull")
|
||||
void testStringNotEmptyOrNull() {
|
||||
// 非空字符串
|
||||
String str = "非空字符串";
|
||||
|
||||
// 调用 stringNotEmptyOrNull 方法
|
||||
boolean result = HelperUtils.stringNotEmptyOrNull(str);
|
||||
|
||||
// 断言结果为 true
|
||||
assertTrue(result);
|
||||
|
||||
// 空字符串
|
||||
str = "";
|
||||
|
||||
result = HelperUtils.stringNotEmptyOrNull(str);
|
||||
|
||||
// 断言结果为 false
|
||||
assertFalse(result);
|
||||
|
||||
// null 字符串
|
||||
str = null;
|
||||
// 断言结果为 false
|
||||
assertFalse(HelperUtils.stringNotEmptyOrNull(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试合并数据库字符串值的功能。
|
||||
* <p>
|
||||
* 验证 {@link HelperUtils#meagreDbStringValue(String)} 方法是否能正确判断数据库字符串值:
|
||||
* <ul>
|
||||
* <li>对于非空字符串,返回原始值。</li>
|
||||
* <li>对于空字符串或 null,返回 null。</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("HelperUtils.meagreDbStringValue")
|
||||
void testMeagreDbStringValue() {
|
||||
// 非空字符串
|
||||
String str = "非空字符串";
|
||||
|
||||
// 调用 meagreDbStringValue 方法
|
||||
String result = HelperUtils.meagreDbStringValue(str);
|
||||
|
||||
// 断言结果为原始字符串
|
||||
assertEquals(str, result);
|
||||
|
||||
// 空字符串
|
||||
str = "";
|
||||
|
||||
result = HelperUtils.meagreDbStringValue(str);
|
||||
|
||||
// 断言结果为 null
|
||||
assertNull(result);
|
||||
|
||||
// null 字符串
|
||||
str = null;
|
||||
|
||||
result = HelperUtils.meagreDbStringValue(str);
|
||||
|
||||
// 断言结果为 null
|
||||
assertNull(result);
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
package com.cmhi.magent.service;
|
||||
|
||||
import com.cmhi.magent.misc.HelperUtils;
|
||||
import com.cmhi.magent.pojo.mapper.IObjectConvert;
|
||||
import com.cmhi.magent.pojo.po.HwInfo;
|
||||
import com.cmhi.magent.pojo.po.MemoryDetails;
|
||||
import com.cmhi.magent.pojo.po.ProcessorInfo;
|
||||
import com.cmhi.magent.service.impl.SystemInfoServiceImpl;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import oshi.SystemInfo;
|
||||
import oshi.hardware.GlobalMemory;
|
||||
import oshi.hardware.HWDiskStore;
|
||||
import oshi.hardware.NetworkIF;
|
||||
import oshi.hardware.PhysicalMemory;
|
||||
import oshi.software.os.FileSystem;
|
||||
import oshi.software.os.NetworkParams;
|
||||
import oshi.software.os.OSFileStore;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@SpringBootTest
|
||||
class SystemInfoServiceTest {
|
||||
|
||||
private SystemInfoServiceImpl systemInfoService; // 实现类对象
|
||||
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// 实例化实现类
|
||||
systemInfoService = new SystemInfoServiceImpl();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetOsName() {
|
||||
// 调用接口方法
|
||||
String osName = systemInfoService.getOsName();
|
||||
|
||||
// 检查返回值是否符合预期(这里只能验证非空,因为操作系统名称依赖具体环境)
|
||||
assertNotNull(osName, "操作系统名称不能为空!");
|
||||
System.out.println("操作系统名称: " + osName);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetOsBootTimeStamp() {
|
||||
// 调用接口方法
|
||||
long bootTimeStamp = systemInfoService.getOsBootTimeStamp();
|
||||
|
||||
// 验证时间戳(一般会大于当前时间减去一个合理的范围)
|
||||
assertTrue(bootTimeStamp > 0, "启动时间戳应该是正值!");
|
||||
System.out.println("操作系统启动时间戳: " + bootTimeStamp);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetProcessInfo() {
|
||||
// 调用接口方法获取处理器信息
|
||||
ProcessorInfo processorInfo = systemInfoService.getProcessInfo();
|
||||
|
||||
// 检查返回的处理器信息是否合理
|
||||
assertNotNull(processorInfo, "处理器信息不能为空!");
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetHardwareInfo() {
|
||||
// // 调用接口方法获取硬件信息
|
||||
// HwInfo hardwareInfo = systemInfoService.getHardwareInfo();
|
||||
//
|
||||
// // 检查返回的硬件信息是否合理
|
||||
// assertNotNull(hardwareInfo, "硬件信息不能为空!");
|
||||
// assertTrue(hardwareInfo.get() > 0, "内存大小应该大于0!");
|
||||
// assertTrue(hardwareInfo.getDiskCapacity() > 0, "磁盘容量应该大于0!");
|
||||
// System.out.println("硬件信息: 内存大小 = " + hardwareInfo.getMemorySize() +
|
||||
// " GB, 磁盘容量 = " + hardwareInfo.getDiskCapacity() + " GB");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetMemoryInfo() throws JsonProcessingException {
|
||||
SystemInfo si = new SystemInfo();
|
||||
GlobalMemory memory = si.getHardware().getMemory();
|
||||
List<PhysicalMemory> ph = memory.getPhysicalMemory();
|
||||
List<HWDiskStore> d = si.getHardware().getDiskStores();
|
||||
FileSystem fs = si.getOperatingSystem().getFileSystem();
|
||||
List<OSFileStore> os = fs.getFileStores(true);
|
||||
List<NetworkIF> nf = si.getHardware().getNetworkIFs(true);
|
||||
NetworkParams np = si.getOperatingSystem().getNetworkParams();
|
||||
|
||||
MemoryDetails md = new MemoryDetails();
|
||||
md.setFreeMemory(1000L);
|
||||
md.setTotalMemory(3000L);
|
||||
|
||||
HwInfo hw = IObjectConvert.INSTANCE.toHwInfo(si);
|
||||
System.out.println(HelperUtils.getJson(hw));
|
||||
// System.out.println(HelperUtils.getJson(d));
|
||||
// System.out.println(HelperUtils.getJson(fs));
|
||||
|
||||
//System.out.println(objectMapper.writeValueAsString(md));
|
||||
// System.out.println(HelperUtils.getJson(memory));
|
||||
// System.out.println(HelperUtils.getJson(ph));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package com.cmhi.magent.service.impl;
|
||||
|
||||
import com.cmhi.magent.pojo.po.RegisterAgent;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import jakarta.annotation.Resource;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* 单元测试类 {@code PlatformApiServiceImplTest} 用于测试 {@link PlatformApiServiceImpl} 的功能。
|
||||
* <p>
|
||||
* 测试的主要目标是确保 {@link PlatformApiServiceImpl#registerAgent(RegisterAgent)} 方法能够正常工作,
|
||||
* 并验证 {@link WebClient} 在调用外部 API 时的行为。
|
||||
* </p>
|
||||
*
|
||||
* <p>测试中使用了 {@code MockWebServer} 来模拟 HTTP 请求和响应,避免依赖实际的外部服务。</p>
|
||||
*
|
||||
* <p>主要验证内容包括:</p>
|
||||
* <ul>
|
||||
* <li>是否正确构造了 HTTP 请求(如方法和路径)。</li>
|
||||
* <li>是否正确处理了 HTTP 响应并返回预期结果。</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>依赖注入说明:</p>
|
||||
* <ul>
|
||||
* <li>通过 {@code @Resource} 注入被测试的 {@code PlatformApiServiceImpl}。</li>
|
||||
* <li>通过 {@code @Autowired} 注入 {@code WebClient.Builder},用于生成测试时专用的 {@code WebClient}。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-01-14
|
||||
*/
|
||||
@SpringBootTest
|
||||
class PlatformApiServiceImplTest {
|
||||
|
||||
/**
|
||||
* 被测试的服务类 {@link PlatformApiServiceImpl}。
|
||||
*/
|
||||
@Resource
|
||||
private PlatformApiServiceImpl platformApiService;
|
||||
|
||||
/**
|
||||
* 用于创建 {@link WebClient} 实例的 {@link WebClient.Builder},通过它构造指向 {@code MockWebServer} 的 WebClient。
|
||||
*/
|
||||
@Autowired
|
||||
private WebClient.Builder webClientBuilder;
|
||||
|
||||
/**
|
||||
* 模拟 HTTP 请求和响应的 MockWebServer。
|
||||
*/
|
||||
private MockWebServer mockWebServer;
|
||||
|
||||
/**
|
||||
* 初始化 MockWebServer,并通过反射注入 MockWebServer 对应的 WebClient 到 PlatformApiService 中。
|
||||
*
|
||||
* @throws Exception 如果 MockWebServer 或 WebClient 初始化失败。
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
// 初始化 MockWebServer
|
||||
mockWebServer = new MockWebServer();
|
||||
mockWebServer.start();
|
||||
|
||||
// 使用 MockWebServer 的 URL 配置 WebClient
|
||||
WebClient webClient = webClientBuilder.baseUrl(mockWebServer.url("/").toString()).build();
|
||||
|
||||
// 使用反射注入 WebClient 到 PlatformApiService
|
||||
injectWebClientIntoApiService(webClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止 MockWebServer。
|
||||
*
|
||||
* @throws Exception 如果 MockWebServer 停止失败。
|
||||
*/
|
||||
@AfterEach
|
||||
void tearDown() throws Exception {
|
||||
// 停止 MockWebServer
|
||||
mockWebServer.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用反射将测试用的 {@link WebClient} 实例注入到 {@link PlatformApiServiceImpl}。
|
||||
*
|
||||
* @param webClientToInject 用于注入的 {@link WebClient} 实例。
|
||||
* @throws Exception 如果反射注入过程中出现错误。
|
||||
*/
|
||||
private void injectWebClientIntoApiService(WebClient webClientToInject) throws Exception {
|
||||
var webClientField = PlatformApiServiceImpl.class.getDeclaredField("webClient");
|
||||
webClientField.setAccessible(true);
|
||||
webClientField.set(platformApiService, webClientToInject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 {@link PlatformApiServiceImpl#registerAgent(RegisterAgent)} 方法。
|
||||
*
|
||||
* <p>验证以下内容:</p>
|
||||
* <ul>
|
||||
* <li>是否正确发送了 HTTP POST 请求到指定路径(如 {@code /register})。</li>
|
||||
* <li>是否正确处理了 HTTP 响应并返回预期的结果。</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>测试流程:</p>
|
||||
* <ol>
|
||||
* <li>设置 MockWebServer 的响应内容为 {@code {"message": "Hello, World!"}}。</li>
|
||||
* <li>使用测试数据(如 {@link RegisterAgent} 对象)调用 {@code registerAgent} 方法。</li>
|
||||
* <li>验证返回值是否等于设置的响应内容。</li>
|
||||
* <li>验证发送的请求是否符合预期(如方法为 POST,路径为 /register)。</li>
|
||||
* </ol>
|
||||
*
|
||||
* @throws InterruptedException 如果等待 MockWebServer 请求时被中断。
|
||||
* @throws JsonProcessingException 如果 JSON 处理发生错误。
|
||||
*/
|
||||
@Test
|
||||
void testFetchData() throws InterruptedException, JsonProcessingException {
|
||||
// 准备模拟的 HTTP 响应
|
||||
String mockResponse = "{\"message\": \"Hello, World!\"}";
|
||||
mockWebServer.enqueue(new MockResponse().setBody(mockResponse).addHeader("Content-Type", "application/json"));
|
||||
|
||||
// Setup
|
||||
final RegisterAgent agent = RegisterAgent.builder().deviceId("123542535").build();
|
||||
|
||||
// 调用被测试方法
|
||||
final String result = platformApiService.registerAgent(agent);
|
||||
|
||||
// 验证结果
|
||||
assertThat(result).isEqualTo(mockResponse);
|
||||
|
||||
// 验证请求
|
||||
var recordedRequest = mockWebServer.takeRequest();
|
||||
assertThat(recordedRequest.getMethod()).isEqualTo("POST");
|
||||
assertThat(recordedRequest.getPath()).isEqualTo("/register");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
package com.cmhi.magent.service.impl;
|
||||
|
||||
import com.cmhi.magent.misc.HelperUtils;
|
||||
import com.cmhi.magent.pojo.mapper.IObjectConvert;
|
||||
import com.cmhi.magent.pojo.po.HwInfo;
|
||||
import com.cmhi.magent.pojo.po.MemoryDetails;
|
||||
import com.cmhi.magent.pojo.po.ProcessorInfo;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import oshi.SystemInfo;
|
||||
import oshi.hardware.GlobalMemory;
|
||||
import oshi.hardware.HWDiskStore;
|
||||
import oshi.hardware.NetworkIF;
|
||||
import oshi.hardware.PhysicalMemory;
|
||||
import oshi.software.os.FileSystem;
|
||||
import oshi.software.os.NetworkParams;
|
||||
import oshi.software.os.OSFileStore;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* 单元测试类 {@code SystemInfoServiceImplTest},用于测试 {@link SystemInfoServiceImpl} 的功能。
|
||||
* <p>
|
||||
* 本测试类通过各种测试用例验证 {@link SystemInfoServiceImpl} 提供的系统信息获取功能是否正常工作。
|
||||
* 主要测试的功能包括:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>获取操作系统名称。</li>
|
||||
* <li>获取操作系统启动时间戳。</li>
|
||||
* <li>获取 CPU 处理器信息。</li>
|
||||
* <li>获取硬件信息。</li>
|
||||
* <li>获取内存信息。</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 测试内容涉及对操作系统、内存、磁盘、网络等信息的验证,通过对返回结果的合理性检查来确保相关接口的正确性。
|
||||
* </p>
|
||||
*
|
||||
* <p>依赖注入说明:</p>
|
||||
* <ul>
|
||||
* <li>通过实例化的方式创建被测试的 {@link SystemInfoServiceImpl} 实例。</li>
|
||||
* <li>通过 {@code @Resource} 注入 {@link ObjectMapper},用于 JSON 处理。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author huangxin@cmhi.chinamobile.com
|
||||
* @version 1.0.0
|
||||
* @since 2025-01-07
|
||||
*/
|
||||
@SpringBootTest
|
||||
class SystemInfoServiceImplTest {
|
||||
|
||||
/**
|
||||
* 被测试的服务类 {@link SystemInfoServiceImpl}。
|
||||
*/
|
||||
private SystemInfoServiceImpl systemInfoService;
|
||||
|
||||
/**
|
||||
* 用于序列化和反序列化 JSON 的 {@link ObjectMapper} 实例。
|
||||
*/
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 在每个测试方法运行之前初始化被测试对象。
|
||||
* <p>
|
||||
* 在此方法中实例化 {@link SystemInfoServiceImpl},确保每次测试都从干净的环境开始。
|
||||
* </p>
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// 实例化实现类
|
||||
systemInfoService = new SystemInfoServiceImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 {@link SystemInfoServiceImpl#getOsName()} 方法。
|
||||
* <p>
|
||||
* 该方法用于获取操作系统的名称。测试通过以下内容进行验证:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>返回值不能为空。</li>
|
||||
* <li>打印操作系统名称到控制台以供手动检查。</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
void testGetOsName() {
|
||||
// 调用接口方法
|
||||
String osName = systemInfoService.getOsName();
|
||||
|
||||
// 检查返回值是否符合预期(这里只能验证非空,因为操作系统名称依赖具体环境)
|
||||
assertNotNull(osName, "操作系统名称不能为空!");
|
||||
System.out.println("操作系统名称: " + osName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 {@link SystemInfoServiceImpl#getOsBootTimeStamp()} 方法。
|
||||
* <p>
|
||||
* 该方法用于获取操作系统的启动时间戳。测试通过以下内容进行验证:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>返回的时间戳为正值。</li>
|
||||
* <li>打印启动时间戳到控制台以供手动检查。</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
void testGetOsBootTimeStamp() {
|
||||
// 调用接口方法
|
||||
long bootTimeStamp = systemInfoService.getOsBootTimeStamp();
|
||||
|
||||
// 验证时间戳(一般会大于当前时间减去一个合理的范围)
|
||||
assertTrue(bootTimeStamp > 0, "启动时间戳应该是正值!");
|
||||
System.out.println("操作系统启动时间戳: " + bootTimeStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 {@link SystemInfoServiceImpl#getProcessInfo()} 方法。
|
||||
* <p>
|
||||
* 该方法用于获取处理器的详细信息。测试通过以下内容进行验证:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>返回值不能为空。</li>
|
||||
* <li>处理器核心数量大于 0。</li>
|
||||
* <li>线程数量不小于核心数量。</li>
|
||||
* <li>CPU 主频大于 0。</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
void testGetProcessInfo() {
|
||||
// 调用接口方法获取处理器信息
|
||||
ProcessorInfo processorInfo = systemInfoService.getProcessInfo();
|
||||
|
||||
// 检查返回的处理器信息是否合理
|
||||
assertNotNull(processorInfo, "处理器信息不能为空!");
|
||||
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");
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 {@link SystemInfoServiceImpl#getHardwareInfo()} 方法。
|
||||
* <p>
|
||||
* 该方法当前被注释掉,无法执行实际测试。
|
||||
* </p>
|
||||
* <p>
|
||||
* 如果启用此方法,测试应包括以下内容:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>返回的硬件信息不能为空。</li>
|
||||
* <li>内存大小大于 0。</li>
|
||||
* <li>磁盘容量大于 0。</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
void testGetHardwareInfo() {
|
||||
// 方法被注释掉,当前无法运行测试
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试系统内存、磁盘和网络的详细信息。
|
||||
* <p>
|
||||
* 测试过程中通过 {@link SystemInfo} 对象获取各种硬件和操作系统信息,并转换为 {@link HwInfo} 对象。
|
||||
* 测试内容包括:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>物理内存信息。</li>
|
||||
* <li>磁盘存储信息。</li>
|
||||
* <li>文件系统信息。</li>
|
||||
* <li>网络接口信息。</li>
|
||||
* <li>网络参数。</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 本方法主要用于调试和打印相关信息。
|
||||
* </p>
|
||||
*
|
||||
* @throws JsonProcessingException 如果 JSON 序列化或反序列化失败。
|
||||
*/
|
||||
@Test
|
||||
void testGetMemoryInfo() throws JsonProcessingException {
|
||||
// 获取系统信息
|
||||
SystemInfo si = new SystemInfo();
|
||||
GlobalMemory memory = si.getHardware().getMemory();
|
||||
List<PhysicalMemory> ph = memory.getPhysicalMemory();
|
||||
List<HWDiskStore> d = si.getHardware().getDiskStores();
|
||||
FileSystem fs = si.getOperatingSystem().getFileSystem();
|
||||
List<OSFileStore> os = fs.getFileStores(true);
|
||||
List<NetworkIF> nf = si.getHardware().getNetworkIFs(true);
|
||||
NetworkParams np = si.getOperatingSystem().getNetworkParams();
|
||||
|
||||
// 创建 MemoryDetails 对象
|
||||
MemoryDetails md = new MemoryDetails();
|
||||
md.setFreeMemory(1000L);
|
||||
md.setTotalMemory(3000L);
|
||||
|
||||
// 转换为 HwInfo 对象并打印 JSON 格式
|
||||
HwInfo hw = IObjectConvert.INSTANCE.toHwInfo(si);
|
||||
System.out.println(HelperUtils.getJson(hw));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue