Skip to content

Commit 4247422

Browse files
authored
Merge pull request #21 from TexasCoding/testing_suite
Testing suite
2 parents 914adaf + 4e77323 commit 4247422

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2739
-9543
lines changed

TEST_REFACTORING_ISSUE.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Test Suite Refactoring Issue
2+
3+
## Overview
4+
The current test suite has significant issues that prevent tests from running properly. Out of 27 test files with 226 tests collected, there are 8 import errors preventing test execution. Additionally, there are major gaps in test coverage and outdated test implementations.
5+
6+
## Critical Issues Found
7+
8+
### 1. Import Errors (8 files affected)
9+
- Tests are importing non-existent classes/functions:
10+
- `RealtimeClient` should be `ProjectXRealtimeClient`
11+
- `ProjectXConfigError` doesn't exist in exceptions.py
12+
- Multiple tests using outdated async class names
13+
14+
### 2. Outdated Test References
15+
- 9 test files still reference old async classes:
16+
- `AsyncProjectX` (now `ProjectX`)
17+
- `AsyncOrderManager` (now `OrderManager`)
18+
- `AsyncPositionManager` (now `PositionManager`)
19+
- `create_async_trading_suite` (now `create_trading_suite`)
20+
21+
### 3. Missing Test Coverage
22+
Critical components with no test coverage:
23+
- **Indicators module** (9 modules, 0 tests)
24+
- momentum indicators
25+
- overlap indicators
26+
- volatility indicators
27+
- volume indicators
28+
- base classes
29+
- **Client module components** (refactored into submodules)
30+
- **Realtime module components** (refactored into submodules)
31+
- **Utils module components** (refactored into submodules)
32+
33+
### 4. Duplicate and Redundant Tests
34+
- Multiple versions of same tests (async and sync)
35+
- Test files for both old and new implementations
36+
- Comprehensive test files that duplicate basic test files
37+
38+
## Specific Files Requiring Fixes
39+
40+
### Files with Import Errors:
41+
1. `test_async_order_manager_comprehensive.py` - RealtimeClient import
42+
2. `test_async_realtime.py` - RealtimeClient import
43+
3. `test_config.py` - ProjectXConfigError import
44+
4. `test_async_integration_comprehensive.py` - RealtimeClient import
45+
5. `test_async_orderbook.py` - RealtimeClient import
46+
6. `test_async_realtime_data_manager.py` - RealtimeClient import
47+
7. `test_integration.py` - RealtimeClient import
48+
8. `test_order_manager_init.py` - RealtimeClient import
49+
9. `test_position_manager_init.py` - RealtimeClient import
50+
51+
### Files with Outdated References:
52+
All async test files need updating to use new non-async class names.
53+
54+
## Proposed Action Plan
55+
56+
### Phase 1: Fix Import Errors
57+
1. Update all `RealtimeClient` imports to `ProjectXRealtimeClient`
58+
2. Remove or fix `ProjectXConfigError` references
59+
3. Update all async class imports to new names
60+
61+
### Phase 2: Remove Redundant Tests
62+
1. Consolidate duplicate async/sync test files
63+
2. Remove tests for deprecated functionality
64+
3. Merge comprehensive test files with basic ones
65+
66+
### Phase 3: Add Missing Test Coverage
67+
1. Create test suite for indicators module:
68+
- Test each indicator category
69+
- Test class-based and function interfaces
70+
- Test Polars DataFrame operations
71+
2. Add tests for refactored modules:
72+
- Client submodules
73+
- Realtime submodules
74+
- Utils submodules
75+
76+
### Phase 4: Modernize Test Structure
77+
1. Use pytest fixtures consistently
78+
2. Add proper mocking for external API calls
79+
3. Implement test markers properly (unit, integration, slow)
80+
4. Add async test support where needed
81+
82+
### Phase 5: Test Organization
83+
1. Restructure tests to mirror source code structure:
84+
```
85+
tests/
86+
├── unit/
87+
│ ├── client/
88+
│ ├── indicators/
89+
│ ├── order_manager/
90+
│ ├── position_manager/
91+
│ └── utils/
92+
├── integration/
93+
└── conftest.py
94+
```
95+
96+
## Success Criteria
97+
- [ ] All tests can be collected without import errors
98+
- [ ] Test coverage > 80% for all modules
99+
- [ ] No duplicate or redundant tests
100+
- [ ] Clear separation between unit and integration tests
101+
- [ ] All tests pass in CI/CD pipeline
102+
- [ ] Tests follow modern pytest patterns
103+
104+
## Priority
105+
**High** - The test suite is currently broken and preventing proper validation of code changes.
106+
107+
## Labels
108+
- bug
109+
- testing
110+
- refactoring
111+
- technical-debt

pytest.ini

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[pytest]
2+
testpaths = tests
3+
python_files = test_*.py
4+
python_classes = Test*
5+
python_functions = test_*
6+
asyncio_mode = auto
7+
8+
# Configure logging during tests
9+
log_cli = True
10+
log_cli_level = INFO
11+
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
12+
log_cli_date_format = %Y-%m-%d %H:%M:%S
13+
14+
# Show extra test summary info
15+
addopts =
16+
--verbose
17+
-xvs

