Add performance regression test suite to CI#391
Conversation
|
😎 Merged manually by @abhimehro - details. |
Co-authored-by: abhimehro <84992105+abhimehro@users.noreply.github.com>
|
👋 Development Partner is reviewing this PR. Will provide feedback shortly. |
| # Use a private IP so no real DNS lookup occurs, making the test fast and deterministic | ||
| main.validate_hostname.cache_clear() | ||
| result = benchmark(main.validate_hostname, "192.168.1.1") | ||
| assert result is False # Private IP is rejected |
Check notice
Code scanning / Bandit
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| main.validate_hostname.cache_clear() | ||
| result = benchmark(main.validate_hostname, "192.168.1.1") | ||
| assert result is False # Private IP is rejected | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S |
Check notice
Code scanning / Bandit
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| main.validate_hostname("10.0.0.1") | ||
| # Now benchmark the cached call | ||
| result = benchmark(main.validate_hostname, "10.0.0.1") | ||
| assert result is False |
Check notice
Code scanning / Bandit
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| # Now benchmark the cached call | ||
| result = benchmark(main.validate_hostname, "10.0.0.1") | ||
| assert result is False | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S |
Check notice
Code scanning / Bandit
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| mock_response = httpx.Response(200, headers=headers) | ||
|
|
||
| result = benchmark(main._parse_rate_limit_headers, mock_response) | ||
| assert result is None # Function returns None |
Check notice
Code scanning / Bandit
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
|
|
||
| result = benchmark(main._parse_rate_limit_headers, mock_response) | ||
| assert result is None # Function returns None | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S |
Check notice
Code scanning / Bandit
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| """Rate limit parsing with no rate-limit headers should complete in <1ms.""" | ||
| mock_response = httpx.Response(200, headers={}) | ||
| result = benchmark(main._parse_rate_limit_headers, mock_response) | ||
| assert result is None |
Check notice
Code scanning / Bandit
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| mock_response = httpx.Response(200, headers={}) | ||
| result = benchmark(main._parse_rate_limit_headers, mock_response) | ||
| assert result is None | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S |
Check notice
Code scanning / Bandit
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| import sys | ||
| import os | ||
|
|
||
| import pytest |
Check warning
Code scanning / Prospector (reported by Codacy)
Unable to import 'pytest' (import-error) Warning test
| import sys | ||
| import os | ||
|
|
||
| import pytest |
Check warning
Code scanning / Prospector (reported by Codacy)
Unused import pytest (unused-import) Warning test
| import os | ||
|
|
||
| import pytest | ||
| import httpx |
Check warning
Code scanning / Prospector (reported by Codacy)
Unable to import 'httpx' (import-error) Warning test
| import httpx | ||
|
|
||
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | ||
| import main |
Check warning
Code scanning / Prospector (reported by Codacy)
Cannot import 'main' due to syntax error 'invalid syntax (, line 1286)' (syntax-error) Warning test
| } | ||
| mock_response = httpx.Response(200, headers=headers) | ||
|
|
||
| result = benchmark(main._parse_rate_limit_headers, mock_response) |
Check warning
Code scanning / Prospector (reported by Codacy)
Access to a protected member _parse_rate_limit_headers of a client class (protected-access) Warning test
| def test_rate_limit_parsing_empty_headers_performance(self, benchmark): | ||
| """Rate limit parsing with no rate-limit headers should complete in <1ms.""" | ||
| mock_response = httpx.Response(200, headers={}) | ||
| result = benchmark(main._parse_rate_limit_headers, mock_response) |
Check warning
Code scanning / Prospector (reported by Codacy)
Access to a protected member _parse_rate_limit_headers of a client class (protected-access) Warning test
| import httpx | ||
|
|
||
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | ||
| import main |
Check warning
Code scanning / Pylint (reported by Codacy)
Import "import main" should be placed at the top of the module Warning test
| class TestPerformanceRegression: | ||
| """Performance regression tests with baseline thresholds.""" | ||
|
|
||
| def test_validate_hostname_performance(self, benchmark): |
Check warning
Code scanning / Pylint (reported by Codacy)
Method could be a function Warning test
| assert result is False # Private IP is rejected | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S | ||
|
|
||
| def test_validate_hostname_cached_performance(self, benchmark): |
Check warning
Code scanning / Pylint (reported by Codacy)
Method could be a function Warning test
| assert result is False | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S | ||
|
|
||
| def test_rate_limit_parsing_performance(self, benchmark): |
Check warning
Code scanning / Pylint (reported by Codacy)
Method could be a function Warning test
| assert result is None # Function returns None | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S | ||
|
|
||
| def test_rate_limit_parsing_empty_headers_performance(self, benchmark): |
Check warning
Code scanning / Pylint (reported by Codacy)
Method could be a function Warning test
| import sys | ||
| import os | ||
|
|
||
| import pytest |
Check notice
Code scanning / Pylint (reported by Codacy)
Unused import pytest Note test
| } | ||
| mock_response = httpx.Response(200, headers=headers) | ||
|
|
||
| result = benchmark(main._parse_rate_limit_headers, mock_response) |
Check notice
Code scanning / Pylint (reported by Codacy)
Access to a protected member _parse_rate_limit_headers of a client class Note test
| def test_rate_limit_parsing_empty_headers_performance(self, benchmark): | ||
| """Rate limit parsing with no rate-limit headers should complete in <1ms.""" | ||
| mock_response = httpx.Response(200, headers={}) | ||
| result = benchmark(main._parse_rate_limit_headers, mock_response) |
Check notice
Code scanning / Pylint (reported by Codacy)
Access to a protected member _parse_rate_limit_headers of a client class Note test
| # Use a private IP so no real DNS lookup occurs, making the test fast and deterministic | ||
| main.validate_hostname.cache_clear() | ||
| result = benchmark(main.validate_hostname, "192.168.1.1") | ||
| assert result is False # Private IP is rejected |
Check notice
Code scanning / Bandit (reported by Codacy)
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| main.validate_hostname.cache_clear() | ||
| result = benchmark(main.validate_hostname, "192.168.1.1") | ||
| assert result is False # Private IP is rejected | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S |
Check notice
Code scanning / Bandit (reported by Codacy)
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| main.validate_hostname("10.0.0.1") | ||
| # Now benchmark the cached call | ||
| result = benchmark(main.validate_hostname, "10.0.0.1") | ||
| assert result is False |
Check notice
Code scanning / Bandit (reported by Codacy)
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| # Now benchmark the cached call | ||
| result = benchmark(main.validate_hostname, "10.0.0.1") | ||
| assert result is False | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S |
Check notice
Code scanning / Bandit (reported by Codacy)
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| mock_response = httpx.Response(200, headers=headers) | ||
|
|
||
| result = benchmark(main._parse_rate_limit_headers, mock_response) | ||
| assert result is None # Function returns None |
Check notice
Code scanning / Bandit (reported by Codacy)
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
|
|
||
| result = benchmark(main._parse_rate_limit_headers, mock_response) | ||
| assert result is None # Function returns None | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S |
Check notice
Code scanning / Bandit (reported by Codacy)
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| """Rate limit parsing with no rate-limit headers should complete in <1ms.""" | ||
| mock_response = httpx.Response(200, headers={}) | ||
| result = benchmark(main._parse_rate_limit_headers, mock_response) | ||
| assert result is None |
Check notice
Code scanning / Bandit (reported by Codacy)
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| mock_response = httpx.Response(200, headers={}) | ||
| result = benchmark(main._parse_rate_limit_headers, mock_response) | ||
| assert result is None | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S |
Check notice
Code scanning / Bandit (reported by Codacy)
Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test
| import httpx | ||
|
|
||
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | ||
| import main |
Check warning
Code scanning / Pylintpython3 (reported by Codacy)
Import "import main" should be placed at the top of the module Warning test
| class TestPerformanceRegression: | ||
| """Performance regression tests with baseline thresholds.""" | ||
|
|
||
| def test_validate_hostname_performance(self, benchmark): |
Check warning
Code scanning / Pylintpython3 (reported by Codacy)
Method could be a function Warning test
| assert result is False # Private IP is rejected | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S | ||
|
|
||
| def test_validate_hostname_cached_performance(self, benchmark): |
Check warning
Code scanning / Pylintpython3 (reported by Codacy)
Method could be a function Warning test
| assert result is False | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S | ||
|
|
||
| def test_rate_limit_parsing_performance(self, benchmark): |
Check warning
Code scanning / Pylintpython3 (reported by Codacy)
Method could be a function Warning test
| assert result is None # Function returns None | ||
| assert benchmark.stats["mean"] < _MAX_MEAN_S | ||
|
|
||
| def test_rate_limit_parsing_empty_headers_performance(self, benchmark): |
Check warning
Code scanning / Pylintpython3 (reported by Codacy)
Method could be a function Warning test
| import sys | ||
| import os | ||
|
|
||
| import pytest |
Check notice
Code scanning / Pylintpython3 (reported by Codacy)
Unused import pytest Note test
| } | ||
| mock_response = httpx.Response(200, headers=headers) | ||
|
|
||
| result = benchmark(main._parse_rate_limit_headers, mock_response) |
Check notice
Code scanning / Pylintpython3 (reported by Codacy)
Access to a protected member _parse_rate_limit_headers of a client class Note test
| def test_rate_limit_parsing_empty_headers_performance(self, benchmark): | ||
| """Rate limit parsing with no rate-limit headers should complete in <1ms.""" | ||
| mock_response = httpx.Response(200, headers={}) | ||
| result = benchmark(main._parse_rate_limit_headers, mock_response) |
Check notice
Code scanning / Pylintpython3 (reported by Codacy)
Access to a protected member _parse_rate_limit_headers of a client class Note test
No automated performance testing meant regressions on hot paths (
validate_hostname,_parse_rate_limit_headers) could ship undetected with no baseline to compare against.Changes
tests/test_performance_regression.pyFour
pytest-benchmarktests covering the two critical hot paths:validate_hostname— cold call (private IP, no DNS) and LRU cache hit_parse_rate_limit_headers— with and without rate-limit headers presentAll assert
benchmark.stats["mean"] < _MAX_MEAN_S(1 ms) against a shared module-level constant to keep threshold changes to a single line..github/workflows/performance.ymlNew workflow triggers on PRs touching
main.pyortests/test_performance_*.pyand on every push tomain. Usesuv(matching existing dev workflow), autosaves benchmark results, and uploads.benchmarks/as an artifact for run-to-run comparison.pyproject.tomlAdded
pytest-benchmark>=4.0.0to[project.optional-dependencies] dev.Original prompt
This section details on the original issue you should resolve
<issue_title>[Code Quality] Add performance regression test suite to CI</issue_title>
<issue_description>### Description
Implement a performance regression test suite to detect performance degradations during development. This prevents unintentional slowdowns and validates optimization efforts.
Problem
Current State:
Impact:
Suggested Changes
1. Add pytest-benchmark dependency
2. Create performance test suite
3. Add CI workflow step
Files Affected
tests/test_performance_regression.py- Regression test suite.github/workflows/performance.yml- CI workflowpyproject.toml- Add pytest-benchmark dependencyrequirements.txt- May need update if used for dev depsSuccess Criteria
Testing Targets (Initial)
Source
Extracted from Daily Perf Improver discussion abhimehro/ctrld-sync#219 which identified this as a key infrastructure need for preventing performance regressions.
Priority
Medium - Prevents future issues but not blocking current work
References
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.