표준전문 테스트 추가

- 종료부 제거
- StandardMessageCoodinator 테스트
- StandardMessageManager init 테스트
- JSON 메시지 파싱 테스트
This commit is contained in:
curry772
2026-04-20 16:54:38 +09:00
parent 18b3e781b1
commit 557a071b1e
8 changed files with 1368 additions and 11 deletions
@@ -48,11 +48,6 @@ class StandardLayoutDJBTest {
assertNotNull(message.findItem("DATA"), "DATA 블록 없음");
}
@Test
void 전문종료부_존재() {
assertNotNull(message.findItem("MESG_END_IDFR_VAL"), "전문종료부 없음");
}
// ----------------------------------------------------------------
// HEAD 핵심 필드 검증
// ----------------------------------------------------------------
@@ -0,0 +1,356 @@
package com.eactive.eai.custom.message;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationContext;
import com.eactive.eai.common.monitor.EAIServiceMonitor;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
/**
* StandardMessageCoordinatorDJB 단위테스트
*
* DB/Spring 없는 환경에서 EAIServerManager·PropManager를 Mockito로 stub 처리.
* ApplicationContextProvider.context에 mock ApplicationContext를 리플렉션으로 주입.
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class StandardMessageCoordinatorDJBTest {
private static final DateTimeFormatter FMT_DATE = DateTimeFormatter.ofPattern("yyyyMMdd");
private StandardMessageManager manager;
private StandardMessageCoordinatorDJB coordinator;
private InterfaceMapper mapper;
private StandardMessage message;
@BeforeAll
void setUpAll() throws Exception {
// ① PropManager mock — STDMessageErrorKeys 정적 초기화가 getProperty(group,key,def)를 호출함.
// def(3번째 인자)를 그대로 반환하여 기본 에러코드 상수값이 설정되도록 함.
PropManager mockPropManager = Mockito.mock(PropManager.class);
Mockito.when(mockPropManager.getProperty(anyString(), anyString(), anyString()))
.thenAnswer(new Answer<String>() {
public String answer(InvocationOnMock inv) {
return (String) inv.getArguments()[2];
}
});
// ② EAIServerManager mock — DB 미연결 환경 대응.
// isPEAIServer/isSEAIServer → false → getSysEnvDvcd()가 "D"(개발)를 반환.
EAIServerManager mockServer = Mockito.mock(EAIServerManager.class);
Mockito.when(mockServer.isPEAIServer()).thenReturn(false);
Mockito.when(mockServer.isSEAIServer()).thenReturn(false);
Mockito.when(mockServer.isMCI()).thenReturn(false);
// ③ EAIServiceMonitor mock — MessageUtil.getTobeCode()가 사용.
// isTimeOutCodes/isBizErrorCodes → false → SYSTEM_ERROR_CODE 분기로 처리.
EAIServiceMonitor mockMonitor = Mockito.mock(EAIServiceMonitor.class);
Mockito.when(mockMonitor.isTimeOutCodes(anyString())).thenReturn(false);
Mockito.when(mockMonitor.isBizErrorCodes(anyString())).thenReturn(false);
// ④ ApplicationContext mock → 세 빈을 반환하도록 설정
ApplicationContext mockCtx = Mockito.mock(ApplicationContext.class);
Mockito.when(mockCtx.getBean(EAIServerManager.class)).thenReturn(mockServer);
Mockito.when(mockCtx.getBean(PropManager.class)).thenReturn(mockPropManager);
Mockito.when(mockCtx.getBean(EAIServiceMonitor.class)).thenReturn(mockMonitor);
// ⑤ ApplicationContextProvider.context(static 필드)에 mock 주입
Field ctxField = ApplicationContextProvider.class.getDeclaredField("context");
ctxField.setAccessible(true);
ctxField.set(null, mockCtx);
// ⑥ StandardMessageManager 초기화 (DJB 테스트용 설정)
System.setProperty(StandardMessageManager.STANDARD_MESSAGE_CONFIG,
"src/test/resources/standard-message-config-test.properties");
manager = StandardMessageManager.getInstance();
manager.init();
}
@BeforeEach
void setUp() {
message = manager.getStandardMessage();
mapper = manager.getMapper();
coordinator = new StandardMessageCoordinatorDJB();
message.setReadPosition(0);
assertNotNull(mapper, "mapper가 null — StandardMessageManager.init() 실패 의심");
}
// ================================================================
// coordinateAfterCreateMessageByRule
// ================================================================
@Test
void GUID_40자_생성_설정() {
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
String guid = mapper.getGuid(message);
assertNotNull(guid, "GUID가 null");
assertEquals(GUIDGeneratorDJB.GUID_LENGTH, guid.length(),
"GUID 길이가 40자가 아님: " + guid.length());
}
@Test
void guid_prgs_no_001_초기화() {
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
assertEquals("001", mapper.getGuidSeq(message), "guid_prgs_no 초기값은 001이어야 함");
}
@Test
void ortr_guid_GUID_동일값_설정() {
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
String guid = mapper.getGuid(message);
String orgGuid = mapper.getOrgGuid(message);
assertEquals(guid, orgGuid, "원거래GUID는 GUID와 동일해야 함");
}
@Test
void frst_mesg_dman_dt_오늘날짜_설정() {
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
String expected = LocalDate.now().format(FMT_DATE);
assertEquals(expected, message.findItemValue("HEAD.frst_mesg_dman_dt"),
"frst_mesg_dman_dt가 오늘 날짜가 아님");
}
@Test
void frst_mesg_dman_time_설정_9자리() {
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
String time = message.findItemValue("HEAD.frst_mesg_dman_time");
assertNotNull(time, "frst_mesg_dman_time이 null");
assertEquals(9, time.length(), "frst_mesg_dman_time은 HHmmssSSS(9자)여야 함: " + time);
assertTrue(time.matches("\\d{9}"), "frst_mesg_dman_time 형식 오류: " + time);
}
@Test
void trnm_sys_dvcd_EAI_설정() {
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
assertEquals("EAI", message.findItemValue("HEAD.trnm_sys_dvcd"));
}
@Test
void sys_env_dvcd_D_설정_mock_isPEAIServer_false() {
// mock: isPEAIServer=false, isSEAIServer=false → "D"(개발) 반환
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
assertEquals("D", message.findItemValue("HEAD.sys_env_dvcd"),
"mock 환경에서 sys_env_dvcd는 D여야 함");
}
@Test
void frst_trnm_ipad_설정() {
coordinator.coordinateAfterCreateMessageByRule(message, null, null);
String ip = message.findItemValue("HEAD.frst_trnm_ipad");
assertNotNull(ip, "frst_trnm_ipad가 null");
assertFalse(ip.trim().isEmpty(), "frst_trnm_ipad가 공백");
}
// ================================================================
// coordinateBeforeStandardMessageSend
// ================================================================
@Test
void data_scop_len_정수값으로_설정() {
coordinator.coordinateBeforeStandardMessageSend(message, "FLAT", "euc-kr");
String len = message.findItemValue("DATA.data_scop_len");
assertNotNull(len, "DATA.data_scop_len이 null");
// NUMBER 타입은 선행 0을 모두 제거: "00000000"(0 바이트) → "" 반환됨
// 빈 문자열은 0 바이트를 의미하므로 0 이상 조건 통과
int dataLen = (len.trim().isEmpty()) ? 0 : Integer.parseInt(len.trim());
assertTrue(dataLen >= 0, "data_scop_len은 0 이상이어야 함: '" + len + "'");
}
@Test
void data_scop_len_BIZ_DATA_비어있을때_0() {
// BIZ_DATA에 데이터 미설정 → 0 바이트 → "00000000" → NUMBER 타입이 "" 반환
coordinator.coordinateBeforeStandardMessageSend(message, "JSON", "utf-8");
String len = message.findItemValue("DATA.data_scop_len");
assertNotNull(len, "DATA.data_scop_len이 null");
int dataLen = (len.trim().isEmpty()) ? 0 : Integer.parseInt(len.trim());
assertEquals(0, dataLen, "BIZ_DATA 미설정 시 data_scop_len은 0이어야 함");
}
// ================================================================
// coordinateBeforeResponse
// ================================================================
@Test
void mesg_rspn_dt_오늘날짜_설정() {
coordinator.coordinateBeforeResponse(message, null, null, "euc-kr");
String expected = LocalDate.now().format(FMT_DATE);
assertEquals(expected, message.findItemValue("HEAD.mesg_rspn_dt"),
"mesg_rspn_dt가 오늘 날짜가 아님");
}
@Test
void mesg_rspn_time_9자리_설정() {
coordinator.coordinateBeforeResponse(message, null, null, "euc-kr");
String time = message.findItemValue("HEAD.mesg_rspn_time");
assertNotNull(time, "mesg_rspn_time이 null");
assertEquals(9, time.length(), "mesg_rspn_time은 HHmmssSSS(9자)여야 함: " + time);
assertTrue(time.matches("\\d{9}"), "mesg_rspn_time 형식 오류: " + time);
}
@Test
void coordinateBeforeResponse_data_scop_len_설정() {
coordinator.coordinateBeforeResponse(message, null, null, "euc-kr");
String len = message.findItemValue("DATA.data_scop_len");
assertNotNull(len);
int dataLen = (len.trim().isEmpty()) ? 0 : Integer.parseInt(len.trim());
assertTrue(dataLen >= 0);
}
// ================================================================
// coordinateSetStandardMessageError
// ================================================================
@Test
void 에러시_procs_rslt_dvcd_F_설정() {
coordinator.coordinateSetStandardMessageError(message, mapper, "RECEAICMM999", "테스트 오류");
assertEquals("F", message.findItemValue("HEAD.procs_rslt_dvcd"),
"오류 시 procs_rslt_dvcd는 F여야 함");
}
@Test
void 에러시_dman_rspn_dvcd_R_설정() {
coordinator.coordinateSetStandardMessageError(message, mapper, "RECEAICMM999", "테스트 오류");
assertEquals(STDMessageKeys.SEND_RECV_CD_RECV,
message.findItemValue("HEAD.dman_rspn_dvcd"),
"오류 시 dman_rspn_dvcd는 R이어야 함");
}
@Test
void 에러시_MSG_msg_dvcd_EM_설정() {
coordinator.coordinateSetStandardMessageError(message, mapper, "RECEAICMM999", "테스트 오류");
assertEquals("EM", message.findItemValue("MSG.msg_dvcd"),
"오류 시 msg_dvcd는 EM이어야 함");
}
@Test
void 에러시_outp_atrb_cd_1_설정() {
coordinator.coordinateSetStandardMessageError(message, mapper, "RECEAICMM999", "테스트 오류");
assertEquals("1", message.findItemValue("MSG.MAIN_MSG.outp_atrb_cd"),
"오류 시 outp_atrb_cd는 1(팝업)이어야 함");
}
@Test
void 에러시_outp_msg_cd_설정됨() {
coordinator.coordinateSetStandardMessageError(message, mapper, "RECEAICMM999", "테스트 오류");
// mock PropManager가 defaultValue("900400")를 반환 → SYSTEM_ERROR_CODE_VALUE="900400"
String errCode = message.findItemValue("MSG.MAIN_MSG.outp_msg_cd");
assertNotNull(errCode, "outp_msg_cd가 null");
assertFalse(errCode.trim().isEmpty(), "outp_msg_cd가 공백");
}
@Test
void 에러시_outp_msg_ctnt_설정됨() {
coordinator.coordinateSetStandardMessageError(message, mapper, "RECEAICMM999", "테스트 오류");
String errMsg = message.findItemValue("MSG.MAIN_MSG.outp_msg_ctnt");
assertNotNull(errMsg, "outp_msg_ctnt가 null");
assertFalse(errMsg.trim().isEmpty(), "outp_msg_ctnt가 공백");
}
@Test
void 에러시_반환값_false() {
boolean result = coordinator.coordinateSetStandardMessageError(message, mapper, "RECEAICMM999", "테스트 오류");
assertFalse(result, "coordinateSetStandardMessageError는 false를 반환해야 함 (BIZ_DATA null 처리)");
}
@Test
void 에러시_msg_scop_len_정수값으로_설정() {
coordinator.coordinateSetStandardMessageError(message, mapper, "RECEAICMM999", "테스트 오류");
// NUMBER 타입이므로 선행 0 제거됨 — 숫자 파싱 가능 여부와 0 이상인지 검증
String scopLen = message.findItemValue("MSG.msg_scop_len");
assertNotNull(scopLen, "msg_scop_len이 null");
assertTrue(Integer.parseInt(scopLen.trim()) >= 0, "msg_scop_len은 0 이상이어야 함: " + scopLen);
}
// ================================================================
// coordinateAfterRecvNonStdSyncResponse
// ================================================================
@Test
void 정상수신시_procs_rslt_dvcd_S_설정() {
coordinator.coordinateAfterRecvNonStdSyncResponse(message);
assertEquals("S", message.findItemValue("HEAD.procs_rslt_dvcd"),
"정상 수신 시 procs_rslt_dvcd는 S여야 함");
}
@Test
void 정상수신시_msg_dvcd_NM_설정() {
coordinator.coordinateAfterRecvNonStdSyncResponse(message);
assertEquals("NM", message.findItemValue("MSG.msg_dvcd"),
"정상 수신 시 msg_dvcd는 NM이어야 함");
}
@Test
void 정상수신시_outp_msg_cd_000000000000_설정() {
coordinator.coordinateAfterRecvNonStdSyncResponse(message);
assertEquals("000000000000", message.findItemValue("MSG.MAIN_MSG.outp_msg_cd"));
}
@Test
void 정상수신시_outp_msg_ctnt_정상처리_설정() {
coordinator.coordinateAfterRecvNonStdSyncResponse(message);
assertEquals("정상처리", message.findItemValue("MSG.MAIN_MSG.outp_msg_ctnt"));
}
@Test
void 정상수신시_msg_list_1건_구성() {
coordinator.coordinateAfterRecvNonStdSyncResponse(message);
// NUMBER 타입이므로 "00001" → "1" 저장됨
String rowcnt = message.findItemValue("MSG.MAIN_MSG.msg_list_rowcnt");
assertNotNull(rowcnt, "msg_list_rowcnt가 null");
assertEquals(1, Integer.parseInt(rowcnt.trim()), "msg_list는 1건이어야 함");
}
@Test
void 정상수신시_msg_scop_len_정수값으로_설정() {
coordinator.coordinateAfterRecvNonStdSyncResponse(message);
// NUMBER 타입이므로 선행 0 제거됨 — 숫자 파싱 가능 여부와 0 이상인지 검증
String scopLen = message.findItemValue("MSG.msg_scop_len");
assertNotNull(scopLen, "msg_scop_len이 null");
assertTrue(Integer.parseInt(scopLen.trim()) >= 0, "msg_scop_len은 0 이상이어야 함: " + scopLen);
}
}
@@ -0,0 +1,509 @@
package com.eactive.eai.custom.message;
import static org.junit.jupiter.api.Assertions.*;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationContext;
import com.eactive.eai.common.monitor.EAIServiceMonitor;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.parser.JsonReader;
import com.eactive.eai.message.service.InterfaceMapper;
import com.eactive.eai.common.message.MessageType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import static org.mockito.ArgumentMatchers.anyString;
/**
* DJBank 표준전문 JSON 처리 흐름 통합 테스트
*
* 검증 시나리오:
* 1. JSON → StandardMessage 파싱 (표준 요청 수신)
* 2. JSON → StandardMessage 파싱 (표준 응답 수신 — MSG 포함)
* 3. 표준 메시지 요청 수신 처리 (coordinateAfterCreateMessageByRule)
* 4. 표준 응답 생성 (coordinateBeforeResponse → JSON 직렬화)
* 5. 비표준 수신 → 정상 응답 표준 생성 (coordinateAfterRecvNonStdSyncResponse → JSON)
* 6. 오류 응답 표준 생성 (coordinateSetStandardMessageError → JSON)
* 7. JSON 왕복(parse → serialize) 일관성
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class StandardMessageJsonFlowTest {
// ----------------------------------------------------------------
// 테스트용 상수 (GUID 40자 고정)
// ----------------------------------------------------------------
private static final String TEST_GUID =
"20260420" + "120000" + "000" + "EAI" + "01" + "123456789012" + "000001";
// 8+6+3+3+2+12+6 = 40자
private static final String TEST_IF_ID = "IF_DJBTEST_001";
private static final String TEST_TX_ID = "TXTEST000001";
private static final DateTimeFormatter FMT_DATE = DateTimeFormatter.ofPattern("yyyyMMdd");
/**
* 표준 요청 JSON (dman_rspn_dvcd=S → MSG 블록 미포함)
* BIZ_DATA는 JSON 오브젝트 — 파싱 후 JSON 문자열로 저장됨
*/
private static final String REQ_JSON =
"{"
+ "\"HEAD\":{"
+ "\"nxgn_stnd_idfr\":\"JERA\","
+ "\"guid\":\"" + TEST_GUID + "\","
+ "\"guid_prgs_no\":\"1\","
+ "\"stnd_mesg_ver\":\"R10\","
+ "\"ortr_guid\":\"" + TEST_GUID + "\","
+ "\"dman_rspn_dvcd\":\"S\","
+ "\"if_id\":\"" + TEST_IF_ID + "\","
+ "\"procs_rslt_dvcd\":\"S\","
+ "\"tx_id\":\"" + TEST_TX_ID + "\","
+ "\"chnl_tycd\":\"EAI\","
+ "\"hmab_dvcd\":\"1\","
+ "\"trnm_sys_dvcd\":\"OPA\","
+ "\"frst_trnm_sys_dvcd\":\"OPA\","
+ "\"sys_env_dvcd\":\"D\","
+ "\"frst_mesg_dman_dt\":\"20260420\","
+ "\"frst_mesg_dman_time\":\"120000000\""
+ "},"
+ "\"DATA\":{"
+ "\"data_dvcd\":\"IO\","
+ "\"data_scop_len\":\"37\","
+ "\"BIZ_DATA\":{\"acct_no\":\"123456789\",\"amt\":\"100000\"}"
+ "}"
+ "}";
/**
* 표준 응답 JSON (dman_rspn_dvcd=R → MSG 블록 포함, 정상)
*/
private static final String RSP_JSON_OK =
"{"
+ "\"HEAD\":{"
+ "\"nxgn_stnd_idfr\":\"JERA\","
+ "\"guid\":\"" + TEST_GUID + "\","
+ "\"guid_prgs_no\":\"2\","
+ "\"stnd_mesg_ver\":\"R10\","
+ "\"ortr_guid\":\"" + TEST_GUID + "\","
+ "\"dman_rspn_dvcd\":\"R\","
+ "\"if_id\":\"" + TEST_IF_ID + "\","
+ "\"procs_rslt_dvcd\":\"S\","
+ "\"tx_id\":\"" + TEST_TX_ID + "\","
+ "\"chnl_tycd\":\"EAI\","
+ "\"hmab_dvcd\":\"1\","
+ "\"trnm_sys_dvcd\":\"EAI\","
+ "\"sys_env_dvcd\":\"D\","
+ "\"frst_mesg_dman_dt\":\"20260420\","
+ "\"frst_mesg_dman_time\":\"120000000\","
+ "\"mesg_rspn_dt\":\"20260420\","
+ "\"mesg_rspn_time\":\"120100000\""
+ "},"
+ "\"MSG\":{"
+ "\"msg_dvcd\":\"NM\","
+ "\"msg_scop_len\":\"0\","
+ "\"MAIN_MSG\":{"
+ "\"outp_atrb_cd\":\"0\","
+ "\"outp_msg_cd\":\"000000000000\","
+ "\"outp_msg_ctnt\":\"정상처리\","
+ "\"msg_list_rowcnt\":\"1\""
+ "}"
+ "},"
+ "\"DATA\":{"
+ "\"data_dvcd\":\"IO\","
+ "\"data_scop_len\":\"37\","
+ "\"BIZ_DATA\":{\"acct_no\":\"123456789\",\"bal\":\"900000\"}"
+ "}"
+ "}";
private StandardMessageManager manager;
private InterfaceMapper mapper;
private JsonReader jsonReader;
private StandardMessageCoordinatorDJB coordinator;
private ObjectMapper jacksonMapper;
@BeforeAll
void setUpAll() throws Exception {
PropManager mockPropManager = Mockito.mock(PropManager.class);
Mockito.when(mockPropManager.getProperty(anyString(), anyString(), anyString()))
.thenAnswer(new Answer<String>() {
public String answer(InvocationOnMock inv) { return (String) inv.getArguments()[2]; }
});
EAIServerManager mockServer = Mockito.mock(EAIServerManager.class);
Mockito.when(mockServer.isPEAIServer()).thenReturn(false);
Mockito.when(mockServer.isSEAIServer()).thenReturn(false);
Mockito.when(mockServer.isMCI()).thenReturn(false);
Mockito.when(mockServer.getLocalServerName()).thenReturn("TEST_SERVER");
Mockito.when(mockServer.getGroupInstId()).thenReturn("TEST_INST");
EAIServiceMonitor mockMonitor = Mockito.mock(EAIServiceMonitor.class);
Mockito.when(mockMonitor.isTimeOutCodes(anyString())).thenReturn(false);
Mockito.when(mockMonitor.isBizErrorCodes(anyString())).thenReturn(false);
ApplicationContext mockCtx = Mockito.mock(ApplicationContext.class);
Mockito.when(mockCtx.getBean(EAIServerManager.class)).thenReturn(mockServer);
Mockito.when(mockCtx.getBean(PropManager.class)).thenReturn(mockPropManager);
Mockito.when(mockCtx.getBean(EAIServiceMonitor.class)).thenReturn(mockMonitor);
Field ctxField = ApplicationContextProvider.class.getDeclaredField("context");
ctxField.setAccessible(true);
ctxField.set(null, mockCtx);
System.setProperty(StandardMessageManager.STANDARD_MESSAGE_CONFIG,
"src/test/resources/standard-message-config-test.properties");
manager = StandardMessageManager.getInstance();
manager.init();
}
@BeforeEach
void setUp() {
mapper = manager.getMapper();
jsonReader = (JsonReader) manager.getReader("JSON");
coordinator = new StandardMessageCoordinatorDJB();
jacksonMapper = new ObjectMapper();
}
// ================================================================
// 1. 표준 요청 JSON 파싱
// ================================================================
@Test
void 요청JSON_파싱_HEAD_guid_40자_정확() throws Exception {
StandardMessage msg = parseReq();
String guid = mapper.getGuid(msg);
assertEquals(TEST_GUID, guid, "파싱된 guid가 입력 JSON과 다름");
assertEquals(GUIDGeneratorDJB.GUID_LENGTH, guid.length(), "GUID 길이가 40자가 아님");
}
@Test
void 요청JSON_파싱_HEAD_if_id_매핑() throws Exception {
StandardMessage msg = parseReq();
assertEquals(TEST_IF_ID, msg.findItemValue("HEAD.if_id").trim());
}
@Test
void 요청JSON_파싱_HEAD_dman_rspn_dvcd_S() throws Exception {
StandardMessage msg = parseReq();
assertEquals("S", msg.findItemValue("HEAD.dman_rspn_dvcd"),
"요청 방향은 dman_rspn_dvcd = S 여야 함");
}
@Test
void 요청JSON_파싱_DATA_BIZ_DATA_JSON_오브젝트_저장() throws Exception {
StandardMessage msg = parseReq();
String bizData = msg.findItemValue("DATA.BIZ_DATA");
assertNotNull(bizData, "BIZ_DATA가 null");
assertFalse(bizData.trim().isEmpty(), "BIZ_DATA가 공백");
// JSON 오브젝트로 파싱 가능한지 검증
JsonNode node = jacksonMapper.readTree(bizData);
assertEquals("123456789", node.path("acct_no").asText(), "BIZ_DATA.acct_no 불일치");
}
@Test
void 요청JSON_파싱_MSG_블록_사이즈_0_숨김() throws Exception {
StandardMessage msg = parseReq();
// dman_rspn_dvcd=S → MSG 블록은 조건 미충족 → size=0(숨김)
// JSON 직렬화 결과에 MSG 키가 없어야 함
String json = msg.toJson();
JsonNode root = jacksonMapper.readTree(json);
assertFalse(root.has("MSG"), "요청 전문 JSON에 MSG 블록이 포함되면 안 됨");
}
// ================================================================
// 2. 표준 응답 JSON 파싱 (MSG 포함)
// ================================================================
@Test
void 응답JSON_파싱_MSG_msg_dvcd_NM() throws Exception {
StandardMessage msg = parseRsp();
assertEquals("NM", msg.findItemValue("MSG.msg_dvcd"),
"정상 응답의 msg_dvcd는 NM이어야 함");
}
@Test
void 응답JSON_파싱_MSG_MAIN_MSG_outp_msg_ctnt_정상처리() throws Exception {
StandardMessage msg = parseRsp();
assertEquals("정상처리", msg.findItemValue("MSG.MAIN_MSG.outp_msg_ctnt"),
"정상 응답의 outp_msg_ctnt는 '정상처리'여야 함");
}
@Test
void 응답JSON_파싱_HEAD_procs_rslt_dvcd_S() throws Exception {
StandardMessage msg = parseRsp();
assertEquals("S", msg.findItemValue("HEAD.procs_rslt_dvcd"),
"정상 응답의 procs_rslt_dvcd는 S여야 함");
}
// ================================================================
// 3. 표준 메시지 수신 처리 — coordinateAfterCreateMessageByRule
// ================================================================
@Test
void 표준수신_coordinateAfterCreateMessageByRule_새GUID_40자_재설정() throws Exception {
StandardMessage msg = parseReq();
coordinator.coordinateAfterCreateMessageByRule(msg, null, null);
String newGuid = mapper.getGuid(msg);
assertNotNull(newGuid, "coordinateAfterCreateMessageByRule 후 GUID null");
assertEquals(GUIDGeneratorDJB.GUID_LENGTH, newGuid.length(), "재설정된 GUID가 40자가 아님");
// Coordinator는 새 GUID를 생성하므로 원본과 달라야 함
assertNotEquals(TEST_GUID, newGuid, "Coordinator가 기존 GUID를 그대로 사용함");
}
@Test
void 표준수신_coordinateAfterCreateMessageByRule_frst_mesg_dman_dt_오늘날짜() throws Exception {
StandardMessage msg = parseReq();
coordinator.coordinateAfterCreateMessageByRule(msg, null, null);
String today = LocalDate.now().format(FMT_DATE);
assertEquals(today, msg.findItemValue("HEAD.frst_mesg_dman_dt"),
"frst_mesg_dman_dt는 오늘 날짜여야 함");
}
@Test
void 표준수신_coordinateAfterCreateMessageByRule_trnm_sys_dvcd_EAI() throws Exception {
StandardMessage msg = parseReq();
coordinator.coordinateAfterCreateMessageByRule(msg, null, null);
assertEquals("EAI", msg.findItemValue("HEAD.trnm_sys_dvcd"),
"coordinateAfterCreateMessageByRule 후 trnm_sys_dvcd는 EAI여야 함");
}
// ================================================================
// 4. 표준 응답 생성 — coordinateBeforeResponse + JSON 직렬화
// ================================================================
@Test
void 표준응답생성_coordinateBeforeResponse_mesg_rspn_dt_오늘날짜() throws Exception {
StandardMessage msg = parseReq();
coordinator.coordinateBeforeResponse(msg, null, null, "utf-8");
String today = LocalDate.now().format(FMT_DATE);
assertEquals(today, msg.findItemValue("HEAD.mesg_rspn_dt"),
"mesg_rspn_dt는 오늘 날짜여야 함");
}
@Test
void 표준응답생성_coordinateBeforeResponse_mesg_rspn_time_9자리() throws Exception {
StandardMessage msg = parseReq();
coordinator.coordinateBeforeResponse(msg, null, null, "utf-8");
String time = msg.findItemValue("HEAD.mesg_rspn_time");
assertNotNull(time, "mesg_rspn_time이 null");
assertEquals(9, time.length(), "mesg_rspn_time은 HHmmssSSS(9자)여야 함: " + time);
assertTrue(time.matches("\\d{9}"), "mesg_rspn_time 형식 오류");
}
@Test
void 표준응답생성_JSON_직렬화_HEAD_포함() throws Exception {
StandardMessage msg = parseReq();
coordinator.coordinateBeforeResponse(msg, null, null, "utf-8");
String json = msg.getDataString(MessageType.JSON, "utf-8");
assertNotNull(json, "직렬화 JSON이 null");
JsonNode root = jacksonMapper.readTree(json);
assertTrue(root.has("HEAD"), "직렬화 JSON에 HEAD 블록 없음");
}
@Test
void 표준응답생성_JSON_직렬화_guid_값_보존() throws Exception {
StandardMessage msg = parseReq();
// Coordinator 호출 없이 파싱된 상태 그대로 직렬화
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertEquals(TEST_GUID, root.path("HEAD").path("guid").asText(),
"직렬화 JSON의 guid가 원본과 다름");
}
@Test
void 표준응답생성_JSON_직렬화_BIZ_DATA_보존() throws Exception {
StandardMessage msg = parseReq();
coordinator.coordinateBeforeResponse(msg, null, null, "utf-8");
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
// BIZ_DATA는 JSON 문자열 또는 JSON 오브젝트로 들어갈 수 있음
assertNotNull(root.path("DATA").get("BIZ_DATA"),
"직렬화 JSON에 DATA.BIZ_DATA 없음");
}
// ================================================================
// 5. 비표준 수신 → 표준 정상 응답 생성
// (외부 시스템에서 온 비표준 응답을 표준 성공 응답으로 변환)
// ================================================================
@Test
void 비표준수신_coordinateAfterRecvNonStdSyncResponse_procs_rslt_dvcd_S() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(msg);
assertEquals("S", msg.findItemValue("HEAD.procs_rslt_dvcd"),
"비표준 정상수신 후 procs_rslt_dvcd는 S여야 함");
}
@Test
void 비표준수신_coordinateAfterRecvNonStdSyncResponse_MSG_msg_dvcd_NM() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(msg);
assertEquals("NM", msg.findItemValue("MSG.msg_dvcd"),
"비표준 정상수신 후 msg_dvcd는 NM이어야 함");
}
@Test
void 비표준수신_정상응답_JSON_직렬화_NM_포함() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(msg);
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertTrue(root.has("MSG"), "정상응답 JSON에 MSG 블록 없음");
assertEquals("NM", root.path("MSG").path("msg_dvcd").asText(),
"정상응답 JSON의 msg_dvcd가 NM이 아님");
}
@Test
void 비표준수신_정상응답_JSON_직렬화_outp_msg_ctnt_정상처리() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(msg);
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertEquals("정상처리",
root.path("MSG").path("MAIN_MSG").path("outp_msg_ctnt").asText(),
"정상응답 JSON의 outp_msg_ctnt가 '정상처리'가 아님");
}
// ================================================================
// 6. 오류 응답 표준 생성 — coordinateSetStandardMessageError + JSON 직렬화
// ================================================================
@Test
void 오류응답_coordinateSetStandardMessageError_procs_rslt_dvcd_F() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(msg, mapper, "RECEAICMM999", "테스트 오류");
assertEquals("F", msg.findItemValue("HEAD.procs_rslt_dvcd"),
"오류 응답의 procs_rslt_dvcd는 F여야 함");
}
@Test
void 오류응답_JSON_직렬화_MSG_블록_포함() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(msg, mapper, "RECEAICMM999", "테스트 오류");
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertTrue(root.has("MSG"), "오류응답 JSON에 MSG 블록이 없음");
}
@Test
void 오류응답_JSON_직렬화_msg_dvcd_EM() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(msg, mapper, "RECEAICMM999", "테스트 오류");
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertEquals("EM", root.path("MSG").path("msg_dvcd").asText(),
"오류응답 JSON의 msg_dvcd가 EM이 아님");
}
@Test
void 오류응답_JSON_직렬화_outp_atrb_cd_1_팝업() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(msg, mapper, "RECEAICMM999", "테스트 오류");
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertEquals("1",
root.path("MSG").path("MAIN_MSG").path("outp_atrb_cd").asText(),
"오류응답 JSON의 outp_atrb_cd가 1(팝업)이 아님");
}
@Test
void 오류응답_JSON_직렬화_procs_rslt_dvcd_F_HEAD에_포함() throws Exception {
StandardMessage msg = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(msg, mapper, "RECEAICMM999", "테스트 오류");
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertEquals("F", root.path("HEAD").path("procs_rslt_dvcd").asText(),
"오류응답 JSON의 HEAD.procs_rslt_dvcd가 F가 아님");
}
// ================================================================
// 7. JSON 왕복 일관성 (parse → serialize)
// ================================================================
@Test
void JSON_왕복_파싱후_직렬화_guid_일치() throws Exception {
StandardMessage msg = parseReq();
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertEquals(TEST_GUID, root.path("HEAD").path("guid").asText(),
"JSON 왕복 후 guid 불일치");
}
@Test
void JSON_왕복_파싱후_직렬화_if_id_일치() throws Exception {
StandardMessage msg = parseReq();
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertEquals(TEST_IF_ID, root.path("HEAD").path("if_id").asText().trim(),
"JSON 왕복 후 if_id 불일치");
}
@Test
void JSON_왕복_응답JSON_파싱후_직렬화_MSG_보존() throws Exception {
StandardMessage msg = parseRsp();
String json = msg.getDataString(MessageType.JSON, "utf-8");
JsonNode root = jacksonMapper.readTree(json);
assertTrue(root.has("MSG"), "응답 JSON 왕복 후 MSG 블록 소실");
assertEquals("NM", root.path("MSG").path("msg_dvcd").asText(),
"응답 JSON 왕복 후 msg_dvcd 불일치");
}
// ================================================================
// helper
// ================================================================
private StandardMessage parseReq() throws Exception {
StandardMessage msg = manager.getStandardMessage();
jsonReader.parse(msg, REQ_JSON);
return msg;
}
private StandardMessage parseRsp() throws Exception {
StandardMessage msg = manager.getStandardMessage();
jsonReader.parse(msg, RSP_JSON_OK);
return msg;
}
}
@@ -0,0 +1,291 @@
package com.eactive.eai.inbound.processor;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationContext;
import com.eactive.eai.adapter.Keys;
import com.eactive.eai.common.monitor.EAIServiceMonitor;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.restrict.RestrictInfoVO;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
/**
* RequestProcessor 단위테스트 — StandardMessageManager/Coordinator 연동 검증
*
* 전략:
* - DB/Spring 없는 환경에서 Mockito + 리플렉션으로 ApplicationContextProvider 주입
* - RequestProcessor 클래스 로드 전(static 블록 실행 전)에 mock ApplicationContext를 주입
* - private 메서드(getInboundErrorResponseForStandard, getInboundErrorResponse)는
* 리플렉션으로 직접 호출하여 Coordinator 연동 결과를 검증
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class RequestProcessorStdMsgTest {
private StandardMessageManager stdMsgManager;
@BeforeAll
void setUpAll() throws Exception {
// ① PropManager mock — STDMessageErrorKeys 정적 초기화용 (def 반환)
PropManager mockPropManager = Mockito.mock(PropManager.class);
Mockito.when(mockPropManager.getProperty(anyString(), anyString(), anyString()))
.thenAnswer(new Answer<String>() {
public String answer(InvocationOnMock inv) {
return (String) inv.getArguments()[2];
}
});
// ② EAIServerManager mock — static 블록의 getLocalServerName/getGroupInstId 대응
EAIServerManager mockServer = Mockito.mock(EAIServerManager.class);
Mockito.when(mockServer.isPEAIServer()).thenReturn(false);
Mockito.when(mockServer.isSEAIServer()).thenReturn(false);
Mockito.when(mockServer.isMCI()).thenReturn(false);
Mockito.when(mockServer.getLocalServerName()).thenReturn("TEST_SERVER");
Mockito.when(mockServer.getGroupInstId()).thenReturn("TEST_INST");
// ③ EAIServiceMonitor mock — MessageUtil.getTobeCode() 사용
EAIServiceMonitor mockMonitor = Mockito.mock(EAIServiceMonitor.class);
Mockito.when(mockMonitor.isTimeOutCodes(anyString())).thenReturn(false);
Mockito.when(mockMonitor.isBizErrorCodes(anyString())).thenReturn(false);
// ④ ApplicationContext mock
ApplicationContext mockCtx = Mockito.mock(ApplicationContext.class);
Mockito.when(mockCtx.getBean(EAIServerManager.class)).thenReturn(mockServer);
Mockito.when(mockCtx.getBean(PropManager.class)).thenReturn(mockPropManager);
Mockito.when(mockCtx.getBean(EAIServiceMonitor.class)).thenReturn(mockMonitor);
// ⑤ ApplicationContextProvider.context(static 필드)에 mock 주입
Field ctxField = ApplicationContextProvider.class.getDeclaredField("context");
ctxField.setAccessible(true);
ctxField.set(null, mockCtx);
// ⑥ StandardMessageManager 초기화
System.setProperty(StandardMessageManager.STANDARD_MESSAGE_CONFIG,
"src/test/resources/standard-message-config-test.properties");
stdMsgManager = StandardMessageManager.getInstance();
stdMsgManager.init();
// ⑦ RequestProcessor 클래스 강제 로드 — mock 주입 완료 후 static 블록 안전 실행
Class.forName("com.eactive.eai.inbound.processor.RequestProcessor");
}
// ================================================================
// getInboundErrorResponseForStandard (private) — Coordinator 연동 검증
//
// 이 메서드 내부 흐름:
// mapper.nextGuidSeq(msg)
// mapper.setSendRecvDivision(msg, R)
// standardManager.getMessageCoordinator().coordinateSetStandardMessageError(...)
// standardMessage.getDataString(messageType, charset)
// ================================================================
@Test
void getInboundErrorResponseForStandard_procs_rslt_dvcd_F_설정() throws Exception {
StandardMessage msg = stdMsgManager.getStandardMessage();
InterfaceMapper mapper = stdMsgManager.getMapper();
callGetInboundErrorResponseForStandard(msg, mapper, "RECEAICMM999", "테스트 오류", "euc-kr", "FLAT");
assertEquals("F", msg.findItemValue("HEAD.procs_rslt_dvcd"),
"오류 응답 생성 시 procs_rslt_dvcd는 F여야 함");
}
@Test
void getInboundErrorResponseForStandard_dman_rspn_dvcd_R_설정() throws Exception {
StandardMessage msg = stdMsgManager.getStandardMessage();
InterfaceMapper mapper = stdMsgManager.getMapper();
callGetInboundErrorResponseForStandard(msg, mapper, "RECEAICMM999", "테스트 오류", "euc-kr", "FLAT");
assertEquals(STDMessageKeys.SEND_RECV_CD_RECV, msg.findItemValue("HEAD.dman_rspn_dvcd"),
"오류 응답 생성 시 dman_rspn_dvcd는 R이어야 함");
}
@Test
void getInboundErrorResponseForStandard_MSG_msg_dvcd_EM_설정() throws Exception {
StandardMessage msg = stdMsgManager.getStandardMessage();
InterfaceMapper mapper = stdMsgManager.getMapper();
callGetInboundErrorResponseForStandard(msg, mapper, "RECEAICMM999", "테스트 오류", "euc-kr", "FLAT");
assertEquals("EM", msg.findItemValue("MSG.msg_dvcd"),
"오류 응답 생성 시 msg_dvcd는 EM이어야 함");
}
@Test
void getInboundErrorResponseForStandard_outp_atrb_cd_1_설정() throws Exception {
StandardMessage msg = stdMsgManager.getStandardMessage();
InterfaceMapper mapper = stdMsgManager.getMapper();
callGetInboundErrorResponseForStandard(msg, mapper, "RECEAICMM999", "테스트 오류", "euc-kr", "FLAT");
assertEquals("1", msg.findItemValue("MSG.MAIN_MSG.outp_atrb_cd"),
"오류 시 outp_atrb_cd는 1(팝업)이어야 함");
}
@Test
void getInboundErrorResponseForStandard_outp_msg_cd_설정됨() throws Exception {
StandardMessage msg = stdMsgManager.getStandardMessage();
InterfaceMapper mapper = stdMsgManager.getMapper();
callGetInboundErrorResponseForStandard(msg, mapper, "RECEAICMM999", "테스트 오류", "euc-kr", "FLAT");
String errCode = msg.findItemValue("MSG.MAIN_MSG.outp_msg_cd");
assertNotNull(errCode, "outp_msg_cd가 null");
assertFalse(errCode.trim().isEmpty(), "outp_msg_cd가 공백");
}
@Test
void getInboundErrorResponseForStandard_예외없이_완료() {
assertDoesNotThrow(() -> {
StandardMessage msg = stdMsgManager.getStandardMessage();
InterfaceMapper mapper = stdMsgManager.getMapper();
callGetInboundErrorResponseForStandard(msg, mapper, "RECEAICMM999", "테스트 오류", "euc-kr", "FLAT");
}, "getInboundErrorResponseForStandard 실행 중 예외 발생");
}
// ================================================================
// getInboundErrorResponse (private) — IF_STANDARD 분기 검증
//
// IF_STANDARD 분기 흐름:
// coordinateBeforeInboundErrorResponse(standardMessage) ← StandardMessageCoordinatorDJB 호출
// getInboundErrorResponseForStandard(...) ← 위 검증된 메서드
// ================================================================
@Test
void getInboundErrorResponse_IF_STANDARD_procs_rslt_dvcd_F_설정() throws Exception {
StandardMessage msg = stdMsgManager.getStandardMessage();
InterfaceMapper mapper = stdMsgManager.getMapper();
Properties prop = new Properties();
prop.setProperty(Processor.STD_MESSAGE, Keys.IF_STANDARD);
prop.setProperty(Processor.MESSAGE_TYPE, "FLAT");
callGetInboundErrorResponse(prop, msg, mapper, "RECEAICMM999", "테스트 오류", "euc-kr");
assertEquals("F", msg.findItemValue("HEAD.procs_rslt_dvcd"),
"IF_STANDARD 오류응답 후 procs_rslt_dvcd는 F여야 함");
}
@Test
void getInboundErrorResponse_IF_STANDARD_msg_dvcd_EM_설정() throws Exception {
StandardMessage msg = stdMsgManager.getStandardMessage();
InterfaceMapper mapper = stdMsgManager.getMapper();
Properties prop = new Properties();
prop.setProperty(Processor.STD_MESSAGE, Keys.IF_STANDARD);
prop.setProperty(Processor.MESSAGE_TYPE, "FLAT");
callGetInboundErrorResponse(prop, msg, mapper, "RECEAICMM999", "테스트 오류", "euc-kr");
assertEquals("EM", msg.findItemValue("MSG.msg_dvcd"),
"IF_STANDARD 오류응답 후 msg_dvcd는 EM이어야 함");
}
@Test
void getInboundErrorResponse_standardMessage_null_비표준_예외없음() {
Properties prop = new Properties();
prop.setProperty(Processor.STD_MESSAGE, "X"); // 비표준 → ExceptionHandler.handle(errMsg)
prop.setProperty(Processor.MESSAGE_TYPE, "FLAT");
assertDoesNotThrow(() ->
callGetInboundErrorResponse(prop, null, null, "RECEAICMM999", "테스트 오류", "euc-kr"),
"standardMessage null 비표준 케이스에서 예외 발생"
);
}
// ================================================================
// checkRestrictTime (public)
// ================================================================
@Test
void checkRestrictTime_start_end_미설정_항상_true() throws Exception {
RequestProcessor rp = new RequestProcessor();
RestrictInfoVO rVo = new RestrictInfoVO();
// params 길이 < 6 → start/end 모두 null → true 반환
rVo.setEAICtrlDsticCtnt("a|b|c|d|e");
assertTrue(rp.checkRestrictTime(rVo), "start/end 미설정 시 true 기대");
}
@Test
void checkRestrictTime_start_0000_end_0000_항상_true() throws Exception {
RequestProcessor rp = new RequestProcessor();
RestrictInfoVO rVo = new RestrictInfoVO();
// end="0000" 이면 코드상 종료시간 체크 블록 건너뜀 → start 0000 이후면 true
rVo.setEAICtrlDsticCtnt("a|b|c|d|e|0000|0000");
assertTrue(rp.checkRestrictTime(rVo), "start=0000/end=0000 설정 시 true 기대");
}
@Test
void checkRestrictTime_end_0001_현재시간_이후_false() throws Exception {
RequestProcessor rp = new RequestProcessor();
RestrictInfoVO rVo = new RestrictInfoVO();
// 종료시간이 00:01이면 00:01 이후(= 거의 항상)는 false 반환
// 단, 자정(00:00) 실행 시에는 통과 — 허용 오차
rVo.setEAICtrlDsticCtnt("a|b|c|d|e|0000|0001");
java.util.Calendar cal = java.util.Calendar.getInstance();
int hour = cal.get(java.util.Calendar.HOUR_OF_DAY);
int minute = cal.get(java.util.Calendar.MINUTE);
boolean result = rp.checkRestrictTime(rVo);
// 00:01 이후(99% 이상의 시간)에는 false여야 함
if (hour > 0 || minute >= 1) {
assertFalse(result, "종료시간(00:01) 이후에는 false여야 함");
}
// 정확히 00:00에 실행되면 검증 생략 (허용)
}
// ================================================================
// helper
// ================================================================
private Object callGetInboundErrorResponseForStandard(
StandardMessage msg, InterfaceMapper mapper,
String errCode, String errMsg, String charset, String messageType) throws Exception {
Method method = RequestProcessor.class.getDeclaredMethod(
"getInboundErrorResponseForStandard",
StandardMessage.class, InterfaceMapper.class,
String.class, String.class, String.class, String.class);
method.setAccessible(true);
try {
return method.invoke(new RequestProcessor(), msg, mapper, errCode, errMsg, charset, messageType);
} catch (InvocationTargetException e) {
throw (Exception) e.getCause();
}
}
private Object callGetInboundErrorResponse(
Properties prop, StandardMessage msg, InterfaceMapper mapper,
String errCode, String errMsg, String charset) throws Exception {
Method method = RequestProcessor.class.getDeclaredMethod(
"getInboundErrorResponse",
Properties.class, StandardMessage.class, InterfaceMapper.class,
String.class, String.class, String.class);
method.setAccessible(true);
try {
return method.invoke(new RequestProcessor(), prop, msg, mapper, errCode, errMsg, charset);
} catch (InvocationTargetException e) {
throw (Exception) e.getCause();
}
}
}
@@ -0,0 +1,188 @@
package com.eactive.eai.message.manager;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import com.eactive.eai.custom.message.GUIDGeneratorDJB;
import com.eactive.eai.custom.message.InterfaceMapperDJB;
import com.eactive.eai.custom.message.StandardMessageCoordinatorDJB;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.parser.StandardReader;
/**
* StandardMessageManager.init() 단위테스트
*
* Singleton 특성상 getInstance()로 접근, init()을 직접 호출하여 검증.
* System.property를 미설정 → 클래스패스의 standard-message-config.properties 로드.
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class StandardMessageManagerInitTest {
private StandardMessageManager manager;
@BeforeAll
void setUp() throws Exception {
// 테스트용 config: layout.file.path에 src/main/resources 상대경로 사용
// (StandardMessageUtil.generateMessageFromCsvFile은 파일시스템 상대경로로 읽음)
System.setProperty(StandardMessageManager.STANDARD_MESSAGE_CONFIG,
"src/test/resources/standard-message-config-test.properties");
manager = StandardMessageManager.getInstance();
manager.init();
}
// ----------------------------------------------------------------
// 1. 표준전문 레이아웃 (StandardMessage)
// ----------------------------------------------------------------
@Test
void standardMessage_정상_로드() {
StandardMessage msg = manager.getStandardMessage();
assertNotNull(msg, "StandardMessage가 null — CSV 로드 실패");
}
@Test
void standardMessage_HEAD_블록_존재() {
StandardMessage msg = manager.getStandardMessage();
assertNotNull(msg.findItem("HEAD"), "HEAD 블록 없음");
}
@Test
void standardMessage_HEAD_guid_40자() {
StandardMessage msg = manager.getStandardMessage();
assertEquals(GUIDGeneratorDJB.GUID_LENGTH, msg.findItem("HEAD.guid").getLength(),
"HEAD.guid 길이는 40자여야 함");
}
@Test
void standardMessage_HEAD_if_id_30자() {
StandardMessage msg = manager.getStandardMessage();
assertEquals(30, msg.findItem("HEAD.if_id").getLength(),
"HEAD.if_id 길이는 30자여야 함");
}
@Test
void standardMessage_DATA_BIZ_DATA_존재() {
StandardMessage msg = manager.getStandardMessage();
assertNotNull(msg.findItem("DATA.BIZ_DATA"), "DATA.BIZ_DATA 없음");
}
// ----------------------------------------------------------------
// 2. InterfaceMapper
// ----------------------------------------------------------------
@Test
void mapper_InterfaceMapperDJB_인스턴스() {
assertNotNull(manager.getMapper(), "mapper가 null");
assertInstanceOf(InterfaceMapperDJB.class, manager.getMapper(),
"mapper가 InterfaceMapperDJB가 아님: " + manager.getMapper().getClass().getName());
}
@Test
void mapper_GUID_경로_매핑_정상() {
StandardMessage msg = manager.getStandardMessage();
InterfaceMapperDJB mapper = (InterfaceMapperDJB) manager.getMapper();
String guid = GUIDGeneratorDJB.getGUID("EAI");
mapper.setGuid(msg, guid);
assertEquals(guid, mapper.getGuid(msg), "GUID 설정/조회 불일치");
}
@Test
void mapper_ResponseType_S_F_변환() {
StandardMessage msg = manager.getStandardMessage();
InterfaceMapperDJB mapper = (InterfaceMapperDJB) manager.getMapper();
// NR → S
mapper.setResponseType(msg, com.ext.eai.common.stdmessage.STDMessageKeys.RESPONSE_TYPE_CODE_N);
assertEquals("S", msg.findItemValue("HEAD.procs_rslt_dvcd"));
// ER → F
mapper.setResponseType(msg, com.ext.eai.common.stdmessage.STDMessageKeys.RESPONSE_TYPE_CODE_E);
assertEquals("F", msg.findItemValue("HEAD.procs_rslt_dvcd"));
}
// ----------------------------------------------------------------
// 3. StandardMessageCoordinator
// ----------------------------------------------------------------
@Test
void coordinator_StandardMessageCoordinatorDJB_인스턴스() {
assertNotNull(manager.getMessageCoordinator(), "messageCoordinator가 null");
assertInstanceOf(StandardMessageCoordinatorDJB.class, manager.getMessageCoordinator(),
"coordinator가 StandardMessageCoordinatorDJB가 아님: "
+ manager.getMessageCoordinator().getClass().getName());
}
// ----------------------------------------------------------------
// 4. Reader 등록
// ----------------------------------------------------------------
@Test
void reader_JSON_등록() {
StandardReader reader = manager.getReader("JSON");
assertNotNull(reader, "JSON reader 미등록");
assertEquals("com.eactive.eai.message.parser.JsonReader",
reader.getClass().getName());
}
@Test
void reader_XML_등록() {
StandardReader reader = manager.getReader("XML");
assertNotNull(reader, "XML reader 미등록");
assertEquals("com.eactive.eai.message.parser.XmlReader",
reader.getClass().getName());
}
@Test
void reader_ASC_등록() {
StandardReader reader = manager.getReader("ASC");
assertNotNull(reader, "ASC(Flat) reader 미등록");
assertEquals("com.eactive.eai.message.parser.FlatReader",
reader.getClass().getName());
}
@Test
void reader_FLAT_등록() {
StandardReader reader = manager.getReader("FLAT");
assertNotNull(reader, "FLAT reader 미등록");
assertEquals("com.eactive.eai.message.parser.FlatReader",
reader.getClass().getName());
}
// ----------------------------------------------------------------
// 5. getStandardMessage() 독립 복사본 반환
// ----------------------------------------------------------------
@Test
void getStandardMessage_호출마다_독립_복사본() {
StandardMessage msg1 = manager.getStandardMessage();
StandardMessage msg2 = manager.getStandardMessage();
assertNotSame(msg1, msg2, "getStandardMessage()는 매번 새 인스턴스를 반환해야 함");
// 한 쪽 수정이 다른 쪽에 영향 없어야 함
msg1.setData("HEAD.guid", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
assertNotEquals(
msg1.findItemValue("HEAD.guid"),
msg2.findItemValue("HEAD.guid"),
"복사본이 원본에 영향을 줌 — clone 미작동");
}
// ----------------------------------------------------------------
// 6. reload() — init() 재실행 후 상태 일관성
// ----------------------------------------------------------------
@Test
void reload_후_mapper_정상() throws Exception {
manager.reload();
assertNotNull(manager.getMapper(), "reload 후 mapper null");
assertInstanceOf(InterfaceMapperDJB.class, manager.getMapper());
}
@Test
void reload_후_standardMessage_정상() throws Exception {
manager.reload();
StandardMessage msg = manager.getStandardMessage();
assertNotNull(msg);
assertNotNull(msg.findItem("HEAD"));
}
}