mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-14 04:07:46 +00:00
725 lines
20 KiB
Go
725 lines
20 KiB
Go
package providers
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNewGoogleProvider(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
|
|
if provider == nil {
|
|
t.Fatal("expected non-nil Google provider")
|
|
}
|
|
|
|
if provider.BaseProvider == nil {
|
|
t.Fatal("expected non-nil BaseProvider")
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_GetType(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
providerType := provider.GetType()
|
|
|
|
if providerType != ProviderTypeGoogle {
|
|
t.Errorf("expected provider type %d, got %d", ProviderTypeGoogle, providerType)
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_GetCapabilities(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
capabilities := provider.GetCapabilities()
|
|
|
|
expectedCapabilities := ProviderCapabilities{
|
|
SupportsRefreshTokens: true,
|
|
RequiresOfflineAccessScope: false,
|
|
RequiresPromptConsent: true,
|
|
PreferredTokenValidation: "id",
|
|
}
|
|
|
|
if capabilities.SupportsRefreshTokens != expectedCapabilities.SupportsRefreshTokens {
|
|
t.Errorf("expected SupportsRefreshTokens %t, got %t", expectedCapabilities.SupportsRefreshTokens, capabilities.SupportsRefreshTokens)
|
|
}
|
|
|
|
if capabilities.RequiresOfflineAccessScope != expectedCapabilities.RequiresOfflineAccessScope {
|
|
t.Errorf("expected RequiresOfflineAccessScope %t, got %t", expectedCapabilities.RequiresOfflineAccessScope, capabilities.RequiresOfflineAccessScope)
|
|
}
|
|
|
|
if capabilities.RequiresPromptConsent != expectedCapabilities.RequiresPromptConsent {
|
|
t.Errorf("expected RequiresPromptConsent %t, got %t", expectedCapabilities.RequiresPromptConsent, capabilities.RequiresPromptConsent)
|
|
}
|
|
|
|
if capabilities.PreferredTokenValidation != expectedCapabilities.PreferredTokenValidation {
|
|
t.Errorf("expected PreferredTokenValidation %q, got %q", expectedCapabilities.PreferredTokenValidation, capabilities.PreferredTokenValidation)
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_BuildAuthParams(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
|
|
tests := []struct {
|
|
name string
|
|
baseParams url.Values
|
|
scopes []string
|
|
expectAccessTypeOffline bool
|
|
expectPromptConsent bool
|
|
expectOfflineAccessRemoved bool
|
|
}{
|
|
{
|
|
name: "basic params with offline_access scope",
|
|
baseParams: url.Values{"client_id": []string{"test-client"}},
|
|
scopes: []string{"openid", "offline_access", "email"},
|
|
expectAccessTypeOffline: true,
|
|
expectPromptConsent: true,
|
|
expectOfflineAccessRemoved: true,
|
|
},
|
|
{
|
|
name: "basic params without offline_access scope",
|
|
baseParams: url.Values{"client_id": []string{"test-client"}},
|
|
scopes: []string{"openid", "email"},
|
|
expectAccessTypeOffline: true,
|
|
expectPromptConsent: true,
|
|
expectOfflineAccessRemoved: false,
|
|
},
|
|
{
|
|
name: "empty scopes",
|
|
baseParams: url.Values{},
|
|
scopes: []string{},
|
|
expectAccessTypeOffline: true,
|
|
expectPromptConsent: true,
|
|
expectOfflineAccessRemoved: false,
|
|
},
|
|
{
|
|
name: "multiple offline_access scopes",
|
|
baseParams: url.Values{},
|
|
scopes: []string{"openid", "offline_access", "email", "offline_access"},
|
|
expectAccessTypeOffline: true,
|
|
expectPromptConsent: true,
|
|
expectOfflineAccessRemoved: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
authParams, err := provider.BuildAuthParams(tt.baseParams, tt.scopes)
|
|
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
return
|
|
}
|
|
|
|
if authParams == nil {
|
|
t.Fatal("expected non-nil auth params")
|
|
}
|
|
|
|
// Check access_type is set to offline
|
|
if tt.expectAccessTypeOffline {
|
|
accessType := authParams.URLValues.Get("access_type")
|
|
if accessType != "offline" {
|
|
t.Errorf("expected access_type 'offline', got %q", accessType)
|
|
}
|
|
}
|
|
|
|
// Check prompt is set to consent
|
|
if tt.expectPromptConsent {
|
|
prompt := authParams.URLValues.Get("prompt")
|
|
if prompt != "consent" {
|
|
t.Errorf("expected prompt 'consent', got %q", prompt)
|
|
}
|
|
}
|
|
|
|
// Check offline_access scope is filtered out
|
|
if tt.expectOfflineAccessRemoved {
|
|
hasOfflineAccess := false
|
|
for _, scope := range authParams.Scopes {
|
|
if scope == "offline_access" {
|
|
hasOfflineAccess = true
|
|
break
|
|
}
|
|
}
|
|
if hasOfflineAccess {
|
|
t.Error("expected offline_access scope to be removed for Google provider")
|
|
}
|
|
}
|
|
|
|
// Verify other scopes are preserved (except offline_access)
|
|
expectedScopes := make([]string, 0, len(tt.scopes))
|
|
for _, scope := range tt.scopes {
|
|
if scope != "offline_access" {
|
|
expectedScopes = append(expectedScopes, scope)
|
|
}
|
|
}
|
|
|
|
if len(authParams.Scopes) != len(expectedScopes) {
|
|
t.Errorf("expected %d scopes after filtering, got %d", len(expectedScopes), len(authParams.Scopes))
|
|
}
|
|
|
|
// Verify other parameters are preserved
|
|
for key, values := range tt.baseParams {
|
|
if key == "access_type" || key == "prompt" {
|
|
continue // These get overridden
|
|
}
|
|
paramValues := authParams.URLValues[key]
|
|
if len(paramValues) != len(values) {
|
|
t.Errorf("expected %d values for param %s, got %d", len(values), key, len(paramValues))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_ValidateTokens(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
|
|
tests := []struct {
|
|
name string
|
|
session *mockSession
|
|
verifier *mockTokenVerifier
|
|
cache *mockTokenCache
|
|
refreshGracePeriod time.Duration
|
|
expectedResult *ValidationResult
|
|
expectError bool
|
|
}{
|
|
{
|
|
name: "unauthenticated with refresh token",
|
|
session: &mockSession{
|
|
authenticated: false,
|
|
refreshToken: "refresh-token",
|
|
},
|
|
verifier: &mockTokenVerifier{},
|
|
cache: &mockTokenCache{},
|
|
expectedResult: &ValidationResult{
|
|
NeedsRefresh: true,
|
|
},
|
|
},
|
|
{
|
|
name: "unauthenticated without refresh token",
|
|
session: &mockSession{
|
|
authenticated: false,
|
|
},
|
|
verifier: &mockTokenVerifier{},
|
|
cache: &mockTokenCache{},
|
|
expectedResult: &ValidationResult{},
|
|
},
|
|
{
|
|
name: "authenticated with valid ID token",
|
|
session: &mockSession{
|
|
authenticated: true,
|
|
accessToken: "access-token",
|
|
idToken: "id.token.here",
|
|
},
|
|
verifier: &mockTokenVerifier{},
|
|
cache: &mockTokenCache{
|
|
data: map[string]map[string]interface{}{
|
|
"id.token.here": {
|
|
"exp": float64(time.Now().Add(time.Hour).Unix()),
|
|
},
|
|
},
|
|
},
|
|
expectedResult: &ValidationResult{
|
|
Authenticated: true,
|
|
},
|
|
},
|
|
{
|
|
name: "authenticated with expired ID token and refresh token",
|
|
session: &mockSession{
|
|
authenticated: true,
|
|
accessToken: "access-token",
|
|
idToken: "expired.token.here",
|
|
refreshToken: "refresh-token",
|
|
},
|
|
verifier: &mockTokenVerifier{
|
|
expiredTokens: map[string]bool{
|
|
"expired.token.here": true,
|
|
},
|
|
},
|
|
cache: &mockTokenCache{},
|
|
expectedResult: &ValidationResult{
|
|
NeedsRefresh: true,
|
|
},
|
|
},
|
|
{
|
|
name: "authenticated with no ID token but has access token and refresh token",
|
|
session: &mockSession{
|
|
authenticated: true,
|
|
accessToken: "access-token",
|
|
refreshToken: "refresh-token",
|
|
},
|
|
verifier: &mockTokenVerifier{},
|
|
cache: &mockTokenCache{},
|
|
expectedResult: &ValidationResult{
|
|
Authenticated: true,
|
|
NeedsRefresh: true,
|
|
},
|
|
},
|
|
{
|
|
name: "authenticated with no tokens but has refresh token",
|
|
session: &mockSession{
|
|
authenticated: true,
|
|
refreshToken: "refresh-token",
|
|
},
|
|
verifier: &mockTokenVerifier{},
|
|
cache: &mockTokenCache{},
|
|
expectedResult: &ValidationResult{
|
|
NeedsRefresh: true,
|
|
},
|
|
},
|
|
{
|
|
name: "authenticated with no tokens and no refresh token",
|
|
session: &mockSession{
|
|
authenticated: true,
|
|
},
|
|
verifier: &mockTokenVerifier{},
|
|
cache: &mockTokenCache{},
|
|
expectedResult: &ValidationResult{
|
|
IsExpired: true,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result, err := provider.ValidateTokens(tt.session, tt.verifier, tt.cache, tt.refreshGracePeriod)
|
|
|
|
if tt.expectError {
|
|
if err == nil {
|
|
t.Error("expected error but got none")
|
|
}
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
return
|
|
}
|
|
|
|
if result == nil {
|
|
t.Fatal("expected non-nil result")
|
|
}
|
|
|
|
if result.Authenticated != tt.expectedResult.Authenticated {
|
|
t.Errorf("expected Authenticated %t, got %t", tt.expectedResult.Authenticated, result.Authenticated)
|
|
}
|
|
|
|
if result.NeedsRefresh != tt.expectedResult.NeedsRefresh {
|
|
t.Errorf("expected NeedsRefresh %t, got %t", tt.expectedResult.NeedsRefresh, result.NeedsRefresh)
|
|
}
|
|
|
|
if result.IsExpired != tt.expectedResult.IsExpired {
|
|
t.Errorf("expected IsExpired %t, got %t", tt.expectedResult.IsExpired, result.IsExpired)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_ValidateConfig(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
|
|
// Google provider uses BaseProvider's ValidateConfig which always returns nil
|
|
err := provider.ValidateConfig()
|
|
if err != nil {
|
|
t.Errorf("unexpected error from ValidateConfig: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_HandleTokenRefresh(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
|
|
// Test that HandleTokenRefresh doesn't fail
|
|
tokenData := &TokenResult{
|
|
IDToken: "id-token",
|
|
AccessToken: "access-token",
|
|
RefreshToken: "refresh-token",
|
|
}
|
|
|
|
err := provider.HandleTokenRefresh(tokenData)
|
|
if err != nil {
|
|
t.Errorf("unexpected error from HandleTokenRefresh: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_ConcurrentAccess(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
|
|
// Track initial goroutine count for memory safety
|
|
initialGoroutines := runtime.NumGoroutine()
|
|
|
|
const numGoroutines = 50
|
|
const numOperationsPerGoroutine = 10
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(numGoroutines)
|
|
|
|
// Test concurrent access to provider methods
|
|
for i := 0; i < numGoroutines; i++ {
|
|
go func(workerID int) {
|
|
defer wg.Done()
|
|
|
|
session := &mockSession{
|
|
authenticated: true,
|
|
accessToken: fmt.Sprintf("access-token-%d", workerID),
|
|
idToken: fmt.Sprintf("id-token-%d", workerID),
|
|
refreshToken: fmt.Sprintf("refresh-token-%d", workerID),
|
|
}
|
|
|
|
verifier := &mockTokenVerifier{}
|
|
cache := &mockTokenCache{
|
|
data: map[string]map[string]interface{}{
|
|
fmt.Sprintf("id-token-%d", workerID): {
|
|
"exp": float64(time.Now().Add(time.Hour).Unix()),
|
|
},
|
|
},
|
|
}
|
|
|
|
for j := 0; j < numOperationsPerGoroutine; j++ {
|
|
// Test GetType
|
|
if provider.GetType() != ProviderTypeGoogle {
|
|
t.Errorf("worker %d: expected Google provider type", workerID)
|
|
return
|
|
}
|
|
|
|
// Test GetCapabilities
|
|
capabilities := provider.GetCapabilities()
|
|
if !capabilities.SupportsRefreshTokens {
|
|
t.Errorf("worker %d: expected refresh token support", workerID)
|
|
return
|
|
}
|
|
|
|
// Test ValidateTokens
|
|
result, err := provider.ValidateTokens(session, verifier, cache, time.Minute)
|
|
if err != nil {
|
|
t.Errorf("worker %d: unexpected error in ValidateTokens: %v", workerID, err)
|
|
return
|
|
}
|
|
if !result.Authenticated {
|
|
t.Errorf("worker %d: expected authenticated result", workerID)
|
|
return
|
|
}
|
|
|
|
// Test BuildAuthParams
|
|
baseParams := url.Values{"client_id": []string{fmt.Sprintf("client-%d", workerID)}}
|
|
scopes := []string{"openid", "email"}
|
|
authParams, err := provider.BuildAuthParams(baseParams, scopes)
|
|
if err != nil {
|
|
t.Errorf("worker %d: unexpected error in BuildAuthParams: %v", workerID, err)
|
|
return
|
|
}
|
|
if authParams == nil {
|
|
t.Errorf("worker %d: expected non-nil auth params", workerID)
|
|
return
|
|
}
|
|
|
|
// Test ValidateConfig
|
|
err = provider.ValidateConfig()
|
|
if err != nil {
|
|
t.Errorf("worker %d: unexpected error in ValidateConfig: %v", workerID, err)
|
|
return
|
|
}
|
|
}
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
// Check for potential goroutine leaks - allow some tolerance for test framework overhead
|
|
finalGoroutines := runtime.NumGoroutine()
|
|
if finalGoroutines > initialGoroutines+5 {
|
|
t.Errorf("potential goroutine leak: started with %d goroutines, ended with %d", initialGoroutines, finalGoroutines)
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_MemorySafety(t *testing.T) {
|
|
const numIterations = 1000
|
|
|
|
initialGoroutines := runtime.NumGoroutine()
|
|
|
|
for i := 0; i < numIterations; i++ {
|
|
provider := NewGoogleProvider()
|
|
|
|
session := &mockSession{
|
|
authenticated: true,
|
|
accessToken: fmt.Sprintf("access-token-%d", i),
|
|
idToken: fmt.Sprintf("id-token-%d", i),
|
|
refreshToken: fmt.Sprintf("refresh-token-%d", i),
|
|
}
|
|
|
|
verifier := &mockTokenVerifier{}
|
|
cache := &mockTokenCache{
|
|
data: map[string]map[string]interface{}{
|
|
fmt.Sprintf("id-token-%d", i): {
|
|
"exp": float64(time.Now().Add(time.Hour).Unix()),
|
|
},
|
|
},
|
|
}
|
|
|
|
// Exercise all provider methods
|
|
_ = provider.GetType()
|
|
_ = provider.GetCapabilities()
|
|
_, _ = provider.ValidateTokens(session, verifier, cache, time.Minute)
|
|
_, _ = provider.BuildAuthParams(url.Values{}, []string{"openid"})
|
|
_ = provider.ValidateConfig()
|
|
_ = provider.HandleTokenRefresh(&TokenResult{})
|
|
}
|
|
|
|
// Force garbage collection
|
|
runtime.GC()
|
|
runtime.GC()
|
|
|
|
finalGoroutines := runtime.NumGoroutine()
|
|
if finalGoroutines > initialGoroutines+5 {
|
|
t.Errorf("potential goroutine leak: started with %d goroutines, ended with %d", initialGoroutines, finalGoroutines)
|
|
}
|
|
}
|
|
|
|
func TestGoogleProvider_EdgeCases(t *testing.T) {
|
|
provider := NewGoogleProvider()
|
|
|
|
t.Run("nil session", func(t *testing.T) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
// Expected behavior for nil session
|
|
t.Logf("Recovered from expected panic: %v", r)
|
|
}
|
|
}()
|
|
|
|
verifier := &mockTokenVerifier{}
|
|
cache := &mockTokenCache{}
|
|
_, err := provider.ValidateTokens(nil, verifier, cache, time.Minute)
|
|
if err == nil {
|
|
t.Error("expected error with nil session")
|
|
}
|
|
})
|
|
|
|
t.Run("nil verifier", func(t *testing.T) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
t.Logf("Recovered from expected panic: %v", r)
|
|
}
|
|
}()
|
|
|
|
session := &mockSession{authenticated: true, idToken: "test.token.here"}
|
|
cache := &mockTokenCache{}
|
|
result, err := provider.ValidateTokens(session, nil, cache, time.Minute)
|
|
// Google provider uses BaseProvider which handles nil verifier gracefully
|
|
if err != nil {
|
|
t.Logf("Got expected error with nil verifier: %v", err)
|
|
} else if result != nil && result.NeedsRefresh {
|
|
t.Logf("Provider handled nil verifier gracefully by requesting refresh")
|
|
}
|
|
})
|
|
|
|
t.Run("nil cache", func(t *testing.T) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
t.Logf("Recovered from expected panic with nil cache: %v", r)
|
|
}
|
|
}()
|
|
session := &mockSession{authenticated: true, accessToken: "test-token"}
|
|
verifier := &mockTokenVerifier{}
|
|
result, err := provider.ValidateTokens(session, verifier, nil, time.Minute)
|
|
// Google provider uses BaseProvider which handles nil cache gracefully
|
|
if err != nil {
|
|
t.Logf("Got expected error with nil cache: %v", err)
|
|
} else if result != nil && result.NeedsRefresh {
|
|
t.Logf("Provider handled nil cache gracefully by requesting refresh")
|
|
}
|
|
})
|
|
|
|
t.Run("empty tokens", func(t *testing.T) {
|
|
session := &mockSession{
|
|
authenticated: true,
|
|
accessToken: "",
|
|
idToken: "",
|
|
refreshToken: "",
|
|
}
|
|
verifier := &mockTokenVerifier{}
|
|
cache := &mockTokenCache{}
|
|
result, err := provider.ValidateTokens(session, verifier, cache, time.Minute)
|
|
if err != nil {
|
|
t.Errorf("unexpected error with empty tokens: %v", err)
|
|
}
|
|
if !result.IsExpired {
|
|
t.Error("expected IsExpired=true for empty tokens without refresh token")
|
|
}
|
|
})
|
|
|
|
t.Run("offline_access scope filtering", func(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
inputScopes []string
|
|
expectScopes []string
|
|
}{
|
|
{
|
|
name: "single offline_access",
|
|
inputScopes: []string{"offline_access"},
|
|
expectScopes: []string{},
|
|
},
|
|
{
|
|
name: "offline_access with others",
|
|
inputScopes: []string{"openid", "offline_access", "email"},
|
|
expectScopes: []string{"openid", "email"},
|
|
},
|
|
{
|
|
name: "multiple offline_access",
|
|
inputScopes: []string{"offline_access", "openid", "offline_access", "profile"},
|
|
expectScopes: []string{"openid", "profile"},
|
|
},
|
|
{
|
|
name: "no offline_access",
|
|
inputScopes: []string{"openid", "email", "profile"},
|
|
expectScopes: []string{"openid", "email", "profile"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
authParams, err := provider.BuildAuthParams(url.Values{}, tt.inputScopes)
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
return
|
|
}
|
|
|
|
if len(authParams.Scopes) != len(tt.expectScopes) {
|
|
t.Errorf("expected %d scopes, got %d", len(tt.expectScopes), len(authParams.Scopes))
|
|
}
|
|
|
|
for i, expectedScope := range tt.expectScopes {
|
|
if i >= len(authParams.Scopes) || authParams.Scopes[i] != expectedScope {
|
|
t.Errorf("expected scope %q at position %d, got %q", expectedScope, i, authParams.Scopes[i])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("very long tokens", func(t *testing.T) {
|
|
longToken := strings.Repeat("a", 5000)
|
|
session := &mockSession{
|
|
authenticated: true,
|
|
idToken: longToken,
|
|
refreshToken: "refresh-token",
|
|
}
|
|
verifier := &mockTokenVerifier{}
|
|
cache := &mockTokenCache{
|
|
data: map[string]map[string]interface{}{
|
|
longToken: {
|
|
"exp": float64(time.Now().Add(time.Hour).Unix()),
|
|
},
|
|
},
|
|
}
|
|
result, err := provider.ValidateTokens(session, verifier, cache, time.Minute)
|
|
if err != nil {
|
|
t.Errorf("unexpected error with very long token: %v", err)
|
|
}
|
|
if result == nil {
|
|
t.Error("expected non-nil result with very long token")
|
|
}
|
|
})
|
|
|
|
t.Run("special characters in parameters", func(t *testing.T) {
|
|
specialParams := url.Values{
|
|
"client_id": []string{"[email protected]"},
|
|
"redirect_uri": []string{"https://example.com/callback?param=value&other=test"},
|
|
"state": []string{"state+with/special=chars&more"},
|
|
}
|
|
scopes := []string{"openid", "email+special", "profile/test"}
|
|
|
|
authParams, err := provider.BuildAuthParams(specialParams, scopes)
|
|
if err != nil {
|
|
t.Errorf("unexpected error with special characters: %v", err)
|
|
return
|
|
}
|
|
|
|
if authParams == nil {
|
|
t.Error("expected non-nil auth params with special characters")
|
|
}
|
|
|
|
// Verify all special parameter values are preserved
|
|
for key, expectedValues := range specialParams {
|
|
if key == "access_type" || key == "prompt" {
|
|
continue // These get overridden
|
|
}
|
|
actualValues := authParams.URLValues[key]
|
|
if len(actualValues) != len(expectedValues) {
|
|
t.Errorf("parameter %s: expected %d values, got %d", key, len(expectedValues), len(actualValues))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// Benchmark tests for performance validation
|
|
func BenchmarkGoogleProvider_GetType(b *testing.B) {
|
|
provider := NewGoogleProvider()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
provider.GetType()
|
|
}
|
|
}
|
|
|
|
func BenchmarkGoogleProvider_GetCapabilities(b *testing.B) {
|
|
provider := NewGoogleProvider()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
provider.GetCapabilities()
|
|
}
|
|
}
|
|
|
|
func BenchmarkGoogleProvider_BuildAuthParams(b *testing.B) {
|
|
provider := NewGoogleProvider()
|
|
baseParams := url.Values{"client_id": []string{"test-client"}}
|
|
scopes := []string{"openid", "email", "profile", "offline_access"}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := provider.BuildAuthParams(baseParams, scopes)
|
|
if err != nil {
|
|
b.Fatalf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkGoogleProvider_ValidateTokens(b *testing.B) {
|
|
provider := NewGoogleProvider()
|
|
session := &mockSession{
|
|
authenticated: true,
|
|
accessToken: "access-token",
|
|
idToken: "id.token.here",
|
|
refreshToken: "refresh-token",
|
|
}
|
|
verifier := &mockTokenVerifier{}
|
|
cache := &mockTokenCache{
|
|
data: map[string]map[string]interface{}{
|
|
"id.token.here": {
|
|
"exp": float64(time.Now().Add(time.Hour).Unix()),
|
|
},
|
|
},
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := provider.ValidateTokens(session, verifier, cache, time.Minute)
|
|
if err != nil {
|
|
b.Fatalf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkGoogleProvider_OfflineAccessFiltering(b *testing.B) {
|
|
provider := NewGoogleProvider()
|
|
baseParams := url.Values{"client_id": []string{"test-client"}}
|
|
scopes := []string{"openid", "offline_access", "email", "offline_access", "profile", "offline_access"}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := provider.BuildAuthParams(baseParams, scopes)
|
|
if err != nil {
|
|
b.Fatalf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
}
|