# Backend Test Import Patterns

## Problem

The `ss-tools` backend uses **relative imports** inside packages (e.g., `from ...models.task import TaskRecord` in `persistence.py`). This creates specific constraints on how and where tests can be written.

## Key Rules

### 1. Packages with `__init__.py` that re-export via relative imports

**Example**: `src/core/task_manager/__init__.py` imports `.manager` → `.persistence` → `from ...models.task` (3-level relative import).

**Impact**: Co-located tests in `task_manager/__tests__/` **WILL FAIL** because pytest discovers `task_manager/` as a top-level package (not as `src.core.task_manager`), and the 3-level `from ...` goes beyond the top-level.

**Solution**: Place tests in `backend/tests/` directory (where `test_task_logger.py` already lives). Import using `from src.core.task_manager.XXX import ...` which works because `backend/` is the pytest rootdir.

### 2. Packages WITHOUT `__init__.py`:

**Example**: `src/core/auth/` has NO `__init__.py`.

**Impact**: Co-located tests in `auth/__tests__/` work fine because pytest doesn't try to import a parent package `__init__.py`.

### 3. Modules with deeply nested relative imports

**Example**: `src/services/llm_provider.py` uses `from ..models.llm import LLMProvider` and `from ..plugins.llm_analysis.models import LLMProviderConfig`.

**Impact**: Direct import (`from src.services.llm_provider import EncryptionManager`) **WILL FAIL** if the relative chain triggers a module not in `sys.path` or if it tries to import beyond root.

**Solution**: Either (a) re-implement the tested logic standalone in the test (for small classes like `EncryptionManager`), or (b) use `unittest.mock.patch` to mock the problematic imports before importing the module.

## Working Test Locations

| Package | `__init__.py`? | Relative imports? | Co-located OK? | Test location |
|---|---|---|---|---|
| `core/task_manager/` | YES | `from ...models.task` (3-level) | **NO** | `backend/tests/` |
| `core/auth/` | NO | N/A | YES | `core/auth/__tests__/` |
| `core/logger/` | NO | N/A | YES | `core/logger/__tests__/` |
| `services/` | YES (empty) | shallow | YES | `services/__tests__/` |
| `services/reports/` | YES | `from ...core.logger` | **NO** (most likely) | `backend/tests/` or mock |
| `models/` | YES | shallow | YES | `models/__tests__/` |

## Safe Import Patterns for Tests

```python
# In backend/tests/test_*.py:
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

# Then import:
from src.core.task_manager.models import Task, TaskStatus
from src.core.task_manager.persistence import TaskPersistenceService
from src.models.report import TaskReport, ReportQuery
```

## Plugin ID Mapping (for report tests)

The `resolve_task_type()` uses **hyphenated** plugin IDs:
- `superset-backup` → `TaskType.BACKUP`
- `superset-migration` → `TaskType.MIGRATION`
- `llm_dashboard_validation` → `TaskType.LLM_VERIFICATION`
- `documentation` → `TaskType.DOCUMENTATION`
- anything else → `TaskType.UNKNOWN`
