強化 PPT 產線與線上預覽
Some checks failed
CD Pipeline / deploy (push) Has been cancelled

This commit is contained in:
OoO
2026-05-18 15:44:11 +08:00
parent 921e9eeb15
commit d2d8dbab65
16 changed files with 980 additions and 27 deletions

View File

@@ -174,6 +174,81 @@ def test_ppt_audit_history_200(client):
assert r.status_code == 200
def test_ppt_audit_history_shows_ppt_schedule_and_db_runs(client, monkeypatch):
"""PPT 產線頁必須呈現六種固定週期與 DB 寫入紀錄。"""
from services import ppt_auto_generation_service as svc
cadences = svc.get_schedule_cadence_status([
{'key': key, 'ready': True}
for key in svc.DEFINED_REPORT_TYPES
])
monkeypatch.setattr(svc, 'get_defined_report_coverage', lambda **_kw: {
'enabled': True,
'items': [],
'missing_report_types': [],
'missing_count': 0,
'ready_count': len(svc.DEFINED_REPORT_TYPES),
'total': len(svc.DEFINED_REPORT_TYPES),
'last_run': None,
'cadences': cadences,
'cadence_summary': ''.join(c['schedule_text'] for c in cadences),
})
monkeypatch.setattr(svc, 'get_generation_run_history', lambda **_kw: [{
'schedule_kind': 'daily',
'schedule_label': '每日',
'report_type': 'daily',
'report_label': '每日日報',
'target_label': '2026/05/17',
'status': 'ready',
'status_label': '已產生',
'file_name': 'ocbot_daily_20260517.pptx',
'file_size_kb': 1024,
'error_msg': '',
'started_at': '2026-05-17 20:30',
'finished_at': '2026-05-17 20:31',
}])
r = client.get('/observability/ppt_audit_history')
html = r.data.decode('utf-8')
for text in ['每日 20:30', '每週一 20:40', '每月 1 日 20:50', '每季首日 21:00', '每半年首日 21:10', '每年 1/1 21:20']:
assert text in html
assert 'ppt_generation_runs' in html
assert '每日日報' in html
def test_ppt_audit_file_view_renders_online_preview(client, monkeypatch, tmp_path):
"""PPTX view 入口應回站內預覽頁,而不是把 PPTX 直接丟給瀏覽器。"""
import zipfile
from services import ppt_preview_service as preview_svc
reports_dir = tmp_path / 'reports'
reports_dir.mkdir()
pptx = reports_dir / 'ocbot_daily_20260517.pptx'
with zipfile.ZipFile(pptx, 'w') as zf:
zf.writestr('[Content_Types].xml', '<Types></Types>')
monkeypatch.setenv('REPORTS_DIR', str(reports_dir))
monkeypatch.setattr(
preview_svc,
'build_ppt_preview',
lambda *_args, **_kwargs: preview_svc.PPTPreviewResult(
ok=True,
pdf_path=str(reports_dir / 'preview.pdf'),
cache_hit=True,
converter='/usr/bin/libreoffice',
),
)
r = client.get('/observability/ppt_audit_file/ocbot_daily_20260517.pptx')
html = r.data.decode('utf-8')
assert r.status_code == 200
assert 'PPT 線上預覽' in html
assert 'action=pdf' in html
assert '下載 PPTX' in html
# ──────────────────────────────────────────────────────────────────────────
# /observability/host_health
# ──────────────────────────────────────────────────────────────────────────

View File

@@ -124,6 +124,30 @@ def test_due_schedule_kinds_include_periodic_boundaries():
]
def test_schedule_cadence_status_exposes_all_periodic_contracts():
from services.ppt_auto_generation_service import get_schedule_cadence_status
cadences = get_schedule_cadence_status([
{"key": "daily", "ready": True},
{"key": "weekly", "ready": False},
{"key": "market_intel", "ready": True},
])
by_key = {cadence["key"]: cadence for cadence in cadences}
assert [cadence["schedule_text"] for cadence in cadences] == [
"每日 20:30",
"每週一 20:40",
"每月 1 日 20:50",
"每季首日 21:00",
"每半年首日 21:10",
"每年 1/1 21:20",
]
assert by_key["weekly"]["report_types"] == ["weekly", "market_intel"]
assert by_key["weekly"]["ready_count"] == 1
assert by_key["weekly"]["missing_report_types"] == ["weekly"]
assert "TTM 滾動 12 月" in by_key["monthly"]["report_labels"]
def test_scheduled_generation_uses_profile_without_generating(monkeypatch):
from services import ppt_auto_generation_service as svc
@@ -144,3 +168,16 @@ def test_scheduled_generation_uses_profile_without_generating(monkeypatch):
"schedule_kind": "weekly",
"force": True,
}]
def test_ppt_preview_reports_missing_converter(monkeypatch, tmp_path):
from services import ppt_preview_service as svc
pptx = tmp_path / "demo.pptx"
pptx.write_bytes(b"fake pptx")
monkeypatch.setattr(svc.shutil, "which", lambda _name: None)
result = svc.build_ppt_preview(pptx, cache_dir=tmp_path / "cache")
assert result.ok is False
assert "LibreOffice" in (result.error or "")