"""Tests unitaires pour user_monitor.py""" from datetime import datetime, timedelta import pytest from user_monitor import UserMonitor class FakeConfig: def get(self, key, default=None): return { "amadea_log_path": "/nonexistent", "user_status_thresholds": {"active_minutes": 5, "inactive_minutes": 30}, "check_interval_minutes": 1, }.get(key, default) def make_monitor(): return UserMonitor(FakeConfig()) # --- Parsing awevents --- def test_parse_awevents_line_basic(): monitor = make_monitor() users, hourly = {}, {h: set() for h in range(24)} cutoff = datetime(2026, 3, 30, 0, 0, 0) line = '2026-03-30 10:34:24.034;INFO ;;;;"login=JENKINS,action=SelectionChange,Label=BAO_Main/MenuPrincipal"\n' monitor._parse_awevents_line(line, users, cutoff, hourly) assert "JENKINS" in users assert users["JENKINS"]["last_action_time"] == datetime(2026, 3, 30, 10, 34, 24) assert users["JENKINS"]["action_count_24h"] == 1 assert users["JENKINS"]["explicit_logout"] is False assert hourly[10] == {"JENKINS"} def test_parse_awevents_line_explicit_logout(): monitor = make_monitor() users, hourly = {}, {h: set() for h in range(24)} cutoff = datetime(2026, 3, 30, 0, 0, 0) line = '2026-03-30 11:34:00.500;INFO ;;;;"login=MB,action=Action,Label=Main/se deconnecter"\n' monitor._parse_awevents_line(line, users, cutoff, hourly) assert users["MB"]["explicit_logout"] is True assert users["MB"]["logout_time"] == datetime(2026, 3, 30, 11, 34, 0) def test_parse_awevents_line_reconnect_after_logout(): monitor = make_monitor() users, hourly = {}, {h: set() for h in range(24)} cutoff = datetime(2026, 3, 30, 0, 0, 0) logout_line = '2026-03-30 11:34:00.500;INFO ;;;;"login=MB,action=Action,Label=Main/se deconnecter"\n' reconnect_line = '2026-03-30 11:34:19.594;INFO ;;;;"login=MB,action=Action,Label=Main/OuvrirCTRL 1/Table"\n' monitor._parse_awevents_line(logout_line, users, cutoff, hourly) assert users["MB"]["explicit_logout"] is True monitor._parse_awevents_line(reconnect_line, users, cutoff, hourly) assert users["MB"]["explicit_logout"] is False def test_parse_awevents_line_invalid_ignored(): monitor = make_monitor() users, hourly = {}, {h: set() for h in range(24)} cutoff = datetime(2026, 3, 30, 0, 0, 0) monitor._parse_awevents_line("ligne invalide sans format attendu\n", users, cutoff, hourly) assert users == {} def test_parse_awevents_action_count_outside_24h(): monitor = make_monitor() users, hourly = {}, {h: set() for h in range(24)} cutoff = datetime(2026, 3, 30, 12, 0, 0) old_line = '2026-03-30 08:00:00.000;INFO ;;;;"login=JENKINS,action=Click,Label=Main/Page"\n' monitor._parse_awevents_line(old_line, users, cutoff, hourly) assert users["JENKINS"]["action_count_24h"] == 0 # --- Calcul de statut --- def test_compute_statuses_actif(): monitor = make_monitor() now = datetime(2026, 3, 30, 12, 0, 0) thresholds = {"active_minutes": 5, "inactive_minutes": 30} users = {"JENKINS": {"last_action_time": now - timedelta(minutes=2), "explicit_logout": False}} monitor._compute_statuses(users, thresholds, now) assert users["JENKINS"]["status"] == "actif" def test_compute_statuses_inactif(): monitor = make_monitor() now = datetime(2026, 3, 30, 12, 0, 0) thresholds = {"active_minutes": 5, "inactive_minutes": 30} users = {"MB": {"last_action_time": now - timedelta(minutes=15), "explicit_logout": False}} monitor._compute_statuses(users, thresholds, now) assert users["MB"]["status"] == "inactif" def test_compute_statuses_deconnecte_timeout(): monitor = make_monitor() now = datetime(2026, 3, 30, 12, 0, 0) thresholds = {"active_minutes": 5, "inactive_minutes": 30} users = {"KO": {"last_action_time": now - timedelta(minutes=45), "explicit_logout": False}} monitor._compute_statuses(users, thresholds, now) assert users["KO"]["status"] == "deconnecte" def test_compute_statuses_deconnecte_explicit(): monitor = make_monitor() now = datetime(2026, 3, 30, 12, 0, 0) thresholds = {"active_minutes": 5, "inactive_minutes": 30} users = {"MB": {"last_action_time": now - timedelta(minutes=2), "explicit_logout": True}} monitor._compute_statuses(users, thresholds, now) assert users["MB"]["status"] == "deconnecte"