Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions TEST_REFACTORING_ISSUE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Test Suite Refactoring Issue

## Overview
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.

## Critical Issues Found

### 1. Import Errors (8 files affected)
- Tests are importing non-existent classes/functions:
- `RealtimeClient` should be `ProjectXRealtimeClient`
- `ProjectXConfigError` doesn't exist in exceptions.py
- Multiple tests using outdated async class names

### 2. Outdated Test References
- 9 test files still reference old async classes:
- `AsyncProjectX` (now `ProjectX`)
- `AsyncOrderManager` (now `OrderManager`)
- `AsyncPositionManager` (now `PositionManager`)
- `create_async_trading_suite` (now `create_trading_suite`)

### 3. Missing Test Coverage
Critical components with no test coverage:
- **Indicators module** (9 modules, 0 tests)
- momentum indicators
- overlap indicators
- volatility indicators
- volume indicators
- base classes
- **Client module components** (refactored into submodules)
- **Realtime module components** (refactored into submodules)
- **Utils module components** (refactored into submodules)

### 4. Duplicate and Redundant Tests
- Multiple versions of same tests (async and sync)
- Test files for both old and new implementations
- Comprehensive test files that duplicate basic test files

## Specific Files Requiring Fixes

### Files with Import Errors:
1. `test_async_order_manager_comprehensive.py` - RealtimeClient import
2. `test_async_realtime.py` - RealtimeClient import
3. `test_config.py` - ProjectXConfigError import
4. `test_async_integration_comprehensive.py` - RealtimeClient import
5. `test_async_orderbook.py` - RealtimeClient import
6. `test_async_realtime_data_manager.py` - RealtimeClient import
7. `test_integration.py` - RealtimeClient import
8. `test_order_manager_init.py` - RealtimeClient import
9. `test_position_manager_init.py` - RealtimeClient import

### Files with Outdated References:
All async test files need updating to use new non-async class names.

## Proposed Action Plan

### Phase 1: Fix Import Errors
1. Update all `RealtimeClient` imports to `ProjectXRealtimeClient`
2. Remove or fix `ProjectXConfigError` references
3. Update all async class imports to new names

### Phase 2: Remove Redundant Tests
1. Consolidate duplicate async/sync test files
2. Remove tests for deprecated functionality
3. Merge comprehensive test files with basic ones

### Phase 3: Add Missing Test Coverage
1. Create test suite for indicators module:
- Test each indicator category
- Test class-based and function interfaces
- Test Polars DataFrame operations
2. Add tests for refactored modules:
- Client submodules
- Realtime submodules
- Utils submodules

### Phase 4: Modernize Test Structure
1. Use pytest fixtures consistently
2. Add proper mocking for external API calls
3. Implement test markers properly (unit, integration, slow)
4. Add async test support where needed

### Phase 5: Test Organization
1. Restructure tests to mirror source code structure:
```
tests/
├── unit/
│ ├── client/
│ ├── indicators/
│ ├── order_manager/
│ ├── position_manager/
│ └── utils/
├── integration/
└── conftest.py
```

## Success Criteria
- [ ] All tests can be collected without import errors
- [ ] Test coverage > 80% for all modules
- [ ] No duplicate or redundant tests
- [ ] Clear separation between unit and integration tests
- [ ] All tests pass in CI/CD pipeline
- [ ] Tests follow modern pytest patterns

## Priority
**High** - The test suite is currently broken and preventing proper validation of code changes.

## Labels
- bug
- testing
- refactoring
- technical-debt
17 changes: 17 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
asyncio_mode = auto

# Configure logging during tests
log_cli = True
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_cli_date_format = %Y-%m-%d %H:%M:%S

# Show extra test summary info
addopts =
--verbose
-xvs
45 changes: 30 additions & 15 deletions src/project_x_py/client/rate_limiter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,39 @@ def __init__(self, max_requests: int, window_seconds: int):
self.requests: list[float] = []
self._lock = asyncio.Lock()

