Skip to content

✅ test: Add Phase 1 test coverage for critical paths#7

Merged
SebastienLaurent-CF merged 10 commits intomainfrom
feat/tests
Nov 23, 2025
Merged

✅ test: Add Phase 1 test coverage for critical paths#7
SebastienLaurent-CF merged 10 commits intomainfrom
feat/tests

Conversation

@SebastienLaurent-CF
Copy link
Copy Markdown
Contributor

Implement comprehensive unit tests for configuration loading and validation, covering happy paths and error cases. Tests validate port ranges, detect conflicts, and ensure proper error handling.

Test Coverage (Phase 1):

  • Config loading and parsing:
    • Valid configuration with multiple forwards
    • Invalid ports (out of range, non-numeric)
    • Port conflicts detection (duplicate local ports)
    • CUE schema validation errors
  • Port validation:
    • Valid range (1-65535)
    • Edge cases (0, 1, 65535, 65536, 99999, negative)
    • Non-numeric ports and malformed specifications
    • Both single ports and local:remote mappings

Files Added:

  • internal/config/config_test.go - Unit tests for config validation
  • internal/config/testdata/valid.cue - Valid configuration test data
  • internal/config/testdata/port-conflict.cue - Port conflict test case
  • internal/config/testdata/invalid-ports.cue - Invalid ports test case
  • internal/config/testdata/duplicate-names.cue - Duplicate names test case

Test Results:

  • 5 test functions with 13 total test cases
  • Port validation edge cases: 9 sub-tests
  • All tests passing (1 skipped for known CUE limitation)

Dependencies Added:

  • github.com/stretchr/testify - Test assertions and utilities

Documentation:

  • Add Testing section to README with commands
  • Document test status and planned phases
  • Include coverage report generation instructions

Test Commands:

go test ./...                    # Run all tests
go test -v ./internal/config     # Verbose config tests
go test -cover ./...             # Show coverage percentage
go test -v -run TestPortValidation ./internal/config  # Specific test

Planned Next Phases:

  • Phase 2 (3-5h): Locator implementations, forward names, hot-reload tests
  • Phase 3 (5-10h): Runner lifecycle, reconnection behavior

Implement comprehensive unit tests for configuration loading and validation,
covering happy paths and error cases. Tests validate port ranges, detect
conflicts, and ensure proper error handling.

Test Coverage (Phase 1):
- Config loading and parsing:
  * Valid configuration with multiple forwards
  * Invalid ports (out of range, non-numeric)
  * Port conflicts detection (duplicate local ports)
  * CUE schema validation errors
- Port validation:
  * Valid range (1-65535)
  * Edge cases (0, 1, 65535, 65536, 99999, negative)
  * Non-numeric ports and malformed specifications
  * Both single ports and local:remote mappings

Files Added:
- internal/config/config_test.go - Unit tests for config validation
- internal/config/testdata/valid.cue - Valid configuration test data
- internal/config/testdata/port-conflict.cue - Port conflict test case
- internal/config/testdata/invalid-ports.cue - Invalid ports test case
- internal/config/testdata/duplicate-names.cue - Duplicate names test case

Test Results:
- 5 test functions with 13 total test cases
- Port validation edge cases: 9 sub-tests
- All tests passing (1 skipped for known CUE limitation)

Dependencies Added:
- github.com/stretchr/testify - Test assertions and utilities

Documentation:
- Add Testing section to README with commands
- Document test status and planned phases
- Include coverage report generation instructions

Test Commands:
```bash
go test ./...                    # Run all tests
go test -v ./internal/config     # Verbose config tests
go test -cover ./...             # Show coverage percentage
go test -v -run TestPortValidation ./internal/config  # Specific test
```

Planned Next Phases:
- Phase 2 (3-5h): Locator implementations, forward names, hot-reload tests
- Phase 3 (5-10h): Runner lifecycle, reconnection behavior
@SebastienLaurent-CF SebastienLaurent-CF self-assigned this Nov 22, 2025
Implement comprehensive test coverage for all locator implementations (pod, service, deployment, statefulset, daemonset) with mocked Kubernetes client. Refactor locator interfaces for better testability.

Architecture Changes:
- Create custom KubernetesClient interface hierarchy for cleaner abstraction:
  * KubernetesClient (CoreV1() + AppsV1())
  * CoreV1Client (Pods() + Services())
  * PodClient (Get() + List())
  * ServiceClient (Get())
  * AppsV1Client (Deployments() + StatefulSets() + DaemonSets())
  * ResourceClient (Get() returning interface{})
- Implement MockKubernetesClient supporting all resource types with helper methods
- Add adapters in runner.go to convert real kubernetes.Interface to custom interfaces
- Refactor locator implementations to use custom interfaces instead of kubernetes.Interface

