Files
llama-swap/internal/server/auth_test.go
T
Benson Wong 62aea0e83d internal/router,server,shared: refactor auth, libs (#839)
- refactor shared http functionality into internal/shared/http.go
- remove stripping of Authorization and x-api-key
- add Request Context middleware to internal/server
- add /ui and /metrics behind auth middleware, fixes #717

Fix #717
Updates: #834
2026-06-13 10:19:04 -07:00

118 lines
3.1 KiB
Go

package server
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/mostlygeek/llama-swap/internal/config"
)
func TestServer_SanitizeAccessControlRequestHeaders(t *testing.T) {
cases := []struct {
in string
want string
}{
{"Content-Type, Authorization", "Content-Type, Authorization"},
{" X-Custom , Accept ", "X-Custom, Accept"},
{"Valid, Bad Header", "Valid"},
{"Bad@Header", ""},
{"", ""},
}
for _, c := range cases {
if got := sanitizeAccessControlRequestHeaderValues(c.in); got != c.want {
t.Errorf("sanitize(%q) = %q, want %q", c.in, got, c.want)
}
}
}
func TestServer_IsTokenChar(t *testing.T) {
for _, r := range "abcXYZ0129!#$%&'*+-.^_`|~" {
if !isTokenChar(r) {
t.Errorf("isTokenChar(%q) = false, want true", r)
}
}
for _, r := range " @()/\t\"" {
if isTokenChar(r) {
t.Errorf("isTokenChar(%q) = true, want false", r)
}
}
}
func TestServer_RequestContextMiddleware(t *testing.T) {
cfg := config.Config{
Models: map[string]config.ModelConfig{
"llama3": {},
},
}
final := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
mw := CreateRequestContextMiddleware(cfg)
t.Run("known model passes through", func(t *testing.T) {
r := httptest.NewRequest(http.MethodPost, "/v1/chat/completions", strings.NewReader(`{"model":"llama3"}`))
r.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
mw(final).ServeHTTP(w, r)
if w.Code != http.StatusOK {
t.Errorf("status = %d, want 200", w.Code)
}
})
t.Run("missing model returns 404", func(t *testing.T) {
r := httptest.NewRequest(http.MethodPost, "/v1/chat/completions", strings.NewReader(`{}`))
r.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
mw(final).ServeHTTP(w, r)
if w.Code != http.StatusNotFound {
t.Errorf("status = %d, want 404", w.Code)
}
})
}
func TestServer_AuthMiddleware(t *testing.T) {
final := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
t.Run("no keys configured passes through", func(t *testing.T) {
mw := CreateAuthMiddleware(config.Config{})
w := httptest.NewRecorder()
mw(final).ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/", nil))
if w.Code != http.StatusOK {
t.Errorf("status = %d, want 200", w.Code)
}
})
cfg := config.Config{RequiredAPIKeys: []string{"secret"}}
t.Run("valid key", func(t *testing.T) {
mw := CreateAuthMiddleware(cfg)
r := httptest.NewRequest(http.MethodGet, "/", nil)
r.Header.Set("Authorization", "Bearer secret")
w := httptest.NewRecorder()
mw(final).ServeHTTP(w, r)
if w.Code != http.StatusOK {
t.Errorf("status = %d, want 200", w.Code)
}
})
t.Run("invalid key", func(t *testing.T) {
mw := CreateAuthMiddleware(cfg)
r := httptest.NewRequest(http.MethodGet, "/", nil)
r.Header.Set("Authorization", "Bearer wrong")
w := httptest.NewRecorder()
mw(final).ServeHTTP(w, r)
if w.Code != http.StatusUnauthorized {
t.Errorf("status = %d, want 401", w.Code)
}
if w.Header().Get("WWW-Authenticate") == "" {
t.Error("missing WWW-Authenticate header")
}
})
}