연주를 끝낸 직후 연결이 끊기면, 아직 서버에 도착하지 않은 녹음을 다시 보낼 수 있어야 합니다. 얼쑤에서는 녹음 파일을 기기의 보관 위치로 옮긴 다음, 어느 세션에 어떤 파일을 보낼지 기록하고 업로드하도록 만들었습니다. 앱을 다시 열어도 그 기록에서 보낼 녹음을 찾을 수 있습니다.
리뷰에서 파일을 옮기는 일과 대기 기록을 저장하는 일 사이에 틈이 있다는 걸 발견했습니다. 새 파일은 이미 보관 위치에 있지만, 상태 조회에서 읽을 대기 기록은 아직 없습니다. 기존 조회 함수는 기록이 없으면 보관 폴더에 남은 파일을 정리했습니다. 이 순간에 조회가 끼어들면 방금 옮긴 녹음도 버려도 되는 파일로 보고 지울 수 있었습니다.
앱 시작과 저장 때 폴더 정리
전송 경로에서는 녹음 파일을 옮기고 대기 기록에 세션 ID, 시작 시각, 새 경로를 저장한 뒤 업로더를 호출합니다. 연결에 실패하면 그 파일과 기록을 남깁니다. 같은 세션으로 다시 보낸 뒤 성공하면 해당 파일과 대기 기록을 지웁니다.
조회에서 보관 폴더를 훑어 기록 없는 파일을 지우는 처리는 빼고, 앱을 켜서 아직 전송을 시작하기 전의 정리 단계로 옮겼습니다. 그때는 저장된 대기 기록이 가리키는 파일을 남깁니다. 새 녹음으로 대기 파일을 교체하는 경로도 방금 옮긴 파일의 경로를 알고 있으므로, 그 파일을 제외하고 남은 파일을 정리할 수 있습니다.
파일 이동 중 상태 조회 재현
테스트에서는 실제 파일 시스템 대신 존재하는 경로를 집합으로 관리하는 대역을 썼습니다. 대역의 파일 이동 함수는 새 경로를 집합에 추가한 직후 콜백을 호출합니다. 그 자리에 상태 조회를 넣으면 대기 기록이 저장되기 전의 순서를 매번 재현할 수 있습니다.
files.onKeep = { uploads.pending() }
폴더 정리를 조회에 되돌린 변형에서는 이 테스트가 실패했습니다. 정리 시점을 옮긴 구현에서는 조회가 같은 위치에 끼어들어도, 연결 실패 뒤 방금 옮긴 파일 한 개와 그 경로를 가리키는 대기 기록 한 건이 남았습니다.
별도의 재전송 테스트에서 업로더 대역은 처음 호출에 연결 실패, 두 번째 호출에 성공을 반환했습니다. 두 호출은 같은 세션을 대상으로 했습니다. 성공 뒤에는 그 파일이 지워졌고, 대기 기록은 0건이 됐습니다. 같은 저장소를 사용해 업로드 객체를 다시 만든 경우에도 대기 중인 세션을 읽고 다시 보낼 수 있었습니다.
전송 중 버튼을 다시 눌렀을 때
즉시 결과를 돌려주는 업로더 대역으로는 첫 재전송이 끝나기 전의 입력을 검사하기 어렵습니다. 가짜 업로더는 이번 호출의 결과를 먼저 꺼낸 뒤 CompletableDeferred<Unit>.await()에서 멈추도록 했습니다. 그 사이 테스트가 재전송을 한 번 더 요청했습니다. 대기 중인 시점의 누적 호출은 두 건이었습니다. 처음 실패한 전송 한 건과 진행 중인 재전송 한 건입니다. 두 번째 누름은 새 요청을 시작하지 않았습니다. complete(Unit)으로 응답을 풀자 전송 중 표시와 업로드 오류가 사라졌습니다.
정지 지점과 실행 환경 고정
테스트의 코루틴은 Dispatchers.Unconfined로 업로더의 대기 지점까지 먼저 진행했습니다. 응답을 풀기 전후에 화면 상태를 읽어, 전송 중과 종료 뒤를 같은 테스트에서 구분했습니다. 이 검사는 공통 화면 로직에 입력이 들어오는 순서를 고정한 결과입니다. 실제 네트워크 지연과 두 스레드의 경쟁은 측정하지 않았습니다.
기기 시계가 빨라도 파일 보관
재전송 기한은 서버의 세션 시작 시각을 기준으로 40분입니다. 기기 시계로 그 시간이 지났다면 재전송을 권하는 안내에서 숨기되 파일은 10분 더 보관했습니다. 그 사이에 요청을 보내면 서버가 만료 여부를 판정합니다.
고정 시계 테스트에서 40분 정각에는 대기 녹음이 조회됐습니다. 정각에서 1ms가 지나면 안내에 쓰는 조회 결과는 비었지만 파일은 남았고, 전송을 요청하면 업로더 대역에 도달했습니다. 50분 정각에도 파일은 남아 있었고, 1ms를 더한 경우에는 파일이 정리됐습니다.
이 검증에서는 파일·시계·업로더를 대역으로 제어했습니다. 확인한 범위는 파일을 옮기는 도중 조회가 들어오는 순서와, 저장된 대기 기록을 다시 읽어 같은 세션으로 보내는 앱 로직입니다.

댓글
댓글과 반응은 GitHub 계정으로 로그인해 남길 수 있어요.