fix(t231): expose freight preflight errors
This commit is contained in:
@@ -845,6 +845,18 @@ func writeUsecaseError(ctx *gin.Context, err error) {
|
||||
case usecase.ErrorKindUnavailable:
|
||||
status = http.StatusServiceUnavailable
|
||||
}
|
||||
switch typed.Code {
|
||||
case "ERP_NOT_CONFIGURED", "ERP_LOGIN_REJECTED":
|
||||
status = http.StatusUnprocessableEntity
|
||||
case "ERP_RESPONSE_INVALID":
|
||||
status = http.StatusBadGateway
|
||||
case "OCR_SERVICE_INVALID", "ERP_UNAVAILABLE":
|
||||
status = http.StatusServiceUnavailable
|
||||
}
|
||||
message := typed.Message
|
||||
if preflightMessage, ok := freightPreflightPublicMessage(typed.Code); ok {
|
||||
message = preflightMessage
|
||||
}
|
||||
details := gin.H{}
|
||||
if len(typed.Fields) > 0 {
|
||||
details["fields"] = typed.Fields
|
||||
@@ -853,12 +865,29 @@ func writeUsecaseError(ctx *gin.Context, err error) {
|
||||
ctx,
|
||||
status,
|
||||
typed.Code,
|
||||
typed.Message,
|
||||
message,
|
||||
typed.Retryable,
|
||||
details,
|
||||
)
|
||||
}
|
||||
|
||||
func freightPreflightPublicMessage(code string) (string, bool) {
|
||||
switch code {
|
||||
case "ERP_NOT_CONFIGURED":
|
||||
return "ERP credentials are not configured", true
|
||||
case "ERP_LOGIN_REJECTED":
|
||||
return "ERP login was rejected", true
|
||||
case "ERP_RESPONSE_INVALID":
|
||||
return "ERP response is invalid", true
|
||||
case "OCR_SERVICE_INVALID":
|
||||
return "OCR service is invalid", true
|
||||
case "ERP_UNAVAILABLE":
|
||||
return "ERP is temporarily unavailable", true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func writePublicError(
|
||||
ctx *gin.Context,
|
||||
status int,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmroubao/backend-api/internal/usecase"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestWriteUsecaseErrorUsesPreflightStatusAndCode(t *testing.T) {
|
||||
testCases := []struct {
|
||||
code string
|
||||
status int
|
||||
}{
|
||||
{"ERP_NOT_CONFIGURED", http.StatusUnprocessableEntity},
|
||||
{"ERP_LOGIN_REJECTED", http.StatusUnprocessableEntity},
|
||||
{"ERP_RESPONSE_INVALID", http.StatusBadGateway},
|
||||
{"OCR_SERVICE_INVALID", http.StatusServiceUnavailable},
|
||||
{"ERP_UNAVAILABLE", http.StatusServiceUnavailable},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.code, func(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
router.GET("/test", func(ctx *gin.Context) {
|
||||
writeUsecaseError(ctx, &usecase.Error{
|
||||
Kind: usecase.ErrorKindUnavailable,
|
||||
Code: testCase.code,
|
||||
Message: "private upstream response is hidden",
|
||||
Fields: map[string]string{},
|
||||
})
|
||||
})
|
||||
response := httptest.NewRecorder()
|
||||
router.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/test", nil))
|
||||
if response.Code != testCase.status ||
|
||||
!strings.Contains(response.Body.String(), testCase.code) ||
|
||||
strings.Contains(response.Body.String(), "private upstream") {
|
||||
t.Fatalf("response = %d / %s", response.Code, response.Body)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user