src/project_x_py/client/rate_limiter.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,39 @@ def __init__(self, max_requests: int, window_seconds: int):
1313
self.requests: list[float] = []
1414
self._lock = asyncio.Lock()
1515

16+
def _calculate_delay(self) -> float:
17+
"""Calculate the delay needed to stay within rate limits.
18+
19+
Returns:
20+
float: Time to wait in seconds, or 0 if no wait is needed
21+
"""
22+
now = time.time()
23+
# Remove old requests outside the window
24+
self.requests = [t for t in self.requests if t > now - self.window_seconds]
25+
26+
if len(self.requests) >= self.max_requests:
27+
# Calculate wait time
28+
oldest_request = self.requests[0]
29+
wait_time = (oldest_request + self.window_seconds) - now
30+
return max(0.0, wait_time)
31+
32+
return 0.0
33+
1634
async def acquire(self) -> None:
1735
"""Wait if necessary to stay within rate limits."""
1836
async with self._lock:
19-
now = time.time()
20-
# Remove old requests outside the window
21-
self.requests = [t for t in self.requests if t > now - self.window_seconds]
22-
23-
if len(self.requests) >= self.max_requests:
24-
# Calculate wait time
25-
oldest_request = self.requests[0]
26-
wait_time = (oldest_request + self.window_seconds) - now
27-
if wait_time > 0:
28-
await asyncio.sleep(wait_time)
29-
# Clean up again after waiting
30-
now = time.time()
31-
self.requests = [
32-
t for t in self.requests if t > now - self.window_seconds
33-
]
37+
# Calculate any needed delay
38+
wait_time = self._calculate_delay()
39+
40+
if wait_time > 0:
41+
await asyncio.sleep(wait_time)
42+
# Clean up again after waiting
43+
now = time.time()
44+
self.requests = [
45+
t for t in self.requests if t > now - self.window_seconds
46+
]
47+
else:
48+
now = time.time()
3449

3550
# Record this request
3651
self.requests.append(now)

tests/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Pytest cache files
2+
__pycache__/
3+
.pytest_cache/
4+
.coverage
5+
htmlcov/

tests/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# ProjectX Python SDK Test Suite
2+
3+
This directory contains comprehensive tests for the ProjectX Python SDK client module.
4+
5+
## Test Structure
6+
7+
The test suite is organized by module and component:
8+
9+
- `tests/conftest.py`: Common fixtures and test utilities
10+
- `tests/test_client.py`: Basic smoke tests for the client module
11+
- `tests/client/`: Detailed component tests
12+
- `test_client_auth.py`: Authentication and token management tests
13+
- `test_http.py`: HTTP client functionality tests
14+
- `test_cache.py`: Caching system tests
15+
- `test_market_data.py`: Market data operations tests
16+
- `test_trading.py`: Trading operations tests
17+
- `test_rate_limiter.py`: Rate limiting functionality tests
18+
- `test_client_integration.py`: Integration tests with multiple components
19+
20+
## Running Tests
21+
22+
To run the full test suite:
23+
24+
```bash
25+
# Run all tests
26+
pytest
27+
28+
# Run with coverage report
29+
pytest --cov=project_x_py
30+
31+
# Run specific test module
32+
pytest tests/client/test_http.py
33+
34+
# Run specific test class
35+
pytest tests/client/test_client_auth.py::TestClientAuth
36+
37+
# Run specific test
38+
pytest tests/client/test_client_auth.py::TestClientAuth::test_authenticate_success
39+
```
40+
41+
## Test Design
42+
43+
The tests are designed with the following principles:
44+
45+
1. **Isolated**: Tests don't make real API calls but use mocks
46+
2. **Complete**: Tests cover both success and failure cases
47+
3. **Efficient**: Tests share fixtures to minimize duplication
48+
4. **Fast**: No unnecessary external dependencies or slow operations
49+
5. **Comprehensive**: All public methods and critical internal methods are tested
50+
51+
## Key Fixtures
52+
53+
- `mock_response`: Creates configurable HTTP responses
54+
- `mock_httpx_client`: Mock HTTP client for testing API calls
55+
- `mock_auth_response`: Standard authentication response
56+
- `mock_instrument`: Sample instrument object
57+
- `mock_bars_data`: Sample OHLCV bar data
58+
- `mock_positions_data`: Sample position data
59+
- `mock_trades_data`: Sample trade data
60+
61+
## Adding New Tests
62+
63+
When adding new tests:
64+
65+
1. Follow the existing structure and naming conventions
66+
2. Use appropriate fixtures from `conftest.py`
67+
3. Test both success and error cases
68+
4. Add docstrings to test classes and methods
69+
5. Use descriptive assertion messages
70+
71+
## Future Improvements
72+
73+
Areas for future test improvements:
74+
75+
- Integration with CI/CD pipeline
76+
- Property-based testing for complex scenarios
77+
- Performance benchmarks
78+
- Snapshot testing for response structures

0 commit comments

Comments
 (0)