def _calculate_delay(self) -> float:
"""Calculate the delay needed to stay within rate limits.

Returns:
float: Time to wait in seconds, or 0 if no wait is needed
"""
now = time.time()
# Remove old requests outside the window
self.requests = [t for t in self.requests if t > now - self.window_seconds]

if len(self.requests) >= self.max_requests:
# Calculate wait time
oldest_request = self.requests[0]
wait_time = (oldest_request + self.window_seconds) - now
return max(0.0, wait_time)

return 0.0

async def acquire(self) -> None:
"""Wait if necessary to stay within rate limits."""
async with self._lock:
now = time.time()
# Remove old requests outside the window
self.requests = [t for t in self.requests if t > now - self.window_seconds]

if len(self.requests) >= self.max_requests:
# Calculate wait time
oldest_request = self.requests[0]
wait_time = (oldest_request + self.window_seconds) - now
if wait_time > 0:
await asyncio.sleep(wait_time)
# Clean up again after waiting
now = time.time()
self.requests = [
t for t in self.requests if t > now - self.window_seconds
]
# Calculate any needed delay
wait_time = self._calculate_delay()

if wait_time > 0:
await asyncio.sleep(wait_time)
# Clean up again after waiting
now = time.time()
self.requests = [
t for t in self.requests if t > now - self.window_seconds
]
else:
now = time.time()

# Record this request
self.requests.append(now)
5 changes: 5 additions & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Pytest cache files
__pycache__/
.pytest_cache/
.coverage
htmlcov/
78 changes: 78 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# ProjectX Python SDK Test Suite

This directory contains comprehensive tests for the ProjectX Python SDK client module.

## Test Structure

The test suite is organized by module and component:

- `tests/conftest.py`: Common fixtures and test utilities
- `tests/test_client.py`: Basic smoke tests for the client module
- `tests/client/`: Detailed component tests
- `test_client_auth.py`: Authentication and token management tests
- `test_http.py`: HTTP client functionality tests
- `test_cache.py`: Caching system tests
- `test_market_data.py`: Market data operations tests
- `test_trading.py`: Trading operations tests
- `test_rate_limiter.py`: Rate limiting functionality tests
- `test_client_integration.py`: Integration tests with multiple components

## Running Tests

To run the full test suite:

```bash
# Run all tests
pytest

# Run with coverage report
pytest --cov=project_x_py

# Run specific test module
pytest tests/client/test_http.py

# Run specific test class
pytest tests/client/test_client_auth.py::TestClientAuth

# Run specific test
pytest tests/client/test_client_auth.py::TestClientAuth::test_authenticate_success
```

## Test Design

The tests are designed with the following principles:

1. **Isolated**: Tests don't make real API calls but use mocks
2. **Complete**: Tests cover both success and failure cases
3. **Efficient**: Tests share fixtures to minimize duplication
4. **Fast**: No unnecessary external dependencies or slow operations
5. **Comprehensive**: All public methods and critical internal methods are tested

## Key Fixtures

- `mock_response`: Creates configurable HTTP responses
- `mock_httpx_client`: Mock HTTP client for testing API calls
- `mock_auth_response`: Standard authentication response
- `mock_instrument`: Sample instrument object
- `mock_bars_data`: Sample OHLCV bar data
- `mock_positions_data`: Sample position data
- `mock_trades_data`: Sample trade data

## Adding New Tests

When adding new tests:

1. Follow the existing structure and naming conventions
2. Use appropriate fixtures from `conftest.py`
3. Test both success and error cases
4. Add docstrings to test classes and methods
5. Use descriptive assertion messages

## Future Improvements

Areas for future test improvements:

- Integration with CI/CD pipeline
- Property-based testing for complex scenarios
- Performance benchmarks
- Snapshot testing for response structures
Loading
Loading