mock

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 7 Imported by: 0

README

Auth Mock Package

This package provides mock implementations for testing authentication-related functionality in the CU CLI.

Overview

The mock package includes:

  • MockAuthProvider - A full mock implementation of the auth.Manager interface
  • KeyringMock - Mock for keyring operations
  • Test fixtures and scenarios for common authentication states
  • Helper methods for easy test setup

Basic Usage

Simple Authentication Test
import (
    "testing"
    "github.com/timimsms/cu/internal/auth/mock"
)

func TestMyCommand(t *testing.T) {
    // Create mock provider
    authMock := mock.NewAuthProvider()
    
    // Set up authentication
    authMock.SetToken("default", "pk_12345678", time.Time{})
    
    // Your test code here
    token, err := authMock.GetToken("default")
    // ...
}
Using Scenarios

The package provides pre-configured scenarios for common test cases:

func TestCommandWithAuth(t *testing.T) {
    provider := mock.NewAuthProvider()
    scenarios := mock.NewScenarios(provider)
    
    // Test with valid authentication
    auth := scenarios.Authenticated()
    // ... test authenticated behavior
    
    // Test without authentication
    auth = scenarios.NotAuthenticated()
    // ... test unauthenticated behavior
    
    // Test with expired token
    auth = scenarios.ExpiredToken()
    // ... test token expiry handling
}

Available Scenarios

Basic Scenarios
  • NotAuthenticated() - No tokens present
  • Authenticated() - Valid token in default workspace
  • AuthenticatedWithEmail() - Token with associated email
  • MultipleWorkspaces() - Multiple authenticated workspaces
Error Scenarios
  • ExpiredToken() - Token that has expired
  • ExpiredWithRefresh() - Expired token with refresh behavior
  • NetworkError() - Simulates network failures
  • KeyringError() - Simulates keyring access errors
  • InvalidToken() - Token with invalid format

Mock Features

Setting Tokens
// Simple token
authMock.SetToken("workspace", "token_value", time.Time{})

// Token with expiry
authMock.SetToken("workspace", "token_value", time.Now().Add(1*time.Hour))

// Token with email
authMock.SetTokenWithEmail("workspace", "token_value", "user@example.com")
Simulating Errors
// Global errors
authMock.SetGetError(errors.New("network timeout"))
authMock.SetSaveError(errors.New("keyring access denied"))

// Workspace-specific errors
authMock.SetError("production", errors.New("access denied"))
Token Refresh
authMock.SetRefreshBehavior(func(workspace string) (*auth.Token, error) {
    return &auth.Token{
        Value: "new_token",
        Workspace: workspace,
    }, nil
})
Call Tracking
// Perform operations
authMock.SaveToken("default", token)
authMock.GetToken("default")

// Verify calls
calls := authMock.GetCalls()
// calls = ["SaveToken(default)", "GetToken(default)"]

Test Fixtures

Predefined Tokens
mock.ValidToken      // "pk_12345678_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
mock.ExpiredToken    // "pk_87654321_ZYXWVUTSRQPONMLKJIHGFEDCBA0987654321"
mock.InvalidToken    // "invalid_token_format"
mock.LegacyToken     // "1234567890abcdef"
mock.RefreshToken    // "pk_refresh_NEWTOKEN1234567890ABCDEFGHIJKLMNOP"
Predefined Workspaces
mock.DefaultWorkspace     // "default"
mock.TestWorkspace        // "test-workspace"
mock.ProductionWorkspace  // "production"
mock.StagingWorkspace     // "staging"
Token Fixtures
mock.TokenFixtures.Valid       // Basic valid token
mock.TokenFixtures.WithEmail   // Token with email
mock.TokenFixtures.Legacy      // Legacy format token
mock.TokenFixtures.Production  // Production workspace token
mock.TokenFixtures.Staging     // Staging workspace token

Integration with Commands

When testing CLI commands that require authentication:

func TestTaskCommand(t *testing.T) {
    authMock := mock.NewAuthProvider()
    authMock.SetToken("default", mock.ValidToken, time.Time{})
    
    // Create command with mocked auth
    cmd := &TaskCommand{
        auth: authMock,
        // ... other dependencies
    }
    
    // Test command execution
    err := cmd.Execute()
    assert.NoError(t, err)
    
    // Verify auth was checked
    calls := authMock.GetCalls()
    assert.Contains(t, calls, "GetCurrentToken()")
}

Testing Error Paths

