-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Overview
This milestone captures structural changes to the ProxySQL codebase that make it inherently more testable over time. Unlike Milestones 2–4 which work around the current architecture, this milestone gradually evolves the architecture itself.
These changes are applied opportunistically — when code is already being modified for features or bug fixes — not as a dedicated refactoring project.
Motivation
The current architecture has 25 global singletons accessed directly throughout the codebase (647+ references). While Milestones 2–4 work around this via stubs and extraction, the root cause remains: tight coupling through global state makes it impossible to test many components without scaffolding the entire system.
Long-term, reducing this coupling improves not just testability but also:
- Debuggability — easier to reason about data flow when dependencies are explicit
- Parallelism — explicit dependencies enable safer concurrent development
- Modularity — components can be reused, replaced, or versioned independently
Candidate Improvements
These are directional — specific scoping will depend on learnings from Milestones 2–4:
1. Dependency Injection for Glo* Singletons
Pass dependencies explicitly via constructors or method parameters instead of reaching for globals. Applied gradually:
- New code uses DI from the start
- Existing code is retrofitted only when already being modified
- Globals remain as a compatibility layer during transition
2. Interface Extraction
Define abstract interfaces (pure virtual base classes) for major components:
IHostGroupsManager— server selection and pool managementIQueryProcessor— rule matchingIAuthentication— credential lookupIMonitor— health checking
Tests can then provide mock implementations. Production code uses the real implementations.
3. Break Up proxysql.h
The mega-header forces every translation unit to depend on everything. Splitting it into focused headers (e.g., proxysql_types.h, proxysql_enums.h, proxysql_forward_decls.h) would:
- Reduce compilation times
- Allow test files to include only what they need
- Make dependency relationships explicit
4. Separate proxysql_structs.h
At ~29,000 lines with thread-local variables, forward declarations, enums, and struct definitions all mixed together, this file is a bottleneck. Splitting by concern would improve build times and testability.
5. CI Integration
- Dedicated CI job for unit tests (runs in seconds, no Docker)
- Unit tests gate PR merging before heavy E2E tests run
- Coverage reporting for unit-tested code paths
- ASAN/TSAN runs for unit tests on every PR
Principles
- Opportunistic, not speculative — make these changes when touching code for other reasons
- Backwards compatible — existing code and tests continue to work during transition
- Measurable — track test coverage, build times, and test execution times to demonstrate value
- No big bang — each change is small, reviewable, and independently valuable
Prerequisites
- Milestones 2–4 substantially complete
- Clear evidence of which architectural constraints are the biggest testing bottlenecks
- Team alignment on the value of these changes vs. their cost
Relationship to Other Milestones
- Milestone 2 (Unit Testing Framework: Milestone 2 — Component Tests via Glo* Stubs #5472) — component unit tests via Glo* stubs
- Milestone 3 (Unit Testing Milestone 3: Extract Testable Logic from Coupled Classes #5479) — extract testable logic from coupled classes
- Milestone 4 (Unit Testing Milestone 4: Component-Level Integration Tests (No Docker) #5480) — lightweight component integration tests
- Milestone 5 (this) — evolve the architecture for inherent testability