Skip to content

fix: 배지 응답 상태코드 정정과 테스트·입력 제약 보강 - #22

Merged
kobenlys merged 8 commits into
mainfrom
develop
Sep 16, 2026
Merged

kobenlys merged 8 commits into
mainfrom
develop

Conversation

@kobenlys

@kobenlys kobenlys commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

🏷️ 작업 유형

  • 🐛 버그 픽스
  • ✨ 개발
  • 📝 문서 추가 및 수정
  • ♻️ 리팩터링
  • 🔧 ETC

📋 변경 사항

요약

배포 시 주의

  • BADGES.md:209 locked 배지 예시 이미지 깨짐
  • 예시 URL octocat?theme=beta-tester, octocat은 미가입 계정
  • 현재 200 잠금 SVG → 배포 후 404
  • README에서 링크되는 공개 문서
  • 문서 미수정으로 결정된 사항

1. 미가입 사용자 배지 응답 404 통일 (cc71356, #21)

요청 이전 이후
미가입 + ?theme=beta-tester 200 잠금 SVG 404 BADGE_001
미가입 + ?theme=gpu 404 BADGE_001 동일
가입 + 미자격 + ?theme=beta-tester 200 잠금 SVG 동일
  • 원인 — 자격 게이트가 사용자 조회보다 선행, 오타 username이 "전용 배지" 안내로 통과
  • 조치 — findGrant 쿼리에 userExists 컬럼 추가, DB 왕복 증가 없음
  • 조치 — BadgeRenderService가 자격 분기 앞에서 BADGE_001 throw

2. 라우팅 미스 4xx 반환 (193b976, #21)

요청 이전 이후
GET /badge/, /badge, /badge/{u}/ 500 SERVER_ERROR 404 NOT_FOUND
POST /badge/{u} 500 SERVER_ERROR 405 METHOD_NOT_ALLOWED
  • 원인 — GlobalExceptionHandler의 @ExceptionHandler(Exception.class)가 Spring MVC 표준 예외까지 포획
  • 부수 피해 — /badge/**가 permitAll이라 미인증 요청만으로 ERROR 스택트레이스 축적 가능
  • 조치 — ErrorResponse 구현 예외 5종 전용 핸들러, 응답 코드·메시지를 예외가 지정한 상태에서 파생
  • 성격 — develop에 이미 있던 기존 결함, 1번 검증 중 발견

3. 그 외

✅ 테스트

결론 — develop 머지 커밋 c583e55e에서 CI 두 잡 모두 통과

  • Unit Tests — success
  • Integration Tests — success, Testcontainers Postgres 실제 실행
명령 건수
./mvnw test 504
./mvnw verify 통합 39
  • TDD 진행, 사이클마다 RED 확인
  • GlobalExceptionHandlerWebMvcTest — 실제 디스패치를 태워 핸들러 도달 경로 검증
  • UserBadgeGrantRepositoryIntegrationTest — 실 Postgres로 userExists alias ↔ getter 매핑 검증

kobenlys and others added 8 commits September 2, 2026 00:23
// given 블록 안에 when( 이 와서 같은 단어가 반대 뜻으로 쓰이는 충돌을
없애기 위해 classic Mockito 를 BDDMockito 로 전환한다.
16개 파일, 동작 변경 없음 (476개 통과 유지).

- when().thenReturn()     -> given().willReturn()
- when().thenThrow()      -> given().willThrow()
- doThrow().when()        -> willThrow().given()
- verify()                -> then().should()
- verify(m, never())      -> then(m).should(never())
- verifyNoInteractions()  -> then().shouldHaveNoInteractions()
- order.verify()          -> then().should(order)

lenient().when() 과 order.verifyNoMoreInteractions() 는 BDDMockito 에
대응 API 가 없어 classic 을 유지한다.
테스트 카테고리 7종 규칙을 기존 코드에 적용한 결과다.

model 이 컬럼 폭(VARCHAR(80))을 넘어도 검증을 통과해 네이티브 INSERT 까지
내려가 500 이 났고, @transactional 이라 그 sync 배치 전체가 롤백됐다.
토큰 필드는 상한이 없어 집계 SUM 에서 bigint 오버플로가 가능했다.

- TokenRecordRequest: model @SiZe(80), 토큰 4필드 @max(1e11)
- SyncRequest: records @SiZe(10000)
- SyncSchemaConstraintTest(신규): 제약값과 DDL 을 대조
- SyncControllerTest(신규): @Valid -> 400, 미인증 -> 401 배선 검증
- CardClaudeBadgeThemeTest: 레벨 임계 직전/직후 9케이스 추가
- 세터 왕복, 복합키 중복 등 회귀 신호 없는 테스트 8건 제거

유닛 493, 통합 37 통과.
refactor: 유닛테스트를 BDDMockito로 포팅
fix: sync 입력 제약 보강 및 회귀 신호 없는 테스트 정리
미가입 username은 이제 모든 테마에서 404 BADGE_001을 받는다.
가입했지만 자격이 없는 경우는 기존대로 200 잠금 SVG다.

기존에는 자격이 필요한 테마(beta-tester)만 200 잠금 SVG를 반환했다.
자격 게이트가 사용자 조회보다 먼저 걸려 오타 username이 걸러지지 않았다.

findGrant 쿼리에 userExists 컬럼을 더해 DB 왕복을 늘리지 않고 판별하며,
BadgeRenderService가 자격 분기보다 앞에서 BADGE_001을 던진다.
/badge/ 같은 라우팅 미스는 404 NOT_FOUND를, POST /badge/{username} 은
405 METHOD_NOT_ALLOWED를 반환한다. ERROR 스택트레이스도 남지 않는다.

기존에는 GlobalExceptionHandler의 catch-all이 Spring MVC 표준 예외까지
삼켜 전부 500 SERVER_ERROR로 나갔다. /badge/** 가 permitAll이라
미인증 요청만으로 ERROR 로그를 쌓을 수 있었다.

ErrorResponse를 구현하는 예외 5종을 전용 핸들러로 잡고, 응답 코드와
메시지를 예외가 지정한 상태에서 파생해 매핑 표 없이 처리한다.
fix: 배지 조회 응답 상태코드 정정 — 미가입 404 통일 및 라우팅 미스 4xx
@kobenlys kobenlys self-assigned this Sep 16, 2026
@kobenlys
kobenlys merged commit 211819a into main Sep 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant