Files
wehub-resource-sync 7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

420 lines
13 KiB
Python

"""Tests for research-related database models."""
import uuid
from datetime import datetime, timezone
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from local_deep_research.database.models import (
Base,
Research,
ResearchHistory,
ResearchMode,
ResearchResource,
ResearchStatus,
ResearchStrategy,
ResearchTask,
SearchQuery,
SearchResult,
)
class TestResearchModels:
"""Test suite for research-related models."""
@pytest.fixture
def engine(self):
"""Create an in-memory SQLite database for testing."""
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
yield engine
engine.dispose()
@pytest.fixture
def session(self, engine):
"""Create a database session for testing."""
Session = sessionmaker(bind=engine)
session = Session()
yield session
session.close()
def test_research_history_creation(self, session):
"""Test creating a ResearchHistory record."""
research = ResearchHistory(
id=str(uuid.uuid4()),
query="What is quantum computing?",
mode="comprehensive",
status="completed",
created_at="2024-01-01T12:00:00",
completed_at="2024-01-01T12:05:00",
duration_seconds=300,
progress=100,
report_path="/reports/quantum_computing.md",
title="Quantum Computing Research",
research_meta={"sources": 10, "quality": "high"},
)
session.add(research)
session.commit()
# Verify the record
saved = session.query(ResearchHistory).first()
assert saved is not None
assert saved.query == "What is quantum computing?"
assert saved.mode == "comprehensive"
assert saved.status == "completed"
assert saved.duration_seconds == 300
assert saved.progress == 100
assert saved.research_meta["sources"] == 10
def test_research_status_enum(self, session):
"""Test Research model with ResearchStatus enum."""
# Create Research with enum status
research = Research(
query="Test query",
status=ResearchStatus.PENDING,
mode=ResearchMode.QUICK,
)
session.add(research)
session.commit()
# Test status transitions
research.status = ResearchStatus.IN_PROGRESS
session.commit()
assert research.status == ResearchStatus.IN_PROGRESS
# Test all status values
for status in ResearchStatus:
r = Research(
query=f"Test {status.value}",
status=status,
mode=ResearchMode.QUICK,
)
session.add(r)
session.commit()
# Verify all statuses
all_research = session.query(Research).all()
assert len(all_research) >= len(ResearchStatus)
def test_research_progress_log(self, session):
"""Test progress log JSON field in ResearchHistory."""
progress_log = {
"steps": [
{"time": "2024-01-01T12:00:00", "message": "Starting research"},
{"time": "2024-01-01T12:01:00", "message": "Searching sources"},
{"time": "2024-01-01T12:03:00", "message": "Analyzing results"},
{"time": "2024-01-01T12:05:00", "message": "Generating report"},
],
"current_step": 4,
"total_steps": 4,
}
research = ResearchHistory(
id=str(uuid.uuid4()),
query="AI research",
mode="normal",
status="completed",
created_at="2024-01-01T12:00:00",
progress_log=progress_log,
progress=100,
)
session.add(research)
session.commit()
# Verify progress log
saved = session.query(ResearchHistory).first()
assert saved.progress_log is not None
assert len(saved.progress_log["steps"]) == 4
assert saved.progress_log["current_step"] == 4
def test_research_task_creation(self, session):
"""Test ResearchTask model."""
task = ResearchTask(
title="Machine Learning Research",
description="Research current ML trends and applications",
status="in_progress",
priority=5,
tags=["ml", "ai", "trends"],
research_metadata={
"estimated_time": "2 hours",
"complexity": "medium",
},
)
session.add(task)
session.commit()
# Verify task
saved = session.query(ResearchTask).first()
assert saved.title == "Machine Learning Research"
assert saved.priority == 5
assert "ml" in saved.tags
assert saved.research_metadata["complexity"] == "medium"
def test_search_query_and_results(self, session):
"""Test SearchQuery and SearchResult models."""
# Create research task first
task = ResearchTask(
title="Test Research", description="Test", status="pending"
)
session.add(task)
session.commit()
# Create search query
query = SearchQuery(
research_task_id=task.id,
query="quantum computing applications",
search_engine="google",
search_type="web",
parameters={"num_results": 10, "time_range": "past_year"},
status="completed",
)
session.add(query)
session.commit()
# Add search results
results = [
SearchResult(
research_task_id=task.id,
search_query_id=query.id,
title="Quantum Computing in 2024",
url="https://example.com/quantum-2024",
snippet="Latest developments in quantum computing...",
relevance_score=0.95,
content="Full article content here...",
content_type="article",
position=1,
domain="example.com",
language="en",
author="Dr. Smith",
fetch_status="fetched",
),
SearchResult(
research_task_id=task.id,
search_query_id=query.id,
title="Practical Quantum Applications",
url="https://example.com/quantum-apps",
snippet="Real-world applications of quantum tech...",
relevance_score=0.87,
position=2,
domain="example.com",
fetch_status="pending",
),
]
session.add_all(results)
session.commit()
# Verify relationships
assert len(query.results) == 2
assert query.results[0].relevance_score == 0.95
assert task.searches[0].query == "quantum computing applications"
def test_research_strategy(self, session):
"""Test ResearchStrategy model.
ResearchStrategy.research_id is a String(36) FK to research_history.id —
the live UUID-keyed table. The legacy Integer FK to the dormant
``research`` table caused FOREIGN KEY constraint failed once
PRAGMA foreign_keys was enabled in v1.6.0; migration 0008 retargets it.
"""
history_id = str(uuid.uuid4())
history = ResearchHistory(
id=history_id,
query="Climate change solutions",
mode="detailed",
status="completed",
created_at="2026-01-01T10:00:00",
)
session.add(history)
session.commit()
strategy = ResearchStrategy(
research_id=history_id, strategy_name="comprehensive_search"
)
session.add(strategy)
session.commit()
saved = session.query(ResearchStrategy).first()
assert saved.strategy_name == "comprehensive_search"
assert saved.research_id == history_id
def test_research_relationships(self, session):
"""Test relationships between research models."""
# Create research history
history = ResearchHistory(
id=str(uuid.uuid4()),
query="AI Ethics",
mode="comprehensive",
status="completed",
created_at="2024-01-01T10:00:00",
)
session.add(history)
session.commit()
# Add resources
resources = [
ResearchResource(
research_id=history.id,
title="AI Ethics Guidelines",
url="https://example.com/ai-ethics",
content_preview="Guidelines for ethical AI development...",
source_type="article",
resource_metadata={"credibility": "high"},
created_at="2024-01-01T10:30:00",
),
ResearchResource(
research_id=history.id,
title="Ethics in Machine Learning",
url="https://example.com/ml-ethics",
content_preview="Exploring ethical considerations in ML...",
source_type="research_paper",
resource_metadata={"peer_reviewed": True},
created_at="2024-01-01T10:45:00",
),
]
session.add_all(resources)
session.commit()
# Verify relationships
assert len(history.resources) == 2
assert history.resources[0].title == "AI Ethics Guidelines"
# Test cascade delete
session.delete(history)
session.commit()
# Resources should be deleted too
remaining_resources = session.query(ResearchResource).count()
assert remaining_resources == 0
def test_research_metadata_handling(self, session):
"""Test JSON metadata fields across models."""
# ResearchHistory with complex metadata
history = ResearchHistory(
id=str(uuid.uuid4()),
query="Complex research",
mode="normal",
status="completed",
created_at="2024-01-01T00:00:00",
research_meta={
"sources": {"academic": 5, "news": 10, "blogs": 3},
"quality_metrics": {
"relevance": 0.85,
"credibility": 0.9,
"recency": 0.95,
},
"search_iterations": 3,
"total_sources_examined": 50,
},
)
session.add(history)
session.commit()
# Verify complex metadata
saved = session.query(ResearchHistory).first()
assert saved.research_meta["sources"]["academic"] == 5
assert saved.research_meta["quality_metrics"]["relevance"] == 0.85
def test_search_result_content(self, session):
"""Test SearchResult content storage and retrieval."""
# Create parent objects
task = ResearchTask(
title="Content Test",
description="Testing content storage",
status="pending",
)
session.add(task)
session.commit()
query = SearchQuery(
research_task_id=task.id,
query="test query",
search_engine="google",
status="completed",
)
session.add(query)
session.commit()
# Large content
large_content = "x" * 10000 # 10KB of content
result = SearchResult(
research_task_id=task.id,
search_query_id=query.id,
title="Large Article",
url="https://example.com/large",
snippet="Beginning of large article...",
content=large_content,
content_type="article",
relevance_score=0.8,
position=1,
domain="example.com",
language="en",
fetch_status="fetched",
fetched_at=datetime.now(timezone.utc),
)
session.add(result)
session.commit()
# Verify content
saved = session.query(SearchResult).first()
assert len(saved.content) == 10000
assert saved.fetch_status == "fetched"
assert saved.domain == "example.com"
def test_research_error_handling(self, session):
"""Test error tracking in research models."""
# Failed research
failed_research = ResearchHistory(
id=str(uuid.uuid4()),
query="This will fail",
mode="quick",
status="failed",
created_at="2024-01-01T00:00:00",
research_meta={
"error": "NetworkError",
"error_message": "Connection timeout",
"retry_count": 3,
"last_error_timestamp": "2024-01-01T00:05:00",
},
)
session.add(failed_research)
session.commit()
# Failed search query
task = ResearchTask(
title="Error Test", description="Test", status="failed"
)
session.add(task)
session.commit()
failed_query = SearchQuery(
research_task_id=task.id,
query="problematic query",
search_engine="bing",
status="failed",
error_message="Rate limit exceeded",
retry_count=5,
)
session.add(failed_query)
session.commit()
# Verify error tracking
assert failed_research.research_meta["error"] == "NetworkError"
assert failed_query.error_message == "Rate limit exceeded"
assert failed_query.retry_count == 5