""" test_telegram_message_templates.py - Telegram 訊息模板測試 2026-03-29 ogt: 新增,驗證 6 種新訊息模板格式正確 符合 feedback_no_mock_testing.md 規範 - 測試實際格式化輸出 """ import pytest from src.services.telegram_gateway import ( DailySummaryMessage, DeploySuccessMessage, RateLimitMessage, RepairReportMessage, ResourceWarnMessage, SentryErrorMessage, TelegramMessage, ) class TestTelegramMessageFormat: """測試現有 TelegramMessage 格式化""" def test_telegram_message_format_basic(self): """測試基本訊息格式化""" msg = TelegramMessage( status_emoji="🚨", risk_level="CRITICAL", resource_name="test-pod-123", root_cause="Test root cause", suggested_action="Restart pod", estimated_downtime="~30s", approval_id="INC-20260329-0001", ) result = msg.format() assert "🚨" in result assert "CRITICAL" in result assert "test-pod-123" in result assert len(result) <= 900 # SOUL.md 限制 def test_telegram_message_with_token_cost(self): """測試含 Token/Cost 的訊息""" msg = TelegramMessage( status_emoji="⚠️", risk_level="MEDIUM", resource_name="api-pod", root_cause="High CPU", suggested_action="Scale up", estimated_downtime="0s", approval_id="INC-20260329-0002", ai_tokens=1500, ai_cost=0.0015, ) result = msg.format() assert "💰 Tokens: 1,500 / $0.0015" in result class TestSentryErrorMessage: """測試 Sentry 錯誤訊息""" def test_sentry_error_format_basic(self): """測試基本 Sentry 錯誤格式""" msg = SentryErrorMessage( error_id="SENTRY-abc123", error_type="TypeError", error_message="Cannot read property 'x' of undefined", service_name="awoooi-api", file_location="src/api/v1/incidents.py:123", ) result = msg.format() assert "🐛" in result assert "SENTRY ERROR" in result assert "TypeError" in result assert "awoooi-api" in result assert len(result) <= 900 def test_sentry_error_with_stack_trace(self): """測試含 Stack Trace 的 Sentry 錯誤""" msg = SentryErrorMessage( error_id="SENTRY-xyz789", error_type="ValueError", error_message="Invalid input", service_name="awoooi-web", file_location="src/components/App.tsx:45", occurrence_count=15, affected_users=3, first_seen="10 分鐘前", stack_trace=[ "incidents.py:123 in get_incident", "service.py:45 in fetch_data", "db.py:89 in query", ], ) result = msg.format() assert "發生次數: 15" in result assert "影響用戶: 3" in result assert "Stack Trace" in result class TestResourceWarnMessage: """測試資源告警訊息""" def test_resource_warn_format_basic(self): """測試基本資源告警格式""" msg = ResourceWarnMessage( resource_id="RES-20260329-0001", pod_name="awoooi-api-7d4b8c9f5-abc12", namespace="awoooi-prod", cpu_percent=92.5, memory_percent=78.0, disk_percent=45.0, ) result = msg.format() assert "⚠️" in result assert "資源告警" in result assert "CPU: 🔴" in result # 92.5% > 90% assert "Memory: 🟡" in result # 78% >= 70% assert "Disk: 🟢" in result # 45% < 70% assert len(result) <= 900 def test_resource_warn_with_limits(self): """測試含限制資訊的資源告警""" msg = ResourceWarnMessage( resource_id="RES-20260329-0002", pod_name="test-pod", cpu_percent=85.0, cpu_limit="500m", memory_percent=60.0, memory_limit="512Mi", ) result = msg.format() assert "(limit: 500m)" in result assert "(limit: 512Mi)" in result class TestRepairReportMessage: """測試自動修復報告""" def test_repair_report_format_basic(self): """測試基本修復報告格式""" msg = RepairReportMessage( report_date="2026-03-29", total_repairs=12, success_count=10, failure_count=2, saved_minutes=45, ) result = msg.format() assert "🔧" in result assert "自動修復報告" in result assert "總修復次數: 12" in result assert "成功: ✅ 10 (83%)" in result assert len(result) <= 900 def test_repair_report_with_top_issues(self): """測試含 Top 問題的修復報告""" msg = RepairReportMessage( report_date="2026-03-29", total_repairs=12, success_count=10, failure_count=2, top_issues=[ ("Pod CrashLoopBackOff", 5), ("OOM Killed", 4), ("Image Pull Failed", 3), ], ai_cost_gemini=0.0234, ai_tokens_total=1823, ) result = msg.format() assert "Top 3 問題" in result assert "Pod CrashLoopBackOff" in result assert "Gemini: $0.0234" in result class TestDailySummaryMessage: """測試每日摘要""" def test_daily_summary_format_basic(self): """測試基本每日摘要格式""" msg = DailySummaryMessage( summary_date="2026-03-29", alert_total=45, alert_critical=2, alert_medium=18, alert_low=25, ) result = msg.format() assert "📊" in result assert "每日摘要" in result assert "總數: 45" in result assert "Critical: 2" in result assert len(result) <= 900 def test_daily_summary_with_full_stats(self): """測試完整統計的每日摘要""" msg = DailySummaryMessage( summary_date="2026-03-29", alert_total=45, auto_repair_count=30, manual_approval_count=10, ignored_count=5, api_availability=99.95, ai_cost=0.15, budget_remaining=9.85, ) result = msg.format() assert "自動修復: 30" in result assert "API: 99.95%" in result assert "預算剩餘: $9.85" in result class TestDeploySuccessMessage: """測試部署成功訊息""" def test_deploy_success_format_basic(self): """測試基本部署成功格式""" msg = DeploySuccessMessage( commit_sha="abc1234567", triggered_by="ogt", environment="Production", ) result = msg.format() assert "✅" in result assert "部署成功" in result assert "abc12345" in result # 前 8 字元 assert "@ogt" in result assert len(result) <= 900 def test_deploy_success_with_e2e(self): """測試含 E2E 結果的部署成功""" msg = DeploySuccessMessage( commit_sha="abc1234567", triggered_by="ogt", api_version="v1.2.3", web_version="v1.2.3", duration_seconds=225, # 3m 45s e2e_passed=26, e2e_total=26, health_check_passed=True, ) result = msg.format() assert "v1.2.3" in result assert "3m 45s" in result assert "✅ 26/26 PASSED" in result class TestRateLimitMessage: """測試 API 限額警告""" def test_rate_limit_format_basic(self): """測試基本限額警告格式""" msg = RateLimitMessage( provider="gemini", daily_usage=450, daily_limit=500, token_usage=85000, token_limit=100000, cost_usd=0.08, ) result = msg.format() assert "⚠️" in result assert "API 限額警告" in result assert "GEMINI API" in result assert "450/500" in result assert "(90%)" in result assert len(result) <= 900 def test_rate_limit_with_suggestions(self): """測試含建議的限額警告""" msg = RateLimitMessage( provider="openai", daily_usage=90, daily_limit=100, suggestions=[ "考慮切換到 Ollama 優先", "或增加每日限額", ], reset_time="明日 00:00", ) result = msg.format() assert "建議" in result assert "切換到 Ollama" in result assert "明日 00:00" in result