Skip to content

[Refactor] 사진 업로드 병렬화 및 테스트 인프라 정비#31

Merged
ddodle merged 2 commits into
mainfrom
refactor/upload-parallelism
Jun 6, 2026
Merged

[Refactor] 사진 업로드 병렬화 및 테스트 인프라 정비#31
ddodle merged 2 commits into
mainfrom
refactor/upload-parallelism

Conversation

@ddodle

@ddodle ddodle commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

✨ PR 유형

어떤 변경 사항이 있나요??

  • 새로운 기능 추가
  • 버그 수정
  • 사용자 UI 디자인 변경 및 추가
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 테스트 추가, 테스트 리팩토링
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

🛠️ 작업내용

업로드 경로 개선

  • PhotoRepository.uploadPhotos를 순차 for 루프에서 withThrowingTaskGroup으로 변경하여 S3 업로드 병렬화
  • URL(string: item.imageUrl)! 강제 언래핑 제거 — PhotoUploadItem.imageUrl 타입을 String에서 URL로 변경하여 타입 시스템 차원에서 보장
  • try? Data(contentsOf:) silent skip 제거 — 한 건이라도 실패하면 TaskGroup이 자동 cancel 후 throw, 사용자에게 정상적으로 노출됨
  • PhotoMetadataExtractor의 임시 파일 쓰기 실패를 try? → 명시적 do/catch + return nil로 처리

테스트 추가

  • PhotoRepositoryTests — 3개 케이스
    • test_uploadPhotos_emptyItems_makesNoRequests
    • test_uploadPhotos_allSuccess_uploadsEachItemThenCallsBatchSave
    • test_uploadPhotos_anyS3Failure_throwsAndSkipsBatchSave
  • TestHelpers — 재사용 가능한 인프라
    • StubURLProtocolURLSession 응답 stub + 요청 기록
    • MockTokenStore — 메모리 기반 TokenStore actor
    • MockTokenRefreshService

기존 테스트 빌드 복구

  • PhotoInfoPerformanceTests — 존재하지 않는 TagRequestDTOUpdateTagRequestDTO
  • DecodingPerformanceTests — album 테스트의 [SearchResponseDTO][AlbumResponseDTO]
  • MemoryPerformanceTestsSearchResponseDtoSearchResponseDTO
  • MockDataFactory — 옛 필드명 privateisSensitive, createdAt에 ISO8601 타임존(Z) 추가

📋 추후 진행 상황

  • 죽은 코드 정리 (ContentView DEBUG 바이패스, Settings/Trash/Help placeholder, UserAPITarget 미사용 case)
  • 에러 타입 통합 (NetworkError / RepositoryError 매핑 일원화)
  • 모듈 분리 및 의존성 단방향 강제

📌 리뷰 포인트

  • PhotoRepository.uploadPhotos의 TaskGroup 내부에서 self.adapter를 로컬로 캡처한 부분, 그리고 JSONDecoder()를 각 task 내에서 새로 만든 점이 의도된 선택인지 확인 부탁드립니다 (Sendable 안전성 우선)
  • PhotoUploadItem.imageUrl 타입 변경의 파급은 PhotoMetadataExtractorPhotoRepository 두 호출처에 한정됩니다
  • StubURLProtocol은 다른 Repository 테스트에서도 그대로 재사용 가능하도록 작성했습니다

✅ Checklist

PR이 다음 요구 사항을 충족하는지 확인해주세요!!!

  • 커밋 메시지 컨벤션에 맞게 작성했습니다
  • 유지-보수를 위해 주석처리를 잘 작성하였는가?

Closes #30

Summary by CodeRabbit

  • 새로운 기능

    • 사진 업로드가 동시 업로드 방식으로 전환되어 처리 속도 향상
  • 버그 수정

    • 파일 읽기/검증 실패 시 더 엄격하게 오류를 전파하여 실패 상황을 명확히 처리
  • 테스트

    • 사진 업로드 동작을 검증하는 통합 테스트 추가
    • 테스트용 네트워크 스텁·토큰 목 등 테스트 헬퍼 확대 및 목데이터 포맷 보강

