Операции, прерванные перезапуском панели, закрываются при старте; снимки: исправления по ревью
- core.interrupt_orphaned_operations() при запуске панели, active_operations_for() по всем задачам - снимки: имена с пробелами, снимки вне панели без кнопок, --force только на «revert requires force», память на паузе учитывается, защита от двойного нажатия, надпись «Создаём снимок…» Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LEUXMcdZo7b87mjkUsPgg
Этот коммит содержится в:
@@ -122,3 +122,25 @@ def test_ufw_rules_follow_forwards(data_dirs, monkeypatch):
|
||||
assert find(calls, "ufw", "delete", "allow", "2222/tcp")
|
||||
assert find(calls, "ufw", "route", "delete", "allow", "in", "on", "eth0")
|
||||
assert json.loads(network_core.UFW_STATE_FILE.read_text()) == []
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- operations orphaned by a restart
|
||||
def test_orphaned_operations_are_closed_on_startup(data_dirs):
|
||||
import core
|
||||
|
||||
running = core.new_operation("snapshot_create", "Снимок web01", vm_name="web01")
|
||||
core.update_operation(running, status="running")
|
||||
done = core.new_operation("backup", "Копия web01", vm_name="web01")
|
||||
core.finish_operation(done, True, "Готово")
|
||||
assert core.active_operations_for("web01")
|
||||
assert core.interrupt_orphaned_operations() == 1
|
||||
assert core.read_operation(running["id"])["status"] == "error" and core.read_operation(running["id"])["interrupted"]
|
||||
assert core.read_operation(done["id"])["status"] == "success"
|
||||
assert core.active_operations_for("web01") == []
|
||||
|
||||
|
||||
def test_snapshot_names_with_spaces_are_listed():
|
||||
from features import snapshots
|
||||
|
||||
rows = snapshots.parse_snapshot_list(" Name Creation Time State\n------\n before update 2026-09-25 10:12:03 +0000 shutoff\n clean 2026-09-10 12:05:00 +0000 running\n")
|
||||
assert [row["name"] for row in rows] == ["before update", "clean"]
|
||||
|
||||
@@ -273,7 +273,8 @@ def test_delete_snapshot_error(logged_in, data_dirs, recorder, monkeypatch):
|
||||
|
||||
|
||||
def test_snapshot_routes_validate_names(logged_in, data_dirs, recorder):
|
||||
assert logged_in.post("/vm/web01/snapshots/-bad/revert", follow_redirects=False).status_code == 400
|
||||
bad = logged_in.post("/vm/web01/snapshots/-bad/revert", follow_redirects=False)
|
||||
assert bad.status_code == 303 and "snapshot_error=" in bad.headers["location"]
|
||||
assert logged_in.post("/vm/web01/snapshots/..%2Fx/delete", follow_redirects=False).status_code in (400, 404)
|
||||
assert logged_in.post("/vm/-bad/snapshots/create", data={}, follow_redirects=False).status_code == 400
|
||||
assert not find(recorder, "virsh", "snapshot-delete") and not find(recorder, "virsh", "snapshot-revert")
|
||||
|
||||
Ссылка в новой задаче
Block a user