package pub import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "perms-system-server/internal/response" "perms-system-server/internal/svc" "perms-system-server/internal/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // TC-0800: handler 薄层契约 —— RefreshTokenHandler 在 Authorization header 缺失时, // 必须把错误透传成 401 "未登录" / 或等价业务错误 (绝不能 200 或 5xx)。 // 同时不应把内部实现细节泄露到 Msg 里。 func TestRefreshTokenHandler_MissingAuthorizationHeader(t *testing.T) { svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) handler := RefreshTokenHandler(svcCtx) req := httptest.NewRequest(http.MethodPost, "/api/auth/refreshToken", strings.NewReader("{}")) req.Header.Set("Content-Type", "application/json") rr := httptest.NewRecorder() handler.ServeHTTP(rr, req) var body response.Body require.NoError(t, json.Unmarshal(rr.Body.Bytes(), &body)) assert.NotEqual(t, 200, body.ErrorCode, "缺 Authorization 必须报错而非 200") assert.True(t, body.ErrorCode == 401 || body.ErrorCode == 400, "缺 Authorization 必须是 401/400; 实际 code=%d msg=%q", body.ErrorCode, body.ErrorMessage) assert.NotContains(t, strings.ToLower(body.ErrorMessage), "sql", "错误文案不得泄露 SQL 实现细节") assert.NotContains(t, strings.ToLower(body.ErrorMessage), "redis", "错误文案不得泄露 Redis 实现细节") } // TC-0801: handler 薄层契约 —— RefreshTokenHandler 在 Authorization 带非法值时 401, 且不 panic。 func TestRefreshTokenHandler_GarbageBearerToken(t *testing.T) { svcCtx := svc.NewServiceContext(testutil.GetTestConfig()) handler := RefreshTokenHandler(svcCtx) req := httptest.NewRequest(http.MethodPost, "/api/auth/refreshToken", strings.NewReader("{}")) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer garbage.token.value") rr := httptest.NewRecorder() handler.ServeHTTP(rr, req) var body response.Body require.NoError(t, json.Unmarshal(rr.Body.Bytes(), &body)) assert.False(t, body.Success) assert.Equal(t, 401, body.ErrorCode, "非法 refresh token 必须 401, 而不是 500 panic 或 200; 实际 code=%d msg=%q", body.ErrorCode, body.ErrorMessage) }