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

450 lines
14 KiB
Python

"""
Tests for news/core/storage.py
Tests cover:
- BaseStorage abstract interface
- CardStorage abstract interface
- RatingStorage abstract interface
- PreferenceStorage abstract interface
- generate_id() utility method
"""
import pytest
from abc import ABC
class TestBaseStorage:
"""Tests for BaseStorage abstract interface."""
def test_cannot_instantiate_directly(self):
"""Test that BaseStorage cannot be instantiated directly."""
from local_deep_research.news.core.storage import BaseStorage
with pytest.raises(TypeError):
BaseStorage()
def test_is_abstract_base_class(self):
"""Test that BaseStorage is an ABC."""
from local_deep_research.news.core.storage import BaseStorage
assert issubclass(BaseStorage, ABC)
def test_defines_create_abstract_method(self):
"""Test that create is an abstract method."""
from local_deep_research.news.core.storage import BaseStorage
assert hasattr(BaseStorage, "create")
assert (
getattr(BaseStorage.create, "__isabstractmethod__", False) is True
)
def test_defines_get_abstract_method(self):
"""Test that get is an abstract method."""
from local_deep_research.news.core.storage import BaseStorage
assert hasattr(BaseStorage, "get")
assert getattr(BaseStorage.get, "__isabstractmethod__", False) is True
def test_defines_update_abstract_method(self):
"""Test that update is an abstract method."""
from local_deep_research.news.core.storage import BaseStorage
assert hasattr(BaseStorage, "update")
assert (
getattr(BaseStorage.update, "__isabstractmethod__", False) is True
)
def test_defines_delete_abstract_method(self):
"""Test that delete is an abstract method."""
from local_deep_research.news.core.storage import BaseStorage
assert hasattr(BaseStorage, "delete")
assert (
getattr(BaseStorage.delete, "__isabstractmethod__", False) is True
)
def test_defines_list_abstract_method(self):
"""Test that list is an abstract method."""
from local_deep_research.news.core.storage import BaseStorage
assert hasattr(BaseStorage, "list")
assert getattr(BaseStorage.list, "__isabstractmethod__", False) is True
def test_generate_id_is_concrete(self):
"""Test that generate_id is a concrete method."""
from local_deep_research.news.core.storage import BaseStorage
assert hasattr(BaseStorage, "generate_id")
assert (
getattr(BaseStorage.generate_id, "__isabstractmethod__", False)
is False
)
def test_generate_id_returns_uuid_string(self):
"""Test that generate_id returns a valid UUID string."""
from local_deep_research.news.core.storage import BaseStorage
# Create a concrete implementation to test generate_id
class ConcreteStorage(BaseStorage):
def create(self, data):
return "id"
def get(self, id):
return None
def update(self, id, data):
return True
def delete(self, id):
return True
def list(self, filters=None, limit=100, offset=0):
return []
storage = ConcreteStorage()
result = storage.generate_id()
assert isinstance(result, str)
assert len(result) == 36 # UUID format: 8-4-4-4-12 with dashes
assert result.count("-") == 4
def test_generate_id_returns_unique_values(self):
"""Test that generate_id returns unique values."""
from local_deep_research.news.core.storage import BaseStorage
class ConcreteStorage(BaseStorage):
def create(self, data):
return "id"
def get(self, id):
return None
def update(self, id, data):
return True
def delete(self, id):
return True
def list(self, filters=None, limit=100, offset=0):
return []
storage = ConcreteStorage()
ids = [storage.generate_id() for _ in range(100)]
# All IDs should be unique
assert len(set(ids)) == 100
class TestCardStorage:
"""Tests for CardStorage abstract interface."""
def test_cannot_instantiate_directly(self):
"""Test that CardStorage cannot be instantiated directly."""
from local_deep_research.news.core.storage import CardStorage
with pytest.raises(TypeError):
CardStorage()
def test_inherits_from_base_storage(self):
"""Test that CardStorage inherits from BaseStorage."""
from local_deep_research.news.core.storage import (
CardStorage,
BaseStorage,
)
assert issubclass(CardStorage, BaseStorage)
def test_defines_get_by_user_abstract_method(self):
"""Test that get_by_user is an abstract method."""
from local_deep_research.news.core.storage import CardStorage
assert hasattr(CardStorage, "get_by_user")
assert (
getattr(CardStorage.get_by_user, "__isabstractmethod__", False)
is True
)
def test_defines_get_latest_version_abstract_method(self):
"""Test that get_latest_version is an abstract method."""
from local_deep_research.news.core.storage import CardStorage
assert hasattr(CardStorage, "get_latest_version")
assert (
getattr(
CardStorage.get_latest_version, "__isabstractmethod__", False
)
is True
)
def test_defines_add_version_abstract_method(self):
"""Test that add_version is an abstract method."""
from local_deep_research.news.core.storage import CardStorage
assert hasattr(CardStorage, "add_version")
assert (
getattr(CardStorage.add_version, "__isabstractmethod__", False)
is True
)
def test_defines_update_latest_info_abstract_method(self):
"""Test that update_latest_info is an abstract method."""
from local_deep_research.news.core.storage import CardStorage
assert hasattr(CardStorage, "update_latest_info")
assert (
getattr(
CardStorage.update_latest_info, "__isabstractmethod__", False
)
is True
)
def test_defines_archive_card_abstract_method(self):
"""Test that archive_card is an abstract method."""
from local_deep_research.news.core.storage import CardStorage
assert hasattr(CardStorage, "archive_card")
assert (
getattr(CardStorage.archive_card, "__isabstractmethod__", False)
is True
)
def test_defines_pin_card_abstract_method(self):
"""Test that pin_card is an abstract method."""
from local_deep_research.news.core.storage import CardStorage
assert hasattr(CardStorage, "pin_card")
assert (
getattr(CardStorage.pin_card, "__isabstractmethod__", False) is True
)
class TestRatingStorage:
"""Tests for RatingStorage abstract interface."""
def test_cannot_instantiate_directly(self):
"""Test that RatingStorage cannot be instantiated directly."""
from local_deep_research.news.core.storage import RatingStorage
with pytest.raises(TypeError):
RatingStorage()
def test_inherits_from_base_storage(self):
"""Test that RatingStorage inherits from BaseStorage."""
from local_deep_research.news.core.storage import (
RatingStorage,
BaseStorage,
)
assert issubclass(RatingStorage, BaseStorage)
def test_defines_get_user_rating_abstract_method(self):
"""Test that get_user_rating is an abstract method."""
from local_deep_research.news.core.storage import RatingStorage
assert hasattr(RatingStorage, "get_user_rating")
assert (
getattr(
RatingStorage.get_user_rating, "__isabstractmethod__", False
)
is True
)
def test_defines_upsert_rating_abstract_method(self):
"""Test that upsert_rating is an abstract method."""
from local_deep_research.news.core.storage import RatingStorage
assert hasattr(RatingStorage, "upsert_rating")
assert (
getattr(RatingStorage.upsert_rating, "__isabstractmethod__", False)
is True
)
def test_defines_get_ratings_summary_abstract_method(self):
"""Test that get_ratings_summary is an abstract method."""
from local_deep_research.news.core.storage import RatingStorage
assert hasattr(RatingStorage, "get_ratings_summary")
assert (
getattr(
RatingStorage.get_ratings_summary, "__isabstractmethod__", False
)
is True
)
def test_defines_get_user_ratings_abstract_method(self):
"""Test that get_user_ratings is an abstract method."""
from local_deep_research.news.core.storage import RatingStorage
assert hasattr(RatingStorage, "get_user_ratings")
assert (
getattr(
RatingStorage.get_user_ratings, "__isabstractmethod__", False
)
is True
)
class TestPreferenceStorage:
"""Tests for PreferenceStorage abstract interface."""
def test_cannot_instantiate_directly(self):
"""Test that PreferenceStorage cannot be instantiated directly."""
from local_deep_research.news.core.storage import PreferenceStorage
with pytest.raises(TypeError):
PreferenceStorage()
def test_inherits_from_base_storage(self):
"""Test that PreferenceStorage inherits from BaseStorage."""
from local_deep_research.news.core.storage import (
PreferenceStorage,
BaseStorage,
)
assert issubclass(PreferenceStorage, BaseStorage)
def test_defines_get_user_preferences_abstract_method(self):
"""Test that get_user_preferences is an abstract method."""
from local_deep_research.news.core.storage import PreferenceStorage
assert hasattr(PreferenceStorage, "get_user_preferences")
assert (
getattr(
PreferenceStorage.get_user_preferences,
"__isabstractmethod__",
False,
)
is True
)
def test_defines_upsert_preferences_abstract_method(self):
"""Test that upsert_preferences is an abstract method."""
from local_deep_research.news.core.storage import PreferenceStorage
assert hasattr(PreferenceStorage, "upsert_preferences")
assert (
getattr(
PreferenceStorage.upsert_preferences,
"__isabstractmethod__",
False,
)
is True
)
def test_defines_add_liked_item_abstract_method(self):
"""Test that add_liked_item is an abstract method."""
from local_deep_research.news.core.storage import PreferenceStorage
assert hasattr(PreferenceStorage, "add_liked_item")
assert (
getattr(
PreferenceStorage.add_liked_item, "__isabstractmethod__", False
)
is True
)
def test_defines_add_disliked_item_abstract_method(self):
"""Test that add_disliked_item is an abstract method."""
from local_deep_research.news.core.storage import PreferenceStorage
assert hasattr(PreferenceStorage, "add_disliked_item")
assert (
getattr(
PreferenceStorage.add_disliked_item,
"__isabstractmethod__",
False,
)
is True
)
def test_defines_update_preference_embedding_abstract_method(self):
"""Test that update_preference_embedding is an abstract method."""
from local_deep_research.news.core.storage import PreferenceStorage
assert hasattr(PreferenceStorage, "update_preference_embedding")
assert (
getattr(
PreferenceStorage.update_preference_embedding,
"__isabstractmethod__",
False,
)
is True
)
class TestConcreteImplementation:
"""Tests for concrete implementation of BaseStorage."""
def test_can_create_concrete_subclass(self):
"""Test that we can create a concrete subclass of BaseStorage."""
from local_deep_research.news.core.storage import BaseStorage
class ConcreteStorage(BaseStorage):
def create(self, data):
return self.generate_id()
def get(self, id):
return {"id": id}
def update(self, id, data):
return True
def delete(self, id):
return True
def list(self, filters=None, limit=100, offset=0):
return []
storage = ConcreteStorage()
# Should be able to call methods
created_id = storage.create({})
assert isinstance(created_id, str)
retrieved = storage.get("test-id")
assert retrieved == {"id": "test-id"}
updated = storage.update("test-id", {"name": "Test"})
assert updated is True
deleted = storage.delete("test-id")
assert deleted is True
listed = storage.list()
assert listed == []
def test_concrete_subclass_must_implement_all_methods(self):
"""Test that concrete subclass must implement all abstract methods."""
from local_deep_research.news.core.storage import BaseStorage
# Missing some methods
class IncompleteStorage(BaseStorage):
def create(self, data):
return "id"
def get(self, id):
return None
# Missing update, delete, list
with pytest.raises(TypeError):
IncompleteStorage()
class TestModuleImports:
"""Tests for module imports."""
def test_all_classes_importable(self):
"""Test that all storage classes can be imported."""
from local_deep_research.news.core.storage import (
BaseStorage,
CardStorage,
RatingStorage,
PreferenceStorage,
)
assert BaseStorage is not None
assert CardStorage is not None
assert RatingStorage is not None
assert PreferenceStorage is not None