Files
traefikoidc/internal/testing/mocks.go
T
lukaszraczylo c3f23cb99b Release 0.7.5 (#70)
* Resolve issue with opaque tokens not being parsed correctly

* Increase test coverage

* Further improvements to test coverage and code quality

* Add new providers.

* fixup! Add new providers.

* Cleanup.

* fixup! Cleanup.

* fixup! fixup! Cleanup.

* fixup! fixup! fixup! Cleanup.

* fixup! fixup! fixup! fixup! Cleanup.

* Memory management optimisation

24 bytes per Put < 256-4096 bytes per buffer allocation avoided (10-170x difference)

* Pooling cleanup.
2025-10-01 12:13:10 +01:00

394 lines
8.3 KiB
Go

// Package testing provides unified mock implementations for tests
package testing
import (
"fmt"
"net/http"
"sync"
"time"
)
// UnifiedMockLogger provides a standard mock logger for all tests
type UnifiedMockLogger struct {
LoggedMessages []string
mu sync.RWMutex
}
func NewUnifiedMockLogger() *UnifiedMockLogger {
return &UnifiedMockLogger{
LoggedMessages: make([]string, 0),
}
}
func (l *UnifiedMockLogger) Debug(msg string) {
l.mu.Lock()
defer l.mu.Unlock()
l.LoggedMessages = append(l.LoggedMessages, fmt.Sprintf("DEBUG: %s", msg))
}
func (l *UnifiedMockLogger) Debugf(format string, args ...interface{}) {
l.Debug(fmt.Sprintf(format, args...))
}
func (l *UnifiedMockLogger) Info(msg string) {
l.mu.Lock()
defer l.mu.Unlock()
l.LoggedMessages = append(l.LoggedMessages, fmt.Sprintf("INFO: %s", msg))
}
func (l *UnifiedMockLogger) Infof(format string, args ...interface{}) {
l.Info(fmt.Sprintf(format, args...))
}
func (l *UnifiedMockLogger) Error(msg string) {
l.mu.Lock()
defer l.mu.Unlock()
l.LoggedMessages = append(l.LoggedMessages, fmt.Sprintf("ERROR: %s", msg))
}
func (l *UnifiedMockLogger) Errorf(format string, args ...interface{}) {
l.Error(fmt.Sprintf(format, args...))
}
func (l *UnifiedMockLogger) GetMessages() []string {
l.mu.RLock()
defer l.mu.RUnlock()
result := make([]string, len(l.LoggedMessages))
copy(result, l.LoggedMessages)
return result
}
func (l *UnifiedMockLogger) Clear() {
l.mu.Lock()
defer l.mu.Unlock()
l.LoggedMessages = l.LoggedMessages[:0]
}
// UnifiedMockSession provides a standard mock session for all tests
type UnifiedMockSession struct {
authenticated bool
idToken string
accessToken string
refreshToken string
email string
csrf string
nonce string
codeVerifier string
incomingPath string
redirectCount int
mu sync.RWMutex
}
func NewUnifiedMockSession() *UnifiedMockSession {
return &UnifiedMockSession{}
}
func (s *UnifiedMockSession) GetAuthenticated() bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.authenticated
}
func (s *UnifiedMockSession) SetAuthenticated(auth bool) error {
s.mu.Lock()
defer s.mu.Unlock()
s.authenticated = auth
return nil
}
func (s *UnifiedMockSession) GetIDToken() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.idToken
}
func (s *UnifiedMockSession) SetIDToken(token string) {
s.mu.Lock()
defer s.mu.Unlock()
s.idToken = token
}
func (s *UnifiedMockSession) GetAccessToken() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.accessToken
}
func (s *UnifiedMockSession) SetAccessToken(token string) {
s.mu.Lock()
defer s.mu.Unlock()
s.accessToken = token
}
func (s *UnifiedMockSession) GetRefreshToken() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.refreshToken
}
func (s *UnifiedMockSession) SetRefreshToken(token string) {
s.mu.Lock()
defer s.mu.Unlock()
s.refreshToken = token
}
func (s *UnifiedMockSession) GetEmail() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.email
}
func (s *UnifiedMockSession) SetEmail(email string) {
s.mu.Lock()
defer s.mu.Unlock()
s.email = email
}
func (s *UnifiedMockSession) GetCSRF() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.csrf
}
func (s *UnifiedMockSession) SetCSRF(csrf string) {
s.mu.Lock()
defer s.mu.Unlock()
s.csrf = csrf
}
func (s *UnifiedMockSession) GetNonce() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.nonce
}
func (s *UnifiedMockSession) SetNonce(nonce string) {
s.mu.Lock()
defer s.mu.Unlock()
s.nonce = nonce
}
func (s *UnifiedMockSession) GetCodeVerifier() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.codeVerifier
}
func (s *UnifiedMockSession) SetCodeVerifier(verifier string) {
s.mu.Lock()
defer s.mu.Unlock()
s.codeVerifier = verifier
}
func (s *UnifiedMockSession) GetIncomingPath() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.incomingPath
}
func (s *UnifiedMockSession) SetIncomingPath(path string) {
s.mu.Lock()
defer s.mu.Unlock()
s.incomingPath = path
}
func (s *UnifiedMockSession) GetRedirectCount() int {
s.mu.RLock()
defer s.mu.RUnlock()
return s.redirectCount
}
func (s *UnifiedMockSession) IncrementRedirectCount() {
s.mu.Lock()
defer s.mu.Unlock()
s.redirectCount++
}
func (s *UnifiedMockSession) ResetRedirectCount() {
s.mu.Lock()
defer s.mu.Unlock()
s.redirectCount = 0
}
func (s *UnifiedMockSession) Save(req *http.Request, rw http.ResponseWriter) error {
return nil
}
func (s *UnifiedMockSession) Clear(req *http.Request, rw http.ResponseWriter) error {
s.mu.Lock()
defer s.mu.Unlock()
s.authenticated = false
s.idToken = ""
s.accessToken = ""
s.refreshToken = ""
s.email = ""
s.csrf = ""
s.nonce = ""
s.codeVerifier = ""
s.incomingPath = ""
s.redirectCount = 0
return nil
}
func (s *UnifiedMockSession) MarkDirty() {}
func (s *UnifiedMockSession) IsDirty() bool {
return false
}
func (s *UnifiedMockSession) ReturnToPoolSafely() {}
// UnifiedMockTokenVerifier provides a standard mock token verifier
type UnifiedMockTokenVerifier struct {
ShouldFail bool
Error error
}
func NewUnifiedMockTokenVerifier() *UnifiedMockTokenVerifier {
return &UnifiedMockTokenVerifier{}
}
func (v *UnifiedMockTokenVerifier) VerifyToken(token string) error {
if v.ShouldFail {
if v.Error != nil {
return v.Error
}
return fmt.Errorf("mock verification failed")
}
return nil
}
// UnifiedMockTokenCache provides a standard mock token cache
type UnifiedMockTokenCache struct {
data map[string]map[string]interface{}
mu sync.RWMutex
}
func NewUnifiedMockTokenCache() *UnifiedMockTokenCache {
return &UnifiedMockTokenCache{
data: make(map[string]map[string]interface{}),
}
}
func (c *UnifiedMockTokenCache) Get(key string) (map[string]interface{}, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
value, exists := c.data[key]
return value, exists
}
func (c *UnifiedMockTokenCache) Set(key string, claims map[string]interface{}, ttl time.Duration) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = claims
}
func (c *UnifiedMockTokenCache) Delete(key string) {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.data, key)
}
func (c *UnifiedMockTokenCache) SetMaxSize(size int) {}
func (c *UnifiedMockTokenCache) Size() int {
c.mu.RLock()
defer c.mu.RUnlock()
return len(c.data)
}
func (c *UnifiedMockTokenCache) Clear() {
c.mu.Lock()
defer c.mu.Unlock()
c.data = make(map[string]map[string]interface{})
}
func (c *UnifiedMockTokenCache) Cleanup() {}
func (c *UnifiedMockTokenCache) Close() {}
func (c *UnifiedMockTokenCache) GetStats() map[string]interface{} {
return map[string]interface{}{
"size": c.Size(),
}
}
// UnifiedMockHTTPClient provides a mock HTTP client for tests
type UnifiedMockHTTPClient struct {
Responses map[string]*http.Response
Errors map[string]error
mu sync.RWMutex
}
func NewUnifiedMockHTTPClient() *UnifiedMockHTTPClient {
return &UnifiedMockHTTPClient{
Responses: make(map[string]*http.Response),
Errors: make(map[string]error),
}
}
func (c *UnifiedMockHTTPClient) Do(req *http.Request) (*http.Response, error) {
c.mu.RLock()
defer c.mu.RUnlock()
url := req.URL.String()
if err, exists := c.Errors[url]; exists {
return nil, err
}
if resp, exists := c.Responses[url]; exists {
return resp, nil
}
// Default response
return &http.Response{
StatusCode: 200,
Body: http.NoBody,
Header: make(http.Header),
}, nil
}
func (c *UnifiedMockHTTPClient) SetResponse(url string, response *http.Response) {
c.mu.Lock()
defer c.mu.Unlock()
c.Responses[url] = response
}
func (c *UnifiedMockHTTPClient) SetError(url string, err error) {
c.mu.Lock()
defer c.mu.Unlock()
c.Errors[url] = err
}
// TestSuite provides a unified test setup and teardown
type TestSuite struct {
Logger *UnifiedMockLogger
Session *UnifiedMockSession
TokenVerifier *UnifiedMockTokenVerifier
TokenCache *UnifiedMockTokenCache
HTTPClient *UnifiedMockHTTPClient
}
func NewTestSuite() *TestSuite {
return &TestSuite{
Logger: NewUnifiedMockLogger(),
Session: NewUnifiedMockSession(),
TokenVerifier: NewUnifiedMockTokenVerifier(),
TokenCache: NewUnifiedMockTokenCache(),
HTTPClient: NewUnifiedMockHTTPClient(),
}
}
func (ts *TestSuite) Setup() {
// Common test setup
ts.Logger.Clear()
ts.Session.Clear(nil, nil)
ts.TokenCache.Clear()
ts.TokenVerifier.ShouldFail = false
ts.TokenVerifier.Error = nil
}
func (ts *TestSuite) Teardown() {
// Common test teardown
ts.TokenCache.Close()
}