# BaoLife/Lichun Test Suite

Comprehensive test suite for the BaoLife backend, focusing on async database operations, game logic, and WebSocket functionality.

## Setup

### 1. Install Test Dependencies

```bash
pip install -r requirements-test.txt
```

### 2. Configure Test Database

The tests use a separate test database to avoid affecting production data.

**Option A: Automatic (uses environment variable)**
```bash
export DB_NAME=lifesim_test
export TEST_MODE=true
```

**Option B: Create test database manually**
```sql
CREATE DATABASE lifesim_test;
USE lifesim_test;
-- Import your schema here
```

## Running Tests

### Run All Tests
```bash
pytest
```

### Run Integration Tests Only
```bash
pytest tests/integration/
```

### Run Specific Test File
```bash
pytest tests/integration/test_database_async.py
```

### Run Specific Test
```bash
pytest tests/integration/test_database_async.py::test_initialize_pool_creates_pool
```

### Run with Coverage
```bash
pytest --cov=ws --cov-report=html
open htmlcov/index.html
```

### Run with Verbose Output
```bash
pytest -v
```

### Run Tests Matching Pattern
```bash
pytest -k "transaction"
```

## Test Structure

```
tests/
├── __init__.py
├── conftest.py                          # Shared fixtures (db_pool, db_transaction, etc.)
├── pytest.ini                           # Pytest configuration (moved to root)
├── README.md                            # This file
│
└── integration/
    ├── __init__.py
    └── test_database_async.py          # 33 async database tests
```

## Test Categories

### Integration Tests: Database Async (33 tests)

**Pool Management (6 tests)**
- `test_initialize_pool_creates_pool` - Verify pool creation
- `test_initialize_pool_connects_to_database` - Verify DB connection
- `test_close_pool_closes_all_connections` - Verify cleanup
- `test_pool_size_respected` - Verify max connections enforced
- `test_pool_connection_reuse` - Verify connection reuse
- `test_pool_exhaustion_waits` - Verify wait behavior when pool full

**Query Execution (5 tests)**
- `test_execute_query_insert` - INSERT operations
- `test_execute_query_update` - UPDATE operations
- `test_execute_query_delete` - DELETE operations
- `test_execute_query_with_parameters` - Parameterized queries
- `test_execute_query_sql_injection_prevented` - SQL injection protection

**Fetch Operations (6 tests)**
- `test_fetch_one_returns_tuple` - Single row as tuple
- `test_fetch_all_returns_list` - Multiple rows as list
- `test_fetch_dict_one_returns_dict` - Single row as dict
- `test_fetch_dict_all_returns_list_of_dicts` - Multiple rows as dicts
- `test_fetch_empty_result` - Empty result handling
- `test_execute_many_batch_insert` - Batch insert operations

**Transactions (5 tests)**
- `test_transaction_commits` - Successful commit
- `test_transaction_rolls_back_on_error` - Rollback on exception
- `test_transaction_context_manager` - Context manager usage
- `test_nested_transactions` - Sequential transactions
- `test_transaction_isolation` - Transaction isolation

**Error Handling (6 tests)**
- `test_pool_not_initialized_raises_error` - Pool initialization check
- `test_query_timeout_handled` - Timeout handling
- `test_connection_lost_reconnects` - Reconnection handling
- `test_database_down_raises_error` - Database unavailable error
- `test_malformed_query_raises_error` - Invalid SQL handling
- `test_get_connection_requires_pool` - Pool requirement check

**Edge Cases (2 tests)**
- `test_concurrent_transactions` - Concurrent transaction handling
- `test_pool_initialization_is_idempotent` - Multiple init calls

## Fixtures

### Database Fixtures (in conftest.py)

**`db_pool`** (session-scoped)
- Creates a connection pool for the entire test session
- Automatically closed after all tests complete
- Pool size: 5 connections

**`db_connection`** (function-scoped)
- Provides a fresh connection for each test
- Automatically returned to pool after test

**`db_transaction`** (function-scoped)
- Provides a connection with transaction
- **Automatically rolls back after test** (cleanup)
- Use this for tests that modify data

**`test_table`** (function-scoped)
- Creates a temporary test table
- Automatically dropped after test
- Table schema: id, name, value, created_at

**`cleanup_pool`** (function-scoped)
- Resets global pool state
- Use for tests that test pool initialization

## Best Practices

### 1. Use Fixtures for Database Access
```python
@pytest.mark.asyncio
async def test_something(db_transaction):
    conn = db_transaction
    async with conn.cursor() as cursor:
        await cursor.execute("INSERT INTO ...")
    # Automatically rolled back
```

### 2. Test Isolation
Each test should be independent and not rely on other tests' data.

### 3. Async Tests
All database tests must be marked with `@pytest.mark.asyncio`:
```python
@pytest.mark.asyncio
async def test_async_operation():
    result = await fetch_one("SELECT 1")
    assert result == (1,)
```

### 4. Error Testing
Use `pytest.raises` for expected errors:
```python
with pytest.raises(RuntimeError, match="Database pool not initialized"):
    await execute_query("SELECT 1")
```

## CI/CD Integration

Add to your GitHub Actions workflow:

```yaml
- name: Run tests
  env:
    DB_NAME: lifesim_test
    TEST_MODE: true
  run: |
    pip install -r requirements-test.txt
    pytest tests/integration/ -v
```

## Coverage Goals

According to TESTING_PLAN.md:
- **Overall target**: 80%+
- **Database operations**: 90%+
- **Integration tests**: 60%+

Current coverage for database_async.py: ~95% (estimated)

## Troubleshooting

### "Database pool not initialized" error
- Ensure `db_pool` fixture is included in test function parameters
- Or run `await initialize_pool()` in test setup

### Connection pool exhausted
- Tests may not be cleaning up connections properly
- Ensure all tests use fixtures or manually release connections

### Test database not found
- Create the test database: `CREATE DATABASE lifesim_test;`
- Or set `DB_NAME` environment variable

### Async warnings
- Ensure all async tests are marked with `@pytest.mark.asyncio`
- Add `asyncio_mode = auto` to pytest.ini (already configured)

## Next Steps

1. Run the test suite to verify setup
2. Add unit tests for game logic (see TESTING_PLAN.md)
3. Add WebSocket integration tests
4. Set up CI/CD pipeline
5. Monitor coverage reports

## Reference

- Full testing plan: `/home/user/lichun/TESTING_PLAN.md`
- Database module: `/home/user/lichun/ws/database_async.py`
- Config: `/home/user/lichun/ws/config.py`
