OCT REM: 1. 增加加解密单元测试用例

This commit is contained in:
HuangXin 2025-01-16 14:49:25 +08:00
parent dce079b86e
commit 231a15117a
20 changed files with 767 additions and 167 deletions

View File

@ -7,7 +7,7 @@ common :
protocol:
check-timestamp : true
timeout-of-seconds: 600
crypto-type : 0
crypto-type : 1
#crypto-key: 12354
# 平台服务配置

View File

@ -41,8 +41,7 @@ import java.io.IOException;
* }
* </pre>
*
* @author
* huangxin@cmhi.chinamobile.com
* @author huangxin@cmhi.chinamobile.com
* @version 1.0.0
* @since 2025-01-07
*/

View File

@ -1,5 +1,9 @@
package com.cmcc.magent.crypto.arithmetic;
import com.cmcc.magent.common.ErrorCode;
import com.cmcc.magent.exception.CommonErrorCodeException;
import com.cmcc.magent.misc.HelperUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
@ -26,10 +30,9 @@ import java.util.Base64;
*
* <p>注意所有方法均为静态无法实例化该类</p>
*
* @author
* huangxin@cmhi.chinamobile.com
* @author huangxin@cmhi.chinamobile.com
* @version 1.0.0
* @since 2023-10
* @since 2025-01-07
*/
@SuppressWarnings({"java:S5542", "java:S5547", "java:S4790"})
public class CryptoHelper {
@ -86,12 +89,25 @@ public class CryptoHelper {
* @return MD5 哈希后的 Base64 字符串
* @throws NoSuchAlgorithmException 如果系统不支持 MD5 算法
*/
public static String md5Encryption(String plaintext) throws NoSuchAlgorithmException {
public static String md5EncryptionWithBase64(String plaintext) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(plaintext.getBytes(StandardCharsets.UTF_8));
return base64Encryption(messageDigest.digest());
}
/**
* 使用 MD5 哈希算法对文本进行哈希处理并返回HASH的结果
*
* @param plaintext 输入的明文字符串
* @return MD5 哈希后的字符串
* @throws NoSuchAlgorithmException 如果系统不支持 MD5 算法
*/
public static String md5Encryption(String plaintext) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(plaintext.getBytes(StandardCharsets.UTF_8));
return HelperUtils.bytesToHexString(messageDigest.digest());
}
/**
* 使用 AES-128 加密字节数组
*
@ -180,6 +196,9 @@ public class CryptoHelper {
public static byte[] aes256Decryption(byte[] ciphertext,
String aesKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
if (ciphertext ==null || ciphertext.length == 0) {
throw new IllegalBlockSizeException("input empty decrypt data");
}
Cipher cipher = Cipher.getInstance(AES_ALGORITHM_STR);
SecretKeySpec key = new SecretKeySpec(sha256Encryption(aesKey), "AES");
cipher.init(Cipher.DECRYPT_MODE, key);

View File

@ -3,6 +3,7 @@ package com.cmcc.magent.interceptor;
import com.cmcc.magent.common.ConstValue;
import com.cmcc.magent.misc.ApiContextUtils;
import com.cmcc.magent.misc.HelperUtils;
import com.cmcc.magent.misc.JsonUtils;
import com.cmcc.magent.misc.ProtocolJsonUtils;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
@ -94,7 +95,7 @@ public class RequestBodyCacheWrapper extends HttpServletRequestWrapper {
try {
// 使用工具类解析请求体并格式化为 JSON
Object obj = ProtocolJsonUtils.jsonGetObject(stringBuilder.toString(), Object.class);
body = HelperUtils.getJson(obj);
body = JsonUtils.getJson(obj);
// 读取请求头并存储到 Map
Enumeration<String> enumeration = request.getHeaderNames();

View File

@ -1,9 +1,5 @@
package com.cmcc.magent.misc;
import com.cmcc.magent.config.ObjectMapperProvider;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@ -13,18 +9,13 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
@ -45,12 +36,6 @@ import java.util.Set;
* @since 2025-01-07
*/
public class HelperUtils {
/**
* 静态 ObjectMapper 实例用于 JSON 操作
*/
private static final ObjectMapper OBJ_MAPPER = ObjectMapperProvider.getMapper();
/**
* 私有构造方法防止实例化
*/
@ -58,18 +43,6 @@ public class HelperUtils {
throw new AssertionError("Instantiating utility class.");
}
/**
* 将对象转换为 JSON 字符串
*
* @param obj 任意对象
* @param <T> 对象的类型
* @return 转换后的 JSON 字符串
* @throws JsonProcessingException 如果 JSON 序列化失败
*/
public static <T> String getJson(T obj) throws JsonProcessingException {
return OBJ_MAPPER.writeValueAsString(obj);
}
/**
* 截断字符串到指定长度超出部分以 "..." 表示
*
@ -194,55 +167,4 @@ public class HelperUtils {
public static String meagreDbStringValue(String str) {
return stringNotEmptyOrNull(str) ? str : null;
}
/**
* 获取 HTTP 请求头的 JSON 表示
*
* @param request HTTP 请求
* @return 请求头的 JSON 表示
* @throws JsonProcessingException 如果 JSON 转换失败
*/
public static String getHttpRequestHeaders(HttpServletRequest request) throws JsonProcessingException {
if (request == null) {
return "{}";
}
Map<String, String> headers = new HashMap<>(32);
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
headers.put(name, request.getHeader(name));
}
return getJson(headers);
}
/**
* 获取 HTTP 请求的源 IP 地址
*
* @param request HTTP 请求
* @return IP 地址
* @throws UnknownHostException 如果无法获取本机地址
*/
public static String getHttpRequestSrcIp(HttpServletRequest request) throws UnknownHostException {
if (request == null) {
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
String unknown = "unknown";
String localhostIp = "127.0.0.1";
String localhostIpv6 = "::1";
String separator = ",";
if (ip == null || ip.isEmpty() || unknown.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (localhostIp.equals(ip) || localhostIpv6.equals(ip)) {
InetAddress inetAddress = InetAddress.getLocalHost();
ip = inetAddress.getHostAddress();
}
if (ip != null && ip.contains(separator)) {
ip = ip.split(separator)[0];
}
return localhostIpv6.equals(ip) ? localhostIp : ip;
}
}

View File

@ -0,0 +1,83 @@
package com.cmcc.magent.misc;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* {@code HttpUtils} 是一个提供 HTTP 相关工具方法的实用类
* <p>
* 此工具类包含对 HTTP 请求头的处理和源 IP 地址的获取等功能
* 所有方法均为静态方法类设计为不可实例化
* </p>
*
* <p><strong>注意</strong>此类的设计为工具类禁止实例化</p>
*
* @author huangxin@cmhi.chinamobile.com
* @version 1.0.0
* @since 2025-01-15
*/
public class HttpUtils {
/**
* 私有构造方法防止实例化
*/
private HttpUtils() {
throw new AssertionError("Instantiating utility class.");
}
/**
* 获取 HTTP 请求头的 JSON 表示
*
* @param request HTTP 请求
* @return 请求头的 JSON 表示
* @throws JsonProcessingException 如果 JSON 转换失败
*/
public static String getHttpRequestHeaders(HttpServletRequest request) throws JsonProcessingException {
if (request == null) {
return "{}";
}
Map<String, String> headers = new HashMap<>(32);
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
headers.put(name, request.getHeader(name));
}
return JsonUtils.getJson(headers);
}
/**
* 获取 HTTP 请求的源 IP 地址
*
* @param request HTTP 请求
* @return IP 地址
* @throws UnknownHostException 如果无法获取本机地址
*/
public static String getHttpRequestSrcIp(HttpServletRequest request) throws UnknownHostException {
if (request == null) {
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
String unknown = "unknown";
String localhostIp = "127.0.0.1";
String localhostIpv6 = "::1";
String separator = ",";
if (ip == null || ip.isEmpty() || unknown.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (localhostIp.equals(ip) || localhostIpv6.equals(ip)) {
InetAddress inetAddress = InetAddress.getLocalHost();
ip = inetAddress.getHostAddress();
}
if (ip != null && ip.contains(separator)) {
ip = ip.split(separator)[0];
}
return localhostIpv6.equals(ip) ? localhostIp : ip;
}
}

View File

@ -0,0 +1,44 @@
package com.cmcc.magent.misc;
import com.cmcc.magent.config.ObjectMapperProvider;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* {@code JsonUtils} 是一个提供 JSON 序列化 相关工具方法的实用类
* <p>
* 此工具类包含将对象序列化为JSON字符串的功能
* 所有方法均为静态方法类设计为不可实例化
* </p>
*
* <p><strong>注意</strong>此类的设计为工具类禁止实例化</p>
*
* @author huangxin@cmhi.chinamobile.com
* @version 1.0.0
* @since 2025-01-15
*/
public class JsonUtils {
/**
* 私有构造方法防止实例化
*/
private JsonUtils() {
throw new AssertionError("Instantiating utility class.");
}
/**
* 静态 ObjectMapper 实例用于 JSON 操作
*/
private static final ObjectMapper OBJ_MAPPER = ObjectMapperProvider.getMapper();
/**
* 将对象转换为 JSON 字符串
*
* @param obj 任意对象
* @param <T> 对象的类型
* @return 转换后的 JSON 字符串
* @throws JsonProcessingException 如果 JSON 序列化失败
*/
public static <T> String getJson(T obj) throws JsonProcessingException {
return OBJ_MAPPER.writeValueAsString(obj);
}
}

View File

@ -5,6 +5,8 @@ import com.cmcc.magent.common.ErrorCode;
import com.cmcc.magent.config.CommonConfigure;
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 com.cmcc.magent.pojo.po.OperationLog;
import com.cmcc.magent.service.OperationLogService;
@ -145,13 +147,13 @@ public class OperationLogServiceImpl implements OperationLogService {
optLog.setHttpPath(url);
// 设置请求 IP 地址
optLog.setRequestIp(HelperUtils.getHttpRequestSrcIp(request));
optLog.setRequestIp(HttpUtils.getHttpRequestSrcIp(request));
// 设置操作结果截取过长字符串以避免数据库存储溢出
optLog.setResult(HelperUtils.truncateString(HelperUtils.getJson(result), MAX_DB_STRING));
optLog.setResult(HelperUtils.truncateString(JsonUtils.getJson(result), MAX_DB_STRING));
// 设置请求头信息
optLog.setRequestHeaders(HelperUtils.truncateString(HelperUtils.getHttpRequestHeaders(request), MAX_DB_STRING));
optLog.setRequestHeaders(HelperUtils.truncateString(HttpUtils.getHttpRequestHeaders(request), MAX_DB_STRING));
// 设置请求体信息
String reqJson = ctx.getRequestBody();
@ -167,7 +169,7 @@ public class OperationLogServiceImpl implements OperationLogService {
}
// 保存日志此处为打印到控制台
log.info("{}", HelperUtils.getJson(optLog));
log.info("{}", JsonUtils.getJson(optLog));
} catch (Exception ignored) {
// 忽略所有异常避免日志记录影响正常业务流程
}

View File

@ -1,6 +1,7 @@
package com.cmcc.magent.service.impl;
import com.cmcc.magent.misc.HelperUtils;
import com.cmcc.magent.misc.JsonUtils;
import com.cmcc.magent.pojo.po.RegisterAgent;
import com.cmcc.magent.service.PlatformApiService;
import com.fasterxml.jackson.core.JsonProcessingException;
@ -50,7 +51,7 @@ public class PlatformApiServiceImpl implements PlatformApiService {
@Override
public String registerAgent(RegisterAgent agent) throws JsonProcessingException {
return webClient.post().uri("/register") // 相对 URL
.bodyValue(HelperUtils.getJson(agent)) // 设置请求体
.bodyValue(JsonUtils.getJson(agent)) // 设置请求体
.retrieve() // 执行请求并获取响应
.bodyToMono(String.class) // 将响应体转换为字符串
.block(); // 阻塞获取结果

View File

@ -7,7 +7,7 @@ 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.HelperUtils;
import com.cmcc.magent.misc.JsonUtils;
import com.cmcc.magent.pojo.dto.ProtocolReq;
import com.cmcc.magent.pojo.vo.ProtocolResp;
import com.cmcc.magent.service.ProtocolSecurityService;
@ -218,7 +218,7 @@ public class ProtocolSecurityServiceImpl implements ProtocolSecurityService {
try {
Method getMsgMethod = orgProtocol.getClass().getMethod("getMsgContent");
Method getCode = orgProtocol.getClass().getMethod("getCode");
msgContentJsonString = HelperUtils.getJson(getMsgMethod.invoke(orgProtocol));
msgContentJsonString = JsonUtils.getJson(getMsgMethod.invoke(orgProtocol));
cryptoObject.setCode((Integer) getCode.invoke(orgProtocol));
} catch (Exception e) {
log.error("Json encode message error: {}", orgProtocol);

View File

@ -3,6 +3,7 @@ package com.cmcc.magent;
import com.cmcc.magent.common.EnumCoverTest;
import com.cmcc.magent.controller.CommonFrameworkApiTest;
import com.cmcc.magent.controller.SystemInfoApiTest;
import com.cmcc.magent.crypto.arithmetic.CryptoHelperTest;
import com.cmcc.magent.misc.HelperUtilsTest;
import com.cmcc.magent.service.impl.PlatformApiServiceImplTest;
import org.junit.jupiter.api.DisplayName;
@ -22,6 +23,7 @@ import org.junit.platform.suite.api.Suite;
* <li>{@link HelperUtilsTest}</li>
* <li>{@link PlatformApiServiceImplTest}</li>
* <li>{@link SystemInfoApiTest}</li>
* <li>{@link CryptoHelperTest}</li>
* </ul>
*
* @author huangxin@cmhi.chinamobile.com
@ -29,7 +31,7 @@ import org.junit.platform.suite.api.Suite;
* @since 2025-01-15
*/
@SelectClasses({CommonFrameworkApiTest.class, EnumCoverTest.class, HelperUtilsTest.class, PlatformApiServiceImplTest.class,
SystemInfoApiTest.class})
SystemInfoApiTest.class, CryptoHelperTest.class})
@DisplayName("接口集成测试")
@Suite
public class IntegrationTestSuite {

View File

@ -1,9 +1,12 @@
package com.cmcc.magent.common;
package com.cmcc.magent.base;
import com.cmcc.magent.MiddlewareAgentApplication;
import com.cmcc.magent.common.ConstValue;
import com.cmcc.magent.common.ErrorCode;
import com.cmcc.magent.common.ProtoCryptoType;
import com.cmcc.magent.config.ProtocolConfigure;
import com.cmcc.magent.misc.HelperUtils;
import com.cmcc.magent.misc.JsonUtils;
import com.cmcc.magent.misc.ProtocolJsonUtils;
import com.cmcc.magent.pojo.dto.ProtocolReq;
import com.cmcc.magent.pojo.po.BaseRespStatus;
@ -33,7 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.
@AutoConfigureMockMvc
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ActiveProfiles({"common", "test", "user"})
public abstract class TestBaseAuthentication {
public abstract class SpringBootTestBase {
protected static final ThreadLocal<HttpHeaders> headersThreadLocal = new ThreadLocal<>();
@Autowired
@ -68,7 +71,7 @@ public abstract class TestBaseAuthentication {
reqInfo.setMsgContent(reqObject);
if (ProtocolConfigure.SECURITY_PROTOCOL_TYPE != ProtoCryptoType.CRYPTO_NONE.getValue()) {
String cipherText = securityService.encryptProtocolString(HelperUtils.getJson(reqObject),
String cipherText = securityService.encryptProtocolString(JsonUtils.getJson(reqObject),
ProtocolConfigure.SECURITY_PROTOCOL_TYPE);
ProtocolReq<String> cipherInfo = new ProtocolReq<>();
@ -76,20 +79,16 @@ public abstract class TestBaseAuthentication {
cipherInfo.setCryptoType(reqInfo.getCryptoType());
cipherInfo.setTimeStamp(System.currentTimeMillis());
cipherInfo.setMsgContent(cipherText);
sendMsgContent = HelperUtils.getJson(cipherInfo);
sendMsgContent = JsonUtils.getJson(cipherInfo);
} else {
sendMsgContent = HelperUtils.getJson(reqInfo);
sendMsgContent = JsonUtils.getJson(reqInfo);
}
build.content(sendMsgContent);
}
String rspValue = mockMvc.perform(build)
.andDo(print())
.andReturn()
.getResponse()
.getContentAsString();
String rspValue = mockMvc.perform(build).andDo(print()).andReturn().getResponse().getContentAsString();
AssertValidString(rspValue);

View File

@ -55,6 +55,7 @@ public class EnumCoverTest {
final String var = UtilsFormatType.FORMAT_NONE.getStringValue();
assertThat(var).isEqualTo("不进行格式化");
assertThat(NoneEnum.NONE_ENUM.getValue()).isEqualTo(0);
assertThat(UtilsFormatType.FORMAT_NONE.getValue()).isEqualTo(4);
assertThat(UtilsFormatType.FORMAT_NONE.getDescription().length()).isGreaterThan(0);

View File

@ -1,6 +1,6 @@
package com.cmcc.magent.controller;
import com.cmcc.magent.common.TestBaseAuthentication;
import com.cmcc.magent.base.SpringBootTestBase;
import com.cmcc.magent.pojo.vo.VersionResp;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
@ExtendWith({SpringExtension.class})
@SuppressWarnings("java:S5786")
@DisplayName("平台通用接口")
public class CommonFrameworkApiTest extends TestBaseAuthentication {
public class CommonFrameworkApiTest extends SpringBootTestBase {
@Test
@DisplayName("获取版本信息")
void testGetVersion() throws Exception {

View File

@ -1,6 +1,6 @@
package com.cmcc.magent.controller;
import com.cmcc.magent.common.TestBaseAuthentication;
import com.cmcc.magent.base.SpringBootTestBase;
import com.cmcc.magent.pojo.vo.GetFileStoreInfoResp;
import com.cmcc.magent.pojo.vo.GetHwInfoResp;
import com.cmcc.magent.pojo.vo.GetMemoryInfoResp;
@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
@ExtendWith({SpringExtension.class})
@SuppressWarnings("java:S5786")
@DisplayName("获取系统信息接口")
public class SystemInfoApiTest extends TestBaseAuthentication {
public class SystemInfoApiTest extends SpringBootTestBase {
@Test
@DisplayName("获取操作系统信息")

View File

@ -2,6 +2,7 @@ package com.cmcc.magent.crypto.arithmetic;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
@ -38,6 +39,7 @@ import static org.junit.jupiter.api.Assertions.fail;
* @version 0.1.0
* @since 2025-01-15
*/
@DisplayName("加密工具类接口")
public class CryptoHelperTest {
private byte[] emptyByteArray;
@ -115,6 +117,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("Base64解密有效Base64字符串应返回解码字节数组")
public void base64Decryption_ValidBase64String_ShouldReturnDecodedBytes() {
String base64Encoded = "SGVsbG8gV29ybGQh"; // "Hello World!" Base64 编码
byte[] expectedDecodedBytes = "Hello World!".getBytes();
@ -123,6 +126,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("Base64解密无效Base64字符串应抛出IllegalArgumentException")
public void base64Decryption_InvalidBase64String_ShouldThrowIllegalArgumentException() {
String invalidBase64 = "InvalidBase64String!@#";
Assertions.assertThrows(IllegalArgumentException.class, () -> {
@ -131,6 +135,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("Base64解密空字符串应返回空字节数组")
public void base64Decryption_EmptyString_ShouldReturnEmptyByteArray() {
String emptyBase64 = "";
byte[] expectedDecodedBytes = new byte[0];
@ -139,6 +144,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("Base64解密空输入应抛出NullPointerException")
public void base64Decryption_NullInput_ShouldThrowNullPointerException() {
Assertions.assertThrows(NullPointerException.class, () -> {
CryptoHelper.base64Decryption(null);
@ -146,6 +152,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("Base64加密空输入应抛出NullPointerException")
public void base64Encryption_NullInput_ShouldThrowNullPointerException() {
assertThrows(NullPointerException.class, () -> {
CryptoHelper.base64Encryption(null);
@ -153,12 +160,14 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("Base64加密空字节数组应返回空字符串")
public void base64Encryption_EmptyByteArray_ShouldReturnEmptyString() {
String result = CryptoHelper.base64Encryption(emptyByteArray);
assertEquals("", result);
}
@Test
@DisplayName("Base64加密非空字节数组应返回编码字符串")
public void base64Encryption_NonEmptyByteArray_ShouldReturnEncodedString() {
String expected = Base64.getEncoder().encodeToString(nonEmptyByteArray);
String result = CryptoHelper.base64Encryption(nonEmptyByteArray);
@ -166,6 +175,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("Base64加密特殊字符字节数组应返回编码字符串")
public void base64Encryption_SpecialCharacterByteArray_ShouldReturnEncodedString() {
String expected = Base64.getEncoder().encodeToString(specialCharacterByteArray);
String result = CryptoHelper.base64Encryption(specialCharacterByteArray);
@ -173,6 +183,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("SHA-256加密有效输入应返回正确的哈希值")
public void sha256Encryption_ValidInput_CorrectHash() throws NoSuchAlgorithmException {
byte[] expectedHash = MessageDigest.getInstance("SHA-256").digest(validInput.getBytes(StandardCharsets.UTF_8));
byte[] actualHash = CryptoHelper.sha256Encryption(validInput);
@ -180,6 +191,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("SHA-256加密空输入应返回正确的哈希值")
public void sha256Encryption_EmptyInput_CorrectHash() throws NoSuchAlgorithmException {
byte[] expectedHash = MessageDigest.getInstance("SHA-256").digest(emptyInput.getBytes(StandardCharsets.UTF_8));
byte[] actualHash = CryptoHelper.sha256Encryption(emptyInput);
@ -187,6 +199,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("SHA-256加密特殊字符输入应返回正确的哈希值")
public void sha256Encryption_SpecialCharInput_CorrectHash() throws NoSuchAlgorithmException {
byte[] expectedHash = MessageDigest.getInstance("SHA-256").digest(specialCharInput.getBytes(StandardCharsets.UTF_8));
byte[] actualHash = CryptoHelper.sha256Encryption(specialCharInput);
@ -194,6 +207,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("SHA-256加密长输入应返回正确的哈希值")
public void sha256Encryption_LongInput_CorrectHash() throws NoSuchAlgorithmException {
byte[] expectedHash = MessageDigest.getInstance("SHA-256").digest(longInput.getBytes(StandardCharsets.UTF_8));
byte[] actualHash = CryptoHelper.sha256Encryption(longInput);
@ -201,32 +215,28 @@ public class CryptoHelperTest {
}
@Test
public void sha256Encryption_InvalidAlgorithm_ThrowsException() {
// 由于 SHA-256 是一个标准算法这个测试实际上不会触发异常
// 如果需要测试异常可以考虑使用一个不存在的算法
// 但是由于我们不能改变被测方法的实现这个测试是多余的
}
@Test
@DisplayName("MD5加密空字符串应返回空哈希")
public void md5Encryption_EmptyString_ReturnsEmptyHash() throws NoSuchAlgorithmException {
String result = CryptoHelper.md5EncryptionWithBase64("");
assertEquals("1B2M2Y8AsgTpgAmY7PhCfg==", result);
}
@Test
@DisplayName("MD5加密普通字符串应返回正确的哈希")
public void md5Encryption_NormalString_ReturnsCorrectHash() throws NoSuchAlgorithmException {
String result = CryptoHelper.md5Encryption("hello");
assertEquals("5d41402abc4b2a76b9719d911017c592".toUpperCase(), result);
}
@Test
@DisplayName("MD5加密特殊字符应返回正确的哈希")
public void md5Encryption_SpecialCharacters_ReturnsCorrectHash() throws NoSuchAlgorithmException {
String result = CryptoHelper.md5EncryptionWithBase64("hello@world!");
assertEquals("hUJFvVnSo9CfRETnYebLXg==", result);
}
@Test
@DisplayName("MD5加密大小写敏感应返回不同的哈希")
public void md5Encryption_CaseSensitivity_ReturnsDifferentHashes() throws NoSuchAlgorithmException {
String resultLower = CryptoHelper.md5Encryption("hello");
String resultUpper = CryptoHelper.md5Encryption("HELLO");
@ -235,6 +245,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-128加密有效输入应成功加密")
public void aes128Encryption_ValidInputs_EncryptedSuccessfully() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] encrypted = CryptoHelper.aes128Encryption(plaintext, aesKey);
Assertions.assertNotNull(encrypted);
@ -242,24 +253,28 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-128解密无效密钥应抛出InvalidKeyException")
public void aes128Decryption_InvalidKey_ShouldThrowInvalidKeyException() {
Executable executable = () -> CryptoHelper.aes128Decryption(validCiphertextA, invalidKeyA);
assertThrows(IllegalBlockSizeException.class, executable);
}
@Test
@DisplayName("AES-128解密无效密文应抛出BadPaddingException")
public void aes128Decryption_InvalidCiphertext_ShouldThrowBadPaddingException() {
Executable executable = () -> CryptoHelper.aes128Decryption(invalidCiphertext, aesKey);
assertThrows(IllegalBlockSizeException.class, executable);
}
@Test
@DisplayName("AES-128解密无效密文应抛出IllegalBlockSizeException")
public void aes128Decryption_InvalidCiphertext_ShouldThrowIllegalBlockSizeException() {
Executable executable = () -> CryptoHelper.aes128Decryption(invalidCiphertext, aesKey);
assertThrows(IllegalBlockSizeException.class, executable);
}
@Test
@DisplayName("AES-256加密有效输入应成功加密")
public void aes256Encryption_ValidInputs_ShouldEncryptSuccessfully() throws Exception {
byte[] encrypted = CryptoHelper.aes256Encryption(VALID_PLAINTEXT_B, VALID_KEY_B);
assertNotNull(encrypted);
@ -267,6 +282,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256加密无效密钥不应抛出InvalidKeyException")
public void aes256Encryption_InvalidKey_ShouldNotThrowInvalidKeyException() throws Exception {
byte[] encrypted = CryptoHelper.aes256Encryption(VALID_PLAINTEXT_B, INVALID_KEY_B);
assertNotNull(encrypted);
@ -274,6 +290,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256加密空明文应返回空密文")
public void aes256Encryption_EmptyPlaintext_ShouldReturnEmptyCiphertext() throws Exception {
byte[] encrypted = CryptoHelper.aes256Encryption(EMPTY_PLAINTEXT_B, VALID_KEY_B);
assertNotNull(encrypted);
@ -281,6 +298,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256加密空明文应抛出IllegalArgumentException")
public void aes256Encryption_NullPlaintext_ShouldThrowIllegalArgumentException() {
assertThrows(IllegalArgumentException.class, () -> {
CryptoHelper.aes256Encryption(null, VALID_KEY_B);
@ -288,6 +306,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256加密空密钥应抛出NullPointerException")
public void aes256Encryption_NullKey_ShouldThrowNullPointerException() {
assertThrows(NullPointerException.class, () -> {
CryptoHelper.aes256Encryption(VALID_PLAINTEXT_B, null);
@ -295,6 +314,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256加密有效256位密钥应成功加密")
public void aes256Encryption_Valid256BitKey_ShouldEncryptSuccessfully() throws Exception {
byte[] encrypted = CryptoHelper.aes256Encryption(VALID_PLAINTEXT_B, VALID_KEY_256_B);
assertNotNull(encrypted);
@ -302,12 +322,14 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256解密有效输入应成功解密")
public void aes256Decryption_ValidInputs_SuccessfulDecryption() throws Exception {
byte[] decryptedText = CryptoHelper.aes256Decryption(validCiphertextB, validAesKey);
assertEquals("Hello, World!", new String(decryptedText));
}
@Test
@DisplayName("AES-256解密无效密钥应抛出BadPaddingException")
public void aes256Decryption_InvalidKey_ThrowsBadPaddingException() {
assertThrows(BadPaddingException.class, () -> {
CryptoHelper.aes256Decryption(validCiphertextB, invalidAesKey);
@ -315,6 +337,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256解密空密文应抛出IllegalBlockSizeException")
public void aes256Decryption_EmptyCiphertext_ThrowsIllegalBlockSizeException() {
assertThrows(IllegalBlockSizeException.class, () -> {
CryptoHelper.aes256Decryption(new byte[0], validAesKey);
@ -322,6 +345,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256解密空密钥应抛出BadPaddingException")
public void aes256Decryption_EmptyKey_ThrowsBadPaddingException() {
assertThrows(BadPaddingException.class, () -> {
CryptoHelper.aes256Decryption(validCiphertextB, "");
@ -329,6 +353,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256解密空密文应抛出IllegalArgumentException")
public void aes256Decryption_NullCiphertext_ThrowsIllegalArgumentException() {
assertThrows(IllegalBlockSizeException.class, () -> {
CryptoHelper.aes256Decryption(null, validAesKey);
@ -336,6 +361,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("AES-256解密空密钥应抛出NullPointerException")
public void aes256Decryption_NullKey_ThrowsNullPointerException() {
assertThrows(NullPointerException.class, () -> {
CryptoHelper.aes256Decryption(validCiphertextB, null);
@ -343,6 +369,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("DES加密有效输入应成功加密")
public void desEncryption_ValidInputs_ShouldEncryptSuccessfully() throws Exception {
byte[] encrypted = CryptoHelper.desEncryption(plaintext, validDesKey);
assertNotNull(encrypted);
@ -350,6 +377,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("DES加密无效密钥不应抛出异常")
public void desEncryption_InvalidKey_ShouldNotThrowException() {
try {
byte[] encrypted = CryptoHelper.desEncryption(plaintext, invalidDesKey);
@ -360,34 +388,7 @@ public class CryptoHelperTest {
}
@Test
public void desEncryption_UnsupportedAlgorithm_ShouldThrowNoSuchAlgorithmException() {
// 由于 DES 是一个标准算法这个测试在当前实现中不会失败
// 如果需要测试算法不支持的情况可以考虑修改方法或使用不同的算法
// 这里我们假设 DES 是支持的因此这个测试没有实际意义
}
@Test
public void desEncryption_UnsupportedPadding_ShouldThrowNoSuchPaddingException() {
// 由于 PKCS5Padding 是一个标准填充这个测试在当前实现中不会失败
// 如果需要测试填充不支持的情况可以考虑修改方法或使用不同的填充
// 这里我们假设 PKCS5Padding 是支持的因此这个测试没有实际意义
}
@Test
public void desEncryption_BadPadding_ShouldThrowBadPaddingException() {
// 由于我们使用的是标准填充和算法这个测试在当前实现中不会失败
// 如果需要测试填充错误的情况可以考虑修改方法或输入
// 这里我们假设填充是正确的因此这个测试没有实际意义
}
@Test
public void desEncryption_IllegalBlockSize_ShouldThrowIllegalBlockSizeException() {
// 由于我们使用的是标准块大小这个测试在当前实现中不会失败
// 如果需要测试块大小错误的情况可以考虑修改方法或输入
// 这里我们假设块大小是合法的因此这个测试没有实际意义
}
@Test
@DisplayName("DES解密无效密钥应抛出InvalidKeyException")
public void desDecryption_InvalidKey_ThrowsInvalidKeyException() {
// 使用无效密钥进行解密期望抛出 InvalidKeyException
assertThrows(IllegalBlockSizeException.class, () -> {
@ -396,6 +397,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("DES解密无效密文应抛出BadPaddingException")
public void desDecryption_InvalidCiphertext_ThrowsBadPaddingException() {
// 使用无效密文进行解密期望抛出 BadPaddingException
byte[] invalidCiphertext = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; // 示例无效密文
@ -405,6 +407,7 @@ public class CryptoHelperTest {
}
@Test
@DisplayName("DES解密无效密文应抛出IllegalBlockSizeException")
public void desDecryption_InvalidCiphertext_ThrowsIllegalBlockSizeException() {
// 使用无效密文进行解密期望抛出 IllegalBlockSizeException
byte[] invalidCiphertext = new byte[]{(byte) 0xFF}; // 示例无效密文

View File

@ -46,7 +46,7 @@ public class HelperUtilsTest {
/**
* 测试 JSON 序列化功能
* <p>
* 验证 {@link HelperUtils#getJson(Object)} 方法是否能正确序列化传入的对象为 JSON 字符串
* 验证 {@link JsonUtils#getJson(Object)} 方法是否能正确序列化传入的对象为 JSON 字符串
* </p>
*
* @throws Exception 如果 JSON 序列化失败
@ -58,7 +58,7 @@ public class HelperUtilsTest {
Long jsonVal = 123L;
// 调用 getJson 方法
String json = HelperUtils.getJson(jsonVal);
String json = JsonUtils.getJson(jsonVal);
// 断言生成的 JSON 字符串不为空
assertNotNull(json);

View File

@ -0,0 +1,109 @@
package com.cmcc.magent.misc;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.Data;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.crypto.IllegalBlockSizeException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* 测试类 {@code JsonUtilsTest} 用于验证 {@code JsonUtils} 工具类的功能是否正常工作
* <p>
* 测试内容包括对象序列化异常处理等场景
* </p>
*
* <p>此测试类基于 JUnit 5使用 {@link SpringBootTest} 注解运行在 Spring Boot 的测试环境中</p>
*
* @author huangxin@cmhi.chinamobile.com
* @version 1.0.0
* @since 2025-01-15
*/
@SpringBootTest
@DisplayName("JSON辅助功能函数")
public class JsonUtilsTest {
/**
* 测试用的 {@code Person} 对象提供测试数据
*/
private Person person;
/**
* 在每个测试运行之前初始化测试数据
* <p>使用 {@link BeforeEach} 注解确保每次运行测试方法前都会执行此初始化逻辑</p>
*/
@BeforeEach
public void setUp() {
person = new Person();
person.setName("John Doe");
person.setAge(30);
}
/**
* 测试 {@code JsonUtils.getJson(Object)} 方法验证对象序列化为 JSON 字符串是否正确
*
* <p>测试内容</p>
* <ul>
* <li>提供一个合法的 {@code Person} 对象</li>
* <li>验证返回的 JSON 字符串与预期值是否一致</li>
* </ul>
*
* @throws JsonProcessingException 如果序列化过程中发生异常
* @see JsonUtils#getJson(Object)
*/
@Test
@DisplayName("对象序列化")
public void getJson_ValidObject_ReturnsJsonString() throws JsonProcessingException {
String expectedJson = "{\"name\":\"John Doe\",\"age\":30}";
String actualJson = JsonUtils.getJson(person);
assertEquals(expectedJson, actualJson);
}
/**
* 测试 {@code JsonUtils.getJson(Object)} 方法验证当对象存在循环引用时是否抛出异常
*
* <p>测试内容</p>
* <ul>
* <li>设置 {@code Person} 对象为自身的好友即创建循环引用</li>
* <li>调用 {@code JsonUtils.getJson(Object)} 方法并验证是否抛出 {@link JsonProcessingException} 异常</li>
* </ul>
*
* @see JsonUtils#getJson(Object)
*/
@Test
@DisplayName("对象序列化异常")
public void getJson_ObjectWithCircularReference_ThrowsJsonProcessingException() {
person.setFriend(person); // 创建循环引用
assertThrows(JsonProcessingException.class, () -> JsonUtils.getJson(person));
}
/**
* 辅助类 {@code Person}用于测试对象序列化功能
* <p>此类包括基本属性 {@code name}{@code age}以及一个指向朋友的引用 {@code friend}</p>
*/
@Data
public static class Person {
/**
* 人的姓名
*/
private String name;
/**
* 人的年龄
*/
private int age;
/**
* 人的朋友可能为另一个 {@code Person} 对象
* <p>
* 可以为空表示当前人没有朋友
* </p>
*/
private Person friend;
}
}

View File

@ -0,0 +1,402 @@
package com.cmcc.magent.service.impl;
import com.cmcc.magent.common.ConstValue;
import com.cmcc.magent.common.ErrorCode;
import com.cmcc.magent.common.ProtoCryptoType;
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;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import static org.junit.jupiter.api.Assertions.assertEquals;
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.when;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@SpringBootTest
@TestMethodOrder(MethodOrderer.MethodName.class)
public class ProtocolSecurityServiceImplTest {
@InjectMocks
private ProtocolSecurityServiceImpl protocolSecurityService;
@Mock
private ProtocolConfigure protocolConfigure;
@Mock
private JsonUtils jsonUtils;
@Mock
private CryptoHelper cryptoHelper;
@Spy
private ObjectMapper objectMapper = new ObjectMapper();
private MockedStatic<CryptoHelper> cryptoHelperMockedStatic;
@BeforeEach
public void setUp() {
cryptoHelperMockedStatic = Mockito.mockStatic(CryptoHelper.class);
when(protocolConfigure.getCryptoKey()).thenReturn("testKey");
}
@AfterEach
public void tearDown() {
cryptoHelperMockedStatic.close();
}
private HttpInputMessage createHttpInputMessage(String content) {
return new HttpInputMessage() {
@Override
public @NotNull InputStream getBody() {
return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
}
@Override
public @NotNull HttpHeaders getHeaders() {
return new HttpHeaders();
}
};
}
private JsonNode mockJsonNode(int cryptoType) {
JsonNode jsonNode = mock(JsonNode.class);
when(jsonNode.path("cryptoType").asInt()).thenReturn(cryptoType);
return jsonNode;
}
@Test
public void encryptProtocolString_Base64_Success() {
String plainText = "test";
String expectedCipherText = "dGVzdA=="; // Base64 of "test"
when(CryptoHelper.base64Encryption(any(byte[].class))).thenReturn(expectedCipherText);
String cipherText = protocolSecurityService.encryptProtocolString(plainText, ProtoCryptoType.CRYPTO_BASE64.getValue());
assertEquals(expectedCipherText, cipherText);
}
@Test
public void encryptProtocolString_AES128_Success() throws Exception {
String plainText = "test";
String expectedCipherText = "someAES128EncodedText"; // Mocked result
when(CryptoHelper.aes128Encryption(any(byte[].class), anyString())).thenReturn("someAES128EncodedText".getBytes());
when(CryptoHelper.base64Encryption(any(byte[].class))).thenReturn(expectedCipherText);
String cipherText = protocolSecurityService.encryptProtocolString(plainText, ProtoCryptoType.CRYPTO_AES128.getValue());
assertEquals(expectedCipherText, cipherText);
}
@Test
public void encryptProtocolString_AES256_Success() throws Exception {
String plainText = "test";
String expectedCipherText = "someAES256EncodedText"; // Mocked result
when(CryptoHelper.aes256Encryption(any(byte[].class), anyString())).thenReturn("someAES256EncodedText".getBytes());
when(CryptoHelper.base64Encryption(any(byte[].class))).thenReturn(expectedCipherText);
String cipherText = protocolSecurityService.encryptProtocolString(plainText, ProtoCryptoType.CRYPTO_AES256.getValue());
assertEquals(expectedCipherText, cipherText);
}
@Test
public void encryptProtocolString_DES_Success() throws Exception {
String plainText = "test";
String expectedCipherText = "someDESEncodedText"; // Mocked result
when(CryptoHelper.desEncryption(any(byte[].class), anyString())).thenReturn("someDESEncodedText".getBytes());
when(CryptoHelper.base64Encryption(any(byte[].class))).thenReturn(expectedCipherText);
String cipherText = protocolSecurityService.encryptProtocolString(plainText, ProtoCryptoType.CRYPTO_DES.getValue());
assertEquals(expectedCipherText, cipherText);
}
@Test
public void encryptProtocolString_UnknownCryptoType_Exception() {
String plainText = "test";
SecurityProtocolException exception = assertThrows(SecurityProtocolException.class,
() -> protocolSecurityService.encryptProtocolString(plainText, 999));
assertEquals(ErrorCode.ERR_ENCRYPT_UNKNOWN, exception.getErr());
}
@Test
public void encryptProtocolString_AES128_Failure() throws Exception {
String plainText = "test";
when(CryptoHelper.aes128Encryption(any(byte[].class),
anyString())).thenThrow(new SecurityProtocolException(ErrorCode.ERR_ENCRYPT_AES128,
"AES128 error"));
SecurityProtocolException exception = assertThrows(SecurityProtocolException.class,
() -> protocolSecurityService.encryptProtocolString(plainText,
ProtoCryptoType.CRYPTO_AES128.getValue()));
assertEquals(ErrorCode.ERR_ENCRYPT_AES128, exception.getErr());
}
@Test
public void encryptProtocolString_AES256_Failure() throws Exception {
String plainText = "test";
when(CryptoHelper.aes256Encryption(any(byte[].class), anyString())).thenThrow(new IllegalBlockSizeException("AES256 error"));
SecurityProtocolException exception = assertThrows(SecurityProtocolException.class,
() -> protocolSecurityService.encryptProtocolString(plainText,
ProtoCryptoType.CRYPTO_AES256.getValue()));
assertEquals(ErrorCode.ERR_ENCRYPT_AES256, exception.getErr());
}
@Test
public void encryptProtocolString_DES_Failure() throws Exception {
String plainText = "test";
when(CryptoHelper.desEncryption(any(byte[].class), anyString())).thenThrow(new IllegalBlockSizeException("DES error"));
SecurityProtocolException exception = assertThrows(SecurityProtocolException.class,
() -> protocolSecurityService.encryptProtocolString(plainText,
ProtoCryptoType.CRYPTO_DES.getValue()));
assertEquals(ErrorCode.ERR_ENCRYPT_3DES, exception.getErr());
}
@Test
public void encryptProtocol_ValidBase64Encryption_Success() {
String expectedCipherText = "base64EncodedString";
ProtocolResp<BaseRespStatus> rspInfo = ProtocolResp.result(new BaseRespStatus());
rspInfo.setCode(0);
rspInfo.setVer(ConstValue.Protocol.VERSION);
rspInfo.setCryptoType(ProtocolConfigure.SECURITY_PROTOCOL_TYPE);
rspInfo.setTimeStamp(System.currentTimeMillis());
when(CryptoHelper.base64Encryption(any(byte[].class))).thenReturn(expectedCipherText);
ProtocolResp<String> result = protocolSecurityService.encryptProtocol(rspInfo, ProtoCryptoType.CRYPTO_BASE64.getValue());
assertEquals(0, result.getCode());
assertEquals(expectedCipherText, result.getMsgContent());
}
@Test
public void encryptProtocol_InvalidCryptoType_ThrowsException() {
ProtocolReq<String> protocolReq = new ProtocolReq<>();
protocolReq.setMsgContent("testMessage");
assertThrows(SecurityProtocolException.class, () -> {
protocolSecurityService.encryptProtocol(protocolReq, 999);
});
}
@Test
public void encryptProtocol_JsonProcessingError_ThrowsException() throws Exception {
ProtocolReq<String> protocolReq = new ProtocolReq<>();
protocolReq.setMsgContent("testMessage");
when(CryptoHelper.base64Encryption(any(byte[].class))).thenReturn("");
assertThrows(SecurityProtocolException.class, () -> {
protocolSecurityService.encryptProtocol(protocolReq, ProtoCryptoType.CRYPTO_BASE64.getValue());
});
}
@Test
public void decryptProtocol_CryptoNone_ReturnsOriginalJson() throws Exception {
String json = "{\"cryptoType\":0,\"msgContent\":\"test\"}";
String result = protocolSecurityService.decryptProtocol(json);
assertEquals(json, result);
}
@Test
public void decryptProtocol_CryptoBase64_DecodesCorrectly() throws Exception {
String json = "{\"cryptoType\":1,\"msgContent\":\"e1wiaXRlbVwiOlwidGVzdFwifQ\"}";
when(CryptoHelper.base64Decryption("e1wiaXRlbVwiOlwidGVzdFwifQ")).thenReturn("{\"item\":\"test\"}".getBytes());
String result = protocolSecurityService.decryptProtocol(json);
assertEquals("{\"cryptoType\":1,\"msgContent\":{\"item\":\"test\"}}", result);
}
@Test
public void decryptProtocol_CryptoAes128_DecryptsCorrectly() throws Exception {
String json = "{\"cryptoType\":2,\"msgContent\":\"encryptedData\"}";
when(CryptoHelper.base64Decryption("encryptedData")).thenReturn("encryptedData".getBytes());
when(CryptoHelper.aes128Decryption(any(byte[].class), anyString())).thenReturn("{\"item\":\"test\"}".getBytes());
String result = protocolSecurityService.decryptProtocol(json);
assertEquals("{\"cryptoType\":2,\"msgContent\":{\"item\":\"test\"}}", result);
}
@Test
public void decryptProtocol_CryptoAes256_DecryptsCorrectly() throws Exception {
String json = "{\"cryptoType\":3,\"msgContent\":\"encryptedData\"}";
when(CryptoHelper.base64Decryption("encryptedData")).thenReturn("encryptedData".getBytes());
when(CryptoHelper.desDecryption(any(byte[].class), anyString())).thenReturn("{\"item\":\"test\"}".getBytes());
String result = protocolSecurityService.decryptProtocol(json);
assertEquals("{\"cryptoType\":3,\"msgContent\":{\"item\":\"test\"}}", result);
}
@Test
public void decryptProtocol_CryptoDes_DecryptsCorrectly() throws Exception {
String json = "{\"cryptoType\":4,\"msgContent\":\"encryptedData\"}";
when(CryptoHelper.base64Decryption("encryptedData")).thenReturn("encryptedData".getBytes());
when(CryptoHelper.aes256Decryption(any(byte[].class), anyString())).thenReturn("{\"item\":\"test\"}".getBytes());
String result = protocolSecurityService.decryptProtocol(json);
assertEquals("{\"cryptoType\":4,\"msgContent\":{\"item\":\"test\"}}", result);
}
@Test
public void decryptProtocol_InvalidCryptoType_ThrowsException() throws JsonProcessingException {
String json = "{\"cryptoType\":5,\"msgContent\":\"test\"}";
assertThrows(SecurityProtocolException.class, () -> protocolSecurityService.decryptProtocol(json));
}
@Test
public void decryptProtocol_UnknownCryptoType_ThrowsException() throws JsonProcessingException {
String json = "{\"cryptoType\":10,\"msgContent\":\"test\"}";
assertThrows(SecurityProtocolException.class, () -> protocolSecurityService.decryptProtocol(json));
}
@Test
public void decryptProtocol_NoEncryption_ReturnsOriginalContent() throws IOException, IOException {
String reqMessage = "{\"cryptoType\":0,\"msgContent\":\"testContent\"}";
HttpInputMessage httpInputMessage = createHttpInputMessage(reqMessage);
DecryptRequestProtocol result = protocolSecurityService.decryptProtocol(httpInputMessage);
assertEquals(reqMessage, new String(result.getBody().readAllBytes(), StandardCharsets.UTF_8));
}
@Test
public void decryptProtocol_Base64Decryption_DecodesContent() throws IOException {
String reqMessage = "{\"cryptoType\":1,\"msgContent\":\"dGVzdENvbnRlbnQ=\"}";
HttpInputMessage httpInputMessage = createHttpInputMessage(reqMessage);
when(CryptoHelper.base64Decryption("dGVzdENvbnRlbnQ=")).thenReturn("testContent".getBytes(StandardCharsets.UTF_8));
DecryptRequestProtocol result = protocolSecurityService.decryptProtocol(httpInputMessage);
assertEquals("{\"cryptoType\":1,\"msgContent\":testContent}",
new String(result.getBody().readAllBytes(), StandardCharsets.UTF_8));
}
@Test
public void decryptProtocol_AES128Decryption_DecodesContent() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {
String reqMessage = "{\"cryptoType\":2,\"msgContent\":\"encryptedContent\"}";
HttpInputMessage httpInputMessage = createHttpInputMessage(reqMessage);
when(CryptoHelper.base64Decryption("encryptedContent")).thenReturn("base64Decoded".getBytes(StandardCharsets.UTF_8));
try {
when(CryptoHelper.aes128Decryption("base64Decoded".getBytes(StandardCharsets.UTF_8),
"testKey")).thenReturn("decryptedContent".getBytes(StandardCharsets.UTF_8));
} catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
e.printStackTrace();
}
DecryptRequestProtocol result = protocolSecurityService.decryptProtocol(httpInputMessage);
assertEquals("{\"cryptoType\":2,\"msgContent\":decryptedContent}",
new String(result.getBody().readAllBytes(), StandardCharsets.UTF_8));
}
@Test
public void decryptProtocol_AES256Decryption_DecodesContent() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {
String reqMessage = "{\"cryptoType\":4,\"msgContent\":\"encryptedContent\"}";
HttpInputMessage httpInputMessage = createHttpInputMessage(reqMessage);
when(CryptoHelper.base64Decryption("encryptedContent")).thenReturn("base64Decoded".getBytes(StandardCharsets.UTF_8));
try {
when(CryptoHelper.aes256Decryption("base64Decoded".getBytes(StandardCharsets.UTF_8),
"testKey")).thenReturn("decryptedContent".getBytes(StandardCharsets.UTF_8));
} catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
e.printStackTrace();
}
DecryptRequestProtocol result = protocolSecurityService.decryptProtocol(httpInputMessage);
assertEquals("{\"cryptoType\":4,\"msgContent\":decryptedContent}",
new String(result.getBody().readAllBytes(), StandardCharsets.UTF_8));
}
@Test
public void decryptProtocol_DESDecryption_DecodesContent() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException {
String reqMessage = "{\"cryptoType\":3,\"msgContent\":\"encryptedContent\"}";
HttpInputMessage httpInputMessage = createHttpInputMessage(reqMessage);
when(CryptoHelper.base64Decryption("encryptedContent")).thenReturn("base64Decoded".getBytes(StandardCharsets.UTF_8));
try {
when(CryptoHelper.desDecryption("base64Decoded".getBytes(StandardCharsets.UTF_8),
"testKey")).thenReturn("decryptedContent".getBytes(StandardCharsets.UTF_8));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException(e);
}
DecryptRequestProtocol result = protocolSecurityService.decryptProtocol(httpInputMessage);
assertEquals("{\"cryptoType\":3,\"msgContent\":decryptedContent}",
new String(result.getBody().readAllBytes(), StandardCharsets.UTF_8));
}
@Test
public void decryptProtocol_UnknownCryptoType_ThrowsException2() throws IOException {
String reqMessage = "{\"cryptoType\":5,\"msgContent\":\"testContent\"}";
HttpInputMessage httpInputMessage = createHttpInputMessage(reqMessage);
assertThrows(SecurityProtocolException.class, () -> protocolSecurityService.decryptProtocol(httpInputMessage));
}
}

View File

@ -1,13 +1,15 @@
package com.cmcc.magent.service.impl;
import com.cmcc.magent.misc.HelperUtils;
import com.cmcc.magent.misc.JsonUtils;
import com.cmcc.magent.pojo.mapper.IObjectConvert;
import com.cmcc.magent.pojo.po.HwInfo;
import com.cmcc.magent.pojo.po.MemoryDetails;
import com.cmcc.magent.pojo.po.ProcessorInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@ -53,6 +55,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* @since 2025-01-07
*/
@SpringBootTest
@Slf4j
public class SystemInfoServiceImplTest {
/**
@ -140,8 +143,13 @@ 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");
System.out.println("处理器信息: 核心数量 = " +
processorInfo.getPhysicalCores() +
", 线程数量 = " +
processorInfo.getLogicalCpu() +
", 主频 = " +
processorInfo.getCpuVendorFreq() +
" GHz");
}
/**
@ -185,22 +193,27 @@ public class SystemInfoServiceImplTest {
@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));
// 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(JsonUtils.getJson(hw));
String json = "{\"cryptoType\":1,\"msgContent\":\"dGVzdA==\"}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(json);
int cryptoType = jsonNode.path("cryptoType").asInt();
log.info("cryptoType: {}", cryptoType);
}
}