Merge remote-tracking branch 'origin/sub_laptop_3' into main_laptop_1
This commit is contained in:
@@ -69,9 +69,14 @@ function advance(ms) {
|
||||
|
||||
/* ---- 가짜 fetch(배수유역 live) ---- */
|
||||
const calls = [];
|
||||
const cancels = []; // 끊김 알림(520-2) — 끊은 차례 번호
|
||||
global.fetch = (url, init) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const call = { url, body: JSON.parse(init.body), aborted: false };
|
||||
if (url.endsWith("/drainage/live/cancel")) {
|
||||
cancels.push(call.body.generation);
|
||||
return resolve({ ok: true, status: 200, json: async () => ({ status: "success" }) });
|
||||
}
|
||||
call.answer = (payload) => resolve({ ok: true, status: 200, json: async () => payload });
|
||||
init.signal.addEventListener("abort", () => {
|
||||
call.aborted = true;
|
||||
@@ -268,7 +273,8 @@ async function main() {
|
||||
await flush();
|
||||
out.savedDone = look();
|
||||
|
||||
// 되돌리기 — 끌기 → [업데이트] 요청 중 → Ctrl+Z = 초안용 답 끊고 저장분 · 표시는 답 올 때까지 그대로
|
||||
// 되돌리기 — 끌기 → [업데이트] 요청 중 → Ctrl+Z = 초안용 답 끊고(서버에도 알림) 저장분 ·
|
||||
// 표시는 저장분의 마지막 낡음으로 바로(520-2)
|
||||
const savedOk = {
|
||||
basins: [{ chainage_m: 100, recommended_facility: "pipe", recommended_diameter_mm: 1200 }],
|
||||
pipe_points: pipes,
|
||||
@@ -279,6 +285,7 @@ async function main() {
|
||||
const draftCall = calls[calls.length - 1];
|
||||
stage(null);
|
||||
out.undoWaiting = { ...look(), aborted: draftCall.aborted, savedLoads };
|
||||
out.undoCancelled = cancels.includes(draftCall.body.generation);
|
||||
savedAnswer(savedOk);
|
||||
await flush();
|
||||
out.undo = { ...look(), savedLoads };
|
||||
|
||||
@@ -125,3 +125,7 @@ def test_metric_sheets_cached_until_source_changes(tmp_path, monkeypatch):
|
||||
assert len(calls) == 2 and first == again # 두 번째는 저장본
|
||||
router._metric_sheets(sheets, tmp_path / "drainage", "EPSG:5179", None) # 좌표계 바뀜
|
||||
assert len(calls) == 4
|
||||
# 메모리 보관(520-2) — 저장본 파일이 없어도 다시 재투영하지 않음
|
||||
(tmp_path / "drainage" / router.SHEET_METRIC_FILENAME).unlink()
|
||||
router._metric_sheets(sheets, tmp_path / "drainage", "EPSG:5179", None)
|
||||
assert len(calls) == 4
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""347-2 「지금 노선으로 셈」 서버 길 · 347-3 관 자리 후보.
|
||||
|
||||
- 늦은 차례: 계산 중 새 차례가 오면 단계 사이에서 그만둠(superseded) · 작업본에 안 씀.
|
||||
- 늦은 차례: 계산 중 새 차례가 오면 단계 사이에서 그만둠(superseded) · 그만둔 셈은 안 남김.
|
||||
- 저장 노선(초안 없음 · 지문 같음) 답만 분석을 남김(520-2) · 초안 노선 · design/save 잠금 중엔 안 남김.
|
||||
- 끊김 알림 = 그 차례가 아직 마지막일 때만 지움(새 차례는 안 끊음).
|
||||
- 메모리 격자로 세부 유역(파일 안 읽음) · 노선 초안 → 그린 노선.
|
||||
- 관 자리 후보: 최대 간격(100 m)을 넘는 구간에만 · 기존 관 자리엔 안 냄 · 관 목록엔 안 넣음.
|
||||
- [확정](recompute) = 낡았으면 배수유역부터 다시 셈 · [저장] = 안 셈.
|
||||
@@ -167,3 +169,63 @@ def test_confirm_recomputes_only_when_stale(monkeypatch, recompute, stale, expec
|
||||
monkeypatch.setattr(basins, "_resolve", resolve)
|
||||
asyncio.run(basins.put_pipe_points(uuid4(), {"points": []}, None, recompute))
|
||||
assert len(calls) == expected and all(calls)
|
||||
|
||||
|
||||
def _patch_keep(monkeypatch):
|
||||
preview = SimpleNamespace(
|
||||
routing=object(), region=SimpleNamespace(split=SimpleNamespace(upstream=[]))
|
||||
)
|
||||
_patch_live(monkeypatch, lambda *args: preview)
|
||||
monkeypatch.setattr(live, "_build", lambda *args: (object(), []))
|
||||
monkeypatch.setattr(live, "live_routing", lambda *args: None)
|
||||
monkeypatch.setattr(live, "_payload", lambda *args: {"status": "success"})
|
||||
writes = []
|
||||
monkeypatch.setattr(live, "write_analysis", lambda *args: writes.append(args[-1]))
|
||||
return writes
|
||||
|
||||
|
||||
def test_saved_route_answer_is_kept(monkeypatch):
|
||||
writes = _patch_keep(monkeypatch)
|
||||
result = asyncio.run(live.post_drainage_live(uuid4(), {"generation": 1, "route": None}))
|
||||
assert result["status"] == "success" and writes == [VERTICES]
|
||||
|
||||
|
||||
def test_draft_route_answer_not_kept(monkeypatch):
|
||||
from B05_Profile import B05_Profile_Router_Replan as replan
|
||||
|
||||
writes = _patch_keep(monkeypatch)
|
||||
moved = [RouteVertex(0.0, 5.0, 100.0, 0.0), RouteVertex(300.0, 5.0, 90.0, 300.0)]
|
||||
|
||||
async def criteria(project_id):
|
||||
return (30.0,)
|
||||
|
||||
monkeypatch.setattr(replan, "_plan_criteria", criteria)
|
||||
monkeypatch.setattr(live, "draft_vertices", lambda draft, radius: moved)
|
||||
monkeypatch.setattr(live, "_open_sampler", lambda *args: None)
|
||||
monkeypatch.setattr(live, "resolve_route_profile", lambda drawn, sampler: (drawn, "x"))
|
||||
draft = {"nodes": [[0, 5], [300, 5]]}
|
||||
asyncio.run(live.post_drainage_live(uuid4(), {"generation": 1, "route": draft}))
|
||||
assert writes == []
|
||||
monkeypatch.setattr(live, "draft_vertices", lambda draft, radius: VERTICES) # 지문 같음
|
||||
asyncio.run(live.post_drainage_live(uuid4(), {"generation": 1, "route": draft}))
|
||||
assert writes == [VERTICES]
|
||||
|
||||
|
||||
def test_not_kept_while_design_save_holds_lock(monkeypatch):
|
||||
writes = _patch_keep(monkeypatch)
|
||||
pid = uuid4()
|
||||
|
||||
async def run():
|
||||
async with live.guard.project_lock(str(pid)):
|
||||
return await live.post_drainage_live(pid, {"generation": 1})
|
||||
|
||||
assert asyncio.run(run())["status"] == "success" and writes == []
|
||||
|
||||
|
||||
def test_cancel_clears_only_latest_generation():
|
||||
pid = uuid4()
|
||||
live._LATEST_GENERATION[str(pid)] = 5
|
||||
assert asyncio.run(live.post_drainage_live_cancel(pid, {"generation": 4}))["stopped"] is False
|
||||
assert live._LATEST_GENERATION[str(pid)] == 5
|
||||
assert asyncio.run(live.post_drainage_live_cancel(pid, {"generation": 5}))["stopped"] is True
|
||||
assert str(pid) not in live._LATEST_GENERATION
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
- 낡지 않아도 [업데이트] = 다시 셈(326-6) · 약속은 답이 오르면 참(B06 [>] 확인 창 뒤 이동).
|
||||
- 요청 중 또 옮기면 앞 요청 끊고 다시 낡음 · 낡은 동안 제안 [적용] · [자동 제안] 끔.
|
||||
- 노선 [저장] 뒤 서버 답이 「낡음」 = 낡음 표시 · 저절로 셈 없음.
|
||||
- 되돌리기로 초안이 없어지면 저장분 다시 받기 · 그 답의 낡음대로 · 초안용 답 끊음(349-0i).
|
||||
- 되돌리기로 초안이 없어지면 저장분 다시 받기 · 그 답의 낡음대로 · 초안용 답 끊음(349-0i) · 서버에 끊김
|
||||
알림 · 표시는 저장분의 마지막 낡음으로 바로(520-2 · 저장 노선 [업데이트] 뒤 = 낡음 즉시 꺼짐).
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -108,7 +109,8 @@ def test_saved_stale_marks_only(r):
|
||||
|
||||
def test_undo_back_to_saved(r):
|
||||
waiting = r["undoWaiting"]
|
||||
assert waiting["aborted"] and look(waiting, "aborted", "savedLoads") == state(True, False, 6)
|
||||
assert waiting["aborted"] and look(waiting, "aborted", "savedLoads") == state(False, False, 6)
|
||||
assert r["undoCancelled"]
|
||||
assert look(r["undo"], "savedLoads") == state(False, False, 6)
|
||||
assert r["undo"]["savedLoads"] == 2
|
||||
assert look(r["undoSavedStale"], "savedLoads") == state(True, False, 6)
|
||||
|
||||
Reference in New Issue
Block a user