fetch_ml/tests/unit/auth/api_key_test.go
Jeremie Fraeys c980167041 test: implement comprehensive test suite with multiple test types
- Add end-to-end tests for complete workflow validation
- Include integration tests for API and database interactions
- Add unit tests for all major components and utilities
- Include performance tests for payload handling
- Add CLI API integration tests
- Include Podman container integration tests
- Add WebSocket and queue execution tests
- Include shell script tests for setup validation

Provides comprehensive test coverage ensuring platform reliability
and functionality across all components and interactions.
2025-12-04 16:55:13 -05:00

185 lines
4.1 KiB
Go

package auth
import (
"testing"
"github.com/jfraeys/fetch_ml/internal/auth"
)
func TestGenerateAPIKey(t *testing.T) {
t.Parallel() // Enable parallel execution
key1 := auth.GenerateAPIKey()
if len(key1) != 64 { // 32 bytes = 64 hex chars
t.Errorf("Expected key length 64, got %d", len(key1))
}
// Test uniqueness
key2 := auth.GenerateAPIKey()
if key1 == key2 {
t.Error("Generated keys should be unique")
}
}
func TestHashAPIKey(t *testing.T) {
t.Parallel() // Enable parallel execution
key := "test-key-123"
hash := auth.HashAPIKey(key)
if len(hash) != 64 { // SHA256 = 64 hex chars
t.Errorf("Expected hash length 64, got %d", len(hash))
}
// Test consistency
hash2 := auth.HashAPIKey(key)
if hash != hash2 {
t.Error("Hash should be consistent for same key")
}
// Test different keys produce different hashes
hash3 := auth.HashAPIKey("different-key")
if hash == hash3 {
t.Error("Different keys should produce different hashes")
}
}
func TestValidateAPIKey(t *testing.T) {
t.Parallel() // Enable parallel execution
config := auth.AuthConfig{
Enabled: true,
APIKeys: map[auth.Username]auth.APIKeyEntry{
"admin": {
Hash: auth.APIKeyHash(auth.HashAPIKey("admin-key")),
Admin: true,
},
"data_scientist": {
Hash: auth.APIKeyHash(auth.HashAPIKey("ds-key")),
Admin: false,
},
},
}
tests := []struct {
name string
apiKey string
wantErr bool
wantUser string
wantAdmin bool
}{
{
name: "valid admin key",
apiKey: "admin-key",
wantErr: false,
wantUser: "admin",
wantAdmin: true,
},
{
name: "valid user key",
apiKey: "ds-key",
wantErr: false,
wantUser: "data_scientist",
wantAdmin: false,
},
{
name: "invalid key",
apiKey: "wrong-key",
wantErr: true,
},
{
name: "empty key",
apiKey: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
user, err := config.ValidateAPIKey(tt.apiKey)
if tt.wantErr {
if err == nil {
t.Error("Expected error but got none")
}
return
}
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
if user.Name != tt.wantUser {
t.Errorf("Expected user %s, got %s", tt.wantUser, user.Name)
}
if user.Admin != tt.wantAdmin {
t.Errorf("Expected admin %v, got %v", tt.wantAdmin, user.Admin)
}
})
}
}
func TestValidateAPIKeyAuthDisabled(t *testing.T) {
t.Setenv("FETCH_ML_ALLOW_INSECURE_AUTH", "1")
defer t.Setenv("FETCH_ML_ALLOW_INSECURE_AUTH", "")
config := auth.AuthConfig{
Enabled: false,
APIKeys: map[auth.Username]auth.APIKeyEntry{}, // Empty
}
user, err := config.ValidateAPIKey("any-key")
if err != nil {
t.Errorf("Unexpected error when auth disabled: %v", err)
}
if user == nil {
t.Fatal("Expected user, got nil")
}
if user.Name != "default" {
t.Errorf("Expected default user, got %s", user.Name)
}
if !user.Admin {
t.Error("Default user should be admin")
}
}
func TestAdminDetection(t *testing.T) {
t.Parallel() // Enable parallel execution
config := auth.AuthConfig{
Enabled: true,
APIKeys: map[auth.Username]auth.APIKeyEntry{
"admin": {Hash: auth.APIKeyHash(auth.HashAPIKey("key1")), Admin: true},
"admin_user": {Hash: auth.APIKeyHash(auth.HashAPIKey("key2")), Admin: true},
"superadmin": {Hash: auth.APIKeyHash(auth.HashAPIKey("key3")), Admin: true},
"regular": {Hash: auth.APIKeyHash(auth.HashAPIKey("key4")), Admin: false},
"user_admin": {Hash: auth.APIKeyHash(auth.HashAPIKey("key5")), Admin: false},
},
}
tests := []struct {
apiKey string
expected bool
}{
{"key1", true}, // admin
{"key2", true}, // admin_user
{"key3", true}, // superadmin
{"key4", false}, // regular
{"key5", false}, // user_admin (not admin based on explicit flag)
}
for _, tt := range tests {
t.Run(tt.apiKey, func(t *testing.T) {
user, err := config.ValidateAPIKey(tt.apiKey)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if user.Admin != tt.expected {
t.Errorf("Expected admin=%v for key %s, got %v", tt.expected, tt.apiKey, user.Admin)
}
})
}
}