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

667 lines
22 KiB
Python

"""
Extended tests for news/exceptions.py
Tests cover:
- NewsAPIException base class
- All derived exception classes
- to_dict() serialization
- Error codes and status codes
- Exception inheritance
"""
class TestNewsAPIException:
"""Tests for NewsAPIException base class."""
def test_inherits_from_exception(self):
"""NewsAPIException inherits from Exception."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test")
assert isinstance(exc, Exception)
def test_stores_message(self):
"""Stores the message."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("Error message")
assert exc.message == "Error message"
def test_default_status_code_is_500(self):
"""Default status_code is 500."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test")
assert exc.status_code == 500
def test_custom_status_code(self):
"""Accepts custom status_code."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test", status_code=404)
assert exc.status_code == 404
def test_default_error_code_is_class_name(self):
"""Default error_code is the class name."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test")
assert exc.error_code == "NewsAPIException"
def test_custom_error_code(self):
"""Accepts custom error_code."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test", error_code="CUSTOM_ERROR")
assert exc.error_code == "CUSTOM_ERROR"
def test_details_defaults_to_empty_dict(self):
"""Details defaults to empty dict."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test")
assert exc.details == {}
def test_custom_details(self):
"""Accepts custom details."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test", details={"key": "value"})
assert exc.details == {"key": "value"}
def test_str_returns_message(self):
"""str() returns the message."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("Error occurred")
assert str(exc) == "Error occurred"
class TestNewsAPIExceptionToDict:
"""Tests for NewsAPIException.to_dict()."""
def test_includes_error(self):
"""Dict includes error message."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("Error message")
data = exc.to_dict()
assert data["error"] == "Error message"
def test_includes_error_code(self):
"""Dict includes error_code."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test", error_code="TEST_ERROR")
data = exc.to_dict()
assert data["error_code"] == "TEST_ERROR"
def test_includes_status_code(self):
"""Dict includes status_code."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test", status_code=400)
data = exc.to_dict()
assert data["status_code"] == 400
def test_includes_details_when_present(self):
"""Dict includes details when provided."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test", details={"field": "value"})
data = exc.to_dict()
assert data["details"] == {"field": "value"}
def test_excludes_details_when_empty(self):
"""Dict excludes details when empty."""
from local_deep_research.news.exceptions import NewsAPIException
exc = NewsAPIException("test")
data = exc.to_dict()
assert "details" not in data
class TestNewsFeatureDisabledException:
"""Tests for NewsFeatureDisabledException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
NewsFeatureDisabledException,
NewsAPIException,
)
exc = NewsFeatureDisabledException()
assert isinstance(exc, NewsAPIException)
def test_default_message(self):
"""Has default message."""
from local_deep_research.news.exceptions import (
NewsFeatureDisabledException,
)
exc = NewsFeatureDisabledException()
assert exc.message == "News system is disabled"
def test_custom_message(self):
"""Accepts custom message."""
from local_deep_research.news.exceptions import (
NewsFeatureDisabledException,
)
exc = NewsFeatureDisabledException("Custom disable message")
assert exc.message == "Custom disable message"
def test_status_code_is_503(self):
"""Status code is 503 (Service Unavailable)."""
from local_deep_research.news.exceptions import (
NewsFeatureDisabledException,
)
exc = NewsFeatureDisabledException()
assert exc.status_code == 503
def test_error_code_is_news_disabled(self):
"""Error code is NEWS_DISABLED."""
from local_deep_research.news.exceptions import (
NewsFeatureDisabledException,
)
exc = NewsFeatureDisabledException()
assert exc.error_code == "NEWS_DISABLED"
class TestInvalidLimitException:
"""Tests for InvalidLimitException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
InvalidLimitException,
NewsAPIException,
)
exc = InvalidLimitException(0)
assert isinstance(exc, NewsAPIException)
def test_includes_limit_in_message(self):
"""Message includes the invalid limit value."""
from local_deep_research.news.exceptions import InvalidLimitException
exc = InvalidLimitException(-5)
assert "-5" in exc.message
def test_status_code_is_400(self):
"""Status code is 400 (Bad Request)."""
from local_deep_research.news.exceptions import InvalidLimitException
exc = InvalidLimitException(0)
assert exc.status_code == 400
def test_error_code_is_invalid_limit(self):
"""Error code is INVALID_LIMIT."""
from local_deep_research.news.exceptions import InvalidLimitException
exc = InvalidLimitException(0)
assert exc.error_code == "INVALID_LIMIT"
def test_details_include_provided_limit(self):
"""Details include provided_limit."""
from local_deep_research.news.exceptions import InvalidLimitException
exc = InvalidLimitException(-10)
assert exc.details["provided_limit"] == -10
def test_details_include_min_limit(self):
"""Details include min_limit."""
from local_deep_research.news.exceptions import InvalidLimitException
exc = InvalidLimitException(0)
assert exc.details["min_limit"] == 1
class TestSubscriptionNotFoundException:
"""Tests for SubscriptionNotFoundException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
SubscriptionNotFoundException,
NewsAPIException,
)
exc = SubscriptionNotFoundException("sub-123")
assert isinstance(exc, NewsAPIException)
def test_includes_subscription_id_in_message(self):
"""Message includes the subscription ID."""
from local_deep_research.news.exceptions import (
SubscriptionNotFoundException,
)
exc = SubscriptionNotFoundException("sub-abc-123")
assert "sub-abc-123" in exc.message
def test_status_code_is_404(self):
"""Status code is 404 (Not Found)."""
from local_deep_research.news.exceptions import (
SubscriptionNotFoundException,
)
exc = SubscriptionNotFoundException("sub-1")
assert exc.status_code == 404
def test_error_code_is_subscription_not_found(self):
"""Error code is SUBSCRIPTION_NOT_FOUND."""
from local_deep_research.news.exceptions import (
SubscriptionNotFoundException,
)
exc = SubscriptionNotFoundException("sub-1")
assert exc.error_code == "SUBSCRIPTION_NOT_FOUND"
def test_details_include_subscription_id(self):
"""Details include subscription_id."""
from local_deep_research.news.exceptions import (
SubscriptionNotFoundException,
)
exc = SubscriptionNotFoundException("sub-xyz")
assert exc.details["subscription_id"] == "sub-xyz"
class TestSubscriptionCreationException:
"""Tests for SubscriptionCreationException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
SubscriptionCreationException,
NewsAPIException,
)
exc = SubscriptionCreationException("Error")
assert isinstance(exc, NewsAPIException)
def test_includes_message_in_error(self):
"""Message includes the provided message."""
from local_deep_research.news.exceptions import (
SubscriptionCreationException,
)
exc = SubscriptionCreationException("Invalid data")
assert "Invalid data" in exc.message
def test_status_code_is_500(self):
"""Status code is 500 (Internal Server Error)."""
from local_deep_research.news.exceptions import (
SubscriptionCreationException,
)
exc = SubscriptionCreationException("Error")
assert exc.status_code == 500
def test_error_code_is_subscription_create_failed(self):
"""Error code is SUBSCRIPTION_CREATE_FAILED."""
from local_deep_research.news.exceptions import (
SubscriptionCreationException,
)
exc = SubscriptionCreationException("Error")
assert exc.error_code == "SUBSCRIPTION_CREATE_FAILED"
def test_accepts_details(self):
"""Accepts optional details."""
from local_deep_research.news.exceptions import (
SubscriptionCreationException,
)
exc = SubscriptionCreationException("Error", details={"field": "topic"})
assert exc.details["field"] == "topic"
class TestSubscriptionUpdateException:
"""Tests for SubscriptionUpdateException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
SubscriptionUpdateException,
NewsAPIException,
)
exc = SubscriptionUpdateException("sub-1", "Error")
assert isinstance(exc, NewsAPIException)
def test_includes_subscription_id_in_message(self):
"""Message includes the subscription ID."""
from local_deep_research.news.exceptions import (
SubscriptionUpdateException,
)
exc = SubscriptionUpdateException("sub-123", "Update failed")
assert "sub-123" in exc.message
def test_includes_error_message(self):
"""Message includes the error message."""
from local_deep_research.news.exceptions import (
SubscriptionUpdateException,
)
exc = SubscriptionUpdateException("sub-1", "Validation error")
assert "Validation error" in exc.message
def test_status_code_is_500(self):
"""Status code is 500."""
from local_deep_research.news.exceptions import (
SubscriptionUpdateException,
)
exc = SubscriptionUpdateException("sub-1", "Error")
assert exc.status_code == 500
def test_details_include_subscription_id(self):
"""Details include subscription_id."""
from local_deep_research.news.exceptions import (
SubscriptionUpdateException,
)
exc = SubscriptionUpdateException("sub-xyz", "Error")
assert exc.details["subscription_id"] == "sub-xyz"
class TestSubscriptionDeletionException:
"""Tests for SubscriptionDeletionException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
SubscriptionDeletionException,
NewsAPIException,
)
exc = SubscriptionDeletionException("sub-1", "Error")
assert isinstance(exc, NewsAPIException)
def test_includes_subscription_id_in_message(self):
"""Message includes the subscription ID."""
from local_deep_research.news.exceptions import (
SubscriptionDeletionException,
)
exc = SubscriptionDeletionException("sub-456", "Delete failed")
assert "sub-456" in exc.message
def test_error_code_is_subscription_delete_failed(self):
"""Error code is SUBSCRIPTION_DELETE_FAILED."""
from local_deep_research.news.exceptions import (
SubscriptionDeletionException,
)
exc = SubscriptionDeletionException("sub-1", "Error")
assert exc.error_code == "SUBSCRIPTION_DELETE_FAILED"
class TestDatabaseAccessException:
"""Tests for DatabaseAccessException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
DatabaseAccessException,
NewsAPIException,
)
exc = DatabaseAccessException("query", "Connection failed")
assert isinstance(exc, NewsAPIException)
def test_includes_operation_in_message(self):
"""Message includes the operation."""
from local_deep_research.news.exceptions import DatabaseAccessException
exc = DatabaseAccessException("insert", "Error")
assert "insert" in exc.message
def test_includes_error_message(self):
"""Message includes the error message."""
from local_deep_research.news.exceptions import DatabaseAccessException
exc = DatabaseAccessException("op", "Connection timeout")
assert "Connection timeout" in exc.message
def test_error_code_is_database_error(self):
"""Error code is DATABASE_ERROR."""
from local_deep_research.news.exceptions import DatabaseAccessException
exc = DatabaseAccessException("op", "Error")
assert exc.error_code == "DATABASE_ERROR"
def test_details_include_operation(self):
"""Details include operation."""
from local_deep_research.news.exceptions import DatabaseAccessException
exc = DatabaseAccessException("update", "Error")
assert exc.details["operation"] == "update"
class TestNewsFeedGenerationException:
"""Tests for NewsFeedGenerationException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
NewsFeedGenerationException,
NewsAPIException,
)
exc = NewsFeedGenerationException("Error")
assert isinstance(exc, NewsAPIException)
def test_includes_message_in_error(self):
"""Message includes the provided message."""
from local_deep_research.news.exceptions import (
NewsFeedGenerationException,
)
exc = NewsFeedGenerationException("No sources available")
assert "No sources available" in exc.message
def test_error_code_is_feed_generation_failed(self):
"""Error code is FEED_GENERATION_FAILED."""
from local_deep_research.news.exceptions import (
NewsFeedGenerationException,
)
exc = NewsFeedGenerationException("Error")
assert exc.error_code == "FEED_GENERATION_FAILED"
def test_includes_user_id_when_provided(self):
"""Details include user_id when provided."""
from local_deep_research.news.exceptions import (
NewsFeedGenerationException,
)
exc = NewsFeedGenerationException("Error", user_id="user-123")
assert exc.details["user_id"] == "user-123"
def test_no_user_id_when_not_provided(self):
"""Details empty when user_id not provided."""
from local_deep_research.news.exceptions import (
NewsFeedGenerationException,
)
exc = NewsFeedGenerationException("Error")
assert "user_id" not in exc.details
class TestResearchProcessingException:
"""Tests for ResearchProcessingException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
ResearchProcessingException,
NewsAPIException,
)
exc = ResearchProcessingException("Error")
assert isinstance(exc, NewsAPIException)
def test_error_code_is_research_processing_failed(self):
"""Error code is RESEARCH_PROCESSING_FAILED."""
from local_deep_research.news.exceptions import (
ResearchProcessingException,
)
exc = ResearchProcessingException("Error")
assert exc.error_code == "RESEARCH_PROCESSING_FAILED"
def test_includes_research_id_when_provided(self):
"""Details include research_id when provided."""
from local_deep_research.news.exceptions import (
ResearchProcessingException,
)
exc = ResearchProcessingException("Error", research_id="res-123")
assert exc.details["research_id"] == "res-123"
class TestNotImplementedException:
"""Tests for NotImplementedException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
NotImplementedException,
NewsAPIException,
)
exc = NotImplementedException("feature")
assert isinstance(exc, NewsAPIException)
def test_includes_feature_in_message(self):
"""Message includes the feature name."""
from local_deep_research.news.exceptions import NotImplementedException
exc = NotImplementedException("AI summarization")
assert "AI summarization" in exc.message
def test_status_code_is_501(self):
"""Status code is 501 (Not Implemented)."""
from local_deep_research.news.exceptions import NotImplementedException
exc = NotImplementedException("feature")
assert exc.status_code == 501
def test_details_include_feature(self):
"""Details include feature."""
from local_deep_research.news.exceptions import NotImplementedException
exc = NotImplementedException("real-time updates")
assert exc.details["feature"] == "real-time updates"
class TestInvalidParameterException:
"""Tests for InvalidParameterException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
InvalidParameterException,
NewsAPIException,
)
exc = InvalidParameterException("param", "value", "message")
assert isinstance(exc, NewsAPIException)
def test_includes_parameter_in_message(self):
"""Message includes the parameter name."""
from local_deep_research.news.exceptions import (
InvalidParameterException,
)
exc = InvalidParameterException("limit", -1, "Must be positive")
assert "limit" in exc.message
def test_includes_error_message(self):
"""Message includes the error description."""
from local_deep_research.news.exceptions import (
InvalidParameterException,
)
exc = InvalidParameterException("limit", -1, "Must be positive")
assert "Must be positive" in exc.message
def test_status_code_is_400(self):
"""Status code is 400 (Bad Request)."""
from local_deep_research.news.exceptions import (
InvalidParameterException,
)
exc = InvalidParameterException("p", "v", "m")
assert exc.status_code == 400
def test_details_include_parameter(self):
"""Details include parameter name."""
from local_deep_research.news.exceptions import (
InvalidParameterException,
)
exc = InvalidParameterException("offset", "abc", "Must be integer")
assert exc.details["parameter"] == "offset"
def test_details_include_value(self):
"""Details include the invalid value."""
from local_deep_research.news.exceptions import (
InvalidParameterException,
)
exc = InvalidParameterException("offset", "abc", "Must be integer")
assert exc.details["value"] == "abc"
class TestSchedulerNotificationException:
"""Tests for SchedulerNotificationException."""
def test_inherits_from_news_api_exception(self):
"""Inherits from NewsAPIException."""
from local_deep_research.news.exceptions import (
SchedulerNotificationException,
NewsAPIException,
)
exc = SchedulerNotificationException("action", "Error")
assert isinstance(exc, NewsAPIException)
def test_includes_action_in_message(self):
"""Message includes the action."""
from local_deep_research.news.exceptions import (
SchedulerNotificationException,
)
exc = SchedulerNotificationException("subscription_create", "Failed")
assert "subscription_create" in exc.message
def test_error_code_is_scheduler_notification_failed(self):
"""Error code is SCHEDULER_NOTIFICATION_FAILED."""
from local_deep_research.news.exceptions import (
SchedulerNotificationException,
)
exc = SchedulerNotificationException("action", "Error")
assert exc.error_code == "SCHEDULER_NOTIFICATION_FAILED"
def test_details_include_action(self):
"""Details include action."""
from local_deep_research.news.exceptions import (
SchedulerNotificationException,
)
exc = SchedulerNotificationException("user_update", "Error")
assert exc.details["action"] == "user_update"