veza/veza-backend-api/internal/api/versioning_test.go
senke ef400ce6f1 api-versioning: add X-API-Deprecated header and frontend deprecation warning
- Backend: Add X-API-Deprecated header alongside existing X-API-Version-Deprecated
- Frontend: Show deprecation warning toast when deprecated API version detected
- Warning shown only once per session to avoid spam
- Includes sunset date in warning message if available
2026-01-15 16:56:21 +01:00

209 lines
4.9 KiB
Go

package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
)
func TestNewVersionManager(t *testing.T) {
logger, _ := zap.NewDevelopment()
vm := NewVersionManager(logger)
assert.NotNil(t, vm)
assert.Equal(t, DefaultAPIVersion, vm.GetDefaultVersion())
assert.NotEmpty(t, vm.GetAllVersions())
}
func TestVersionManager_RegisterVersion(t *testing.T) {
logger, _ := zap.NewDevelopment()
vm := NewVersionManager(logger)
version := &APIVersion{
Version: "v2",
Deprecated: false,
Description: "New API version",
}
vm.RegisterVersion(version)
retrieved, exists := vm.GetVersion("v2")
require.True(t, exists)
assert.Equal(t, version, retrieved)
}
func TestVersionManager_GetVersion_NotFound(t *testing.T) {
logger, _ := zap.NewDevelopment()
vm := NewVersionManager(logger)
_, exists := vm.GetVersion("v99")
assert.False(t, exists)
}
func TestNormalizeVersion(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"v1", "v1"},
{"1", "v1"},
{"V1", "v1"},
{" v2 ", "v2"},
{"2", "v2"},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
result := normalizeVersion(tt.input)
assert.Equal(t, tt.expected, result)
})
}
}
func TestParseAcceptHeader(t *testing.T) {
tests := []struct {
name string
accept string
expected string
}{
{
name: "vnd.veza.v1",
accept: "application/vnd.veza.v1+json",
expected: "v1",
},
{
name: "vnd.veza.v2",
accept: "application/vnd.veza.v2+json",
expected: "v2",
},
{
name: "multiple accept types",
accept: "application/json, application/vnd.veza.v1+json",
expected: "v1",
},
{
name: "no version",
accept: "application/json",
expected: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := parseAcceptHeader(tt.accept)
assert.Equal(t, tt.expected, result)
})
}
}
func TestVersionMiddleware_HeaderXAPIVersion(t *testing.T) {
gin.SetMode(gin.TestMode)
logger, _ := zap.NewDevelopment()
vm := NewVersionManager(logger)
router := gin.New()
router.Use(VersionMiddleware(vm))
router.GET("/test", func(c *gin.Context) {
version := GetAPIVersion(c)
c.JSON(200, gin.H{"version": version})
})
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/test", nil)
req.Header.Set(APIVersionHeader, "v1")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "v1", w.Header().Get(APIVersionHeader))
}
func TestVersionMiddleware_AcceptHeader(t *testing.T) {
gin.SetMode(gin.TestMode)
logger, _ := zap.NewDevelopment()
vm := NewVersionManager(logger)
router := gin.New()
router.Use(VersionMiddleware(vm))
router.GET("/test", func(c *gin.Context) {
version := GetAPIVersion(c)
c.JSON(200, gin.H{"version": version})
})
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/test", nil)
req.Header.Set(AcceptHeaderVersion, "application/vnd.veza.v1+json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestVersionMiddleware_InvalidVersion(t *testing.T) {
gin.SetMode(gin.TestMode)
logger, _ := zap.NewDevelopment()
vm := NewVersionManager(logger)
router := gin.New()
router.Use(VersionMiddleware(vm))
router.GET("/test", func(c *gin.Context) {
c.JSON(200, gin.H{"ok": true})
})
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/test", nil)
req.Header.Set(APIVersionHeader, "v99")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestVersionMiddleware_DeprecatedVersion(t *testing.T) {
gin.SetMode(gin.TestMode)
logger, _ := zap.NewDevelopment()
vm := NewVersionManager(logger)
// Enregistrer une version dépréciée
vm.RegisterVersion(&APIVersion{
Version: "v0",
Deprecated: true,
SunsetDate: "2025-12-31T00:00:00Z",
Description: "Deprecated version",
})
router := gin.New()
router.Use(VersionMiddleware(vm))
router.GET("/test", func(c *gin.Context) {
c.JSON(200, gin.H{"ok": true})
})
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/test", nil)
req.Header.Set(APIVersionHeader, "v0")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "true", w.Header().Get("X-API-Deprecated"))
assert.Equal(t, "true", w.Header().Get("X-API-Version-Deprecated"))
assert.Equal(t, "2025-12-31T00:00:00Z", w.Header().Get("Sunset"))
}
func TestVersionInfoHandler(t *testing.T) {
gin.SetMode(gin.TestMode)
logger, _ := zap.NewDevelopment()
vm := NewVersionManager(logger)
router := gin.New()
router.GET("/api/versions", VersionInfoHandler(vm))
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/api/versions", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "current_version")
assert.Contains(t, w.Body.String(), "versions")
}