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() { 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; } }