Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
93 lines
3.2 KiB
Go
93 lines
3.2 KiB
Go
package handler
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/Tencent/WeKnora/internal/config"
|
|
"github.com/Tencent/WeKnora/internal/types"
|
|
"github.com/Tencent/WeKnora/internal/types/interfaces"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type usernameLoginService struct {
|
|
interfaces.UserService
|
|
received *types.LoginRequest
|
|
}
|
|
|
|
func (s *usernameLoginService) Login(_ context.Context, req *types.LoginRequest) (*types.LoginResponse, error) {
|
|
s.received = req
|
|
return &types.LoginResponse{Success: true, User: &types.User{ID: "test-user"}, Token: "test-token"}, nil
|
|
}
|
|
|
|
func TestLoginAcceptsUsernameAndLegacyEmailRequests(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
body map[string]string
|
|
status int
|
|
}{
|
|
{"username without email", map[string]string{"username": "alice", "password": "123"}, http.StatusOK},
|
|
{"trim username", map[string]string{"username": " alice ", "password": "123"}, http.StatusOK},
|
|
{"Unicode password", map[string]string{"username": "alice", "password": "三个字"}, http.StatusOK},
|
|
{"legacy email", map[string]string{"email": "alice@example.com", "password": "123"}, http.StatusOK},
|
|
{"missing identifier", map[string]string{"password": "123"}, http.StatusBadRequest},
|
|
{"blank identifier", map[string]string{"username": " ", "password": "123"}, http.StatusBadRequest},
|
|
{"missing password", map[string]string{"username": "alice"}, http.StatusBadRequest},
|
|
}
|
|
gin.SetMode(gin.TestMode)
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
svc := &usernameLoginService{}
|
|
h := &AuthHandler{userService: svc}
|
|
r := gin.New()
|
|
r.Use(errorCapture())
|
|
r.POST("/auth/login", h.Login)
|
|
payload, err := json.Marshal(tc.body)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
req := httptest.NewRequest(http.MethodPost, "/auth/login", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
response := httptest.NewRecorder()
|
|
r.ServeHTTP(response, req)
|
|
if response.Code != tc.status {
|
|
t.Fatalf("status=%d body=%s, want %d", response.Code, response.Body, tc.status)
|
|
}
|
|
if tc.status != http.StatusOK {
|
|
if svc.received != nil {
|
|
t.Fatal("invalid input reached the login service")
|
|
}
|
|
return
|
|
}
|
|
if svc.received == nil || svc.received.Password != tc.body["password"] {
|
|
t.Fatalf("password changed before authentication: %+v", svc.received)
|
|
}
|
|
if tc.body["username"] != "" && svc.received.Username != "alice" {
|
|
t.Fatalf("username=%q, want alice", svc.received.Username)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRegisterAcceptsThreeCharacterPassword(t *testing.T) {
|
|
called := false
|
|
svc := &stubRegisterUserService{register: func(_ context.Context, req *types.RegisterRequest) (*types.User, error) {
|
|
called = true
|
|
if req.Password != "123" {
|
|
t.Fatalf("password=%q", req.Password)
|
|
}
|
|
return &types.User{ID: "created-user"}, nil
|
|
}}
|
|
h := &AuthHandler{userService: svc, configInfo: &config.Config{Auth: &config.AuthConfig{}}}
|
|
body := validRegisterBody()
|
|
body["password"] = "123"
|
|
response := doRegister(t, newRegisterTestRouter(h), body)
|
|
if response.Code != http.StatusCreated || !called {
|
|
t.Fatalf("status=%d body=%s service_called=%v", response.Code, response.Body, called)
|
|
}
|
|
}
|