업로드 경로
- PhotoRepository.uploadPhotos를 TaskGroup으로 변경하여 S3 업로드 병렬화
- 강제 언래핑(URL(string:)!)과 try? silent skip 제거 → 한 건 실패 시 전체 throw로 표면화
- PhotoUploadItem.imageUrl 타입을 String에서 URL로 변경
- PhotoMetadataExtractor의 임시 파일 쓰기 실패를 명시적 nil 반환으로 처리

테스트
- PhotoRepository 단위 테스트 3개 추가 (빈 입력, 전체 성공, 일부 실패)
- StubURLProtocol, MockTokenStore 등 재사용 가능한 테스트 인프라 추가
- 기존 테스트의 깨진 DTO 참조 정리
  (TagRequestDTO → UpdateTagRequestDTO, SearchResponseDto → SearchResponseDTO 등)
- MockDataFactory를 현재 DTO 스키마에 맞춰 갱신 (isSensitive 필드, ISO8601 타임존)
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Linter diff in the way? Review this PR in Change Stack to focus on meaningful changes and expand context only when needed.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 84bba084-9217-4ebf-bb76-7bd27f164f18

📥 Commits

Reviewing files that changed from the base of the PR and between e10f808 and abb3307.

📒 Files selected for processing (1)
  • Rephoto_iOSTests/MemoryPerformanceTests.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • Rephoto_iOSTests/MemoryPerformanceTests.swift

Walkthrough

PhotoRepository의 uploadPhotos를 withThrowingTaskGroup로 병렬화하고, PhotoUploadItem.imageUrl을 URL로 변경했으며, 임시 파일 쓰기 실패 처리를 명시적으로 바꾸고, 테스트 헬퍼(StubURLProtocol 등)와 통합 테스트·성능 테스트 참조를 정정했습니다.

변경사항

사진 업로드 병렬화 및 테스트 인프라

Layer / File(s) Summary
도메인 모델 및 서비스 타입 안전성 개선
Rephoto_iOS/Features/Home/Domain/Models/PhotoUploadItem.swift, Rephoto_iOS/Features/Home/Domain/Services/PhotoMetadataExtractor.swift
PhotoUploadItem.imageUrlString에서 URL로 변경하고, 임시 파일 쓰기 실패를 do/catch로 처리해 실패 시 nil을 반환하도록 변경했습니다.
Repository 동시 업로드 구현
Rephoto_iOS/Features/Home/Data/Repositories/PhotoRepository.swift
uploadPhotos(items:)withThrowingTaskGroup 기반 병렬 처리로 전환하고, 빈 입력 조기 반환 및 try 기반 에러 전파로 실패 시 전체가 throw되도록 변경했습니다.
테스트 헬퍼 및 모의 객체 구축
Rephoto_iOSTests/TestHelpers.swift
StubURLProtocol, MockTokenStore, MockTokenRefreshService를 추가하여 네트워크/인증 계층 테스트 인프라를 제공합니다.
Repository 통합 테스트
Rephoto_iOSTests/PhotoRepositoryTests.swift
StubURLProtocol을 사용해 빈 입력/전체 성공/부분 실패 시나리오별로 S3 업로드 요청 수, 배치 저장 호출, 에러 전파를 검증하는 통합 테스트를 추가했습니다.
기존 성능 테스트 DTO 타입 정정
Rephoto_iOSTests/DecodingPerformanceTests.swift, Rephoto_iOSTests/MemoryPerformanceTests.swift, Rephoto_iOSTests/MockDataFactory.swift, Rephoto_iOSTests/PhotoInfoPerformanceTests.swift
성능 테스트 내 DTO 참조와 테스트 데이터 포맷을 정정했습니다 (예: SearchResponseDtoSearchResponseDTO, TagRequestDTOUpdateTagRequestDTO, createdAt 포맷 및 민감도 키 수정).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Grit-23/Rephoto_Frontend_iOS#21: 클린 아키텍처 리팩토링에서 도입된 PhotoRepository 업로드 파이프라인 및 타입 변경과 연관됩니다.

