forked from LiveCarta/ContentAutomation
Store posting results to a mongodb
This commit is contained in:
@@ -4,6 +4,7 @@ import pytest
|
||||
|
||||
from content_automation.adapters.storage.base import StorageAdapterBase
|
||||
from content_automation.controller import PublishController
|
||||
from content_automation.models import PublishedContentRecord
|
||||
from content_automation.settings import AppSettings
|
||||
|
||||
|
||||
@@ -29,6 +30,23 @@ class FakeAdapter:
|
||||
return f"{self.name}-post-id"
|
||||
|
||||
|
||||
class FakeAdapterWithResponsePayload:
|
||||
def __init__(self, payload: object) -> None:
|
||||
self.name = "adapter-with-payload"
|
||||
self._payload = payload
|
||||
|
||||
def post_media(self, media_url: str, caption: str) -> object:
|
||||
return self._payload
|
||||
|
||||
|
||||
class FakePublishedContentStore:
|
||||
def __init__(self) -> None:
|
||||
self.records: list[PublishedContentRecord] = []
|
||||
|
||||
def save(self, record: PublishedContentRecord) -> None:
|
||||
self.records.append(record)
|
||||
|
||||
|
||||
def test_controller_publishes_to_all_configured_networks() -> None:
|
||||
settings = AppSettings.model_validate(
|
||||
{"target_social_networks": ["instagram", "youtube"]}
|
||||
@@ -47,6 +65,47 @@ def test_controller_publishes_to_all_configured_networks() -> None:
|
||||
assert result == {"instagram": "instagram-post-id", "youtube": "youtube-post-id"}
|
||||
|
||||
|
||||
def test_controller_stores_published_content_with_youtube_id_only() -> None:
|
||||
settings = AppSettings.model_validate(
|
||||
{"target_social_networks": ["instagram", "youtube"]}
|
||||
)
|
||||
published_content_store = FakePublishedContentStore()
|
||||
controller = PublishController(
|
||||
settings=settings,
|
||||
storage=FakeStorage(exists_result=True),
|
||||
social_adapters={
|
||||
"instagram": FakeAdapterWithResponsePayload(
|
||||
{"id": "ig-123", "status": "ok"}
|
||||
),
|
||||
"youtube": FakeAdapterWithResponsePayload(
|
||||
{
|
||||
"id": "yt-456",
|
||||
"kind": "youtube#video",
|
||||
"snippet": {"title": "hello"},
|
||||
}
|
||||
),
|
||||
},
|
||||
published_content_store=published_content_store,
|
||||
)
|
||||
|
||||
result = controller.publish(relative_path="video.mp4", caption="hello")
|
||||
|
||||
assert result["youtube"] == {
|
||||
"id": "yt-456",
|
||||
"kind": "youtube#video",
|
||||
"snippet": {"title": "hello"},
|
||||
}
|
||||
assert len(published_content_store.records) == 1
|
||||
saved_record = published_content_store.records[0]
|
||||
assert saved_record.relative_path == "video.mp4"
|
||||
assert saved_record.caption == "hello"
|
||||
assert saved_record.platform_responses["instagram"] == {
|
||||
"id": "ig-123",
|
||||
"status": "ok",
|
||||
}
|
||||
assert saved_record.platform_responses["youtube"] == "yt-456"
|
||||
|
||||
|
||||
def test_controller_raises_when_file_missing() -> None:
|
||||
settings = AppSettings.model_validate({"target_social_networks": ["youtube"]})
|
||||
controller = PublishController(
|
||||
|
||||
115
tests/test_publish_store.py
Normal file
115
tests/test_publish_store.py
Normal file
@@ -0,0 +1,115 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from content_automation.adapters.publish_store import MongoPublishedContentStore
|
||||
from content_automation.factories import build_published_content_store
|
||||
from content_automation.models import PublishedContentRecord
|
||||
from content_automation.settings import AppSettings
|
||||
|
||||
|
||||
class FakeCollection:
|
||||
def __init__(self) -> None:
|
||||
self.documents: list[dict[str, object]] = []
|
||||
|
||||
def insert_one(self, document: dict[str, object]) -> None:
|
||||
self.documents.append(document)
|
||||
|
||||
|
||||
class FakeDatabase:
|
||||
def __init__(self, collection: FakeCollection) -> None:
|
||||
self._collection = collection
|
||||
|
||||
def __getitem__(self, collection_name: str) -> FakeCollection:
|
||||
return self._collection
|
||||
|
||||
|
||||
class FakeMongoClient:
|
||||
def __init__(self, connection_uri: str) -> None:
|
||||
self.connection_uri = connection_uri
|
||||
self.collection = FakeCollection()
|
||||
|
||||
def __getitem__(self, database_name: str) -> FakeDatabase:
|
||||
return FakeDatabase(self.collection)
|
||||
|
||||
|
||||
def test_mongo_published_content_store_saves_record(monkeypatch) -> None:
|
||||
fake_client = FakeMongoClient("mongodb://example:27017")
|
||||
|
||||
monkeypatch.setattr(
|
||||
"content_automation.adapters.publish_store.mongodb.MongoClient",
|
||||
lambda connection_uri: fake_client,
|
||||
)
|
||||
|
||||
store = MongoPublishedContentStore(
|
||||
connection_uri="mongodb://example:27017",
|
||||
database_name="content_automation",
|
||||
collection_name="published_content",
|
||||
)
|
||||
|
||||
store.save(
|
||||
PublishedContentRecord(
|
||||
relative_path="media/video.mp4",
|
||||
media_url="https://cdn.example.com/media/video.mp4",
|
||||
caption="caption",
|
||||
platform_responses={
|
||||
"instagram": {"id": "ig-1"},
|
||||
"youtube": "yt-1",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
assert len(fake_client.collection.documents) == 1
|
||||
assert fake_client.collection.documents[0]["relative_path"] == "media/video.mp4"
|
||||
assert fake_client.collection.documents[0]["platform_responses"] == {
|
||||
"instagram": {"id": "ig-1"},
|
||||
"youtube": "yt-1",
|
||||
}
|
||||
|
||||
|
||||
def test_build_published_content_store_returns_none_when_disabled() -> None:
|
||||
settings = AppSettings.model_validate({"mongodb": {"enabled": False}})
|
||||
|
||||
store = build_published_content_store(settings)
|
||||
|
||||
assert store is None
|
||||
|
||||
|
||||
def test_build_published_content_store_requires_connection_uri() -> None:
|
||||
settings = AppSettings.model_validate({"mongodb": {"enabled": True}})
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
build_published_content_store(settings)
|
||||
|
||||
|
||||
def test_build_published_content_store_returns_mongo_store(monkeypatch) -> None:
|
||||
class FakeMongoStore:
|
||||
def __init__(
|
||||
self,
|
||||
connection_uri: str,
|
||||
database_name: str,
|
||||
collection_name: str,
|
||||
) -> None:
|
||||
self.connection_uri = connection_uri
|
||||
self.database_name = database_name
|
||||
self.collection_name = collection_name
|
||||
|
||||
monkeypatch.setattr("content_automation.factories.MongoPublishedContentStore", FakeMongoStore)
|
||||
|
||||
settings = AppSettings.model_validate(
|
||||
{
|
||||
"mongodb": {
|
||||
"enabled": True,
|
||||
"connection_uri": "mongodb://localhost:27017",
|
||||
"database_name": "content_automation",
|
||||
"collection_name": "published_content",
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
store = build_published_content_store(settings)
|
||||
|
||||
assert isinstance(store, FakeMongoStore)
|
||||
assert store.connection_uri == "mongodb://localhost:27017"
|
||||
assert store.database_name == "content_automation"
|
||||
assert store.collection_name == "published_content"
|
||||
@@ -9,6 +9,15 @@ def test_settings_parse_nested_env(monkeypatch) -> None:
|
||||
monkeypatch.setenv("CONTENT_AUTOMATION_YOUTUBE__USE_RESUMABLE_UPLOAD", "true")
|
||||
monkeypatch.setenv("CONTENT_AUTOMATION_STORAGE__BACKEND", "s3")
|
||||
monkeypatch.setenv("CONTENT_AUTOMATION_STORAGE__S3__BUCKET_NAME", "bucket-a")
|
||||
monkeypatch.setenv("CONTENT_AUTOMATION_MONGODB__ENABLED", "true")
|
||||
monkeypatch.setenv(
|
||||
"CONTENT_AUTOMATION_MONGODB__CONNECTION_URI",
|
||||
"mongodb://localhost:27017",
|
||||
)
|
||||
monkeypatch.setenv(
|
||||
"CONTENT_AUTOMATION_MONGODB__DATABASE_NAME",
|
||||
"content-automation",
|
||||
)
|
||||
|
||||
settings = AppSettings()
|
||||
|
||||
@@ -17,3 +26,6 @@ def test_settings_parse_nested_env(monkeypatch) -> None:
|
||||
assert settings.youtube.use_resumable_upload is True
|
||||
assert settings.storage.backend == "s3"
|
||||
assert settings.storage.s3.bucket_name == "bucket-a"
|
||||
assert settings.mongodb.enabled is True
|
||||
assert settings.mongodb.connection_uri == "mongodb://localhost:27017"
|
||||
assert settings.mongodb.database_name == "content-automation"
|
||||
|
||||
Reference in New Issue
Block a user