feat(phase-6): Complete testing and deployment setup

Testing:
- Add pytest configuration (pytest.ini)
- Add test fixtures (tests/conftest.py)
- Add ContentGenerator tests (13 tests)
- Add ContentScheduler tests (16 tests)
- Add PublisherManager tests (16 tests)
- All 45 tests passing

Production Docker:
- Add docker-compose.prod.yml with healthchecks, resource limits
- Add Dockerfile.prod with multi-stage build, non-root user
- Add nginx.prod.conf with SSL, rate limiting, security headers
- Add .env.prod.example template

Maintenance Scripts:
- Add backup.sh for database and media backups
- Add restore.sh for database restoration
- Add cleanup.sh for log rotation and Docker cleanup
- Add healthcheck.sh with Telegram alerts

Documentation:
- Add DEPLOY.md with complete deployment guide

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-28 02:12:34 +00:00
parent 354270be98
commit 85bda6abcf
15 changed files with 2296 additions and 0 deletions

124
tests/conftest.py Normal file
View File

@@ -0,0 +1,124 @@
"""
Test fixtures and configuration.
"""
import pytest
from unittest.mock import MagicMock, AsyncMock, patch
from datetime import datetime, timedelta
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.core.database import Base
# In-memory SQLite for testing
TEST_DATABASE_URL = "sqlite:///:memory:"
@pytest.fixture
def test_engine():
"""Create an in-memory SQLite engine for testing."""
engine = create_engine(
TEST_DATABASE_URL,
connect_args={"check_same_thread": False}
)
Base.metadata.create_all(bind=engine)
yield engine
Base.metadata.drop_all(bind=engine)
@pytest.fixture
def test_session(test_engine):
"""Create a test database session."""
TestSessionLocal = sessionmaker(
autocommit=False, autoflush=False, bind=test_engine
)
session = TestSessionLocal()
yield session
session.close()
@pytest.fixture
def mock_openai_client():
"""Mock OpenAI client for DeepSeek API tests."""
mock_client = MagicMock()
mock_response = MagicMock()
mock_response.choices = [MagicMock()]
mock_response.choices[0].message.content = "Generated test content #TechTip #AI"
mock_client.chat.completions.create.return_value = mock_response
return mock_client
@pytest.fixture
def mock_httpx_client():
"""Mock httpx client for API calls."""
mock_client = AsyncMock()
mock_response = AsyncMock()
mock_response.status_code = 200
mock_response.json.return_value = {"id": "123", "success": True}
mock_client.get.return_value = mock_response
mock_client.post.return_value = mock_response
return mock_client
@pytest.fixture
def sample_product():
"""Sample product data for testing."""
return {
"name": "Laptop HP Pavilion",
"description": "Laptop potente para trabajo y gaming",
"price": 15999.00,
"category": "laptops",
"specs": {
"processor": "Intel Core i5",
"ram": "16GB",
"storage": "512GB SSD"
},
"highlights": ["Alta velocidad", "Diseño compacto", "Garantía 2 años"]
}
@pytest.fixture
def sample_service():
"""Sample service data for testing."""
return {
"name": "Automatización con IA",
"description": "Automatiza tus procesos con inteligencia artificial",
"category": "ai_automation",
"target_sectors": ["retail", "manufactura", "servicios"],
"benefits": ["Reduce costos", "Aumenta productividad", "24/7 operación"],
"call_to_action": "Agenda una demo gratuita"
}
@pytest.fixture
def sample_interaction():
"""Sample interaction data for testing."""
return {
"content": "¿Qué procesador recomiendas para edición de video?",
"type": "comment",
"platform": "x",
"author": "user123"
}
@pytest.fixture
def mock_settings():
"""Mock settings for testing."""
with patch('app.core.config.settings') as mock:
mock.DEEPSEEK_API_KEY = "test-api-key"
mock.DEEPSEEK_BASE_URL = "https://api.deepseek.com"
mock.BUSINESS_NAME = "Consultoría AS"
mock.BUSINESS_LOCATION = "Tijuana, México"
mock.BUSINESS_WEBSITE = "https://consultoria-as.com"
mock.CONTENT_TONE = "Profesional pero accesible"
yield mock
@pytest.fixture
def fixed_datetime():
"""Fixed datetime for consistent testing."""
return datetime(2024, 6, 15, 10, 0, 0) # Saturday 10:00