Skip to content

[Template] 스냅샷 왕복을 실제 MySQL 위에서 본다 [ #395 ] - #397

Merged
dldnsgkr merged 1 commit into
developfrom
unhak/template-catalog-roundtrip-test
Sep 25, 2026
Merged

dldnsgkr merged 1 commit into
developfrom
unhak/template-catalog-roundtrip-test

Conversation

@dldnsgkr

Copy link
Copy Markdown
Collaborator

#396 을 머지한 뒤 dev 에서 스냅샷 행을 직접 보다가 발견한 검증 공백을 메운다. 프로덕션 코드 변경 없음 — 테스트만 추가한다.

무엇을 봤나

payload=17272B  템플릿 17종  fetched_at=2026-09-25 16:14:17  age=32736s   ← NOW() 기준 9.1시간
앱 기동: 01:13:33 KST (Sep 26)

fetched_at 이 UTC 로 저장되고 MySQL NOW() 는 KST 다(JDBC URL 이 serverTimezone=Asia/Seoul). Sep 25 16:14 UTC = Sep 26 01:14 KST — 기동 직후 받은 것이니 값 자체는 맞다.

문제는 그게 아니라, 쓸 때와 읽을 때의 변환이 대칭인지 확인된 적이 없었다는 것이다.

왜 기존 테스트로는 부족했나

TemplateCatalogSnapshotStoreTest 는 리포지토리를 목으로 둔다. Jackson 왕복은 진짜를 태웠지만 JDBC 는 타지 않는다. 나이 계산이 걸려 있는 구간이 테스트 밖에 있었다.

어긋나면 조용히 망가진다.

어긋나는 방향 결과
나이가 부풀려진다 상한(기본 24h)에 먼저 걸려 복원이 안 된다 — 기능이 있는데 안 도는 상태
나이가 줄어든다 너무 낡은 목록을 복원한다 — 없어진 템플릿을 고르게 된다

어느 쪽도 예외를 던지지 않는다. 그래서 테스트가 없으면 아무도 모른다.

추가한 것 — 실제 MySQL 위 5건

테스트 무엇을 막나
넣은 Instant 가 그대로 읽힌다 시간대·정밀도 비대칭
DB 를 거쳐 온 나이가 실제 경과와 같다 (3h → 3h) 나이 계산 전체
상한 판정이 실제 DB 값으로도 맞다 25h 거부 / 상한을 48h 로 늘리면 같은 행이 복원 — 거부 이유가 나이였음까지 확인
두 번 저장하면 UPDATE 로 가고 행이 하나 detached 엔티티를 더티체킹으로 고치려 했다면 여기서 걸린다
contentHints·tags·sourceUrl 까지 왕복 반쯤 복원된 목록으로 에이전트를 돌리는 것

민감도 — 이 테스트가 정말 잡는가

fetched_at 을 datetime(6) → datetime 으로 깎고 돌렸다.

실패: 저장한 그 시각이 그대로 읽힌다
  expected: 2026-09-25T15:45:34.659232Z
   but was: 2026-09-25T15:45:35Z

ddl-auto: validate 는 이 차이를 잡지 않는다. 컬럼 타입 이름만 보기 때문이다.

그 확인에서 거짓 통과를 한 번 봤다

첫 시도에서 "0건 실패" 가 나왔다. 실제로는 gradle 이 실패했고, 내가 직전 실행의 결과 XML 을 읽고 있었다. 결과 디렉터리를 지우고 총 건수까지 세니 제대로 1건 실패가 나왔다.

실패 수만 세면 "테스트가 안 돌았다" 와 "전부 통과했다" 가 같은 값으로 보인다. 이 세션에서 같은 모양의 함정을 이미 한 번 겪었다(ElementTree 의 falsy element).

검증

전체 1762건 통과(직전 1757 + 신규 5), 실패 0, skip 12.

참고 — #395 는 이미 닫혔다(PR #396). 이 PR 은 그 구현의 검증 공백만 메운다.

🤖 Generated with Claude Code

https://claude.ai/code/session_013y8USoCXTsRTATAhy88M93

#395 를 머지한 뒤 dev 에서 행을 직접 보다가 fetched_at 이 MySQL NOW() 와
9시간 차이나는 것을 봤다. 저장은 UTC 이고 NOW() 는 KST(JDBC URL 이
serverTimezone=Asia/Seoul)라서 그 자체는 정상이지만, 쓸 때와 읽을 때의 변환이
대칭인지는 확인된 적이 없었다.

기존 단위 테스트는 리포지토리를 목으로 두므로 JDBC 를 타지 않는다. 즉 나이
계산이 걸려 있는 구간이 테스트 밖에 있었다. 어긋나면 조용히 망가진다 —
나이가 부풀려지면 상한(기본 24h)에 먼저 걸려 복원이 안 되고, 줄어들면 너무
낡은 목록을 복원한다. 어느 쪽도 예외를 던지지 않는다.

실제 MySQL 위에서 다섯 가지를 본다.
  넣은 Instant 가 그대로 읽힌다 (정확히 같은 값)
  DB 를 거쳐 돌아온 나이가 실제 경과와 같다 (3시간 → 3시간)
  상한 판정이 실제 DB 값으로도 맞다 (25h 거부 / 상한 48h 로 늘리면 복원)
  두 번 저장하면 UPDATE 로 가고 행이 하나다 (트랜잭션 없이 merge)
  contentHints·tags·sourceUrl 까지 왕복한다

민감도도 확인했다. fetched_at 을 datetime(6) → datetime 으로 깎으면
"저장한 그 시각이 그대로 읽힌다" 가 실패한다.
  expected: 2026-09-25T15:45:34.659232Z
   but was: 2026-09-25T15:45:35Z
ddl-auto: validate 는 이 차이를 잡지 않는다.

그 민감도 확인에서 한 번 거짓 통과를 봤다 — 첫 시도에서 "0건 실패" 가 나왔는데,
gradle 은 실패했고 내가 직전 실행의 결과 XML 을 읽고 있었다. 결과 파일을 지우고
총 건수까지 세니 제대로 1건 실패로 나왔다. 실패 수만 세면 "테스트가 안 돌았다" 와
"전부 통과했다" 가 같은 값으로 보인다.

전체 1762건 통과(직전 1757 + 신규 5), 실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013y8USoCXTsRTATAhy88M93
@dldnsgkr
dldnsgkr merged commit 7446866 into develop Sep 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant