test: add comprehensive tests for NotebookLM-RAG integration
Add test coverage for new integration components:
New Test Files:
- test_notebooklm_indexer.py: Unit tests for NotebookLMIndexerService
* test_sync_notebook_success: Verify successful notebook sync
* test_sync_notebook_not_found: Handle non-existent notebooks
* test_extract_source_content_success/failure: Content extraction
* test_delete_notebook_index_success/failure: Index management
* test_end_to_end_sync_flow: Integration verification
- test_notebooklm_sync.py: API route tests
* test_sync_notebook_endpoint: POST /notebooklm/sync/{id}
* test_list_indexed_notebooks_endpoint: GET /notebooklm/indexed
* test_delete_notebook_index_endpoint: DELETE /notebooklm/sync/{id}
* test_get_sync_status_endpoint: GET /notebooklm/sync/{id}/status
* test_query_with_notebook_ids: Query with notebook filters
* test_query_notebooks_endpoint: POST /query/notebooks
All tests use mocking to avoid external dependencies.
This commit is contained in:
243
tests/unit/test_agentic_rag/test_api/test_notebooklm_sync.py
Normal file
243
tests/unit/test_agentic_rag/test_api/test_notebooklm_sync.py
Normal file
@@ -0,0 +1,243 @@
|
||||
"""Tests for NotebookLM Sync API routes."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
from uuid import uuid4
|
||||
|
||||
|
||||
class TestNotebookLMSyncRoutes:
|
||||
"""Test suite for NotebookLM sync API routes."""
|
||||
|
||||
@pytest.fixture
|
||||
def client(self):
|
||||
"""Create a test client."""
|
||||
from fastapi.testclient import TestClient
|
||||
from agentic_rag.api.main import app
|
||||
|
||||
return TestClient(app)
|
||||
|
||||
@pytest.fixture
|
||||
def mock_indexer_service(self):
|
||||
"""Create a mock indexer service."""
|
||||
service = MagicMock()
|
||||
service.sync_notebook = AsyncMock()
|
||||
service.get_indexed_notebooks = AsyncMock()
|
||||
service.delete_notebook_index = AsyncMock()
|
||||
return service
|
||||
|
||||
@pytest.fixture
|
||||
def mock_notebook_service(self):
|
||||
"""Create a mock notebook service."""
|
||||
service = MagicMock()
|
||||
service.get = AsyncMock()
|
||||
return service
|
||||
|
||||
def test_sync_notebook_endpoint(self, client, mock_indexer_service, mock_notebook_service):
|
||||
"""Test the sync notebook endpoint."""
|
||||
notebook_id = str(uuid4())
|
||||
|
||||
with (
|
||||
patch(
|
||||
"agentic_rag.api.routes.notebooklm_sync.get_notebooklm_indexer",
|
||||
return_value=mock_indexer_service,
|
||||
),
|
||||
patch(
|
||||
"agentic_rag.api.routes.notebooklm_sync.NotebookService",
|
||||
return_value=mock_notebook_service,
|
||||
),
|
||||
):
|
||||
# Setup mock responses
|
||||
mock_notebook = MagicMock()
|
||||
mock_notebook.id = notebook_id
|
||||
mock_notebook.title = "Test Notebook"
|
||||
mock_notebook_service.get.return_value = mock_notebook
|
||||
|
||||
mock_indexer_service.sync_notebook.return_value = {
|
||||
"sync_id": str(uuid4()),
|
||||
"notebook_id": notebook_id,
|
||||
"notebook_title": "Test Notebook",
|
||||
"status": "success",
|
||||
"sources_indexed": 5,
|
||||
"total_chunks": 42,
|
||||
"sources": [],
|
||||
}
|
||||
|
||||
# Make request
|
||||
response = client.post(f"/api/v1/notebooklm/sync/{notebook_id}")
|
||||
|
||||
# Verify
|
||||
assert response.status_code == 202
|
||||
data = response.json()
|
||||
assert data["status"] == "success"
|
||||
assert data["notebook_id"] == notebook_id
|
||||
assert data["sources_indexed"] == 5
|
||||
|
||||
def test_list_indexed_notebooks_endpoint(self, client, mock_indexer_service):
|
||||
"""Test listing indexed notebooks."""
|
||||
with patch(
|
||||
"agentic_rag.api.routes.notebooklm_sync.get_notebooklm_indexer",
|
||||
return_value=mock_indexer_service,
|
||||
):
|
||||
mock_indexer_service.get_indexed_notebooks.return_value = [
|
||||
{
|
||||
"notebook_id": str(uuid4()),
|
||||
"notebook_title": "Notebook 1",
|
||||
"sources_count": 3,
|
||||
"chunks_count": 25,
|
||||
"last_sync": "2026-01-01T00:00:00Z",
|
||||
}
|
||||
]
|
||||
|
||||
response = client.get("/api/v1/notebooklm/indexed")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 1
|
||||
assert len(data["notebooks"]) == 1
|
||||
|
||||
def test_delete_notebook_index_endpoint(self, client, mock_indexer_service):
|
||||
"""Test deleting notebook index."""
|
||||
notebook_id = str(uuid4())
|
||||
|
||||
with patch(
|
||||
"agentic_rag.api.routes.notebooklm_sync.get_notebooklm_indexer",
|
||||
return_value=mock_indexer_service,
|
||||
):
|
||||
mock_indexer_service.delete_notebook_index.return_value = True
|
||||
|
||||
response = client.delete(f"/api/v1/notebooklm/sync/{notebook_id}")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["deleted"] is True
|
||||
assert data["notebook_id"] == notebook_id
|
||||
|
||||
def test_get_sync_status_endpoint(self, client, mock_indexer_service):
|
||||
"""Test getting sync status."""
|
||||
notebook_id = str(uuid4())
|
||||
|
||||
with patch(
|
||||
"agentic_rag.api.routes.notebooklm_sync.get_notebooklm_indexer",
|
||||
return_value=mock_indexer_service,
|
||||
):
|
||||
mock_indexer_service.get_indexed_notebooks.return_value = [
|
||||
{
|
||||
"notebook_id": notebook_id,
|
||||
"notebook_title": "Test Notebook",
|
||||
"sources_count": 3,
|
||||
"chunks_count": 25,
|
||||
"last_sync": "2026-01-01T00:00:00Z",
|
||||
}
|
||||
]
|
||||
|
||||
response = client.get(f"/api/v1/notebooklm/sync/{notebook_id}/status")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["status"] == "indexed"
|
||||
assert data["notebook_id"] == notebook_id
|
||||
|
||||
def test_sync_notebook_not_found(self, client, mock_indexer_service, mock_notebook_service):
|
||||
"""Test sync with non-existent notebook."""
|
||||
notebook_id = str(uuid4())
|
||||
|
||||
with (
|
||||
patch(
|
||||
"agentic_rag.api.routes.notebooklm_sync.get_notebooklm_indexer",
|
||||
return_value=mock_indexer_service,
|
||||
),
|
||||
patch(
|
||||
"agentic_rag.api.routes.notebooklm_sync.NotebookService",
|
||||
return_value=mock_notebook_service,
|
||||
),
|
||||
):
|
||||
mock_notebook_service.get.side_effect = Exception("Notebook not found")
|
||||
|
||||
response = client.post(f"/api/v1/notebooklm/sync/{notebook_id}")
|
||||
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
class TestQueryWithNotebooks:
|
||||
"""Test suite for query endpoints with notebook support."""
|
||||
|
||||
@pytest.fixture
|
||||
def client(self):
|
||||
"""Create a test client."""
|
||||
from fastapi.testclient import TestClient
|
||||
from agentic_rag.api.main import app
|
||||
|
||||
return TestClient(app)
|
||||
|
||||
@pytest.fixture
|
||||
def mock_rag_service(self):
|
||||
"""Create a mock RAG service."""
|
||||
service = MagicMock()
|
||||
service.query = AsyncMock()
|
||||
service.query_notebooks = AsyncMock()
|
||||
return service
|
||||
|
||||
def test_query_with_notebook_ids(self, client, mock_rag_service):
|
||||
"""Test query with notebook IDs filter."""
|
||||
with (
|
||||
patch("agentic_rag.api.routes.query.get_rag_service", return_value=mock_rag_service),
|
||||
patch("agentic_rag.core.config.Settings.is_provider_configured", return_value=True),
|
||||
):
|
||||
notebook_ids = [str(uuid4()), str(uuid4())]
|
||||
mock_rag_service.query.return_value = {
|
||||
"question": "Test question",
|
||||
"answer": "Test answer",
|
||||
"sources": [],
|
||||
"provider": "openai",
|
||||
"model": "gpt-4",
|
||||
"filters_applied": {"notebook_ids": notebook_ids, "include_documents": True},
|
||||
}
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/query",
|
||||
json={
|
||||
"question": "Test question",
|
||||
"notebook_ids": notebook_ids,
|
||||
"include_documents": True,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["question"] == "Test question"
|
||||
assert data["filters_applied"]["notebook_ids"] == notebook_ids
|
||||
|
||||
def test_query_notebooks_endpoint(self, client, mock_rag_service):
|
||||
"""Test the notebooks-only query endpoint."""
|
||||
with (
|
||||
patch("agentic_rag.api.routes.query.get_rag_service", return_value=mock_rag_service),
|
||||
patch("agentic_rag.core.config.Settings.is_provider_configured", return_value=True),
|
||||
):
|
||||
notebook_ids = [str(uuid4())]
|
||||
mock_rag_service.query_notebooks.return_value = {
|
||||
"question": "Test question",
|
||||
"answer": "Test answer from notebooks",
|
||||
"sources": [
|
||||
{
|
||||
"text": "Source text",
|
||||
"source_type": "notebooklm",
|
||||
"notebook_id": notebook_ids[0],
|
||||
"notebook_title": "Test Notebook",
|
||||
"source_title": "Source 1",
|
||||
}
|
||||
],
|
||||
"provider": "openai",
|
||||
"model": "gpt-4",
|
||||
"filters_applied": {"notebook_ids": notebook_ids, "include_documents": False},
|
||||
}
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/query/notebooks",
|
||||
json={"question": "Test question", "notebook_ids": notebook_ids},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["answer"] == "Test answer from notebooks"
|
||||
assert len(data["sources"]) == 1
|
||||
assert data["sources"][0]["source_type"] == "notebooklm"
|
||||
Reference in New Issue
Block a user