2026-05-13 19:57:34 +09:00
|
|
|
"""E2E test configuration.
|
|
|
|
|
|
2026-05-14 09:05:24 +09:00
|
|
|
These tests are SKIPPED by default unless a valid LLM provider is configured.
|
|
|
|
|
The repo's `.env` file is auto-loaded so the same settings used by the app
|
|
|
|
|
also drive the test run.
|
2026-05-13 19:57:34 +09:00
|
|
|
|
2026-05-14 09:05:24 +09:00
|
|
|
Provider별 통과 조건:
|
|
|
|
|
- openai : `LLM_API_KEY` 필요 (LM Studio 등 OpenAI-호환 로컬 서버는 더미 키도 OK)
|
|
|
|
|
- ollama : 별도 키 불필요 (로컬 데몬만 동작하면 됨)
|
|
|
|
|
|
|
|
|
|
To run:
|
2026-05-13 19:57:34 +09:00
|
|
|
pytest tests/e2e -m e2e
|
|
|
|
|
|
2026-05-14 09:05:24 +09:00
|
|
|
LLM 호출이 실제로 일어남. OpenAI 클라우드는 비용 발생, 로컬 LLM은 무료.
|
2026-05-13 19:57:34 +09:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
for p in (REPO_ROOT, REPO_ROOT / "vendored" / "ontocast"):
|
|
|
|
|
if str(p) not in sys.path:
|
|
|
|
|
sys.path.insert(0, str(p))
|
|
|
|
|
|
2026-05-14 09:05:24 +09:00
|
|
|
# Auto-load .env so e2e tests pick up the same LLM settings as the app.
|
|
|
|
|
_env_path = REPO_ROOT / ".env"
|
|
|
|
|
if _env_path.exists():
|
|
|
|
|
try:
|
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
|
|
|
|
load_dotenv(_env_path, override=False)
|
|
|
|
|
except ImportError:
|
|
|
|
|
# python-dotenv가 없으면 직접 간단 파싱.
|
|
|
|
|
for line in _env_path.read_text(encoding="utf-8").splitlines():
|
|
|
|
|
line = line.strip()
|
|
|
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
|
|
|
continue
|
|
|
|
|
key, _, value = line.partition("=")
|
|
|
|
|
os.environ.setdefault(key.strip(), value.strip())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _llm_configured() -> bool:
|
|
|
|
|
"""Provider별로 e2e 실행 가능 여부 판단."""
|
|
|
|
|
provider = (os.environ.get("LLM_PROVIDER") or "openai").lower()
|
|
|
|
|
if provider == "ollama":
|
|
|
|
|
# Ollama는 별도 API 키 불필요.
|
|
|
|
|
return True
|
|
|
|
|
# openai 또는 OpenAI-호환 로컬 서버 — 더미 키라도 들어 있어야 OK.
|
|
|
|
|
return bool(os.environ.get("LLM_API_KEY"))
|
|
|
|
|
|
2026-05-13 19:57:34 +09:00
|
|
|
|
|
|
|
|
def pytest_collection_modifyitems(
|
|
|
|
|
config: pytest.Config, items: list[pytest.Item]
|
|
|
|
|
) -> None:
|
2026-05-14 09:05:24 +09:00
|
|
|
"""Skip e2e tests unless the LLM provider is properly configured."""
|
|
|
|
|
if _llm_configured():
|
2026-05-13 19:57:34 +09:00
|
|
|
return
|
2026-05-14 09:05:24 +09:00
|
|
|
provider = (os.environ.get("LLM_PROVIDER") or "openai").lower()
|
2026-05-13 19:57:34 +09:00
|
|
|
skip_marker = pytest.mark.skip(
|
2026-05-14 09:05:24 +09:00
|
|
|
reason=(
|
|
|
|
|
f"E2E tests require LLM provider config. "
|
|
|
|
|
f"Provider={provider!r}, LLM_API_KEY={'set' if os.environ.get('LLM_API_KEY') else 'missing'}."
|
|
|
|
|
)
|
2026-05-13 19:57:34 +09:00
|
|
|
)
|
|
|
|
|
for item in items:
|
|
|
|
|
if "tests/e2e" in str(item.fspath).replace("\\", "/"):
|
|
|
|
|
item.add_marker(skip_marker)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pytest_configure(config: pytest.Config) -> None:
|
|
|
|
|
config.addinivalue_line(
|
|
|
|
|
"markers",
|
|
|
|
|
"e2e: end-to-end test that requires a real LLM and may cost money",
|
|
|
|
|
)
|