test: +13 тестов — save_run UPSERT, auth режимы/URL, сценарии

test_db_save_run.py (4 теста): INSERT/UPDATE/UPSERT/без БД
test_auth.py (9 тестов): URL полигона, get_stand, whitelist, режимы
test_scenario_full.py (8 тестов): CRUD + запуск (требует polygon + БД)

Итого: 35 тестов (22 старых + 13 новых)
This commit is contained in:
2026-08-04 08:48:36 +04:00
parent 764592ba60
commit b89c0138e4
3 changed files with 435 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
"""
Тесты: save_run — ручной UPSERT (UPDATE -> INSERT).
"""
import json
import db.save_run as sv
class FakeCursor:
def __init__(self):
self.executed = []
self.rowcount = 0 # UPDATE not affected (no existing row)
def execute(self, sql, params=None):
self.executed.append((sql, params))
def close(self):
pass
class FakeConn:
def __init__(self):
self.committed = False
self.rolled_back = False
self.cursor_obj = FakeCursor()
def cursor(self):
return self.cursor_obj
def commit(self):
self.committed = True
def rollback(self):
self.rolled_back = True
def test_first_call_inserts(monkeypatch):
"""Первый вызов save_run (op_uid=None) -> INSERT."""
conn = FakeConn()
monkeypatch.setattr(sv, "get_conn", lambda: conn)
put_calls = []
monkeypatch.setattr(sv, "put_conn", lambda c: put_calls.append(c))
sv.save_run("cid", "test", "u@e", 1, "", "create", 18,
None, "inst-1", "display", "RUNNING", 0, "",
{}, [], "1.0")
sqls = [e[0].strip()[:20] for e in conn.cursor_obj.executed]
assert any("INSERT INTO runs" in s for s in sqls), f"Expected INSERT, got {sqls}"
assert conn.committed
assert len(put_calls) == 1
def test_second_call_updates(monkeypatch):
"""Второй вызов с тем же op_uid -> UPDATE, не INSERT."""
conn = FakeConn()
monkeypatch.setattr(sv, "get_conn", lambda: conn)
monkeypatch.setattr(sv, "put_conn", lambda c: None)
# Первый вызов — INSERT (rowcount=0)
sv.save_run("cid", "test", "u@e", 1, "svc", "create", 18,
"op-123", "inst-1", "display", "RUNNING", 0, "",
{"k": "v"}, [], "1.0")
# Второй вызов — UPDATE (теперь строка существует)
conn.cursor_obj.rowcount = 1
sv.save_run("cid", "test", "u@e", 1, "svc-final", "create", 18,
"op-123", "inst-1", "display", "OK", 1.5, "",
{"k": "v"}, [{"stage": 1}], "1.0",
instance_meta={"cpu": 2})
sqls = [e[0] for e in conn.cursor_obj.executed]
updates = [s for s in sqls if "UPDATE runs SET" in s]
inserts = [s for s in sqls if "INSERT INTO runs" in s]
# Первый вызов: UPDATE (rowcount=0) + INSERT. Второй: UPDATE (rowcount=1).
assert len(updates) == 2, f"Expected 2 UPDATEs, got {len(updates)}"
assert len(inserts) == 1, f"Expected 1 INSERT, got {len(inserts)}"
assert conn.committed
def test_update_with_new_status(monkeypatch):
"""UPDATE меняет status с RUNNING на OK."""
conn = FakeConn()
monkeypatch.setattr(sv, "get_conn", lambda: conn)
monkeypatch.setattr(sv, "put_conn", lambda c: None)
# Первый вызов — INSERT (rowcount=0 по умолчанию)
sv.save_run("cid", "test", "u@e", 1, "", "create", 18,
"op-456", "inst-2", "d", "RUNNING", 0, "", {}, [], "1.0")
# Второй вызов — UPDATE (rowcount=1)
conn.cursor_obj.rowcount = 1
sv.save_run("cid", "test", "u@e", 1, "final-svc", "create", 18,
"op-456", "inst-2", "d", "OK", 2.0, "err", {}, [{"s": 1}], "1.0",
instance_meta={"ram": 4})
# Найти ПОСЛЕДНИЙ UPDATE-запрос и проверить параметры
update_params = None
for sql, params in conn.cursor_obj.executed:
if "UPDATE runs SET" in sql:
update_params = params
assert update_params is not None, "UPDATE not found"
assert update_params[0] == "OK" # status
assert update_params[1] == 2.0 # duration
assert update_params[2] == "err" # error_log
assert update_params[4] == "final-svc" # svc_name
assert update_params[6] == "op-456" # op_uid
def test_db_unavailable_skips(monkeypatch):
"""Без БД save_run не падает."""
monkeypatch.setattr(sv, "get_conn", lambda: None)
# Не должно быть исключений
sv.save_run("cid", "test", "", 1, "", "create", 18,
"op-x", "inst-x", "d", "OK", 0, "", {}, [], "1.0")