Poem

🐰
순서를 건너뛰고 병렬로 달려,
파일은 URL로 품고, 에러는 숨기지 않아,
테스트는 단단히, 스텁은 기다려,
토끼가 박수치며 말하네: 잘했어, 짝짝!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항인 사진 업로드 병렬화와 테스트 인프라 정비를 명확하게 요약하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿의 모든 주요 섹션을 포함하고 있으며, 작업내용, 추후 진행사항, 리뷰 포인트, 체크리스트가 상세하게 작성되어 있습니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 #30의 목표를 충족합니다: TaskGroup을 통한 병렬 업로드, 타입 안전성 개선, 안전한 에러 전파, 테스트 인프라 추가, 기존 테스트 복구 등이 완전히 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #30의 범위 내에 있습니다: 업로드 경로 개선, PhotoUploadItem 타입 변경, 테스트 추가, 기존 테스트 DTO 참조 복구가 모두 명시된 목표와 직접 관련이 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/upload-parallelism

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ddodle ddodle self-assigned this Jun 5, 2026
@ddodle

ddodle commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Rephoto_iOS/Features/Home/Data/Repositories/PhotoRepository.swift`:
- Around line 33-40: The child tasks in withThrowingTaskGroup capture
self.adapter which must be Sendable; either make MoyaNetworkAdapter conform to
Sendable (or annotate as `@unchecked` Sendable if safe) so adapter can be captured
(update the MoyaNetworkAdapter type declaration), or avoid capturing adapter by
extracting the needed request operation out of the task (e.g., create a local,
Sendable-safe request function or copy any required data before group.addTask)
and call that inside the `@Sendable` closure; update references in PhotoRepository
where adapter is used inside the group (adapter, withThrowingTaskGroup, addTask)
accordingly.

In `@Rephoto_iOSTests/MemoryPerformanceTests.swift`:
- Around line 38-39: The test currently swallows decode failures with `try?`
which can make the memory benchmark measure a nil path; replace the `try?
JSONDecoder().decode(SearchResponseDTO.self, from: data)` usage in this test
(the `retainedSearchResult` assignment) with an explicit do-catch around
`JSONDecoder().decode`, on success assign to `retainedSearchResult`, and on
failure call `XCTFail` with the decoding error so the test fails instead of
measuring a no-op path (keep the subsequent
`XCTAssertEqual(retainedSearchResult?.searchResults.count, 500)` intact).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 69664a4f-6be0-4433-a67b-51af38b3d7c0

📥 Commits

Reviewing files that changed from the base of the PR and between d8b938d and e10f808.

📒 Files selected for processing (9)
  • Rephoto_iOS/Features/Home/Data/Repositories/PhotoRepository.swift
  • Rephoto_iOS/Features/Home/Domain/Models/PhotoUploadItem.swift
  • Rephoto_iOS/Features/Home/Domain/Services/PhotoMetadataExtractor.swift
  • Rephoto_iOSTests/DecodingPerformanceTests.swift
  • Rephoto_iOSTests/MemoryPerformanceTests.swift
  • Rephoto_iOSTests/MockDataFactory.swift
  • Rephoto_iOSTests/PhotoInfoPerformanceTests.swift
  • Rephoto_iOSTests/PhotoRepositoryTests.swift
  • Rephoto_iOSTests/TestHelpers.swift

Comment thread Rephoto_iOS/Features/Home/Data/Repositories/PhotoRepository.swift
Comment thread Rephoto_iOSTests/MemoryPerformanceTests.swift Outdated
- 디코딩 실패가 silent로 nil 경로를 측정하던 문제 수정
- 실패 시 XCTFail로 명시 → 다른 성능 테스트와 패턴 통일
@ddodle ddodle merged commit 8690767 into main Jun 6, 2026
2 checks passed
@ddodle ddodle deleted the refactor/upload-parallelism branch June 6, 2026 04:38
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.

♻️ Refactor: 사진 업로드 병렬화 및 테스트 인프라 정비

1 participant