여러 줄 주석이 설명보다 경위(예전·실측·지적)를 적고 있어 읽는 사람이 결론을 찾기 어려웠다. - 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>
120 lines
5.4 KiB
Python
120 lines
5.4 KiB
Python
"""이 경로가 절대 하면 안 되는 것:"""
|
|
import uuid
|
|
|
|
from common.enums import BuildStatus, JobStatus, SiteStatus
|
|
from crud.job_crud import JobQueue
|
|
from worker.handlers import build_handler
|
|
from worker.runner import Worker
|
|
|
|
from tests.test_build_publish import _approved_media, _place, _verified_facts
|
|
|
|
|
|
async def _run():
|
|
assert await Worker("w", JobQueue(), build_handler(), job_deadline_sec=60).process_one() is True
|
|
|
|
|
|
async def _publish(client, h, pid, intro="하조대 해변 도보 3분 거리의 펜션입니다."):
|
|
await _verified_facts(client, h, pid, {"intro": intro})
|
|
job_id = (await client.post(f"/v1/place/{pid}/site/build", headers=h, json={"publish": True})).json()["job_id"]
|
|
await _run()
|
|
return (await client.get(f"/v1/job/{job_id}", headers=h)).json()["job"]["result"]
|
|
|
|
|
|
async def test_rollback_to_earlier_version(auth_headers, client, db_engine):
|
|
"""검증: v1 발행 → v2 발행 → v1 로 롤백."""
|
|
h = await auth_headers("u1")
|
|
pid = await _place(client, h)
|
|
await _approved_media(db_engine, pid)
|
|
|
|
r1 = await _publish(client, h, pid, "v1 소개 — 하조대 해변 도보 3분 거리의 펜션입니다.")
|
|
assert r1["published"] is True
|
|
r2 = await _publish(client, h, pid, "v2 소개 — 리모델링을 마친 하조대 앞 오션뷰 펜션입니다.")
|
|
assert r2["published"] is True
|
|
assert r2["version"] == r1["version"] + 1
|
|
|
|
job_id = (await client.post(
|
|
f"/v1/place/{pid}/site/version/rollback", headers=h, json={"target_version": r1["version"]}
|
|
)).json()["job_id"]
|
|
await _run()
|
|
job = (await client.get(f"/v1/job/{job_id}", headers=h)).json()["job"]
|
|
assert job["status"] == JobStatus.DONE.value, job.get("last_error")
|
|
result = job["result"]
|
|
assert result["rolled_back"] is True, result.get("error")
|
|
assert result["target_version"] == r1["version"]
|
|
|
|
site = (await client.get(f"/v1/place/{pid}/site", headers=h)).json()
|
|
assert site["site"]["status"] == SiteStatus.PUBLISHED.value
|
|
assert site["current_version"]["version"] == r1["version"]
|
|
assert site["current_version"]["build_status"] == BuildStatus.BUILT.value
|
|
|
|
versions = (await client.get(f"/v1/place/{pid}/site/version/list", headers=h)).json()["versions"]
|
|
# 롤백은 새 버전을 만들지 않는다 — v1·v2 두 개뿐이어야 한다.
|
|
assert len(versions) == 2
|
|
|
|
|
|
async def test_rollback_rejects_current_version(auth_headers, client, db_engine):
|
|
"""검증: 지금 공개 중인 버전으로 롤백을 시도한다."""
|
|
h = await auth_headers("u1")
|
|
pid = await _place(client, h)
|
|
await _approved_media(db_engine, pid)
|
|
r1 = await _publish(client, h, pid)
|
|
|
|
job_id = (await client.post(
|
|
f"/v1/place/{pid}/site/version/rollback", headers=h, json={"target_version": r1["version"]}
|
|
)).json()["job_id"]
|
|
await _run()
|
|
job = (await client.get(f"/v1/job/{job_id}", headers=h)).json()["job"]
|
|
assert job["status"] != JobStatus.DONE.value
|
|
assert "이미" in (job.get("last_error") or "")
|
|
|
|
site = (await client.get(f"/v1/place/{pid}/site", headers=h)).json()
|
|
assert site["current_version"]["version"] == r1["version"]
|
|
|
|
|
|
async def test_rollback_rejects_unknown_version(auth_headers, client, db_engine):
|
|
"""검증: 존재하지 않는 버전 번호로 롤백을 시도한다."""
|
|
h = await auth_headers("u1")
|
|
pid = await _place(client, h)
|
|
await _approved_media(db_engine, pid)
|
|
r1 = await _publish(client, h, pid)
|
|
|
|
job_id = (await client.post(
|
|
f"/v1/place/{pid}/site/version/rollback", headers=h, json={"target_version": 999}
|
|
)).json()["job_id"]
|
|
await _run()
|
|
job = (await client.get(f"/v1/job/{job_id}", headers=h)).json()["job"]
|
|
assert job["status"] != JobStatus.DONE.value
|
|
|
|
site = (await client.get(f"/v1/place/{pid}/site", headers=h)).json()
|
|
assert site["site"]["status"] == SiteStatus.PUBLISHED.value
|
|
assert site["current_version"]["version"] == r1["version"]
|
|
|
|
|
|
async def test_failed_rollback_keeps_current_published_version(auth_headers, client, db_engine, monkeypatch):
|
|
"""검증: 롤백 대상 렌더가 실패한다(구조화 데이터 불일치로 시뮬레이션)."""
|
|
from services import render_service
|
|
|
|
h = await auth_headers("u1")
|
|
pid = await _place(client, h)
|
|
await _approved_media(db_engine, pid)
|
|
r1 = await _publish(client, h, pid, "v1 소개 — 하조대 해변 도보 3분 거리의 펜션입니다.")
|
|
r2 = await _publish(client, h, pid, "v2 소개 — 리모델링을 마친 하조대 앞 오션뷰 펜션입니다.")
|
|
site_before = (await client.get(f"/v1/place/{pid}/site", headers=h)).json()
|
|
assert site_before["current_version"]["version"] == r2["version"]
|
|
|
|
async def _broken(payload_path, site_version, timeout_sec):
|
|
raise render_service.RenderFailed("렌더러가 죽었다(시뮬레이션)")
|
|
|
|
monkeypatch.setattr(render_service, "render_site", _broken)
|
|
|
|
job_id = (await client.post(
|
|
f"/v1/place/{pid}/site/version/rollback", headers=h, json={"target_version": r1["version"]}
|
|
)).json()["job_id"]
|
|
await _run()
|
|
job = (await client.get(f"/v1/job/{job_id}", headers=h)).json()["job"]
|
|
assert job["status"] == JobStatus.DONE.value
|
|
assert job["result"]["rolled_back"] is False
|
|
|
|
site_after = (await client.get(f"/v1/place/{pid}/site", headers=h)).json()
|
|
assert site_after["current_version"]["version"] == r2["version"], "실패했는데 공개 버전이 바뀌었다"
|