Files
artex/server/auth_localized_test.go
dela 0335d572de
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
detections / detections (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
First Commit
2026-10-09 08:38:16 +08:00

76 lines
2.9 KiB
Go

package server
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
// 인증 응답 문구의 한국어화(백로그 F3b)를 지키는 회귀 방어 테스트다. DB 가 없어도
// 도는 두 경로로 확인한다: ① requireAuth 미들웨어는 pg 를 거치지 않으므로 실제 HTTP
// 응답 본문까지 검사하고, ② 나머지 핸들러 문구는 명명 상수라 상수 자체를 검사한다.
// 한국어 판정은 F3a 가 만든 assertKoreanError 헬퍼(한글 포함·중국어 한자 0)를 재사용한다.
// TestRequireAuthMessagesLocalized 는 토큰이 없거나 잘못됐을 때 requireAuth 가 돌려주는
// 401 응답 본문이 한국어이고 중국어 한자가 없음을 실제 HTTP 핸들러로 확인한다. 이
// 미들웨어는 데이터베이스를 쓰지 않아 DB 없는 환경에서도 끝까지 실행된다.
func TestRequireAuthMessagesLocalized(t *testing.T) {
s := &Server{jwtKey: []byte(strings.Repeat("k", 32))}
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
})
h := s.requireAuth(next)
cases := []struct {
name string
bearer string
want string
}{
{"토큰 없음", "", authErrUnauthorized},
{"토큰 무효", "Bearer not-a-valid-token", authErrTokenInvalid},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/api/tasks", nil)
if c.bearer != "" {
r.Header.Set("Authorization", c.bearer)
}
rec := httptest.NewRecorder()
h.ServeHTTP(rec, r)
if rec.Code != http.StatusUnauthorized {
t.Fatalf("상태 코드 = %d, 기대 401", rec.Code)
}
body := rec.Body.String()
if !strings.Contains(body, c.want) {
t.Errorf("응답 본문에 %q 가 없습니다: %s", c.want, body)
}
assertKoreanError(t, c.name, body)
})
}
}
// TestAuthErrorConstantsLocalized 는 인증 핸들러가 쓰는 사용자 노출 문구 상수가 모두
// 한글을 포함하고 중국어 한자를 포함하지 않음을 단언한다. requireAuth 로 직접 칠 수
// 없는(= pg 를 거치는) 핸들러의 문구까지 DB 없이 회귀를 잡는다.
func TestAuthErrorConstantsLocalized(t *testing.T) {
consts := map[string]string{
"authErrUnauthorized": authErrUnauthorized,
"authErrTokenInvalid": authErrTokenInvalid,
"authErrPasswordAlreadySet": authErrPasswordAlreadySet,
"authErrPasswordEmpty": authErrPasswordEmpty,
"authErrNewPasswordEmpty": authErrNewPasswordEmpty,
"authErrPasswordHash": authErrPasswordHash,
"authErrSaveFailedPrefix": authErrSaveFailedPrefix,
"authErrTokenGen": authErrTokenGen,
"authErrBadRequest": authErrBadRequest,
"authErrPasswordNotInit": authErrPasswordNotInit,
"authErrCurrentPasswordWrong": authErrCurrentPasswordWrong,
"authErrBadCredential": authErrBadCredential,
}
for name, msg := range consts {
assertKoreanError(t, name, msg)
}
}