chore(home): mirror from kalinamall (9883e6a) with papatramp URLs
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
"""Tests for RDP flap auto-disconnect setting and service."""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from app.config import get_settings
|
||||
from app.models import Host
|
||||
from app.models.ui_settings import UI_SETTINGS_ROW_ID, UiSettings
|
||||
from app.services.ingest import ingest_event
|
||||
from app.services.problems import maybe_create_problem
|
||||
from app.services.rdp_flap_auto_disconnect import maybe_auto_disconnect_stuck_rdp_session
|
||||
from app.services.rdp_flap_settings import get_effective_rdp_flap_settings, upsert_rdp_flap_settings
|
||||
from app.services.winrm_connect import WinRmCmdResult
|
||||
from tests.test_ingest import VALID_EVENT
|
||||
|
||||
|
||||
def _payload(**overrides):
|
||||
base = {
|
||||
**VALID_EVENT,
|
||||
"event_id": str(uuid.uuid4()),
|
||||
"occurred_at": datetime.now(timezone.utc).isoformat(),
|
||||
}
|
||||
base.update(overrides)
|
||||
return base
|
||||
|
||||
|
||||
def _ingest(db, occurred_at: datetime, **overrides):
|
||||
payload = _payload(**overrides)
|
||||
payload["occurred_at"] = occurred_at.isoformat()
|
||||
event, _ = ingest_event(db, payload)
|
||||
db.flush()
|
||||
return event
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def rdg_settings(monkeypatch):
|
||||
monkeypatch.setenv("SAC_RDG_FLAP_WINDOW_MIN_SEC", "1")
|
||||
monkeypatch.setenv("SAC_RDG_FLAP_WINDOW_MAX_SEC", "10")
|
||||
monkeypatch.setenv("SAC_RDG_FLAP_DEDUP_SEC", "30")
|
||||
monkeypatch.setenv("SAC_WIN_ADMIN_USER", r"B26\admin")
|
||||
monkeypatch.setenv("SAC_WIN_ADMIN_PASSWORD", "secret")
|
||||
get_settings.cache_clear()
|
||||
yield
|
||||
get_settings.cache_clear()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def rdg_hosts(db_session):
|
||||
ws = Host(
|
||||
hostname="TSA-PC",
|
||||
os_family="windows",
|
||||
product="rdp-login-monitor",
|
||||
ipv4="192.168.163.100",
|
||||
)
|
||||
gw = Host(
|
||||
hostname="K6A-DC3",
|
||||
os_family="windows",
|
||||
product="rdp-login-monitor",
|
||||
ipv4="192.168.160.40",
|
||||
)
|
||||
db_session.add_all([ws, gw])
|
||||
db_session.commit()
|
||||
return ws, gw
|
||||
|
||||
|
||||
def test_rdp_flap_settings_default_disabled(db_session):
|
||||
cfg = get_effective_rdp_flap_settings(db_session)
|
||||
assert cfg.auto_disconnect is False
|
||||
assert cfg.source == "default"
|
||||
|
||||
|
||||
def test_rdp_flap_settings_upsert(db_session):
|
||||
upsert_rdp_flap_settings(db_session, auto_disconnect=True)
|
||||
cfg = get_effective_rdp_flap_settings(db_session)
|
||||
assert cfg.auto_disconnect is True
|
||||
row = db_session.get(UiSettings, UI_SETTINGS_ROW_ID)
|
||||
assert row is not None
|
||||
assert row.auto_rdp_flap_disconnect is True
|
||||
|
||||
|
||||
def test_auto_disconnect_skipped_when_disabled(db_session, rdg_settings, rdg_hosts, monkeypatch):
|
||||
ws, gw = rdg_hosts
|
||||
t0 = datetime.now(timezone.utc)
|
||||
user = r"B26\TSA"
|
||||
details = {"user": user, "internal_ip": ws.ipv4}
|
||||
gw_payload = {
|
||||
"host": {"hostname": gw.hostname, "os_family": "windows", "ipv4": gw.ipv4},
|
||||
"source": {"product": "rdp-login-monitor", "product_version": "2.1.8-SAC"},
|
||||
}
|
||||
|
||||
_ingest(
|
||||
db_session,
|
||||
t0,
|
||||
**gw_payload,
|
||||
type="rdg.connection.success",
|
||||
category="auth",
|
||||
severity="info",
|
||||
title="302",
|
||||
summary="302",
|
||||
details=details,
|
||||
)
|
||||
end = _ingest(
|
||||
db_session,
|
||||
t0 + timedelta(seconds=4),
|
||||
**gw_payload,
|
||||
type="rdg.connection.disconnected",
|
||||
category="auth",
|
||||
severity="info",
|
||||
title="303",
|
||||
summary="303",
|
||||
details=details,
|
||||
)
|
||||
maybe_create_problem(db_session, end)
|
||||
|
||||
mock_logoff = MagicMock()
|
||||
monkeypatch.setattr("app.services.rdp_flap_auto_disconnect.execute_logoff_via_winrm", mock_logoff)
|
||||
|
||||
result = maybe_auto_disconnect_stuck_rdp_session(db_session, end)
|
||||
assert result is None
|
||||
mock_logoff.assert_not_called()
|
||||
|
||||
|
||||
def test_auto_disconnect_rdg_flap_calls_logoff(db_session, rdg_settings, rdg_hosts, monkeypatch):
|
||||
ws, gw = rdg_hosts
|
||||
upsert_rdp_flap_settings(db_session, auto_disconnect=True)
|
||||
t0 = datetime.now(timezone.utc)
|
||||
user = r"B26\TSA"
|
||||
details = {"user": user, "internal_ip": ws.ipv4}
|
||||
gw_payload = {
|
||||
"host": {"hostname": gw.hostname, "os_family": "windows", "ipv4": gw.ipv4},
|
||||
"source": {"product": "rdp-login-monitor", "product_version": "2.1.8-SAC"},
|
||||
}
|
||||
|
||||
_ingest(
|
||||
db_session,
|
||||
t0,
|
||||
**gw_payload,
|
||||
type="rdg.connection.success",
|
||||
category="auth",
|
||||
severity="info",
|
||||
title="302",
|
||||
summary="302",
|
||||
details=details,
|
||||
)
|
||||
_ingest(
|
||||
db_session,
|
||||
t0 + timedelta(seconds=1),
|
||||
host={"hostname": ws.hostname, "os_family": "windows", "ipv4": ws.ipv4},
|
||||
source={"product": "rdp-login-monitor", "product_version": "2.1.8-SAC"},
|
||||
type="rdp.login.success",
|
||||
category="auth",
|
||||
severity="info",
|
||||
title="login",
|
||||
summary="login",
|
||||
details={"user": user},
|
||||
)
|
||||
end = _ingest(
|
||||
db_session,
|
||||
t0 + timedelta(seconds=4),
|
||||
**gw_payload,
|
||||
type="rdg.connection.disconnected",
|
||||
category="auth",
|
||||
severity="info",
|
||||
title="303",
|
||||
summary="303",
|
||||
details=details,
|
||||
)
|
||||
maybe_create_problem(db_session, end)
|
||||
|
||||
qwinsta_stdout = "SESSIONNAME USERNAME ID STATE\n rdp-tcp#0 B26\\TSA 5 Active\n"
|
||||
monkeypatch.setattr(
|
||||
"app.services.rdp_flap_auto_disconnect.list_windows_sessions",
|
||||
lambda host, cfg: (
|
||||
[],
|
||||
WinRmCmdResult(ok=True, message="ok", target=host.ipv4 or "", stdout=qwinsta_stdout),
|
||||
),
|
||||
)
|
||||
mock_logoff = MagicMock(return_value=SimpleNamespace(status="completed", result_stderr=None, result_stdout="ok"))
|
||||
monkeypatch.setattr("app.services.rdp_flap_auto_disconnect.execute_logoff_via_winrm", mock_logoff)
|
||||
|
||||
result = maybe_auto_disconnect_stuck_rdp_session(db_session, end)
|
||||
assert result is not None
|
||||
assert result.ok is True
|
||||
assert result.session_ids == (5,)
|
||||
mock_logoff.assert_called_once()
|
||||
assert end.details["rdp_flap_auto_disconnect"]["ok"] is True
|
||||
|
||||
|
||||
def test_auto_disconnect_direct_rdp_failed(db_session, rdg_settings, rdg_hosts, monkeypatch):
|
||||
ws, _gw = rdg_hosts
|
||||
upsert_rdp_flap_settings(db_session, auto_disconnect=True)
|
||||
t0 = datetime.now(timezone.utc)
|
||||
user = r"B26\TSA"
|
||||
ws_payload = {
|
||||
"host": {"hostname": ws.hostname, "os_family": "windows", "ipv4": ws.ipv4},
|
||||
"source": {"product": "rdp-login-monitor", "product_version": "2.1.8-SAC"},
|
||||
}
|
||||
|
||||
_ingest(
|
||||
db_session,
|
||||
t0,
|
||||
**ws_payload,
|
||||
type="rdp.login.success",
|
||||
category="auth",
|
||||
severity="info",
|
||||
title="login",
|
||||
summary="login",
|
||||
details={"user": user},
|
||||
)
|
||||
failed = _ingest(
|
||||
db_session,
|
||||
t0 + timedelta(seconds=30),
|
||||
**ws_payload,
|
||||
type="rdp.login.failed",
|
||||
category="auth",
|
||||
severity="warning",
|
||||
title="failed",
|
||||
summary="failed",
|
||||
details={"user": user},
|
||||
)
|
||||
|
||||
qwinsta_stdout = "SESSIONNAME USERNAME ID STATE\n rdp-tcp#0 B26\\TSA 3 Active\n"
|
||||
monkeypatch.setattr(
|
||||
"app.services.rdp_flap_auto_disconnect.list_windows_sessions",
|
||||
lambda host, cfg: (
|
||||
[],
|
||||
WinRmCmdResult(ok=True, message="ok", target=host.ipv4 or "", stdout=qwinsta_stdout),
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.services.rdp_flap_auto_disconnect.terminate_windows_session",
|
||||
lambda host, cfg, sid: WinRmCmdResult(ok=True, message="ok", target=host.ipv4 or ""),
|
||||
)
|
||||
|
||||
result = maybe_auto_disconnect_stuck_rdp_session(db_session, failed)
|
||||
assert result is not None
|
||||
assert result.ok is True
|
||||
assert result.session_ids == (3,)
|
||||
Reference in New Issue
Block a user