Spaces:
Running
Running
| from pathlib import Path | |
| import pytest | |
| from pydantic import ValidationError | |
| from app.copilot.actions import ACTION_DEFINITIONS | |
| from app.social.schemas.posts import SocialPostCreate, SocialPostValidation | |
| def test_canonical_copy_and_project_provenance_are_strict() -> None: | |
| payload = SocialPostCreate.model_validate({ | |
| "project_id": "123e4567-e89b-12d3-a456-426614174000", | |
| "caption": "Release update", | |
| "hashtags": ["#release", "release", "media"], | |
| "targets": [{ | |
| "social_account_id": "x-account", | |
| "caption": {"text": "X override"}, | |
| "x": {"text": "X override"}, | |
| }], | |
| }) | |
| assert payload.caption == "Release update" | |
| assert payload.hashtags == ["release", "media"] | |
| with pytest.raises(ValidationError): | |
| SocialPostCreate.model_validate({ | |
| "targets": [{ | |
| "social_account_id": "x-account", | |
| "caption": {}, | |
| "x": {"text": "valid"}, | |
| "unknown_provider_payload": {}, | |
| }], | |
| }) | |
| def test_structured_validation_is_per_target() -> None: | |
| result = SocialPostValidation.model_validate({ | |
| "post_id": "post-1", | |
| "valid": False, | |
| "targets": [{ | |
| "target_id": "target-1", | |
| "provider": "youtube", | |
| "account_id": "account-1", | |
| "valid": False, | |
| "errors": [{"code": "SOCIAL_MEDIA_INVALID", "message": "Invalid media."}], | |
| "warnings": [], | |
| }], | |
| }) | |
| assert not result.valid | |
| assert result.targets[0].errors[0].code == "SOCIAL_MEDIA_INVALID" | |
| def test_copilot_external_publishing_actions_require_confirmation() -> None: | |
| definitions = { | |
| item.type: item for item in ACTION_DEFINITIONS | |
| if item.type.startswith("publishing.") | |
| } | |
| assert set(definitions) == { | |
| "publishing.validate", | |
| "publishing.create_post", | |
| "publishing.schedule", | |
| "publishing.publish", | |
| "publishing.cancel", | |
| } | |
| for name in ("publishing.schedule", "publishing.publish", "publishing.cancel"): | |
| assert definitions[name].external_side_effect | |
| assert definitions[name].requires_confirmation | |
| def test_additive_migration_extends_existing_social_tables() -> None: | |
| sql = Path("app/social/migrations/0008_unified_publishing.sql").read_text() | |
| lowered = sql.lower() | |
| assert "alter table social_posts" in lowered | |
| assert "foreign key (project_id) references projects(id)" in lowered | |
| assert "force row level security" in lowered | |
| assert "create table social_posts" not in lowered | |
| assert "create table social_jobs" not in lowered | |