Merge branch 'feature/standard-message-djb'

This commit is contained in:
curry772
2026-04-23 14:14:58 +09:00
5 changed files with 551 additions and 5 deletions
@@ -205,6 +205,9 @@ public class StandardMessageCoordinatorDJB extends DefaultStandardMessageCoordin
InterfaceMapper mapper = manager.getMapper();
mapper.setResponseType(responseMessage, STDMessageKeys.RESPONSE_TYPE_CODE_N);
// 요청응답구분 = 응답(R) — dman_rspn_dvcd 기본값이 S(요청)이므로 반드시 설정
mapper.setSendRecvDivision(responseMessage, STDMessageKeys.SEND_RECV_CD_RECV);
// MSG 영역 활성화
StandardItem msgItem = responseMessage.findItem("MSG");
if (msgItem != null) {
@@ -16,10 +16,9 @@ SEND_TIME=HEAD.frst_mesg_dman_time
RECV_TIME=HEAD.mesg_rspn_time
SYSTEM_TYPE=HEAD.trnm_sys_dvcd
TIMEOUT=HEAD.gnrz_tmot_tktm
INST_CODE=HEAD.eai_node_dvcd
INST_CODE=HEAD.xtis_cd
USER_ID=HEAD.tlrno
REQ_SYS_CODE=HEAD.chnl_tycd
# MSG 영역 (응답 시 활성화)
REQ_SYS_CODE=
ERROR_CODE=MSG.MAIN_MSG.outp_msg_cd
ERROR_MSG=MSG.MAIN_MSG.outp_msg_ctnt
RESPONSE_TYPE=HEAD.procs_rslt_dvcd
@@ -0,0 +1,544 @@
package com.eactive.eai.custom.message;
import static org.junit.jupiter.api.Assertions.*;
import java.lang.reflect.Field;
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.StandardItem;
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.parser.StandardReader;
import com.eactive.eai.message.service.InterfaceMapper;
import static org.mockito.ArgumentMatchers.anyString;
/**
* DJBank 표준전문 FLAT 직렬화/파싱 흐름 통합 테스트
*
* 검증 시나리오:
* 1. FlatReader 등록 확인
* 2. 비ERP 요청 FLAT 왕복 — HEAD 보존, EZDATA/MSG 바이트 미포함
* 3. ERP 요청 FLAT 왕복 — EZDATA 포함 보존
* 4. 오류 응답 FLAT 왕복 — MSG EM 포함 보존
* 5. 정상 응답 FLAT 왕복 — MSG NM 포함 보존
* 6. 거래로그 시나리오 — FLAT 바이트 길이 검증 (조건부 블록 포함 여부)
*
* 핵심 버그 (EZDATA FLAT 오류):
* JSON 파싱 시 JSON에 없는 조건부 블록(EZDATA, MSG)은 isHidden=false 로 남는다.
* toByteArray() GROUP 케이스에서 size=0 이면서 refPath/refValue 가 있는 경우
* isHidden 체크만으로는 불충분 → FLAT에 비활성 블록 바이트가 잘못 포함된다.
*
* 수정: toByteArray() / getBytesDataLength() GROUP 케이스를
* toJson() 과 동일하게 size==0 이면 무조건 skip 으로 변경
* (StandardItem.java 두 곳)
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class StandardMessageFlatFlowTest {
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_FLAT01";
private static final String TEST_TX_ID = "TXTEST000003";
private static final String FLAT_CHARSET = "euc-kr";
/** 비ERP 요청 JSON — dman_rspn_dvcd=S, corp_tlwn_virt_brcd 미설정 */
private static final String NON_ERP_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\":\"00000037\","
+ "\"BIZ_DATA\":{\"acct_no\":\"123456789\",\"amt\":\"100000\"}"
+ "}"
+ "}";
/** ERP 요청 JSON — corp_tlwn_virt_brcd=ERP, EZDATA 포함 */
private static final String ERP_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\","
+ "\"corp_tlwn_virt_brcd\":\"ERP\","
+ "\"trnm_sys_dvcd\":\"OPA\","
+ "\"frst_trnm_sys_dvcd\":\"OPA\","
+ "\"sys_env_dvcd\":\"D\","
+ "\"frst_mesg_dman_dt\":\"20260420\","
+ "\"frst_mesg_dman_time\":\"120000000\""
+ "},"
+ "\"EZDATA\":{"
+ "\"login_mhod_dvcd\":\"1\","
+ "\"elfn_bnkn_dvcd\":\"01\","
+ "\"usr_no\":\"USR0000000000001\","
+ "\"rgsr_id\":\"REG_ID_000000001\","
+ "\"secu_media_dvcd\":\"00\","
+ "\"secu_media_sta_dvcd\":\"00\","
+ "\"brll_srcd_yn\":\"N\","
+ "\"next_data_exis_yn\":\"N\","
+ "\"page_no\":\"00001\","
+ "\"page_size\":\"00020\","
+ "\"dup_tx_yn\":\"N\""
+ "},"
+ "\"DATA\":{"
+ "\"data_dvcd\":\"IO\","
+ "\"data_scop_len\":\"00000037\","
+ "\"BIZ_DATA\":{\"acct_no\":\"987654321\",\"amt\":\"500000\"}"
+ "}"
+ "}";
private StandardMessageManager manager;
private InterfaceMapper mapper;
private StandardReader flatReader;
private JsonReader jsonReader;
private StandardMessageCoordinatorDJB coordinator;
@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();
flatReader = manager.getReader("FLAT");
jsonReader = (JsonReader) manager.getReader("JSON");
coordinator = new StandardMessageCoordinatorDJB();
}
// ================================================================
// 1. FlatReader 등록 확인
// ================================================================
@Test
void FlatReader_등록_확인() {
assertNotNull(flatReader, "FlatReader가 등록되지 않음 (reader.FLAT 설정 확인)");
}
// ================================================================
// 2. 비ERP 요청 FLAT 왕복 — HEAD 보존, EZDATA/MSG 비포함
//
// [버그] 수정 전: EZDATA(1500B) + MSG(10B) 가 FLAT에 잘못 포함
// → FlatReader 파싱 시 overflow 예외 발생
// [수정] StandardItem.toByteArray() GROUP 케이스: size==0 이면 무조건 skip
// ================================================================
@Test
void 비ERP요청_FLAT_파싱_예외없음() throws Exception {
StandardMessage src = parseJson(NON_ERP_REQ_JSON);
String flatStr = src.toFixedString(false, FLAT_CHARSET);
StandardMessage dst = manager.getStandardMessage();
assertDoesNotThrow(() -> flatReader.parse(dst, flatStr),
"비ERP FLAT 파싱 중 예외 발생 — EZDATA 바이트 오버플로우 버그 확인 필요\n"
+ "원인: StandardItem.toByteArray() GROUP size==0 skip 조건 미적용");
}
@Test
void 비ERP요청_FLAT_왕복_HEAD_guid_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(NON_ERP_REQ_JSON));
assertEquals(TEST_GUID, dst.findItemValue("HEAD.guid").trim(),
"FLAT 왕복 후 HEAD.guid 불일치");
}
@Test
void 비ERP요청_FLAT_왕복_HEAD_if_id_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(NON_ERP_REQ_JSON));
assertEquals(TEST_IF_ID, dst.findItemValue("HEAD.if_id").trim(),
"FLAT 왕복 후 HEAD.if_id 불일치");
}
@Test
void 비ERP요청_FLAT_왕복_HEAD_dman_rspn_dvcd_S() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(NON_ERP_REQ_JSON));
assertEquals("S", dst.findItemValue("HEAD.dman_rspn_dvcd").trim(),
"FLAT 왕복 후 HEAD.dman_rspn_dvcd 불일치");
}
@Test
void 비ERP요청_FLAT_왕복_HEAD_stnd_mesg_ver_R10() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(NON_ERP_REQ_JSON));
assertEquals("R10", dst.findItemValue("HEAD.stnd_mesg_ver").trim(),
"FLAT 왕복 후 HEAD.stnd_mesg_ver 불일치");
}
@Test
void 비ERP요청_FLAT_왕복_DATA_data_dvcd_IO() throws Exception {
// [버그] 수정 전: MSG 바이트가 잘못 포함 → DATA.data_dvcd 자리에 MSG 바이트 읽힘 ("NM")
StandardMessage dst = flatRoundTrip(parseJson(NON_ERP_REQ_JSON));
assertEquals("IO", dst.findItemValue("DATA.data_dvcd").trim(),
"FLAT 왕복 후 DATA.data_dvcd 불일치 — MSG 바이트 오염 가능성");
}
@Test
void 비ERP요청_FLAT_왕복_EZDATA_비활성() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(NON_ERP_REQ_JSON));
StandardItem ezdataItem = dst.findItem("EZDATA");
assertTrue(ezdataItem == null || ezdataItem.isHidden() || ezdataItem.getSize() == 0,
"비ERP FLAT 왕복 후 EZDATA 블록이 활성 상태이면 안 됨");
}
// ================================================================
// 3. ERP 요청 FLAT 왕복 — EZDATA 포함
// ================================================================
@Test
void ERP요청_FLAT_파싱_예외없음() throws Exception {
StandardMessage src = parseJson(ERP_REQ_JSON);
String flatStr = src.toFixedString(false, FLAT_CHARSET);
StandardMessage dst = manager.getStandardMessage();
assertDoesNotThrow(() -> flatReader.parse(dst, flatStr),
"ERP FLAT 파싱 중 예외 발생");
}
@Test
void ERP요청_FLAT_왕복_HEAD_guid_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals(TEST_GUID, dst.findItemValue("HEAD.guid").trim(),
"ERP FLAT 왕복 후 HEAD.guid 불일치");
}
@Test
void ERP요청_FLAT_왕복_HEAD_corp_tlwn_virt_brcd_ERP() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals("ERP", dst.findItemValue("HEAD.corp_tlwn_virt_brcd").trim(),
"ERP FLAT 왕복 후 HEAD.corp_tlwn_virt_brcd 불일치");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_활성() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
StandardItem ezdataItem = dst.findItem("EZDATA");
assertNotNull(ezdataItem, "ERP FLAT 왕복 후 EZDATA 블록 없음");
assertFalse(ezdataItem.isHidden(), "ERP FLAT 왕복 후 EZDATA 블록이 hidden 상태");
assertTrue(ezdataItem.getSize() > 0, "ERP FLAT 왕복 후 EZDATA 블록 size가 0");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_login_mhod_dvcd_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals("1", dst.findItemValue("EZDATA.login_mhod_dvcd").trim(),
"ERP FLAT 왕복 후 EZDATA.login_mhod_dvcd 불일치");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_elfn_bnkn_dvcd_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals("01", dst.findItemValue("EZDATA.elfn_bnkn_dvcd").trim(),
"ERP FLAT 왕복 후 EZDATA.elfn_bnkn_dvcd 불일치");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_usr_no_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals("USR0000000000001", dst.findItemValue("EZDATA.usr_no").trim(),
"ERP FLAT 왕복 후 EZDATA.usr_no 불일치");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_rgsr_id_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals("REG_ID_000000001", dst.findItemValue("EZDATA.rgsr_id").trim(),
"ERP FLAT 왕복 후 EZDATA.rgsr_id 불일치");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_secu_media_dvcd_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals("00", dst.findItemValue("EZDATA.secu_media_dvcd").trim(),
"ERP FLAT 왕복 후 EZDATA.secu_media_dvcd 불일치");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_dup_tx_yn_보존() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals("N", dst.findItemValue("EZDATA.dup_tx_yn").trim(),
"ERP FLAT 왕복 후 EZDATA.dup_tx_yn 불일치");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_NUMBER_page_no_보존() throws Exception {
// page_no 는 NUMBER 타입: "00001" → toTypeValue() 선행 0 제거 → "1"
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
String pageNo = dst.findItemValue("EZDATA.page_no").trim();
assertFalse(pageNo.isEmpty(), "ERP FLAT 왕복 후 EZDATA.page_no가 비어 있음");
assertEquals(1, Integer.parseInt(pageNo),
"ERP FLAT 왕복 후 EZDATA.page_no 값 불일치");
}
@Test
void ERP요청_FLAT_왕복_EZDATA_NUMBER_page_size_보존() throws Exception {
// page_size 는 NUMBER 타입: "00020" → "20"
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
String pageSize = dst.findItemValue("EZDATA.page_size").trim();
assertFalse(pageSize.isEmpty(), "ERP FLAT 왕복 후 EZDATA.page_size가 비어 있음");
assertEquals(20, Integer.parseInt(pageSize),
"ERP FLAT 왕복 후 EZDATA.page_size 값 불일치");
}
@Test
void ERP요청_FLAT_왕복_DATA_data_dvcd_IO() throws Exception {
// [버그] 수정 전: MSG 바이트가 잘못 포함 → DATA.data_dvcd 자리에 MSG 바이트 읽힘
StandardMessage dst = flatRoundTrip(parseJson(ERP_REQ_JSON));
assertEquals("IO", dst.findItemValue("DATA.data_dvcd").trim(),
"ERP FLAT 왕복 후 DATA.data_dvcd 불일치 — MSG 바이트 오염 가능성");
}
// ================================================================
// 4. 오류 응답 FLAT 왕복 — MSG EM 포함
// coordinateSetStandardMessageError() → MSG.size=1, MAIN_MSG.size=1
// ================================================================
@Test
void 오류응답_FLAT_파싱_예외없음() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(src, mapper, "RECEAICMM999", "테스트 오류");
String flatStr = src.toFixedString(false, FLAT_CHARSET);
StandardMessage dst = manager.getStandardMessage();
assertDoesNotThrow(() -> flatReader.parse(dst, flatStr),
"오류응답 FLAT 파싱 중 예외 발생");
}
@Test
void 오류응답_FLAT_왕복_HEAD_procs_rslt_dvcd_F() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(src, mapper, "RECEAICMM999", "테스트 오류");
assertEquals("F", flatRoundTrip(src).findItemValue("HEAD.procs_rslt_dvcd").trim(),
"오류응답 FLAT 왕복 후 HEAD.procs_rslt_dvcd가 F가 아님");
}
@Test
void 오류응답_FLAT_왕복_MSG_msg_dvcd_EM() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(src, mapper, "RECEAICMM999", "테스트 오류");
assertEquals("EM", flatRoundTrip(src).findItemValue("MSG.msg_dvcd").trim(),
"오류응답 FLAT 왕복 후 MSG.msg_dvcd가 EM이 아님");
}
@Test
void 오류응답_FLAT_왕복_MSG_outp_atrb_cd_1_팝업() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(src, mapper, "RECEAICMM999", "테스트 오류");
assertEquals("1", flatRoundTrip(src).findItemValue("MSG.MAIN_MSG.outp_atrb_cd").trim(),
"오류응답 FLAT 왕복 후 MSG.MAIN_MSG.outp_atrb_cd가 1(팝업)이 아님");
}
@Test
void 오류응답_FLAT_왕복_MSG_MAIN_MSG_활성() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateSetStandardMessageError(src, mapper, "RECEAICMM999", "테스트 오류");
StandardItem mainMsgItem = flatRoundTrip(src).findItem("MSG.MAIN_MSG");
assertNotNull(mainMsgItem, "오류응답 FLAT 왕복 후 MSG.MAIN_MSG 블록 없음");
assertTrue(mainMsgItem.getSize() > 0,
"오류응답 FLAT 왕복 후 MSG.MAIN_MSG size가 0");
}
// ================================================================
// 5. 정상 응답 FLAT 왕복 — MSG NM 포함
// coordinateAfterRecvNonStdSyncResponse() → MSG.size=1, MAIN_MSG.size=1
// ================================================================
@Test
void 정상응답_FLAT_파싱_예외없음() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(src);
String flatStr = src.toFixedString(false, FLAT_CHARSET);
StandardMessage dst = manager.getStandardMessage();
assertDoesNotThrow(() -> flatReader.parse(dst, flatStr),
"정상응답 FLAT 파싱 중 예외 발생");
}
@Test
void 정상응답_FLAT_왕복_MSG_msg_dvcd_NM() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(src);
assertEquals("NM", flatRoundTrip(src).findItemValue("MSG.msg_dvcd").trim(),
"정상응답 FLAT 왕복 후 MSG.msg_dvcd가 NM이 아님");
}
@Test
void 정상응답_FLAT_왕복_MSG_활성() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(src);
StandardMessage dst = flatRoundTrip(src);
StandardItem msgItem = dst.findItem("MSG");
assertNotNull(msgItem, "정상응답 FLAT 왕복 후 MSG 블록 없음");
assertFalse(msgItem.isHidden(), "정상응답 FLAT 왕복 후 MSG 블록이 hidden 상태");
assertTrue(msgItem.getSize() > 0, "정상응답 FLAT 왕복 후 MSG 블록 size가 0");
}
@Test
void 정상응답_FLAT_왕복_MSG_MAIN_MSG_활성() throws Exception {
StandardMessage src = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(src);
StandardItem mainMsgItem = flatRoundTrip(src).findItem("MSG.MAIN_MSG");
assertNotNull(mainMsgItem, "정상응답 FLAT 왕복 후 MSG.MAIN_MSG 블록 없음");
assertTrue(mainMsgItem.getSize() > 0,
"정상응답 FLAT 왕복 후 MSG.MAIN_MSG size가 0");
}
// ================================================================
// 6. 거래로그 시나리오 — FLAT 바이트 길이로 조건부 블록 포함 여부 검증
//
// [버그] 수정 전: 비ERP 에도 EZDATA(1500B) 포함 → ERP 와 길이 동일
// [수정] 비ERP FLAT < ERP FLAT (EZDATA 1500바이트 차이)
// ================================================================
@Test
void 거래로그_비ERP_FLAT_길이가_ERP_FLAT_보다_짧음() throws Exception {
byte[] nonErpBytes = parseJson(NON_ERP_REQ_JSON)
.toFixedString(false, FLAT_CHARSET).getBytes(FLAT_CHARSET);
byte[] erpBytes = parseJson(ERP_REQ_JSON)
.toFixedString(false, FLAT_CHARSET).getBytes(FLAT_CHARSET);
// EZDATA = 1500바이트 — ERP FLAT 이 비ERP FLAT 보다 길어야 함
// 버그 발생 시: 둘 다 EZDATA 포함 → 길이 동일 → 검증 실패
assertTrue(erpBytes.length > nonErpBytes.length,
String.format("ERP FLAT 길이(%d) > 비ERP FLAT 길이(%d) 이어야 함 (EZDATA 1500B 차이)",
erpBytes.length, nonErpBytes.length));
}
@Test
void 거래로그_요청_FLAT_길이가_응답_FLAT_보다_짧음() throws Exception {
// 요청(dman_rspn_dvcd=S): MSG 비활성 / 응답: MSG 활성 → 응답이 더 긺
StandardMessage rspMsg = manager.getStandardMessage();
coordinator.coordinateAfterRecvNonStdSyncResponse(rspMsg);
byte[] reqBytes = parseJson(NON_ERP_REQ_JSON)
.toFixedString(false, FLAT_CHARSET).getBytes(FLAT_CHARSET);
byte[] rspBytes = rspMsg.toFixedString(false, FLAT_CHARSET).getBytes(FLAT_CHARSET);
// 버그 발생 시: 요청도 MSG 바이트 포함 → 길이 역전 가능
assertTrue(rspBytes.length > reqBytes.length,
String.format("응답 FLAT 길이(%d) > 요청 FLAT 길이(%d) 이어야 함 (MSG 블록 포함 여부)",
rspBytes.length, reqBytes.length));
}
@Test
void 비ERP요청_FLAT_왕복_HEAD_chnl_tycd_EAI값확인() throws Exception {
StandardMessage dst = flatRoundTrip(parseJson(NON_ERP_REQ_JSON));
assertEquals("EAI", dst.findItemValue("HEAD.chnl_tycd").trim(),
"FLAT 왕복 후 HEAD.chnl_tycd EAI 확인");
}
// ================================================================
// helpers
// ================================================================
private StandardMessage parseJson(String json) throws Exception {
StandardMessage msg = manager.getStandardMessage();
jsonReader.parse(msg, json);
return msg;
}
/**
* FLAT 왕복: src → toFixedString(false, euc-kr) → FlatReader.parse() → dst
* STDMessageDAO.addRestoreSTDMessage / getRestoreSTDMessage 와 동일한 흐름
*/
private StandardMessage flatRoundTrip(StandardMessage src) throws Exception {
String flatStr = src.toFixedString(false, FLAT_CHARSET);
StandardMessage dst = manager.getStandardMessage();
flatReader.parse(dst, flatStr);
return dst;
}
}