Files
omnex/control-plane/api/internal/test/helpers_test.go
T
Nuxgrid 6b4274d12b
docker-publish / publish (push) Failing after 14m14s
feat: add api
2026-07-27 16:06:19 +02:00

112 lines
3.4 KiB
Go

// 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
}