package utils import ( "os" "testing" "time" ) func TestGetDatabaseConfig(t *testing.T) { // Clean up environment before test cleanupDBEnv := func() { os.Unsetenv("DATABASE_URL") os.Unsetenv("DB_HOST") os.Unsetenv("DB_PORT") os.Unsetenv("DB_USER") os.Unsetenv("DB_PASSWORD") os.Unsetenv("DB_NAME") os.Unsetenv("DB_SSLMODE") } t.Run("Default configuration", func(t *testing.T) { cleanupDBEnv() config := GetDatabaseConfig() if config.URL != "sqlite://./app.db" { t.Errorf("Expected default URL 'sqlite://./app.db', got '%s'", config.URL) } if config.Driver != "sqlite3" { t.Errorf("Expected driver 'sqlite3', got '%s'", config.Driver) } if config.Host != "localhost" { t.Errorf("Expected host 'localhost', got '%s'", config.Host) } if config.Port != 5432 { t.Errorf("Expected port 5432, got %d", config.Port) } }) t.Run("PostgreSQL configuration", func(t *testing.T) { cleanupDBEnv() os.Setenv("DATABASE_URL", "postgres://user:pass@host:5433/dbname") os.Setenv("DB_HOST", "custom-host") os.Setenv("DB_PORT", "5433") os.Setenv("DB_USER", "custom-user") os.Setenv("DB_PASSWORD", "custom-pass") os.Setenv("DB_NAME", "custom-db") os.Setenv("DB_SSLMODE", "require") defer cleanupDBEnv() config := GetDatabaseConfig() if config.Driver != "postgres" { t.Errorf("Expected driver 'postgres', got '%s'", config.Driver) } if config.Host != "custom-host" { t.Errorf("Expected host 'custom-host', got '%s'", config.Host) } if config.Port != 5433 { t.Errorf("Expected port 5433, got %d", config.Port) } if config.User != "custom-user" { t.Errorf("Expected user 'custom-user', got '%s'", config.User) } if config.SSLMode != "require" { t.Errorf("Expected sslmode 'require', got '%s'", config.SSLMode) } }) t.Run("Unknown database URL defaults to sqlite3", func(t *testing.T) { cleanupDBEnv() os.Setenv("DATABASE_URL", "unknown://user:pass@host:1234/dbname") defer cleanupDBEnv() config := GetDatabaseConfig() if config.Driver != "sqlite3" { t.Errorf("Expected driver 'sqlite3' for unknown URL, got '%s'", config.Driver) } if config.URL != "unknown://user:pass@host:1234/dbname" { t.Errorf("URL should be preserved as-is, got '%s'", config.URL) } }) } func TestGetServerConfig(t *testing.T) { cleanupServerEnv := func() { os.Unsetenv("PORT") os.Unsetenv("HOST") os.Unsetenv("READ_TIMEOUT") os.Unsetenv("WRITE_TIMEOUT") os.Unsetenv("SHUTDOWN_TIMEOUT") os.Unsetenv("LOG_LEVEL") } t.Run("Default configuration", func(t *testing.T) { cleanupServerEnv() config := GetServerConfig("8080") if config.Port != "8080" { t.Errorf("Expected port '8080', got '%s'", config.Port) } if config.Host != "" { t.Errorf("Expected empty host, got '%s'", config.Host) } if config.ReadTimeout != 30*time.Second { t.Errorf("Expected read timeout 30s, got %v", config.ReadTimeout) } if config.LogLevel != "info" { t.Errorf("Expected log level 'info', got '%s'", config.LogLevel) } }) t.Run("Custom configuration", func(t *testing.T) { cleanupServerEnv() os.Setenv("PORT", "9000") os.Setenv("HOST", "127.0.0.1") os.Setenv("READ_TIMEOUT", "45s") os.Setenv("WRITE_TIMEOUT", "60s") os.Setenv("SHUTDOWN_TIMEOUT", "10s") os.Setenv("LOG_LEVEL", "debug") defer cleanupServerEnv() config := GetServerConfig("8080") if config.Port != "9000" { t.Errorf("Expected port '9000', got '%s'", config.Port) } if config.Host != "127.0.0.1" { t.Errorf("Expected host '127.0.0.1', got '%s'", config.Host) } if config.ReadTimeout != 45*time.Second { t.Errorf("Expected read timeout 45s, got %v", config.ReadTimeout) } if config.WriteTimeout != 60*time.Second { t.Errorf("Expected write timeout 60s, got %v", config.WriteTimeout) } if config.ShutdownTimeout != 10*time.Second { t.Errorf("Expected shutdown timeout 10s, got %v", config.ShutdownTimeout) } if config.LogLevel != "debug" { t.Errorf("Expected log level 'debug', got '%s'", config.LogLevel) } }) } func TestServerConfigGetListenAddress(t *testing.T) { tests := []struct { name string host string port string expected string }{ { name: "With host", host: "127.0.0.1", port: "8080", expected: "127.0.0.1:8080", }, { name: "Without host", host: "", port: "8080", expected: ":8080", }, { name: "With localhost", host: "localhost", port: "3000", expected: "localhost:3000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { config := ServerConfig{ Host: tt.host, Port: tt.port, } result := config.GetListenAddress() if result != tt.expected { t.Errorf("GetListenAddress() = %v, want %v", result, tt.expected) } }) } } func TestGetAuthConfig(t *testing.T) { cleanupAuthEnv := func() { os.Unsetenv("JWT_SECRET") os.Unsetenv("TOKEN_EXPIRATION") os.Unsetenv("JWT_ISSUER") os.Unsetenv("REQUIRE_MFA") } t.Run("Default configuration", func(t *testing.T) { cleanupAuthEnv() config := GetAuthConfig("test-service") if config.JWTSecret != "dev-secret-test-service" { t.Errorf("Expected JWT secret 'dev-secret-test-service', got '%s'", config.JWTSecret) } if config.TokenExpiration != 24*time.Hour { t.Errorf("Expected token expiration 24h, got %v", config.TokenExpiration) } if config.Issuer != "knowfoolery-test-service" { t.Errorf("Expected issuer 'knowfoolery-test-service', got '%s'", config.Issuer) } if config.RequireMFA != false { t.Errorf("Expected require MFA false, got %v", config.RequireMFA) } }) t.Run("Custom configuration", func(t *testing.T) { cleanupAuthEnv() os.Setenv("JWT_SECRET", "custom-secret") os.Setenv("TOKEN_EXPIRATION", "2h") os.Setenv("JWT_ISSUER", "custom-issuer") os.Setenv("REQUIRE_MFA", "true") defer cleanupAuthEnv() config := GetAuthConfig("test-service") if config.JWTSecret != "custom-secret" { t.Errorf("Expected JWT secret 'custom-secret', got '%s'", config.JWTSecret) } if config.TokenExpiration != 2*time.Hour { t.Errorf("Expected token expiration 2h, got %v", config.TokenExpiration) } if config.Issuer != "custom-issuer" { t.Errorf("Expected issuer 'custom-issuer', got '%s'", config.Issuer) } if config.RequireMFA != true { t.Errorf("Expected require MFA true, got %v", config.RequireMFA) } }) } func TestEnvironmentChecks(t *testing.T) { cleanupEnv := func() { os.Unsetenv("ENVIRONMENT") } tests := []struct { name string envValue string isProd bool isDev bool getEnv string }{ { name: "Production environment", envValue: "production", isProd: true, isDev: false, getEnv: "production", }, { name: "Prod environment", envValue: "prod", isProd: true, isDev: false, getEnv: "prod", }, { name: "Development environment", envValue: "development", isProd: false, isDev: true, getEnv: "development", }, { name: "Dev environment", envValue: "dev", isProd: false, isDev: true, getEnv: "dev", }, { name: "Default environment", envValue: "", isProd: false, isDev: true, getEnv: "development", }, { name: "Custom environment", envValue: "staging", isProd: false, isDev: false, getEnv: "staging", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cleanupEnv() if tt.envValue != "" { os.Setenv("ENVIRONMENT", tt.envValue) defer cleanupEnv() } if IsProduction() != tt.isProd { t.Errorf("IsProduction() = %v, want %v", IsProduction(), tt.isProd) } if IsDevelopment() != tt.isDev { t.Errorf("IsDevelopment() = %v, want %v", IsDevelopment(), tt.isDev) } if GetEnvironment() != tt.getEnv { t.Errorf("GetEnvironment() = %v, want %v", GetEnvironment(), tt.getEnv) } }) } } func TestGetServiceName(t *testing.T) { cleanupEnv := func() { os.Unsetenv("SERVICE_NAME") } t.Run("Default service name", func(t *testing.T) { cleanupEnv() result := GetServiceName("default-service") if result != "default-service" { t.Errorf("Expected 'default-service', got '%s'", result) } }) t.Run("Custom service name", func(t *testing.T) { cleanupEnv() os.Setenv("SERVICE_NAME", "custom-service") defer cleanupEnv() result := GetServiceName("default-service") if result != "custom-service" { t.Errorf("Expected 'custom-service', got '%s'", result) } }) } func TestGetVersion(t *testing.T) { cleanupEnv := func() { os.Unsetenv("VERSION") } t.Run("Default version", func(t *testing.T) { cleanupEnv() result := GetVersion() if result != "development" { t.Errorf("Expected 'development', got '%s'", result) } }) t.Run("Custom version", func(t *testing.T) { cleanupEnv() os.Setenv("VERSION", "1.2.3") defer cleanupEnv() result := GetVersion() if result != "1.2.3" { t.Errorf("Expected '1.2.3', got '%s'", result) } }) } func TestLogSafeMethods(t *testing.T) { t.Run("DatabaseConfig LogSafe", func(t *testing.T) { config := DatabaseConfig{ Driver: "postgres", Host: "localhost", Port: 5432, User: "testuser", Password: "secret-password", Database: "testdb", SSLMode: "disable", } safe := config.LogSafe() // Check that all non-sensitive fields are present if safe["driver"] != "postgres" { t.Error("Driver not present in safe log") } if safe["host"] != "localhost" { t.Error("Host not present in safe log") } if safe["port"] != 5432 { t.Error("Port not present in safe log") } // Check that password is NOT present if _, exists := safe["password"]; exists { t.Error("Password should not be present in safe log") } }) t.Run("ServerConfig LogSafe", func(t *testing.T) { config := ServerConfig{ Port: "8080", Host: "localhost", ReadTimeout: 30 * time.Second, WriteTimeout: 45 * time.Second, LogLevel: "debug", } safe := config.LogSafe() if safe["port"] != "8080" { t.Error("Port not present in safe log") } if safe["log_level"] != "debug" { t.Error("Log level not present in safe log") } }) t.Run("AuthConfig LogSafe", func(t *testing.T) { config := AuthConfig{ JWTSecret: "secret-jwt-key", TokenExpiration: 24 * time.Hour, Issuer: "test-issuer", RequireMFA: true, } safe := config.LogSafe() // Check that non-sensitive fields are present if safe["issuer"] != "test-issuer" { t.Error("Issuer not present in safe log") } if safe["require_mfa"] != true { t.Error("RequireMFA not present in safe log") } // Check that JWT secret is NOT present if _, exists := safe["jwt_secret"]; exists { t.Error("JWT secret should not be present in safe log") } }) }