refactor(core): 任务与模型协议治理 - 拆分服务职责并禁止已发起任务取消
This commit is contained in:
74
backend/internal/handler/response_test.go
Normal file
74
backend/internal/handler/response_test.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"infinite-canvas/backend/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type failureEnvelope struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func TestFailServiceProjectsAppError(t *testing.T) {
|
||||
recorder, context := responseTestContext()
|
||||
err := service.NewAppError(http.StatusTooManyRequests, "请求过于频繁,请稍后重试")
|
||||
err.Code = 42901
|
||||
|
||||
failService(context, err)
|
||||
|
||||
response := decodeFailureEnvelope(t, recorder)
|
||||
if recorder.Code != http.StatusTooManyRequests || response.Code != 42901 || response.Msg != err.Message {
|
||||
t.Fatalf("response = status %d, body %#v", recorder.Code, response)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFailServiceHidesUnclassifiedInternalError(t *testing.T) {
|
||||
recorder, context := responseTestContext()
|
||||
failService(context, errors.New("database password=secret"))
|
||||
|
||||
response := decodeFailureEnvelope(t, recorder)
|
||||
if recorder.Code != http.StatusInternalServerError || response.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("response = status %d, body %#v", recorder.Code, response)
|
||||
}
|
||||
if response.Msg != internalErrorMessage || strings.Contains(recorder.Body.String(), "password=secret") {
|
||||
t.Fatalf("internal error leaked in response: %s", recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestFailInternalKeepsStatusWithoutLeakingCause(t *testing.T) {
|
||||
recorder, context := responseTestContext()
|
||||
failInternal(context, http.StatusServiceUnavailable, errors.New("redis://user:password@private-host"))
|
||||
|
||||
response := decodeFailureEnvelope(t, recorder)
|
||||
if recorder.Code != http.StatusServiceUnavailable || response.Msg != "服务暂时不可用,请稍后重试" {
|
||||
t.Fatalf("response = status %d, body %#v", recorder.Code, response)
|
||||
}
|
||||
if strings.Contains(recorder.Body.String(), "private-host") {
|
||||
t.Fatalf("internal cause leaked in response: %s", recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func responseTestContext() (*httptest.ResponseRecorder, *gin.Context) {
|
||||
recorder := httptest.NewRecorder()
|
||||
context, _ := gin.CreateTestContext(recorder)
|
||||
context.Request = httptest.NewRequest(http.MethodGet, "/api/test", nil)
|
||||
return recorder, context
|
||||
}
|
||||
|
||||
func decodeFailureEnvelope(t *testing.T, recorder *httptest.ResponseRecorder) failureEnvelope {
|
||||
t.Helper()
|
||||
var response failureEnvelope
|
||||
if err := json.Unmarshal(recorder.Body.Bytes(), &response); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
return response
|
||||
}
|
||||
Reference in New Issue
Block a user