func TestAuthErrors(t *testing.T) {
    tests := []struct {
        name    string
        setup   func(*mock.AuthProvider)
        wantErr error
    }{
        {
            name: "not authenticated",
            setup: func(m *mock.AuthProvider) {
                // No setup - no tokens
            },
            wantErr: errors.ErrNotAuthenticated,
        },
        {
            name: "token expired",
            setup: func(m *mock.AuthProvider) {
                m.SetToken("default", mock.ExpiredToken, time.Now().Add(-1*time.Hour))
            },
            wantErr: errors.ErrTokenExpired,
        },
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            authMock := mock.NewAuthProvider()
            tt.setup(authMock)
            
            _, err := authMock.GetCurrentToken()
            assert.ErrorIs(t, err, tt.wantErr)
        })
    }
}

Best Practices

  1. Reset between tests: Always reset the mock to ensure test isolation

    authMock.Reset()
    
  2. Use scenarios for common cases: Leverage pre-built scenarios instead of manual setup

    auth := scenarios.Authenticated()
    
  3. Test error paths: Always test both success and failure cases

    // Success case
    authMock.SetToken("default", mock.ValidToken, time.Time{})
    
    // Error case
    authMock.SetGetError(errors.New("network error"))
    
  4. Verify auth usage: Use call tracking to ensure auth is properly checked

    calls := authMock.GetCalls()
    assert.Contains(t, calls, "IsAuthenticated(default)")
    
  5. Use fixtures for consistency: Use predefined tokens and workspaces

    authMock.SetToken(mock.DefaultWorkspace, mock.ValidToken, time.Time{})
    

Common Test Patterns

Table-Driven Tests with Auth
func TestCommandVariations(t *testing.T) {
    tests := []struct {
        name      string
        authSetup func(*mock.AuthProvider)
        wantErr   bool
    }{
        {
            name: "authenticated user",
            authSetup: func(m *mock.AuthProvider) {
                m.SetToken(mock.DefaultWorkspace, mock.ValidToken, time.Time{})
            },
            wantErr: false,
        },
        {
            name:      "unauthenticated user",
            authSetup: func(m *mock.AuthProvider) {},
            wantErr:   true,
        },
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            authMock := mock.NewAuthProvider()
            tt.authSetup(authMock)
            
            // Test your command/function
            err := YourFunction(authMock)
            if tt.wantErr {
                assert.Error(t, err)
            } else {
                assert.NoError(t, err)
            }
        })
    }
}

This mock package provides a comprehensive testing foundation for all authentication-related functionality in the CU CLI, enabling thorough testing of both success and error paths.

Documentation

Overview

Package mock provides test fixtures for authentication testing

Package mock provides mock implementations for auth testing

Index

Constants

View Source
const (
	// ValidToken represents a valid API token
	ValidToken = "pk_12345678_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" // #nosec G101 - Test fixture

	// ExpiredToken represents an expired API token
	ExpiredToken = "pk_87654321_ZYXWVUTSRQPONMLKJIHGFEDCBA0987654321" // #nosec G101 - Test fixture

	// InvalidToken represents a malformed token
	InvalidToken = "invalid_token_format"

	// LegacyToken represents a legacy format token (plain string)
	LegacyToken = "1234567890abcdef" // #nosec G101 - Test fixture

	// RefreshToken represents a token used for refresh scenarios
	RefreshToken = "pk_refresh_NEWTOKEN1234567890ABCDEFGHIJKLMNOP" // #nosec G101 - This is a test fixture, not a real credential
)

Common test tokens

View Source
const (
	// DefaultWorkspace is the default workspace name
	DefaultWorkspace = "default"

	// TestWorkspace is a test workspace name
	TestWorkspace = "test-workspace"

	// ProductionWorkspace is a production workspace name
	ProductionWorkspace = "production"

	// StagingWorkspace is a staging workspace name
	StagingWorkspace = "staging"
)

Common test workspaces

View Source
const (
	// TestEmail is a test user email
	TestEmail = "test@example.com"

	// AdminEmail is an admin user email
	AdminEmail = "admin@example.com"
)

Common test emails

Variables

