File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
package kr.itn.itnhub.process;
import kr.itn.itnhub.AbstractDbTest;
import kr.itn.itnhub.org.Organization;
import kr.itn.itnhub.org.OrganizationMapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import java.io.ByteArrayInputStream;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
* 권리처리 엑셀의 업로드↔다운로드 왕복.
*
* <p>업로드는 컬럼 번호({@code ProcessParser.COL_*})로, 다운로드는 헤더 이름
* ({@code ProcessService.COLUMN_HEADERS})으로 각각 따로 정의돼 있다. 두 정의가 어긋나면
* "내려받아 고쳐서 다시 올리는" 흐름에서 값이 조용히 사라진다. 그 어긋남을 여기서 잡는다.</p>
*/
class ProcessExcelRoundTripTest extends AbstractDbTest {
@Autowired
ProcessService service;
@Autowired
ProcessParser parser;
@Autowired
OrganizationMapper orgMapper;
@Autowired
JdbcTemplate jdbc;
private Long orgId;
@BeforeEach
void setUp() {
jdbc.update("delete from process_item");
jdbc.update("delete from organization where org_no = '920'");
Organization org = new Organization();
org.setOrgNo("920");
org.setOrgName("왕복테스트기관");
org.setChannelSlug("920");
orgMapper.upsertBySeed(org);
orgId = orgMapper.findByOrgNoAndOrgName("920", "왕복테스트기관").getId();
}
@AfterEach
void cleanUp() {
jdbc.update("delete from process_item");
jdbc.update("delete from organization where org_no = '920'");
}
/** 헤더 이름과 파서가 읽는 컬럼이 같은 자리를 가리키는지. 한쪽만 고치면 여기서 깨진다. */
@Test
void 헤더_이름과_파서_컬럼이_같은_자리를_가리킨다() {
assertHeader(ProcessParser.COL_SEQ, "순번");
assertHeader(ProcessParser.COL_SITE_NAME, "사이트명");
assertHeader(ProcessParser.COL_CATEGORY, "범주");
assertHeader(ProcessParser.COL_BOARD_NAME, "게시판명");
assertHeader(ProcessParser.COL_POST_TITLE, "게시물제목");
assertHeader(ProcessParser.COL_URL, "URL주소");
assertHeader(ProcessParser.COL_DESCRIPTION, "설명");
assertHeader(ProcessParser.COL_HAS_ATTACHMENT, "첨부파일여부");
assertHeader(ProcessParser.COL_PRIOR_KOGL_TYPE, "기존 공공누리유형(+AI)");
assertHeader(ProcessParser.COL_CONTRACT_DOCS, "계약서 유무");
assertHeader(ProcessParser.COL_PRODUCED_DATE, "제작일");
assertHeader(ProcessParser.COL_PUBLISHED_DATE, "공표일");
assertHeader(ProcessParser.COL_REVIEW_MAJOR, "권리확인(대분류)");
assertHeader(ProcessParser.COL_REVIEW_MINOR, "권리확인(세부)");
assertHeader(ProcessParser.COL_REVIEW_RESULT, "처리 구분");
assertHeader(ProcessParser.COL_REVIEW_KOGL_TYPE, "공공누리 유형");
assertHeader(ProcessParser.COL_REVIEW_AI_TYPE, "AI유형");
assertHeader(ProcessParser.COL_REVIEW_OPINION, "의견");
assertHeader(ProcessParser.COL_REVIEW_NOTE, "비고");
assertHeader(ProcessParser.COL_JUDGED_KOGL_TYPE, "공공누리유형(판정)");
assertHeader(ProcessParser.COL_JUDGED_AI_TYPE, "AI유형(판정)");
assertHeader(ProcessParser.COL_FINAL_OPINION, "최종의견");
assertHeader(ProcessParser.COL_JUDGMENT_BASIS, "판단근거");
assertHeader(ProcessParser.COL_PROCESS_STATUS, "처리상태");
}
private void assertHeader(int column, String expected) {
assertThat(ProcessService.COLUMN_HEADERS[column])
.as("%d번 열의 헤더", column)
.isEqualTo(expected);
}
/**
* 기존 증빙자료는 예외다. 기관이 보내오는 실제 파일은 헤더가 T열인데 데이터가 U열에 있어
* 파서가 U를 먼저 읽고, 비어 있으면 헤더 자리인 T를 읽는다. 이 어긋남 자체를 명시적으로
* 남겨 두어, 나중에 누가 "헤더랑 다르네" 하고 한쪽만 고치다 깨뜨리지 않게 한다.
*/
@Test
void 기존_증빙자료만_헤더와_데이터_열이_다르다() {
assertThat(ProcessService.COLUMN_HEADERS[19]).isEqualTo("기존 증빙자료");
assertThat(ProcessParser.COL_PRIOR_EVIDENCE_HEADER).isEqualTo(19);
assertThat(ProcessParser.COL_PRIOR_EVIDENCE).isEqualTo(20);
}
/** 기관 원본처럼 U열에 값이 있는 파일도 그대로 읽어야 한다(다운로드 파일만 고치면 안 된다). */
@Test
void 원본처럼_U열에_값이_있어도_읽는다() throws Exception {
byte[] xlsx = ProcessParserFixtures.withPriorEvidenceAt(ProcessParser.COL_PRIOR_EVIDENCE, "원본증빙");
List<ProcessRow> rows = parser.parse(new ByteArrayInputStream(xlsx));
assertThat(rows).hasSize(1);
assertThat(rows.get(0).priorEvidence()).isEqualTo("원본증빙");
}
/** 내려받은 파일을 그대로 다시 올렸을 때 값이 살아남아야 한다. */
@Test
void 내려받아_다시_올려도_값이_그대로다() {
jdbc.update("insert into process_item (org_id, seq, site_name, category, board_name, "
+ "post_title, url, description, has_attachment, prior_kogl_type, contract_docs, "
+ "produced_date, published_date, review_major, review_minor, review_result, "
+ "review_kogl_type, review_ai_type, review_opinion, review_note, prior_evidence, "
+ "judged_kogl_type, judged_ai_type, final_opinion, judgment_basis, process_status) "
+ "values (?, 1, '사이트', '범주', '게시판', '제목', 'http://x', '설명', '있음', "
+ "'4유형', '양도계약서', '2026-01-02', '2026-01-03', '제3자 권리', '초상권 포함', "
+ "'권리처리 추진', '보류', 'Y', '의견', '비고', '증빙자료', '0유형', 'Y', "
+ "'최종의견', '판단근거', '처리완료')",
orgId);
byte[] xlsx = service.downloadWorkbook(orgId);
List<ProcessRow> rows = parser.parse(new ByteArrayInputStream(xlsx));
assertThat(rows).hasSize(1);
ProcessRow row = rows.get(0);
assertThat(row.siteName()).isEqualTo("사이트");
assertThat(row.category()).isEqualTo("범주");
assertThat(row.boardName()).isEqualTo("게시판");
assertThat(row.postTitle()).isEqualTo("제목");
assertThat(row.url()).isEqualTo("http://x");
assertThat(row.description()).isEqualTo("설명");
assertThat(row.hasAttachment()).isEqualTo("있음");
assertThat(row.priorKoglType()).isEqualTo("4유형");
assertThat(row.contractDocs()).isEqualTo("양도계약서");
assertThat(row.producedDate()).isEqualTo("2026-01-02");
assertThat(row.publishedDate()).isEqualTo("2026-01-03");
assertThat(row.reviewMajor()).isEqualTo("제3자 권리");
assertThat(row.reviewMinor()).isEqualTo("초상권 포함");
assertThat(row.reviewResult()).isEqualTo("권리처리 추진");
assertThat(row.reviewKoglType()).isEqualTo("보류");
assertThat(row.reviewAiType()).isEqualTo("Y");
assertThat(row.reviewOpinion()).isEqualTo("의견");
assertThat(row.reviewNote()).isEqualTo("비고");
assertThat(row.judgedKoglType()).isEqualTo("0유형");
assertThat(row.judgedAiType()).isEqualTo("Y");
assertThat(row.finalOpinion()).isEqualTo("최종의견");
assertThat(row.judgmentBasis()).isEqualTo("판단근거");
assertThat(row.processStatus()).isEqualTo("처리완료");
// 기존 증빙자료는 다운로드가 T열에 쓰고 파서가 U열을 읽어 왕복에서 사라진다.
assertThat(row.priorEvidence())
.as("내려받아 다시 올렸을 때 기존 증빙자료")
.isEqualTo("증빙자료");
}
}