Test Coverage (Phase 2):
- Pod locator (6 tests):
  * Pod found and running
  * Pod not found error handling
  * Pod not running states (pending, failed, succeeded, unknown)
- Service locator (3 tests):
  * Service found with running backing pod
  * Service not found error handling
  * No running pods for service error
- Resource locators (3 tests):
  * Deployment, StatefulSet, DaemonSet selector-based discovery
- Locator builder (16 tests):
  * Pod format routing (direct name)
  * Service formats: svc/, service/, services/
  * Deployment formats: dep/, deployment/, deployments/
  * StatefulSet formats: sts/, statefulset/, statefulsets/
  * DaemonSet formats: ds/, daemonset/, daemonsets/
  * Invalid format and too many slashes error handling

Files Added:
- internal/locator/mock_kubernetes.go - Complete mock client implementation (240+ lines)
- internal/locator/locator_test.go - Comprehensive locator tests (350+ lines)

Files Modified:
- internal/locator/locator.go - Define custom interfaces, refactor BuildLocator
- internal/locator/pod.go - Use KubernetesClient interface
- internal/locator/service.go - Use KubernetesClient interface
- internal/locator/selector_based_locator.go - Use KubernetesClient interface with type assertions
- internal/app/runner.go - Add adapter implementations (100+ lines) for real k8s client
- fwkeeper.cue - Example configuration updates

Test Results:
- Total: 38 tests passing
  * Phase 1 (config): 7 tests
  * Phase 2 (locators): 31 tests (28 locator + 3 builder specific)
- All tests passing, full project builds successfully

Benefits:
- Better interface segregation - clients only depend on methods they use
- Cleaner testing - mock client implements simple interfaces
- Adapter pattern maintains compatibility with real kubernetes.Interface
- Reduced coupling between locator implementations and Kubernetes client API
- Foundation for Phase 3 testing (runner lifecycle, reconnection behavior)

Planned Next Phases:
- Phase 3 (5-10h): Runner lifecycle, reconnection behavior, graceful shutdown
- Phase 4: Integration tests with real Kubernetes connectivity
Implement comprehensive test coverage for runner initialization, lifecycle management, and configuration handling. Tests validate graceful shutdown, context propagation, and internal state management.

Test Coverage (Phase 3 - 8 new tests):
- Runner lifecycle (4 tests):
  * Basic startup and initialization
  * Graceful shutdown without hanging or panics
  * Context cancellation propagation and handling
  * Multiple start/stop cycles for clean reuse
- Configuration management (4 tests):
  * Configuration change detection and storage
  * Empty configuration handling (zero forwarders)
  * Config path storage and retrieval
  * Forwarder map initialization and synchronization
…anges

Implement comprehensive test coverage for configuration hot-reload, change detection, and dynamic forwarder management. Tests validate configuration state management, mutex protection, and configuration change detection without requiring Kubernetes cluster access.

Test Coverage (Phase 4 - 6 new tests):
- Configuration change detection (5 sub-tests):
  * Identical configurations (no change detected)
  * Namespace changes trigger detection
  * Resource changes trigger detection
  * Port additions trigger detection
  * Port modifications trigger detection
- Configuration reload scenarios (5 tests):
  * Adding new forwarders during reload
  * Removing existing forwarders
  * Port configuration changes
  * Mutex protection during concurrent access
  * Complex scenarios (add, keep, remove forwarders)
…tate management

Implement comprehensive test coverage for configuration reload, forwarder lifecycle management, and file watcher logic. Tests validate state transitions, forwarder cleanup, and path comparison without requiring Kubernetes connectivity or file system integration.

Test Coverage (Phase 5 - 8 new tests, 17 sub-tests):
- baseName() helper function (6 sub-tests):
  * Unix absolute paths
  * Unix relative paths
  * Windows absolute paths
  * Filename only
  * Empty strings
  * Paths with trailing slashes
- Forwarder lifecycle management (2 tests):
  * stopForwarder() removes entries from maps
  * stopForwarder() handles non-existent forwarders gracefully
- Configuration reload and state management (4 tests):
  * Config state properly updated during reload
  * Complex state transitions (add/remove/modify forwarders)
  * Log configuration preserved across reloads
  * Multiple sequential reloads work correctly
- File watcher path comparison logic (3 sub-tests):
  * Exact path matches detected
  * Absolute paths matched correctly
  * Different files handled correctly
…nfig reload

Implement comprehensive test coverage for configuration file loading, file system monitoring, and real-world config reload scenarios. Tests validate config parsing from actual files, error handling for invalid configurations, and file modification detection without requiring live file system watcher integration.