View Source
var CommonScenarios = []TestScenario{
	{
		Name:        "not_authenticated",
		Description: "No authentication tokens present",
		Setup: func(p *AuthProvider) {
			p.Reset()
		},
		Validate: func(p *AuthProvider) error {
			if p.IsAuthenticated(DefaultWorkspace) {
				return errors.New("expected not authenticated")
			}
			return nil
		},
	},
	{
		Name:        "valid_authentication",
		Description: "Valid token in default workspace",
		Setup: func(p *AuthProvider) {
			p.Reset()
			p.SetToken(DefaultWorkspace, ValidToken, time.Time{})
		},
		Validate: func(p *AuthProvider) error {
			if !p.IsAuthenticated(DefaultWorkspace) {
				return errors.New("expected authenticated")
			}
			token, err := p.GetToken(DefaultWorkspace)
			if err != nil {
				return err
			}
			if token.Value != ValidToken {
				return errors.New("unexpected token value")
			}
			return nil
		},
	},
	{
		Name:        "expired_token",
		Description: "Token has expired",
		Setup: func(p *AuthProvider) {
			p.Reset()
			p.SetToken(DefaultWorkspace, ExpiredToken, time.Now().Add(-1*time.Hour))
		},
		Validate: func(p *AuthProvider) error {
			_, err := p.GetToken(DefaultWorkspace)
			if err != cuerrors.ErrTokenExpired {
				return errors.New("expected token expired error")
			}
			return nil
		},
	},
	{
		Name:        "multiple_workspaces",
		Description: "Multiple workspaces with different tokens",
		Setup: func(p *AuthProvider) {
			p.Reset()
			p.SetTokenWithEmail(DefaultWorkspace, ValidToken, TestEmail)
			p.SetTokenWithEmail(ProductionWorkspace, ValidToken, AdminEmail)
			p.SetTokenWithEmail(StagingWorkspace, ValidToken, TestEmail)
		},
		Validate: func(p *AuthProvider) error {
			workspaces, err := p.ListWorkspaces()
			if err != nil {
				return err
			}
			if len(workspaces) != 3 {
				return errors.New("expected 3 workspaces")
			}

			for _, ws := range []string{DefaultWorkspace, ProductionWorkspace, StagingWorkspace} {
				if !p.IsAuthenticated(ws) {
					return fmt.Errorf("workspace %s not authenticated", ws)
				}
			}

			prodToken, _ := p.GetToken(ProductionWorkspace)
			if prodToken.Email != AdminEmail {
				return errors.New("unexpected email for production workspace")
			}

			return nil
		},
	},
}

CommonScenarios provides a set of common test scenarios

View Source
var ErrorScenarios = struct {
	NetworkTimeout   error
	KeyringAccess    error
	InvalidToken     error
	TokenExpired     error
	NotAuthenticated error
	PermissionDenied error
}{
	NetworkTimeout:   errors.New("network error: connection timeout"),
	KeyringAccess:    errors.New("keyring error: access denied"),
	InvalidToken:     cuerrors.ErrInvalidToken,
	TokenExpired:     cuerrors.ErrTokenExpired,
	NotAuthenticated: cuerrors.ErrNotAuthenticated,
	PermissionDenied: errors.New("permission denied: insufficient privileges"),
}

ErrorScenarios provides common error scenarios

View Source
var TokenFixtures = struct {
	Valid      *auth.Token
	WithEmail  *auth.Token
	Legacy     *auth.Token
	Production *auth.Token
	Staging    *auth.Token
}{
	Valid: &auth.Token{
		Value:     ValidToken,
		Workspace: DefaultWorkspace,
	},
	WithEmail: &auth.Token{
		Value:     ValidToken,
		Workspace: DefaultWorkspace,
		Email:     TestEmail,
	},
	Legacy: &auth.Token{
		Value:     LegacyToken,
		Workspace: DefaultWorkspace,
	},
	Production: &auth.Token{
		Value:     ValidToken,
		Workspace: ProductionWorkspace,
		Email:     AdminEmail,
	},
	Staging: &auth.Token{
		Value:     ValidToken,
		Workspace: StagingWorkspace,
		Email:     TestEmail,
	},
}

TokenFixtures provides pre-configured tokens for testing

Functions

This section is empty.

Types

type AuthProvider

type AuthProvider struct {
	// contains filtered or unexported fields
}

AuthProvider is a mock implementation of auth.Manager for testing

func NewAuthProvider

func NewAuthProvider() *AuthProvider

NewAuthProvider creates a new mock auth provider

func (*AuthProvider) DeleteToken

func (m *AuthProvider) DeleteToken(workspace string) error

DeleteToken mocks deleting a token

func (*AuthProvider) GetCalls

func (m *AuthProvider) GetCalls() []string

GetCalls returns the list of method calls made

func (*AuthProvider) GetCurrentToken

func (m *AuthProvider) GetCurrentToken() (*auth.Token, error)

GetCurrentToken mocks getting the current workspace token

func (*AuthProvider) GetToken

func (m *AuthProvider) GetToken(workspace string) (*auth.Token, error)

GetToken mocks retrieving a token

func (*AuthProvider) IsAuthenticated

func (m *AuthProvider) IsAuthenticated(workspace string) bool

IsAuthenticated mocks checking authentication status

func (*AuthProvider) ListWorkspaces

func (m *AuthProvider) ListWorkspaces() ([]string, error)

ListWorkspaces mocks listing workspaces

func (*AuthProvider) Reset

func (m *AuthProvider) Reset()

Reset clears all state and call history

func (*AuthProvider) SaveToken

func (m *AuthProvider) SaveToken(workspace string, token *auth.Token) error

