fetch_ml/tests/unit/config/validation_test.go
Jeremie Fraeys d87c556afa
test(all): update test suite for scheduler and security features
Update comprehensive test coverage:
- E2E tests with scheduler integration
- Integration tests with tenant isolation
- Unit tests with security assertions
- Security tests with audit validation
- Audit verification tests
- Auth tests with tenant scoping
- Config validation tests
- Container security tests
- Worker tests with scheduler mock
- Environment pool tests
- Load tests with distributed patterns
- Test fixtures with scheduler support
- Update go.mod/go.sum with new dependencies
2026-02-26 12:08:46 -05:00

213 lines
5.6 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
"testing"
"github.com/jfraeys/fetch_ml/internal/config"
)
// MockValidator implements the Validator interface for testing
type MockValidator struct {
errorMsg string
shouldFail bool
}
func (m *MockValidator) Validate() error {
if m.shouldFail {
return fmt.Errorf("validation error: %s", m.errorMsg)
}
return nil
}
func TestValidateConfig(t *testing.T) {
t.Parallel() // Enable parallel execution
// Test with valid validator
validValidator := &MockValidator{shouldFail: false}
err := config.ValidateConfig(validValidator)
if err != nil {
t.Errorf("Expected no error for valid validator, got %v", err)
}
// Test with invalid validator
invalidValidator := &MockValidator{shouldFail: true, errorMsg: "validation failed"}
err = config.ValidateConfig(invalidValidator)
if err == nil {
t.Error("Expected error for invalid validator")
}
if err.Error() != "validation error: validation failed" {
t.Errorf("Expected error message 'validation error: validation failed', got %s", err.Error())
}
}
func TestValidatePort(t *testing.T) {
t.Parallel() // Enable parallel execution
// Test valid ports
validPorts := []int{1, 22, 80, 443, 6379, 65535}
for _, port := range validPorts {
err := config.ValidatePort(port)
if err != nil {
t.Errorf("Expected no error for valid port %d, got %v", port, err)
}
}
// Test invalid ports
invalidPorts := []int{0, -1, 65536, 100000}
for _, port := range invalidPorts {
err := config.ValidatePort(port)
if err == nil {
t.Errorf("Expected error for invalid port %d", port)
}
}
}
func TestValidateDirectory(t *testing.T) {
t.Parallel() // Enable parallel execution
// Test empty path
err := config.ValidateDirectory("")
if err == nil {
t.Error("Expected error for empty path")
}
// Test non-existent directory
err = config.ValidateDirectory("/nonexistent/directory")
if err == nil {
t.Error("Expected error for non-existent directory")
}
// Test existing directory
tempDir := t.TempDir()
err = config.ValidateDirectory(tempDir)
if err != nil {
t.Errorf("Expected no error for existing directory %s, got %v", tempDir, err)
}
// Test file instead of directory
tempFile := filepath.Join(tempDir, "test_file")
err = os.WriteFile(tempFile, []byte("test"), 0600)
if err != nil {
t.Fatalf("Failed to create test file: %v", err)
}
err = config.ValidateDirectory(tempFile)
if err == nil {
t.Error("Expected error for file path")
}
// Test directory with environment variable expansion
// Reuse the tempDir path so validation succeeds after expansion
_ = os.Setenv("TEST_DIR", tempDir)
defer func() { _ = os.Unsetenv("TEST_DIR") }()
err = config.ValidateDirectory("$TEST_DIR")
if err != nil {
t.Errorf("Expected no error for expanded directory path, got %v", err)
}
// Test directory with tilde expansion (if home directory is available)
home, err := os.UserHomeDir()
if err == nil {
// Create a test directory in home
testHomeDir := filepath.Join(home, "test_fetch_ml")
err = os.MkdirAll(testHomeDir, 0750)
if err == nil {
defer func() { _ = os.RemoveAll(tempDir) }()
err = config.ValidateDirectory("~/test_fetch_ml")
if err != nil {
t.Errorf("Expected no error for tilde expanded path, got %v", err)
}
}
}
}
func TestValidateRedisAddr(t *testing.T) {
t.Parallel() // Enable parallel execution
// Test valid Redis addresses
validAddrs := []string{
"localhost:6379",
"127.0.0.1:6379",
"redis.example.com:6379",
"10.0.0.1:6380",
"[::1]:6379", // IPv6
}
for _, addr := range validAddrs {
err := config.ValidateRedisAddr(addr)
if err != nil {
t.Errorf("Expected no error for valid Redis address %s, got %v", addr, err)
}
}
// Test invalid Redis addresses
invalidAddrs := []string{
"", // empty
"localhost", // missing port
":6379", // missing host
"localhost:", // missing port number
"localhost:abc", // non-numeric port
"localhost:-1", // negative port
"localhost:0", // port too low
"localhost:65536", // port too high
"localhost:999999", // port way too high
"multiple:colons:6379", // too many colons
}
for _, addr := range invalidAddrs {
err := config.ValidateRedisAddr(addr)
if err == nil {
t.Errorf("Expected error for invalid Redis address %s", addr)
}
}
}
func TestValidateRedisAddrEdgeCases(t *testing.T) {
t.Parallel() // Enable parallel execution
// Test edge case ports
edgeCases := []struct {
addr string
shouldErr bool
}{
{"localhost:1", false}, // minimum valid port
{"localhost:65535", false}, // maximum valid port
{"localhost:0", true}, // below minimum
{"localhost:65536", true}, // above maximum
}
for _, tc := range edgeCases {
err := config.ValidateRedisAddr(tc.addr)
if tc.shouldErr && err == nil {
t.Errorf("Expected error for Redis address %s", tc.addr)
}
if !tc.shouldErr && err != nil {
t.Errorf("Expected no error for Redis address %s, got %v", tc.addr, err)
}
}
}
func TestValidatorInterface(t *testing.T) {
t.Parallel() // Enable parallel execution
// Test that our mock properly implements the interface
var _ config.Validator = &MockValidator{}
// Test that the interface works as expected
validator := &MockValidator{shouldFail: false}
err := validator.Validate()
if err != nil {
t.Errorf("MockValidator should not fail when shouldFail is false")
}
validator = &MockValidator{shouldFail: true, errorMsg: "test error"}
err = validator.Validate()
if err == nil {
t.Error("MockValidator should fail when shouldFail is true")
}
}