Test Coverage (Phase 6 - 8 new tests):
- Configuration loading from real files (2 tests):
  * Single forwarder configuration from file
  * Multiple forwarders configuration with various port mappings
- File modification detection and reload (1 test):
  * File changes are detected and configuration reloaded correctly
- Configuration error handling (2 tests):
  * Invalid configuration file with bad values
  * Missing/non-existent configuration file
- File path handling and parsing (2 tests):
  * Config file path parsing (directory extraction from various path formats)
  * Config path storage in runner with real files
- Runner integration with config files (1 test):
  * Runner initialization with config file
…utdown

Implement comprehensive test coverage for graceful shutdown, context cancellation, and signal handling integration. Tests validate shutdown completeness, WaitGroup synchronization, context propagation, and safe multiple shutdown calls without requiring real OS signal handling.

Test Coverage (Phase 7 - 10 new tests):
- Graceful shutdown behavior (1 test):
  * Shutdown completes without hanging (timeout protection)
- Context cancellation and propagation (2 tests):
  * Context is cancelled on shutdown
  * Context integration throughout runner lifecycle
- Goroutine and WaitGroup management (3 tests):
  * Watcher goroutine stops on shutdown
  * Multiple shutdown calls are safe
  * WaitGroup synchronization works correctly
- Cancel function lifecycle (1 test):
  * Cancel function exists after start, nil before
- Forwarder map persistence (1 test):
  * Forwarder maps survive shutdown (app manages cleanup)
- Logger and logging (2 tests):
  * Logger accessible during and after shutdown
  * Shutdown logging doesn't panic
…TERM)

Implement comprehensive test coverage for OS signal handling integration. Tests validate signal notification setup, signal channel creation, SIGHUP for configuration reload, SIGTERM for shutdown, and multiple signal handling scenarios without requiring actual OS signal injection.

Test Coverage (Phase 8 - 9 new tests):
- Signal infrastructure setup (3 tests):
  * Signal notification can be set up for SIGHUP/SIGTERM
  * Signal channel creation and cleanup
  * Signal handling setup and teardown
- Signal channel operations (2 tests):
  * Signal channel buffering for multiple signals
  * Signal channel creation and send/receive
- Runner integration with signals (2 tests):
  * Signal channel works within runner context
  * Multiple signal channels can coexist
- Signal-specific handlers (2 tests):
  * SIGHUP configuration reload infrastructure
  * SIGTERM shutdown infrastructure
…port parsing)

Implement 11 comprehensive tests for Forwarder package without Kubernetes dependencies to ensure CI compatibility:

**RetryConfig Tests (4 tests)**:
- Default exponential backoff configuration validation
- Exponential backoff calculation with multiplier and max delay constraints
- Max delay enforcement preventing unbounded growth
- Jitter option for retry timing variance

**Port Parsing & Configuration Tests (7 tests)**:
- Port specification parsing (single ports, mapped ports, IPv6 addresses)
- PortForwardConfiguration validation with sub-tests:
  * Single port handling (8080 → local:8080, remote:8080)
  * Mapped port handling (8080:3000 → local:8080, remote:3000)
  * Multiple port configurations
  * Mixed mapped and unmapped ports
  * Empty port list edge case
- Port mapping edge cases (high ports, low ports, port identity mapping)
- Forwarder configuration creation and info methods
- Custom retry configuration with overrides
Eliminate 9 adapter types that added unnecessary indirection to the codebase.
The adapters (kubernetesClientAdapter, coreV1Adapter, podAdapter, serviceAdapter,
appsV1Adapter, deploymentAdapter, statefulSetAdapter, daemonSetAdapter) were
thin wrappers that simply passed through to kubernetes.Interface without adding value.

Changes:
- Removed 98 lines of adapter boilerplate from internal/app/runner.go
- Simplified locator interfaces to use kubernetes.Interface directly
- Updated pod.go, service.go, and selector_based_locator.go type signatures
- Refactored locator_test.go to use standard kubernetes/fake.Clientset
- Deleted mock_kubernetes.go (243 lines, replaced by fake.Clientset)
- Fixed TestRunnerConfigChangeDetection to use fake client for validation

Benefits:
- 30% reduction in runner.go code
- Improved maintainability by removing abstraction layers
- Aligns with Kubernetes ecosystem testing standards (fake.Clientset)
- Single source of truth: kubernetes.Interface
- Zero test regressions: 78/78 tests passing
@SebastienLaurent-CF SebastienLaurent-CF merged commit d06b5d7 into main Nov 23, 2025
2 checks passed
@SebastienLaurent-CF SebastienLaurent-CF deleted the feat/tests branch November 23, 2025 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant