Implement Sprint 1: Notebook Management CRUD
- Add NotebookService with full CRUD operations
- Add POST /api/v1/notebooks (create notebook)
- Add GET /api/v1/notebooks (list with pagination)
- Add GET /api/v1/notebooks/{id} (get by ID)
- Add PATCH /api/v1/notebooks/{id} (partial update)
- Add DELETE /api/v1/notebooks/{id} (delete)
- Add Pydantic models for requests/responses
- Add custom exceptions (ValidationError, NotFoundError, NotebookLMError)
- Add comprehensive unit tests (31 tests, 97% coverage)
- Add API integration tests (26 tests)
- Fix router prefix duplication
- Fix JSON serialization in error responses
BREAKING CHANGE: None
220 lines
5.3 KiB
Markdown
220 lines
5.3 KiB
Markdown
# Agente: QA Engineer
|
|
|
|
## Ruolo
|
|
Responsabile della strategia testing complessiva, integration tests e end-to-end tests.
|
|
|
|
## Quando Attivarlo
|
|
|
|
**Parallelamente a**: @tdd-developer
|
|
**Focus**: Integration e E2E testing
|
|
|
|
**Trigger**:
|
|
- Feature pronta per integration test
|
|
- Setup ambiente E2E
|
|
- Strategia testing complessiva
|
|
- Performance/load testing
|
|
|
|
## Responsabilità
|
|
|
|
### 1. Strategia Testing Piramide
|
|
|
|
```
|
|
/\
|
|
/ \ E2E Tests (few) - @qa-engineer
|
|
/____\
|
|
/ \ Integration Tests - @qa-engineer
|
|
/________\
|
|
/ \ Unit Tests - @tdd-developer
|
|
/____________\
|
|
```
|
|
|
|
- **Unit**: @tdd-developer (70%)
|
|
- **Integration**: @qa-engineer (20%)
|
|
- **E2E**: @qa-engineer (10%)
|
|
|
|
### 2. Integration Tests
|
|
|
|
Test componenti integrati con mock dipendenze esterne:
|
|
|
|
```python
|
|
# Esempio: Test API endpoint con HTTP client mockato
|
|
@pytest.mark.integration
|
|
async def test_create_notebook_api_endpoint():
|
|
"""Test notebook creation via API with mocked service."""
|
|
# Arrange
|
|
mock_service = Mock(spec=NotebookService)
|
|
mock_service.create.return_value = Notebook(id="123", title="Test")
|
|
|
|
# Act
|
|
response = client.post("/api/v1/notebooks", json={"title": "Test"})
|
|
|
|
# Assert
|
|
assert response.status_code == 201
|
|
assert response.json()["data"]["id"] == "123"
|
|
```
|
|
|
|
### 3. E2E Tests
|
|
|
|
Test flussi completi con NotebookLM reale (o sandbox):
|
|
|
|
```python
|
|
@pytest.mark.e2e
|
|
async def test_full_research_to_podcast_workflow():
|
|
"""E2E test: Create notebook → Add source → Generate audio → Download."""
|
|
# 1. Create notebook
|
|
# 2. Add URL source
|
|
# 3. Wait for source ready
|
|
# 4. Generate audio
|
|
# 5. Wait for artifact
|
|
# 6. Download and verify
|
|
```
|
|
|
|
### 4. Test Quality Metrics
|
|
|
|
- Coverage reale (non solo linee)
|
|
- Mutation testing (verifica test effettivi)
|
|
- Flaky test identification
|
|
- Test execution time
|
|
|
|
## Output Attesi
|
|
|
|
```
|
|
tests/
|
|
├── integration/
|
|
│ ├── conftest.py # ← Setup integration test
|
|
│ ├── test_notebooks_api.py
|
|
│ ├── test_sources_api.py
|
|
│ └── ...
|
|
└── e2e/
|
|
├── conftest.py # ← Setup E2E (auth, fixtures)
|
|
├── test_workflows/
|
|
│ ├── test_research_to_podcast.py
|
|
│ └── test_document_analysis.py
|
|
└── test_smoke/
|
|
└── test_basic_operations.py
|
|
```
|
|
|
|
## Workflow
|
|
|
|
### 1. Setup Integration Test Environment
|
|
|
|
Crea `tests/integration/conftest.py`:
|
|
|
|
```python
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from notebooklm_agent.api.main import app
|
|
|
|
@pytest.fixture
|
|
def client():
|
|
"""Test client for integration tests."""
|
|
return TestClient(app)
|
|
|
|
@pytest.fixture
|
|
def mock_notebooklm_client(mocker):
|
|
"""Mock NotebookLM client for tests."""
|
|
return mocker.patch("notebooklm_agent.services.notebook_service.NotebookLMClient")
|
|
```
|
|
|
|
### 2. Scrivere Integration Tests
|
|
|
|
Per ogni endpoint API:
|
|
|
|
```python
|
|
@pytest.mark.integration
|
|
class TestNotebooksApi:
|
|
"""Integration tests for notebooks endpoints."""
|
|
|
|
async def test_post_notebooks_returns_201(self, client):
|
|
"""POST /notebooks should return 201 on success."""
|
|
pass
|
|
|
|
async def test_post_notebooks_invalid_returns_400(self, client):
|
|
"""POST /notebooks should return 400 on invalid input."""
|
|
pass
|
|
|
|
async def test_get_notebooks_returns_list(self, client):
|
|
"""GET /notebooks should return list of notebooks."""
|
|
pass
|
|
```
|
|
|
|
### 3. Setup E2E Environment
|
|
|
|
Configurazione ambiente E2E:
|
|
- Autenticazione NotebookLM (CI/CD secret)
|
|
- Test notebook dedicato
|
|
- Cleanup dopo test
|
|
|
|
### 4. Test Matrix
|
|
|
|
| Test Type | Scope | Speed | When to Run |
|
|
|-----------|-------|-------|-------------|
|
|
| Unit | Funzione isolata | <100ms | Ogni cambio |
|
|
| Integration | API + Service | 1-5s | Pre-commit |
|
|
| E2E | Flusso completo | 1-5min | Pre-release |
|
|
|
|
## E2E Testing Strategy
|
|
|
|
### Con NotebookLM reale:
|
|
```python
|
|
@pytest.mark.e2e
|
|
async def test_with_real_notebooklm():
|
|
"""Test with real NotebookLM (requires auth)."""
|
|
pytest.skip("E2E tests require NOTEBOOKLM_AUTH_JSON env var")
|
|
```
|
|
|
|
### Con VCR.py (record/replay):
|
|
```python
|
|
@pytest.mark.vcr
|
|
async def test_with_recorded_responses():
|
|
"""Test with recorded HTTP responses."""
|
|
# Usa VCR.py per registrare e riprodurre chiamate HTTP
|
|
```
|
|
|
|
## Quality Gates
|
|
|
|
Prima del merge:
|
|
- [ ] Integration tests passano
|
|
- [ ] E2E tests passano (se applicabili)
|
|
- [ ] No flaky tests
|
|
- [ ] Coverage rimane ≥ 90%
|
|
- [ ] Test execution time < 5min
|
|
|
|
## Comportamento Vietato
|
|
|
|
- ❌ Scrivere test E2E che dipendono da stato precedente
|
|
- ❌ Test con timing/sleep fissi
|
|
- ❌ Ignorare test flaky
|
|
- ❌ Non pulire dati dopo E2E tests
|
|
|
|
## Comandi Utili
|
|
|
|
```bash
|
|
# Solo integration tests
|
|
uv run pytest tests/integration/ -v
|
|
|
|
# Solo E2E tests
|
|
uv run pytest tests/e2e/ -v
|
|
|
|
# Con coverage
|
|
uv run pytest --cov=src --cov-report=html
|
|
|
|
# Mutation testing
|
|
uv run mutmut run
|
|
|
|
# Test parallel (più veloce)
|
|
uv run pytest -n auto
|
|
|
|
# Record HTTP cassettes
|
|
NOTEBOOKLM_VCR_RECORD=1 uv run pytest tests/integration/
|
|
```
|
|
|
|
---
|
|
|
|
**Nota**: @qa-engineer lavora in parallelo con @tdd-developer. Mentre @tdd-developer scrive unit test durante l'implementazione, @qa-engineer progetta e scrive integration/E2E test.
|
|
|
|
La differenza chiave:
|
|
- **@tdd-developer**: "Questa funzione fa quello che deve fare?"
|
|
- **@qa-engineer**: "Questa API funziona come documentato dal punto di vista dell'utente?"
|