Files
wehub-resource-sync 7a0da7932b
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
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

239 lines
7.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Coverage tests for local_deep_research/domain_classifier/classifier.py
Tests focus on paths not exercised by existing tests:
- DOMAIN_CATEGORIES structure
- DomainClassifier.__init__ stores attributes correctly
- _get_llm() lazy-initialises and caches the LLM
- _build_classification_prompt() with and without samples
- _get_domain_samples() SQL query is built correctly (mocked session)
- classify_domain() returns None on exception
- get_classification() returns None on exception
- get_all_classifications() returns [] on exception
- get_categories_summary() returns {} on exception
- classify_all_domains() with force_update=True skips existing check
"""
from unittest.mock import MagicMock, patch
# ---------------------------------------------------------------------------
# DOMAIN_CATEGORIES constant
# ---------------------------------------------------------------------------
class TestDomainCategories:
def test_categories_dict_is_not_empty(self):
from local_deep_research.domain_classifier.classifier import (
DOMAIN_CATEGORIES,
)
assert isinstance(DOMAIN_CATEGORIES, dict)
assert len(DOMAIN_CATEGORIES) > 0
def test_other_category_present(self):
from local_deep_research.domain_classifier.classifier import (
DOMAIN_CATEGORIES,
)
assert "Other" in DOMAIN_CATEGORIES
def test_all_values_are_lists(self):
from local_deep_research.domain_classifier.classifier import (
DOMAIN_CATEGORIES,
)
for cat, subcats in DOMAIN_CATEGORIES.items():
assert isinstance(subcats, list), f"{cat} should have a list"
# ---------------------------------------------------------------------------
# DomainClassifier.__init__
# ---------------------------------------------------------------------------
class TestDomainClassifierInit:
def test_stores_username_and_snapshot(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
clf = DomainClassifier(username="alice", settings_snapshot={"k": "v"})
assert clf.username == "alice"
assert clf.settings_snapshot == {"k": "v"}
assert clf.llm is None
def test_defaults_snapshot_to_none(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
clf = DomainClassifier(username="bob")
assert clf.settings_snapshot is None
# ---------------------------------------------------------------------------
# _get_llm lazy initialisation
# ---------------------------------------------------------------------------
class TestGetLlm:
def test_llm_created_only_once(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
clf = DomainClassifier(username="u")
mock_llm = MagicMock()
with patch(
"local_deep_research.domain_classifier.classifier.get_llm",
return_value=mock_llm,
) as mock_get:
r1 = clf._get_llm()
r2 = clf._get_llm()
assert r1 is mock_llm
assert r2 is mock_llm
mock_get.assert_called_once()
# ---------------------------------------------------------------------------
# _build_classification_prompt
# ---------------------------------------------------------------------------
class TestBuildClassificationPrompt:
def _make_clf(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
return DomainClassifier(username="u")
def test_prompt_contains_domain(self):
clf = self._make_clf()
prompt = clf._build_classification_prompt("example.com", [])
assert "example.com" in prompt
def test_prompt_contains_json_instruction(self):
clf = self._make_clf()
prompt = clf._build_classification_prompt("example.com", [])
assert "JSON" in prompt
def test_prompt_includes_sample_titles(self):
clf = self._make_clf()
samples = [{"title": "Hello World", "preview": "short preview"}]
prompt = clf._build_classification_prompt("blog.io", samples)
assert "Hello World" in prompt
def test_prompt_without_samples_uses_fallback_text(self):
clf = self._make_clf()
prompt = clf._build_classification_prompt("unknown.io", [])
assert "No samples available" in prompt
# ---------------------------------------------------------------------------
# classify_domain exception returns None
# ---------------------------------------------------------------------------
class TestClassifyDomainException:
def test_db_exception_returns_none(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
clf = DomainClassifier(username="u")
with patch(
"local_deep_research.domain_classifier.classifier.get_user_db_session",
side_effect=Exception("db fail"),
):
result = clf.classify_domain("example.com")
assert result is None
# ---------------------------------------------------------------------------
# get_classification exception returns None
# ---------------------------------------------------------------------------
class TestGetClassificationException:
def test_db_exception_returns_none(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
clf = DomainClassifier(username="u")
with patch(
"local_deep_research.domain_classifier.classifier.get_user_db_session",
side_effect=Exception("db fail"),
):
result = clf.get_classification("example.com")
assert result is None
# ---------------------------------------------------------------------------
# get_all_classifications exception returns []
# ---------------------------------------------------------------------------
class TestGetAllClassificationsException:
def test_db_exception_returns_empty_list(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
clf = DomainClassifier(username="u")
with patch(
"local_deep_research.domain_classifier.classifier.get_user_db_session",
side_effect=Exception("db fail"),
):
result = clf.get_all_classifications()
assert result == []
# ---------------------------------------------------------------------------
# get_categories_summary exception returns {}
# ---------------------------------------------------------------------------
class TestGetCategoriesSummaryException:
def test_db_exception_returns_empty_dict(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
clf = DomainClassifier(username="u")
with patch(
"local_deep_research.domain_classifier.classifier.get_user_db_session",
side_effect=Exception("db fail"),
):
result = clf.get_categories_summary()
assert result == {}
# ---------------------------------------------------------------------------
# classify_all_domains outer exception
# ---------------------------------------------------------------------------
class TestClassifyAllDomainsException:
def test_outer_exception_returns_error_dict(self):
from local_deep_research.domain_classifier.classifier import (
DomainClassifier,
)
clf = DomainClassifier(username="u")
with patch(
"local_deep_research.domain_classifier.classifier.get_user_db_session",
side_effect=Exception("db fail"),
):
result = clf.classify_all_domains()
assert isinstance(result, dict)
assert (
"error" in result
or "failed" in result
or result.get("total", -1) >= 0
)