bibimbap/.atp/work-session/20260624-100749/implementation/W2-2-fix1.md

106 lines
7.5 KiB
Markdown

---
phase: implementation
agent: implementation-advisor
agent_version: 1
generated_at: 2026-06-24T00:00:00+09:00
fix: W2-2-fix1 (누락 테스트 2건 보완)
concerns: []
concerns_checked: true
workers_spawned: 0
planned_workers: 2
actual_workers: 0
self_verification:
checklist_passed: true
unused_diagnostics: 0
test_compile: pass
---
# 구현 보고 — W2-2-fix1 (누락 신규 테스트 2건 작성)
## 누락 진단 재확인
W2-2 설계 파일영향맵 L275-276 의 신규 테스트 2건이 직전 구현에서 누락됨.
원인: 소유 태그 `(검증)` 을 verification-advisor 작성으로 오독. 테스트 작성은 구현 산출물(verification 은 실행만, Write 없음). 본 fix 가 이 2 파일만 작성.
## 변경 목록
| 파일 | worker | 결과 요약 |
|---|---|---|
| `src/test/java/com/pandoli365/bibimbap/security/JamRoleGateTest.java` | advisor 직접 | 신규. isJudge 4건 + isOwnEntry 4건 = 8 테스트 |
| `src/test/java/com/pandoli365/bibimbap/controller/JamJudgeAdminControllerTest.java` | advisor 직접 | 신규. 지정/해제/조회 게이트·CSRF·404·409·성공 = 16 테스트 |
## 테스트 케이스 ↔ VP 매핑
### JamRoleGateTest (VP-2, VP-3)
- `isJudgeReturnsTrueForAssignedUser` — VP-2 지정 유저 true
- `isJudgeReturnsFalseForUnassignedUser` — VP-2 미지정 false
- `isJudgeReturnsFalseWhenUnauthenticated` — VP-2 미인증 false (mapper 미호출 검증)
- `isJudgeReturnsFalseForNullSession` — VP-2 보강(null 세션 방어, mapper 미호출)
- `isOwnEntryTrueForPersonalEntry` — VP-3 ① 개인출품 true
- `isOwnEntryTrueForTeamMemberEntry` — VP-3 ② 팀멤버출품 true
- `isOwnEntryFalseForOthersEntry` — VP-3 ③ 타인/타팀 false
- `isOwnEntryFalseForInactiveEntry` — VP-3 ④ 비활성(is_delete) false
### JamJudgeAdminControllerTest (VP-1, VP-4, VP-5, VP-6)
- `assignReturns401WhenUnauthenticated` — VP-1 미인증 401
- `assignReturns403WhenLacksPermission` — VP-1 무키 403
- `assignRejectsMissingCsrfBeforeMapperAccess` — VP-5 지정 CSRF 누락 403 + mapper 미호출
- `assignReturns404WhenJamMissing` — 404 잼 없음
- `assignReturns404WhenTargetUserMissing` — 404 대상 유저 없음
- `assignReturns409WhenAlreadyJudge` — VP-6 멱등 재지정 409 (insert 미호출)
- `assignInsertsJudgeWhenAuthorized` — VP-1/VP-4 통과·누구나 지정 성공
- `removeReturns403WhenLacksPermission` — VP-1 해제 무키 403
- `removeRejectsMissingCsrfBeforeMapperAccess` — VP-5 해제 CSRF 누락 403 + mapper 미호출
- `removeReturns404WhenNotAssigned` — 해제 404(지정 안 됨)
- `removeDeletesJudgeWhenAuthorized` — 해제 성공 removed:true
- `listReturns401WhenUnauthenticated` — VP-1 조회 미인증 401
- `listReturns403WhenLacksPermission` — VP-1 조회 무키 403
- `listReturnsJudgesWhenAuthorized` — 조회 성공(judges 목록)
> 게이트 통과의 ADMIN / SUBADMIN+키 구분: 컨트롤러는 PermissionGate 만 소비하므로(role 직접체크 없음, J3-A) `gate.isAuthenticated` + `gate.has(GAME_JAM_MANAGE)` 반환값으로 표현(JamAdminControllerTest 동형). role 분기 L3 스모크는 verification 영역.
## Bash 단계 (advisor 직접)
- `./mvnw -o -q test-compile` (JAVA_HOME=openjdk@21) → EXIT=0, 에러 0. 두 신규 테스트 컴파일 성공.
- `-Dmaven.compiler.showWarnings=true` 재컴파일 → 경고 0건(unused import/변수 없음).
- 테스트 **실행은 하지 않음**(verification 영역). test-compile 은 빌드/타입체크라 advisor 영역.
## 시그니처 정합 자가확인 (정적 전수)
| 소비 대상 | 실제 시그니처(실측) | 테스트 정합 |
|---|---|---|
| `JamRoleGate(JamJudgesMapper, JamEntriesMapper)` 생성자 | 확인 | ✓ |
| `JamRoleGate.isJudge(HttpSession, long)` → boolean | 세션 userId attr `"userId"`, null→false | ✓ |
| `JamRoleGate.isOwnEntry(long, long, long)` → boolean | jamEntriesMapper 위임 | ✓ |
| `JamJudgesMapper.exists/insert/delete/listByJam` | exists(long,long)→bool, insert(long,long,long)→int, delete(long,long)→int, listByJam(long)→List | ✓ |
| `JamEntriesMapper.isOwnEntry(long,long,long)` → boolean | @Param 3종 | ✓ |
| `JamJudgeAdminController(JamsMapper, UsersMapper, JamJudgesMapper, PermissionGate)` | 확인 | ✓ |
| 핸들러 `assign(long,long,HttpServletRequest,HttpSession)` / `remove(long,long,req,session)` / `list(long,session)` | ResponseEntity<Map<String,Object>> 반환 | ✓ |
| `PermissionGate.isAuthenticated/has` | isAuthenticated(session), has(session,String) | ✓ |
| `UsersMapper.getUser(long)` → UserData | 확인 | ✓ |
| `JamsMapper.getById(long)` → JamData | 확인 | ✓ |
| `CsrfTokens.HEADER_NAME / SESSION_ATTRIBUTE / errorBody()` | JamAdminControllerTest 동형 사용 | ✓ |
| POJO setter: JamData.setId/setTitle/setStatus, UserData.setId, JamJudgeData.setUserId/setDisplayName/setAssignedBy | 전수 존재 | ✓ |
| PermissionKeys.GAME_JAM_MANAGE | enum 상수 존재 | ✓ |
전례 보강: W2-1 1차의 `response()` 누락 컴파일 FAIL 재발 방지 — 컨트롤러 ResponseEntity 반환·헬퍼 흐름을 실측 후 테스트가 동일 흐름 가정. test-compile EXIT=0 으로 정합 입증.
### MockitoExtension STRICT_STUBS 점검
- JamJudgeAdminControllerTest: `@ExtendWith(MockitoExtension.class)` → strict stubbing. 각 테스트의 stub 전수가 핸들러 흐름(requireJamManage→CSRF→getById→getUser→exists→insert / requireJamManage→CSRF→delete / requireJamManage→listByJam)에서 모두 소비되도록 over-stub 0 으로 구성. UnnecessaryStubbingException 위험 0.
- JamRoleGateTest: plain `mock()`(MockitoExtension 미사용) → strict stub 비적용, unused stub 무관.
## 설계와의 차이 (worker 계획 vs 실제)
- **전환 사유**: 파일 수 2 < 8 AND 예상 줄수 합산 410 < 500 advisor 직접 실행 선택(병렬 worker 이득 미미). 중요한 근거: 테스트의 컴파일 정합이 핵심 리스크(W2-1 1차 FAIL 전례) 시그니처 전수 정합을 advisor 직접 통제하는 편이 안전.
- `planned_workers: 2`(code-writer 1파일 1worker 원칙상 계획) `actual_workers: 0`.
- 선택 파일: JamRoleGateTest.java, JamJudgeAdminControllerTest.java.
## BibimbapApplicationTests @MockBean 현황(VP-8/AC-T6 — 본 fix 무수정 확인)
- `JamJudgesMapper`(L74), `JamRoleGate`(L89), `JamEntriesMapper`(L71) 전수 이미 @MockBean 등록됨(직전 W2-2 구현이 등록). contextLoads 보존 fix 추가 등록 불요.
## concerns 검토
리스트. fix 테스트 2건 작성만이며 설계 VP-1~6 그대로 실현. main 코드/스키마/기존 테스트 무수정(제약 준수). 설계와의 충돌·비현실 발견 없음.
## Verification 을 위한 힌트
- acceptance criteria = design.md 검증 포인트 VP-1~8 + AC-T1~T7.
- fix 채운 VP: VP-1(게이트), VP-2(isJudge), VP-3(isOwnEntry), VP-5(CSRF), VP-6(멱등), VP-4 일부(누구나 지정 성공).
- L2(dev DB contract): VP-3 팀멤버/④비활성, VP-6 UNIQUE 거부, VP-7 alias 매핑 isOwnEntry/listByJam SQL 실측은 verification L2 게이트 소관(단위 테스트는 매퍼 위임 정합만 커버).
- AC-T 전수 게이트(AC-T1 DDL 제약수, AC-T2 핸들러 게이트수, AC-T3 CSRF수, AC-T4 isOwnEntry 양경로, AC-T5 `${` 0, AC-T6 @MockBean, AC-T7 전역 RBAC 무변경) grep/구조 검증 verification 영역.
- 영향받는 테스트 파일(신규): 변경 목록 2건. 기존 테스트 무영향(신규 파일 추가만).
- full `./mvnw -o test` 의무(설계 concern 2, §30): 신규 매퍼/게이트 @MockBean contextLoads 포함 verification 실행.