fix(setup):修复系统初始化故障问题
This commit is contained in:
1 parent
3256d84c30
commit
4f749930d6
4 files changed
+163
-3
No files matched your search
@@ -2,6 +2,7 @@ package setup
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"unicode/utf8"
|
||||
|
||||
@@ -69,19 +70,19 @@ func HandleSetupInitialize(r *ghttp.Request) {
|
||||
|
||||
// Validate username format
|
||||
if utf8.RuneCountInString(req.Username) < 3 || utf8.RuneCountInString(req.Username) > 20 {
|
||||
response.ErrorMsg(r, consts.CodeSetupInvalidUsername, consts.MsgSetupInvalidUsername)
|
||||
response.ErrorWithCode(r, http.StatusUnprocessableEntity, consts.CodeSetupInvalidUsername, consts.MsgSetupInvalidUsername)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate password strength
|
||||
if err := common.ValidatePassword(req.Password); err != nil {
|
||||
response.ErrorMsg(r, consts.CodePasswordTooWeak, err.Error())
|
||||
response.ErrorWithCode(r, http.StatusUnprocessableEntity, consts.CodePasswordTooWeak, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Validate password confirmation
|
||||
if req.Password != req.ConfirmPassword {
|
||||
response.ErrorMsg(r, consts.CodeSetupPasswordMismatch, consts.MsgSetupPasswordMismatch)
|
||||
response.ErrorWithCode(r, http.StatusUnprocessableEntity, consts.CodeSetupPasswordMismatch, consts.MsgSetupPasswordMismatch)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package setup_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
|
||||
"github.com/qianfree/team-api/internal/consts"
|
||||
setuphandler "github.com/qianfree/team-api/internal/handler/setup"
|
||||
)
|
||||
|
||||
func TestHandleSetupInitializeValidationErrors(t *testing.T) {
|
||||
s := g.Server(guid.S())
|
||||
s.SetDumpRouterMap(false)
|
||||
s.BindHandler("/initialize", setuphandler.HandleSetupInitialize)
|
||||
|
||||
server := httptest.NewServer(s)
|
||||
defer server.Close()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
body string
|
||||
wantCode int
|
||||
}{
|
||||
{
|
||||
name: "invalid username",
|
||||
body: `{"username":"ab","password":"Password1","confirmPassword":"Password1"}`,
|
||||
wantCode: consts.CodeSetupInvalidUsername,
|
||||
},
|
||||
{
|
||||
name: "weak password",
|
||||
body: `{"username":"admin","password":"short","confirmPassword":"short"}`,
|
||||
wantCode: consts.CodePasswordTooWeak,
|
||||
},
|
||||
{
|
||||
name: "password mismatch",
|
||||
body: `{"username":"admin","password":"Password1","confirmPassword":"Password2"}`,
|
||||
wantCode: consts.CodeSetupPasswordMismatch,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
res, err := server.Client().Post(
|
||||
server.URL+"/initialize",
|
||||
"application/json",
|
||||
strings.NewReader(tt.body),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("POST /initialize: %v", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusUnprocessableEntity {
|
||||
t.Errorf("status = %d, want %d", res.StatusCode, http.StatusUnprocessableEntity)
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Code int `json:"code"`
|
||||
}
|
||||
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if body.Code != tt.wantCode {
|
||||
t.Errorf("code = %d, want %d", body.Code, tt.wantCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package response
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
@@ -128,6 +129,9 @@ func ErrorMsg(r *ghttp.Request, code int, message string) {
|
||||
// ErrorWithCode writes an error with separate HTTP status and business code.
|
||||
// Use this when HTTP status differs from the business code (e.g., HTTP 401 with code 10020).
|
||||
func ErrorWithCode(r *ghttp.Request, httpStatus int, code int, message string) {
|
||||
if httpStatus < 100 || httpStatus > 599 {
|
||||
httpStatus = http.StatusInternalServerError
|
||||
}
|
||||
requestID := getRequestID(r)
|
||||
r.Response.WriteHeader(httpStatus)
|
||||
r.Response.WriteJson(jsonResp{
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package response_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
|
||||
apiresponse "github.com/qianfree/team-api/internal/response"
|
||||
)
|
||||
|
||||
func TestErrorResponseStatusAndCode(t *testing.T) {
|
||||
s := g.Server(guid.S())
|
||||
s.SetDumpRouterMap(false)
|
||||
s.BindHandler("/standard", func(r *ghttp.Request) {
|
||||
apiresponse.ErrorMsg(r, http.StatusBadRequest, "bad request")
|
||||
})
|
||||
s.BindHandler("/business", func(r *ghttp.Request) {
|
||||
apiresponse.ErrorWithCode(r, http.StatusUnprocessableEntity, 10079, "invalid username")
|
||||
})
|
||||
s.BindHandler("/invalid-status", func(r *ghttp.Request) {
|
||||
apiresponse.ErrorWithCode(r, 10079, 10079, "invalid username")
|
||||
})
|
||||
|
||||
server := httptest.NewServer(s)
|
||||
defer server.Close()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
wantStatus int
|
||||
wantCode int
|
||||
}{
|
||||
{
|
||||
name: "standard HTTP error",
|
||||
path: "/standard",
|
||||
wantStatus: http.StatusBadRequest,
|
||||
wantCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "business error uses separate HTTP status",
|
||||
path: "/business",
|
||||
wantStatus: http.StatusUnprocessableEntity,
|
||||
wantCode: 10079,
|
||||
},
|
||||
{
|
||||
name: "invalid HTTP status falls back to internal error",
|
||||
path: "/invalid-status",
|
||||
wantStatus: http.StatusInternalServerError,
|
||||
wantCode: 10079,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
res, err := server.Client().Get(server.URL + tt.path)
|
||||
if err != nil {
|
||||
t.Fatalf("GET %s: %v", tt.path, err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != tt.wantStatus {
|
||||
t.Errorf("status = %d, want %d", res.StatusCode, tt.wantStatus)
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Code int `json:"code"`
|
||||
}
|
||||
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if body.Code != tt.wantCode {
|
||||
t.Errorf("code = %d, want %d", body.Code, tt.wantCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user