SaveToken mocks saving a token

func (*AuthProvider) SetCurrentWorkspace

func (m *AuthProvider) SetCurrentWorkspace(workspace string)

SetCurrentWorkspace sets the current workspace

func (*AuthProvider) SetDeleteError

func (m *AuthProvider) SetDeleteError(err error)

SetDeleteError sets error for DeleteToken calls

func (*AuthProvider) SetError

func (m *AuthProvider) SetError(workspace string, err error)

SetError sets an error for a specific workspace

func (*AuthProvider) SetGetError

func (m *AuthProvider) SetGetError(err error)

SetGetError sets error for GetToken calls

func (*AuthProvider) SetListError

func (m *AuthProvider) SetListError(err error)

SetListError sets error for ListWorkspaces calls

func (*AuthProvider) SetRefreshBehavior

func (m *AuthProvider) SetRefreshBehavior(fn func(workspace string) (*auth.Token, error))

SetRefreshBehavior sets custom token refresh behavior

func (*AuthProvider) SetSaveError

func (m *AuthProvider) SetSaveError(err error)

SetSaveError sets error for SaveToken calls

func (*AuthProvider) SetToken

func (m *AuthProvider) SetToken(workspace string, token string, expiry time.Time)

SetToken sets a token for testing

func (*AuthProvider) SetTokenWithEmail

func (m *AuthProvider) SetTokenWithEmail(workspace, token, email string)

SetTokenWithEmail sets a token with email for testing

type KeyringMock

type KeyringMock struct {
	// contains filtered or unexported fields
}

KeyringMock provides a mock implementation of the keyring interface

func NewKeyringMock

func NewKeyringMock() *KeyringMock

NewKeyringMock creates a new keyring mock

func (*KeyringMock) Delete

func (k *KeyringMock) Delete(service, account string) error

Delete removes a secret from the mock keyring

func (*KeyringMock) Get

func (k *KeyringMock) Get(service, account string) (string, error)

Get retrieves a secret from the mock keyring

func (*KeyringMock) Reset

func (k *KeyringMock) Reset()

Reset clears all stored secrets and errors

func (*KeyringMock) Set

func (k *KeyringMock) Set(service, account, secret string) error

Set stores a secret in the mock keyring

func (*KeyringMock) SetError

func (k *KeyringMock) SetError(err error)

SetError sets an error to be returned by all operations

func (*KeyringMock) StoreJSON

func (k *KeyringMock) StoreJSON(service, account string, v interface{}) error

StoreJSON stores a JSON-serializable value

type Scenarios

type Scenarios struct {
	// contains filtered or unexported fields
}

Scenarios provides pre-configured auth scenarios

func NewScenarios

func NewScenarios(provider *AuthProvider) *Scenarios

NewScenarios creates a new scenarios helper

func (*Scenarios) Authenticated

func (s *Scenarios) Authenticated() *AuthProvider

Authenticated sets up a scenario with valid authentication

func (*Scenarios) AuthenticatedWithEmail

func (s *Scenarios) AuthenticatedWithEmail() *AuthProvider

AuthenticatedWithEmail sets up authentication with email

func (*Scenarios) ExpiredToken

func (s *Scenarios) ExpiredToken() *AuthProvider

ExpiredToken sets up a scenario with an expired token

func (*Scenarios) ExpiredWithRefresh

func (s *Scenarios) ExpiredWithRefresh() *AuthProvider

ExpiredWithRefresh sets up expired token with refresh behavior

func (*Scenarios) InvalidToken

func (s *Scenarios) InvalidToken() *AuthProvider

InvalidToken sets up a scenario with invalid token format

func (*Scenarios) KeyringError

func (s *Scenarios) KeyringError() *AuthProvider

KeyringError sets up a scenario with keyring errors

func (*Scenarios) LegacyFormat

func (s *Scenarios) LegacyFormat() *AuthProvider

LegacyFormat sets up a scenario with legacy token format

func (*Scenarios) MultipleWorkspaces

func (s *Scenarios) MultipleWorkspaces() *AuthProvider

MultipleWorkspaces sets up multiple authenticated workspaces

func (*Scenarios) NetworkError

func (s *Scenarios) NetworkError() *AuthProvider

NetworkError sets up a scenario with network errors

func (*Scenarios) NotAuthenticated

func (s *Scenarios) NotAuthenticated() *AuthProvider

NotAuthenticated sets up a scenario with no authentication

func (*Scenarios) PartialError

func (s *Scenarios) PartialError() *AuthProvider

PartialError sets up specific workspace errors

type TestScenario

type TestScenario struct {
	Name        string
	Description string
	Setup       func(*AuthProvider)
	Validate    func(*AuthProvider) error
}

TestScenario represents a test scenario configuration

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL