@@ -0,0 +1,111 @@
|
||||
// Package apitest regroupe les tests unitaires et de sécurité de l'API Omnex
|
||||
// (tests en boîte noire, isolés du code de production dans un dossier dédié).
|
||||
package apitest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/omnex/control-plane/api/internal/auth"
|
||||
"github.com/omnex/control-plane/api/internal/config"
|
||||
"github.com/omnex/control-plane/api/internal/demos"
|
||||
"github.com/omnex/control-plane/api/internal/leads"
|
||||
"github.com/omnex/control-plane/api/internal/router"
|
||||
"github.com/omnex/control-plane/api/internal/session"
|
||||
)
|
||||
|
||||
const testSecret = "01234567890123456789012345678901"
|
||||
|
||||
// seedUsers : UserStore mémoire pour les tests.
|
||||
type seedUsers map[string]auth.User
|
||||
|
||||
func (m seedUsers) ByUsername(username string) (auth.User, bool) { u, ok := m[username]; return u, ok }
|
||||
|
||||
func (m seedUsers) Create(username, passwordHash string, role auth.Role) (auth.User, error) {
|
||||
u := auth.User{ID: "u-" + username, Username: username, PasswordHash: passwordHash, Role: role}
|
||||
m[username] = u
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// testEnv : dépendances assemblées pour un test HTTP.
|
||||
type testEnv struct {
|
||||
engine *gin.Engine
|
||||
issuer *auth.Issuer
|
||||
sessions session.Manager
|
||||
}
|
||||
|
||||
func newTestEnv(t *testing.T) testEnv {
|
||||
return newTestEnvOpts(t)
|
||||
}
|
||||
|
||||
// newTestEnvOpts permet de configurer un code d'inscription.
|
||||
func newTestEnvOpts(t *testing.T) testEnv {
|
||||
t.Helper()
|
||||
gin.SetMode(gin.TestMode)
|
||||
iss := auth.NewIssuer([]byte(testSecret), time.Minute)
|
||||
sessions := session.NewMemManager(time.Hour)
|
||||
|
||||
hash, _ := auth.HashPassword("correct-horse")
|
||||
users := seedUsers{"sales": {ID: "u1", Username: "sales", PasswordHash: hash, Role: auth.RoleClient}}
|
||||
|
||||
demoSvc := demos.NewService(demos.NewMemStore(), demos.NewMemPool(), demos.NoopProvisioner{}, demos.Config{})
|
||||
|
||||
deps := router.Deps{
|
||||
Cfg: config.Config{Env: "test", AllowedOrigins: []string{"http://localhost:5173"}},
|
||||
Issuer: iss,
|
||||
Sessions: sessions,
|
||||
AuthH: auth.NewHandler(users, sessions, iss, false),
|
||||
LeadsH: leads.NewHandler(leads.NewMemStore()),
|
||||
DemosH: demos.NewHandler(demoSvc),
|
||||
}
|
||||
return testEnv{engine: router.New(deps), issuer: iss, sessions: sessions}
|
||||
}
|
||||
|
||||
// token : JWT commercial (rôle sales) adossé à une vraie session Redis(mem).
|
||||
func (e testEnv) token(t *testing.T) string { return e.tokenAs(t, auth.RoleClient) }
|
||||
|
||||
// adminToken : JWT administrateur.
|
||||
func (e testEnv) adminToken(t *testing.T) string { return e.tokenAs(t, auth.RoleAdmin) }
|
||||
|
||||
func (e testEnv) tokenAs(t *testing.T, role auth.Role) string {
|
||||
t.Helper()
|
||||
sid, err := e.sessions.Create(context.Background(), session.Session{UserID: "u1", Role: string(role)})
|
||||
if err != nil {
|
||||
t.Fatalf("create session: %v", err)
|
||||
}
|
||||
tok, err := e.issuer.Issue("u1", role, sid)
|
||||
if err != nil {
|
||||
t.Fatalf("issue token: %v", err)
|
||||
}
|
||||
return tok
|
||||
}
|
||||
|
||||
func (e testEnv) do(method, path, token string, body any) *httptest.ResponseRecorder {
|
||||
var buf bytes.Buffer
|
||||
if body != nil {
|
||||
_ = json.NewEncoder(&buf).Encode(body)
|
||||
}
|
||||
req := httptest.NewRequest(method, path, &buf)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
if token != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
e.engine.ServeHTTP(w, req)
|
||||
return w
|
||||
}
|
||||
|
||||
func decode[T any](t *testing.T, w *httptest.ResponseRecorder) T {
|
||||
t.Helper()
|
||||
var v T
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &v); err != nil {
|
||||
t.Fatalf("decode: %v — body=%s", err, w.Body)
|
||||
}
|
||||
return v
|
||||
}
|
||||
Reference in New Issue
Block a user