Skip to content

Commit fe0d52e

Browse files
committed
Move rate limiting and ShareJson to another plugin
1 parent 4ece6ce commit fe0d52e

24 files changed

Lines changed: 277 additions & 3161 deletions

README.rst

Lines changed: 7 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -140,95 +140,27 @@ Examples
140140
"""10% of requests"""
141141
assert api.delete("/data/old").status_code == 204
142142
143-
**Conditional stop with shared state across workers:**
143+
**Conditional stop:**
144144

145145
.. code-block:: python
146146
147-
import pytest
148147
from pytest_load_testing import weight, stop_load_testing
149148
150-
@pytest.fixture(scope="session")
151-
def error_tracker(shared_json_fixture_factory):
152-
"""Track errors across all workers."""
153-
return shared_json_fixture_factory(
154-
name="errors",
155-
on_first_worker={'count': 0}
156-
)
157-
158149
@weight(1)
159-
def test_health_check(request, error_tracker):
150+
def test_health_check(request):
160151
response = api.get("/health")
161152
if response.json()["status"] == "critical":
162153
stop_load_testing(request, "System health critical")
163154
assert response.status_code == 200
164155
165-
@weight(10)
166-
def test_normal_operation(error_tracker):
167-
try:
168-
assert api.get("/api/data").status_code == 200
169-
except AssertionError:
170-
with error_tracker.locked_dict() as data:
171-
data['count'] += 1
172-
173-
See the full documentation for more details on concurrent fixtures and shared state.
174-
175-
176-
Rate Limiting
177-
~~~~~~~~~~~~~
178-
179-
The plugin provides a ``rate_limiter_fixture_factory`` for enforcing rate limits across workers:
180-
181-
.. code-block:: python
182-
183-
import pytest
184-
from pytest_load_testing import weight, stop_load_testing
185-
from pytest_load_testing.token_bucket_rate_limiter import RateLimit
186-
187-
@pytest.fixture(scope="session")
188-
def api_limiter(rate_limiter_fixture_factory, request):
189-
"""Rate limiter that stops tests if rate drift exceeds 20%."""
190-
191-
def on_drift(limiter_id, current_rate, target_rate, drift):
192-
message = (
193-
f"Rate drift for {limiter_id}: "
194-
f"current={current_rate:.2f}/hr, target={target_rate}/hr, "
195-
f"drift={drift:.2%}"
196-
)
197-
stop_load_testing(request, message)
198-
199-
return rate_limiter_fixture_factory(
200-
name="api_limiter",
201-
hourly_rate=RateLimit.per_second(10), # 10 calls/second
202-
max_drift=0.2, # 20% tolerance
203-
on_drift_callback=on_drift
204-
)
205-
206-
@weight(1)
207-
def test_api_call(api_limiter):
208-
with api_limiter.rate_limited_context() as ctx:
209-
# Context entry waits if rate limit would be exceeded
210-
response = api.get("/data")
211-
assert response.status_code == 200
212-
assert ctx.call_count >= 1
213-
214-
**Key Features:**
215-
216-
* **Token Bucket Algorithm**: Allows controlled bursts while maintaining average rate
217-
* **Shared State**: Rate limiting coordinated across all workers
218-
* **Drift Detection**: Monitors actual vs. target rate and triggers callbacks
219-
* **Max Calls**: Optional limit on total calls with callback
220-
* **Dynamic Rates**: Support for callable rate functions
221156
222-
**Rate Limit Helpers:**
223-
224-
.. code-block:: python
157+
Rate Limiting and Shared State
158+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225159

226-
RateLimit.per_second(10) # 10 calls per second
227-
RateLimit.per_minute(600) # 600 calls per minute
228-
RateLimit.per_hour(3600) # 3600 calls per hour
229-
RateLimit.per_day(86400) # 86400 calls per day
160+
For rate limiting and shared state management across pytest-xdist workers,
161+
see the companion package `pytest-xdist-rate-limit`_.
230162

231-
See the full documentation for more examples and advanced usage.
163+
.. _`pytest-xdist-rate-limit`: https://github.com/xverges/pytest-xdist-rate-limit
232164

233165

234166
License

examples/conftest.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
"""Conftest for examples to ensure fixtures work with xdist."""
1+
"""Conftest for examples."""
22

3-
from pytest_load_testing.concurrent_fixtures import (
4-
rate_limiter_fixture_factory,
5-
shared_json_fixture_factory,
6-
)
7-
8-
# Re-export the fixtures so they're available in examples
9-
__all__ = ["shared_json_fixture_factory", "rate_limiter_fixture_factory"]
3+
# No special fixtures needed for basic load testing examples

examples/test_load_example.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""
2+
Example: Load testing with weighted distribution
3+
4+
Run with: pytest -n auto --load-test examples/test_load_example.py
5+
6+
This demonstrates:
7+
1. Weighted test selection (tests run with different frequencies)
8+
2. Conditional stopping based on iteration count
9+
10+
TEST_CODE:
11+
```python
12+
result = pytester.runpytest('--load-test', '-n', '2', '-v')
13+
result.stdout.fnmatch_lines([
14+
'*Interrupted: Test session completed*',
15+
])
16+
assert result.ret == pytest.ExitCode.INTERRUPTED
17+
```
18+
"""
19+
20+
import pytest
21+
22+
from pytest_load_testing import stop_load_testing, weight
23+
24+
# Simple counter without shared state
25+
_iteration_count = 0
26+
27+
28+
@pytest.fixture
29+
def iteration_counter(request):
30+
"""Common fixture that tracks iterations and stops after threshold."""
31+
global _iteration_count
32+
_iteration_count += 1
33+
34+
# Stop after 100 total test executions
35+
if _iteration_count >= 100:
36+
stop_load_testing(request, "Test session completed")
37+
38+
39+
@weight(70)
40+
def test_read_heavy(iteration_counter):
41+
"""70% of requests - simulates read-heavy operations."""
42+
assert True
43+
44+
45+
@weight(20)
46+
def test_write_operations(iteration_counter):
47+
"""20% of requests - simulates write operations."""
48+
assert True
49+
50+
51+
@weight(10)
52+
def test_admin_operations(iteration_counter):
53+
"""10% of requests - simulates admin operations."""
54+
assert True
55+
56+
57+
@weight(1)
58+
def test_health_check(iteration_counter):
59+
"""1% of requests - simulates health check."""
60+
assert True

examples/test_rate_limiter_example.py

Lines changed: 0 additions & 141 deletions
This file was deleted.

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ classifiers = [
3737
dependencies = [
3838
"pytest>=6.2.0",
3939
"pytest-xdist>=2.0.0",
40-
"filelock>=3.0.0",
4140
]
4241
[project.urls]
4342
Repository = "https://github.com/xverges/pytest-xdist-load-testing"
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
"""pytest-xdist-load-testing: Load testing scheduler for pytest-xdist."""
22

33
from .api import stop_load_testing, weight
4-
from .concurrent_fixtures import SharedJson, shared_json_fixture_factory
5-
from .token_bucket_rate_limiter import RateLimit, TokenBucketRateLimiter
64

75
__version__ = "0.1.0"
86
__all__ = [
97
"weight",
108
"stop_load_testing",
11-
"shared_json_fixture_factory",
12-
"SharedJson",
13-
"RateLimit",
14-
"TokenBucketRateLimiter",
159
]

0 commit comments

Comments
 (0)