여러 줄 주석이 설명보다 경위(예전·실측·지적)를 적고 있어 읽는 사람이 결론을 찾기 어려웠다. - ts·tsx·js·mjs·css·py 478개: 여러 줄 주석은 첫 문장 한 줄로, 과거형·날짜 문장은 삭제 - 주석 위치는 TypeScript 파서·파이썬 tokenize/ast 로 찾는다 — 문자열 안의 # · /* 는 건드리지 않는다 - eslint·ts·noqa·type: ignore 같은 지시 주석은 그대로 둔다 파이썬 275개 정리 전후 AST 동일, TS 298개 주석 뺀 토큰 동일(빈 JSX 주석 10곳만 차이). site·frontend·admin tsc, site vitest 105 passed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
101 lines
3.3 KiB
Python
101 lines
3.3 KiB
Python
"""일정 생성은 **언제** 걸리나."""
|
|
import uuid
|
|
|
|
from services import story_service
|
|
from services.llm import perplexity
|
|
from services.local_content_service import LocalContentService
|
|
|
|
|
|
class _Place:
|
|
"""`_ensure_region_stories` 와 `run_local_sync` 가 getattr 로만 읽는 최소 객체."""
|
|
|
|
def __init__(self):
|
|
self.place_id = uuid.uuid4()
|
|
self.region_code = "52군산시"
|
|
self.name = "스테이,머뭄"
|
|
self.road_address = "전북특별자치도 군산시 절골길 18"
|
|
self.address = self.road_address
|
|
|
|
|
|
class _SyncResult:
|
|
"""`sync_place_by_id` 가 돌려주는 모양(ResSyncPlace)의 최소 대역."""
|
|
|
|
class result:
|
|
success = True
|
|
|
|
msg = ""
|
|
festivals = attractions = restaurants = 0
|
|
|
|
|
|
async def test_local_sync_job_generates_itineraries(monkeypatch, db_engine):
|
|
"""검증: LOCAL_SYNC 잡이 일정 생성을 부른다."""
|
|
called: list = []
|
|
|
|
async def fake_ensure(place_id):
|
|
called.append(place_id)
|
|
return {"place_id": str(place_id), "counts": {"1박 2일": 5, "2박 3일": 5}, "notes": []}
|
|
|
|
async def fake_sync(self, place_id):
|
|
return _SyncResult()
|
|
|
|
monkeypatch.setattr("services.itinerary_llm_service.ensure_generated_by_id", fake_ensure)
|
|
monkeypatch.setattr(LocalContentService, "sync_place_by_id", fake_sync)
|
|
|
|
pid = uuid.uuid4()
|
|
out = await story_service.run_local_sync({
|
|
"payload": {"place_id": str(pid), "region_code": "52군산시",
|
|
"region_label": "전북특별자치도 군산시"},
|
|
})
|
|
|
|
assert called == [pid]
|
|
assert out["itineraries"]["counts"] == {"1박 2일": 5, "2박 3일": 5}
|
|
|
|
|
|
async def test_canvas_enqueues_job_when_only_itineraries_are_missing(monkeypatch, db_engine):
|
|
"""검증: 이야기는 다 찼지만 일정이 없는 업장이 캔버스를 연다."""
|
|
enqueued: list = []
|
|
|
|
async def fake_enqueue(place):
|
|
enqueued.append(place.place_id)
|
|
return "job-1"
|
|
|
|
async def no_missing_kinds(region_code):
|
|
return []
|
|
|
|
async def two_missing_durations(place_id):
|
|
return ["1박 2일", "2박 3일"]
|
|
|
|
monkeypatch.setattr(perplexity, "is_configured", lambda: True)
|
|
monkeypatch.setattr(story_service, "missing_kinds", no_missing_kinds)
|
|
monkeypatch.setattr(story_service, "enqueue_region_job", fake_enqueue)
|
|
monkeypatch.setattr("services.itinerary_llm_service.missing_durations", two_missing_durations)
|
|
|
|
place = _Place()
|
|
await LocalContentService()._ensure_region_stories(place)
|
|
|
|
assert enqueued == [place.place_id]
|
|
|
|
|
|
async def test_canvas_does_not_enqueue_when_everything_is_filled(monkeypatch, db_engine):
|
|
"""검증: 이야기도 일정도 다 있는 업장."""
|
|
enqueued: list = []
|
|
|
|
async def fake_enqueue(place):
|
|
enqueued.append(place.place_id)
|
|
return "job-1"
|
|
|
|
async def no_missing_kinds(region_code):
|
|
return []
|
|
|
|
async def no_missing_durations(place_id):
|
|
return []
|
|
|
|
monkeypatch.setattr(perplexity, "is_configured", lambda: True)
|
|
monkeypatch.setattr(story_service, "missing_kinds", no_missing_kinds)
|
|
monkeypatch.setattr(story_service, "enqueue_region_job", fake_enqueue)
|
|
monkeypatch.setattr("services.itinerary_llm_service.missing_durations", no_missing_durations)
|
|
|
|
await LocalContentService()._ensure_region_stories(_Place())
|
|
|
|
assert enqueued == []
|