암복호화 함수 이름 변경 및 단위테스트 추가

- 클래스이름 오타 수정
- Parser 단위 테스트 추가
This commit is contained in:
curry772
2026-06-01 08:58:08 +09:00
parent e2950a339f
commit eff7b31490
4 changed files with 254 additions and 12 deletions
@@ -13,17 +13,17 @@ import com.eactive.eai.common.security.CryptoModuleService;
/**
* JEP 트랜스포머 함수 DJB ERP 연동 복호화.
*
* 사용법: DJBErpDecryt(encBase64, moduleName) DJBErpDecryt(encBase64, moduleName,
* groupSeq)
* 사용법: DJBErpDecryt(encBase64, moduleName)
*
* 파라미터: encBase64 : Base64 인코딩된 암호문 (String) moduleName : DB에 등록된 암호화 모듈명
* (String) groupSeq : 도출용 그룹 시퀀스 (String, 선택). 미전달 context로 호출.
* 파라미터:
* encBase64 : Base64 인코딩된 암호문
* moduleName : DB에 등록된 암호화 모듈명
*
* 반환값: 복호화된 평문 (String)
*/
public class DJBDecryt extends PostfixMathCommand {
public class DJBDecrypt extends PostfixMathCommand {
public DJBDecryt() {
public DJBDecrypt() {
numberOfParameters = -1;
}
@@ -21,9 +21,9 @@ import com.eactive.eai.common.security.CryptoModuleService;
*
* 반환값: Base64 인코딩된 암호문 (String)
*/
public class DJBEncryt extends PostfixMathCommand {
public class DJBEncrypt extends PostfixMathCommand {
public DJBEncryt() {
public DJBEncrypt() {
numberOfParameters = -1;
}
@@ -0,0 +1,242 @@
package com.eactive.eai.custom.transformer.function;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.GenericApplicationContext;
import com.eactive.eai.common.security.CryptoModuleService;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.transformer.engine.Parser;
/**
* DJBEncrypt / DJBDecrypt — Parser 표현식 통합 테스트.
*
* DJBCryptoFunctionTest 는 Stack 직접 호출 방식으로 run() 을 검증하고,
* 이 클래스는 Parser 를 통해 JEP 수식으로 함수를 호출하는 통합 경로를 검증한다.
*/
@TestMethodOrder(MethodOrderer.DisplayName.class)
@DisplayName("DJBEncrypt / DJBDecrypt — Parser 변수/상수 혼합 테스트")
class DJBCryptoFunctionParserTest {
private static final String MODULE = "AES_MODULE";
private static final String PLAIN_TEXT = "hello-djb";
private static final byte[] PLAIN_BYTES = PLAIN_TEXT.getBytes(StandardCharsets.UTF_8);
private static final byte[] CIPHER_BYTES = {0x01, 0x02, 0x03, 0x04};
private static final String ENC_BASE64 = Base64.getEncoder().encodeToString(CIPHER_BYTES);
private static GenericApplicationContext ctx;
private static CryptoModuleService mockService;
private Parser parser;
// =========================================================================
// 클래스 초기화 — mock CryptoModuleService 를 Spring 컨텍스트에 등록
// =========================================================================
@BeforeAll
static void setUpClass() throws Exception {
mockService = mock(CryptoModuleService.class);
ctx = new GenericApplicationContext();
ctx.getBeanFactory().registerSingleton("cryptoModuleService", mockService);
ctx.registerBeanDefinition("applicationContextProvider",
BeanDefinitionBuilder.genericBeanDefinition(ApplicationContextProvider.class)
.getBeanDefinition());
ctx.refresh();
}
@AfterAll
static void tearDownClass() {
if (ctx != null) ctx.close();
}
@BeforeEach
void setUp() throws Exception {
reset(mockService);
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class))).thenReturn(CIPHER_BYTES);
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class))).thenReturn(PLAIN_BYTES);
parser = new Parser();
parser.getJep().addFunction("DJBEncrypt", new DJBEncrypt());
parser.getJep().addFunction("DJBDecrypt", new DJBDecrypt());
}
// =========================================================================
// 1. DJBEncrypt
// =========================================================================
@Test
@DisplayName("1-1. 암호화 — 평문 변수 + 상수 모듈명 → Base64 반환")
void encrypt_variablePlain_constantModule() throws Exception {
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", PLAIN_TEXT);
assertEquals(ENC_BASE64, parser.getValueAsObject());
}
@Test
@DisplayName("1-2. 암호화 — 평문·모듈명 모두 변수")
void encrypt_bothVariables() throws Exception {
parser.parse("DJBEncrypt(plain, moduleName)");
parser.addVariable("plain", PLAIN_TEXT);
parser.addVariable("moduleName", MODULE);
assertEquals(ENC_BASE64, parser.getValueAsObject());
}
@Test
@DisplayName("1-3. 암호화 — parse 1회, 변수값 교체 반복 평가")
void encrypt_reuseParser_multipleEvaluations() throws Exception {
// identity: plainBytes 그대로 반환 → Base64 encoding 경로 검증에 집중
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenAnswer(inv -> (byte[]) inv.getArgument(3));
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", "first");
String r1 = (String) parser.getValueAsObject();
parser.addVariable("plain", "second");
String r2 = (String) parser.getValueAsObject();
assertEquals(Base64.getEncoder().encodeToString("first".getBytes(StandardCharsets.UTF_8)), r1);
assertEquals(Base64.getEncoder().encodeToString("second".getBytes(StandardCharsets.UTF_8)), r2);
}
@Test
@DisplayName("1-4. 암호화 — 한글 평문이 UTF-8 인코딩되어 서비스에 전달된다")
void encrypt_koreanPlainText_utf8Encoded() throws Exception {
String korean = "한글평문";
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", korean);
parser.getValueAsObject();
verify(mockService).encrypt(eq(MODULE), anyMap(), isNull(),
eq(korean.getBytes(StandardCharsets.UTF_8)));
}
// =========================================================================
// 2. DJBDecrypt
// =========================================================================
@Test
@DisplayName("2-1. 복호화 — Base64 변수 + 상수 모듈명 → 평문 반환")
void decrypt_variableEnc_constantModule() throws Exception {
parser.parse("DJBDecrypt(enc, \"" + MODULE + "\")");
parser.addVariable("enc", ENC_BASE64);
assertEquals(PLAIN_TEXT, parser.getValueAsObject());
}
@Test
@DisplayName("2-2. 복호화 — Base64·모듈명 모두 변수")
void decrypt_bothVariables() throws Exception {
parser.parse("DJBDecrypt(enc, moduleName)");
parser.addVariable("enc", ENC_BASE64);
parser.addVariable("moduleName", MODULE);
assertEquals(PLAIN_TEXT, parser.getValueAsObject());
}
@Test
@DisplayName("2-3. 복호화 — parse 1회, 변수값 교체 반복 평가")
void decrypt_reuseParser_multipleEvaluations() throws Exception {
// identity: cipherBytes 그대로 반환 → Base64 decoding 경로 검증에 집중
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenAnswer(inv -> (byte[]) inv.getArgument(3));
parser.parse("DJBDecrypt(enc, \"" + MODULE + "\")");
String firstEnc = Base64.getEncoder().encodeToString("first".getBytes(StandardCharsets.UTF_8));
String secondEnc = Base64.getEncoder().encodeToString("second".getBytes(StandardCharsets.UTF_8));
parser.addVariable("enc", firstEnc);
assertEquals("first", parser.getValueAsObject());
parser.addVariable("enc", secondEnc);
assertEquals("second", parser.getValueAsObject());
}
// =========================================================================
// 3. 라운드트립
// =========================================================================
@Test
@DisplayName("3-1. 라운드트립 — 암호화 결과를 복호화하면 원문과 일치")
void roundTrip_encryptThenDecrypt_returnsOriginal() throws Exception {
// 암호화
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", PLAIN_TEXT);
String encryptedBase64 = (String) parser.getValueAsObject();
// 복호화
parser.parse("DJBDecrypt(enc, \"" + MODULE + "\")");
parser.addVariable("enc", encryptedBase64);
assertEquals(PLAIN_TEXT, parser.getValueAsObject());
}
@Test
@DisplayName("3-2. 라운드트립 — 한글 평문")
void roundTrip_koreanPlainText() throws Exception {
String korean = "한글평문테스트";
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenReturn(korean.getBytes(StandardCharsets.UTF_8));
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class)))
.thenReturn(korean.getBytes(StandardCharsets.UTF_8));
parser.parse("DJBEncrypt(plain, \"" + MODULE + "\")");
parser.addVariable("plain", korean);
String enc = (String) parser.getValueAsObject();
parser.parse("DJBDecrypt(enc, \"" + MODULE + "\")");
parser.addVariable("enc", enc);
assertEquals(korean, parser.getValueAsObject());
}
// =========================================================================
// 4. 오류 처리
// =========================================================================
@Test
@DisplayName("4-1. 암호화 — 파라미터 1개이면 예외")
void encrypt_singleParam_throwsException() {
assertThrows(Exception.class, () -> {
parser.parse("DJBEncrypt(plain)");
parser.addVariable("plain", PLAIN_TEXT);
parser.getValueAsObject();
});
}
@Test
@DisplayName("4-2. 복호화 — 파라미터 1개이면 예외")
void decrypt_singleParam_throwsException() {
assertThrows(Exception.class, () -> {
parser.parse("DJBDecrypt(enc)");
parser.addVariable("enc", ENC_BASE64);
parser.getValueAsObject();
});
}
@Test
@DisplayName("4-3. 복호화 — 유효하지 않은 Base64 상수이면 예외")
void decrypt_invalidBase64Constant_throwsException() {
assertThrows(Exception.class, () -> {
parser.parse("DJBDecrypt(\"!!invalid!!\", \"" + MODULE + "\")");
parser.getValueAsObject();
});
}
}
@@ -44,8 +44,8 @@ class DJBCryptoFunctionTest {
private static GenericApplicationContext ctx;
private static CryptoModuleService mockService;
private DJBDecryt decryt;
private DJBEncryt encryt;
private DJBDecrypt decryt;
private DJBEncrypt encryt;
// =========================================================================
// 클래스 초기화
@@ -73,8 +73,8 @@ class DJBCryptoFunctionTest {
reset(mockService);
when(mockService.decrypt(any(), anyMap(), isNull(), any(byte[].class))).thenReturn(PLAIN_BYTES);
when(mockService.encrypt(any(), anyMap(), isNull(), any(byte[].class))).thenReturn(CIPHER_BYTES);
decryt = new DJBDecryt();
encryt = new DJBEncryt();
decryt = new DJBDecrypt();
encryt = new DJBEncrypt();
}
// =========================================================================