Files
ewoooc/tests/test_competitor_intel_cache.py
OoO 296269bd43
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
串接 PChome 人工覆核成效指標
2026-05-20 10:16:44 +08:00

102 lines
4.1 KiB
Python

from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_competitor_intel_cache_reuses_memory_and_shared_file(tmp_path, monkeypatch):
from services import competitor_intel_repository as repo
monkeypatch.setattr(repo, "_CACHE_FILE", Path(tmp_path) / "competitor_intel_cache.pkl")
repo._MEM_CACHE.clear()
calls = {"count": 0}
def producer():
calls["count"] += 1
return {"valid_matches": 7, "match_rate": 0.1}
first = repo._cached_payload("coverage:test", producer, ttl_seconds=60)
second = repo._cached_payload("coverage:test", producer, ttl_seconds=60)
repo._MEM_CACHE.clear()
third = repo._cached_payload("coverage:test", producer, ttl_seconds=60)
assert first == second == third == {"valid_matches": 7, "match_rate": 0.1}
assert calls["count"] == 1
def test_clear_competitor_intel_cache_removes_shared_file(tmp_path, monkeypatch):
from services import competitor_intel_repository as repo
cache_file = Path(tmp_path) / "competitor_intel_cache.pkl"
monkeypatch.setattr(repo, "_CACHE_FILE", cache_file)
repo._MEM_CACHE["x"] = {"time": 1, "value": {"ok": True}}
cache_file.write_bytes(b"stale")
repo.clear_competitor_intel_cache()
assert repo._MEM_CACHE == {}
assert not cache_file.exists()
def test_competitor_ppt_results_keep_pending_diagnostics_in_export():
source = (ROOT / "services" / "competitor_intel_repository.py").read_text(encoding="utf-8")
assert "LEFT JOIN valid_competitor" in source
assert "\"found\": found" in source
assert "\"match_status\"" in source
assert "\"candidate_count\"" in source
assert "\"unit_comparison\"" in source
assert "build_unit_price_comparison" in source
assert "(vc.pchome_price IS NULL)" in source
def test_competitor_review_queue_is_canonical_unit_price_handoff():
source = (ROOT / "services" / "competitor_intel_repository.py").read_text(encoding="utf-8")
daily_template = (ROOT / "templates" / "daily_sales.html").read_text(encoding="utf-8")
growth_template = (ROOT / "templates" / "growth_analysis.html").read_text(encoding="utf-8")
assert "def fetch_competitor_review_queue" in source
assert "\"review_queue\": fetch_competitor_review_queue" in source
assert "\"unit_comparable_count\"" in source
assert "manual_review_summary" in source
assert "manual_accept_count" in source
assert "manual_reject_count" in source
assert "manual_unit_price_count" in source
assert "competitor_match_reviews" in source
assert "\"status_label\"" in source
assert "\"action_label\"" in source
assert "build_unit_price_comparison" in source
assert "需單位價覆核" in daily_template
assert "人工採用" in daily_template
assert "人工否決" in daily_template
assert "人工單位價" in daily_template
assert "competitor_intel.review_queue" in daily_template
assert "coverage.unit_comparable_count" in growth_template
assert "coverage.manual_accept_count" in growth_template
assert "coverage.manual_reject_count" in growth_template
assert "coverage.manual_unit_price_count" in growth_template
def test_competitor_ppt_prompt_uses_neutral_ewooc_viewpoint():
source = (ROOT / "routes" / "openclaw_bot_routes.py").read_text(encoding="utf-8")
assert "EwoooC 商品營運視角" in source
assert "待補資料不可當成成功配對" in source
assert "高信心比對" in source
assert "待補身份/價格" in source
assert "需單位價比較" in source
assert "單位價覆核樣本" in source
assert "我方 = PChome" not in source
assert "請以 PChome 視角" not in source
def test_top_competitor_risks_reads_latest_momo_price_after_valid_competitor_filter():
source = (ROOT / "services" / "competitor_intel_repository.py").read_text(encoding="utf-8")
risk_source = source.split("def _fetch_top_competitor_risks_uncached", 1)[1].split("def fetch_competitor_review_queue", 1)[0]
assert "FROM valid_competitor vc" in risk_source
assert "JOIN LATERAL" in risk_source
assert "WHERE pr.product_id = p.id" in risk_source
assert "ROW_NUMBER() OVER (PARTITION BY p.id" not in risk_source