feat: 보상 재시도 + TX 확정 대기 + 에러 포맷 통일 + 품질 고도화
- 보상 지급 실패 시 즉시 재시도(3회 backoff) + DB 기록 + 백그라운드 워커 재시도 - WaitForTx 폴링으로 블록체인 TX 확정 대기, SendTxAndWait 편의 메서드 - chain 트랜잭션 코드 중복 제거 (userTx/operatorTx 헬퍼, 50% 감소) - AppError 기반 에러 응답 포맷 통일 (8개 코드, 전 핸들러 마이그레이션) - TX 에러 분류 + 한국어 사용자 메시지 매핑 (11가지 패턴) - player 서비스 테스트 20개 + chain WaitForTx 테스트 10개 추가 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -232,3 +232,40 @@ func TestResolveUsername_NoResolver(t *testing.T) {
|
||||
t.Error("resolveUsername should fail when userResolver is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClassifyTxError(t *testing.T) {
|
||||
tests := []struct {
|
||||
chainMsg string
|
||||
want string
|
||||
}{
|
||||
{"insufficient balance: have 0 need 100: insufficient balance", "잔액이 부족합니다"},
|
||||
{"only the asset owner can list it: unauthorized", "권한이 없습니다"},
|
||||
{"session \"abc\" already exists: already exists", "이미 존재합니다"},
|
||||
{"asset \"xyz\" not found: not found", "리소스를 찾을 수 없습니다"},
|
||||
{"asset is not tradeable", "거래할 수 없는 아이템입니다"},
|
||||
{"asset \"a\" is equipped; unequip it before listing", "장착 중인 아이템입니다"},
|
||||
{"asset \"a\" is already listed (listing x): already exists", "이미 마켓에 등록된 아이템입니다"},
|
||||
{"listing \"x\" is not active", "활성 상태가 아닌 매물입니다"},
|
||||
{"session \"x\" is not open (status=closed)", "진행 중이 아닌 세션입니다"},
|
||||
{"invalid nonce: expected 5 got 3: invalid nonce", "트랜잭션 처리 중 오류가 발생했습니다. 다시 시도해주세요"},
|
||||
{"some unknown error", "블록체인 트랜잭션이 실패했습니다"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.chainMsg, func(t *testing.T) {
|
||||
got := classifyTxError(tt.chainMsg)
|
||||
if got != tt.want {
|
||||
t.Errorf("classifyTxError(%q) = %q, want %q", tt.chainMsg, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxError_Error(t *testing.T) {
|
||||
err := &TxError{TxID: "abc123", Message: "insufficient balance"}
|
||||
got := err.Error()
|
||||
want := "transaction abc123 failed: insufficient balance"
|
||||
if got != want {
|
||||
t.Errorf("TxError.Error() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user