Files
atm/tests/test_commands.py
Marius Mutu 6f71c1d633 feat(lifecycle): /window + stop screenshot-uri la închiderea bursei
Fix #1: la tranziția market_closed scheduler-ul e oprit forțat și FSM
resetat la IDLE (_handle_market_closed), ca o bulină dark_* rămasă PRIMED
să nu mai trimită screenshot-uri periodice după închidere — și ca scheduler-ul
să poată reporni curat în sesiunea următoare (muchia 0->1 n_primed_global).

Fix #2: comandă Telegram /window HH:MM-HH:MM (sau HH:MM HH:MM) — fereastră
de monitorizare în ora locală, recurentă zilnic, ANDed cu operating_hours;
în afara intervalului pauză automată. /window off șterge fereastra.
Discord e webhook outbound, fără poller — comanda e doar Telegram.

DOX pass: src/atm + notifier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 13:25:41 +03:00

104 lines
3.2 KiB
Python

"""Tests for atm.commands — /pause /resume parsing (Commit 5)."""
from __future__ import annotations
from unittest.mock import MagicMock
from atm.commands import Command, TelegramPoller
def _make_poller() -> TelegramPoller:
cfg = MagicMock()
cfg.bot_token = "tok"
cfg.chat_id = "123"
cfg.allowed_chat_ids = ("123",)
cfg.poll_timeout_s = 1
return TelegramPoller(cfg, MagicMock(), MagicMock())
def test_parse_pause():
p = _make_poller()
assert p._parse_command("pause") == Command(action="pause")
assert p._parse_command("/pause") == Command(action="pause")
def test_parse_resume_plain():
p = _make_poller()
assert p._parse_command("resume") == Command(action="resume")
assert p._parse_command("/resume") == Command(action="resume")
def test_parse_resume_force():
p = _make_poller()
# "resume force" → value=1 signals force-resume of canary drift
cmd = p._parse_command("resume force")
assert cmd is not None
assert cmd.action == "resume"
assert cmd.value == 1
def test_parse_rebase_plain():
p = _make_poller()
assert p._parse_command("rebase") == Command(action="rebase")
assert p._parse_command("/rebase") == Command(action="rebase")
def test_parse_rebase_confirm():
p = _make_poller()
cmd = p._parse_command("rebase confirm")
assert cmd is not None
assert cmd.action == "rebase"
assert cmd.value == 1
def test_parse_help():
p = _make_poller()
assert p._parse_command("h") == Command(action="help")
assert p._parse_command("/h") == Command(action="help")
assert p._parse_command("help") == Command(action="help")
assert p._parse_command("/help") == Command(action="help")
def test_parse_existing_commands_still_work():
"""Regression: adding pause/resume must not break stop/status/ss/interval."""
p = _make_poller()
assert p._parse_command("stop") == Command(action="stop")
assert p._parse_command("status") == Command(action="status")
assert p._parse_command("ss") == Command(action="ss")
assert p._parse_command("3") == Command(action="set_interval", value=180)
def test_parse_window_dash():
p = _make_poller()
cmd = p._parse_command("window 19:40-21:45")
assert cmd == Command(action="window", window=("19:40", "21:45"))
assert p._parse_command("/window 19:40-21:45") == cmd
def test_parse_window_space():
p = _make_poller()
assert p._parse_command("window 20:50 22:45") == Command(
action="window", window=("20:50", "22:45")
)
def test_parse_window_zero_pads_hour():
p = _make_poller()
assert p._parse_command("window 9:05-9:30") == Command(
action="window", window=("09:05", "09:30")
)
def test_parse_window_off_clears():
p = _make_poller()
assert p._parse_command("window off") == Command(action="window", window=None)
assert p._parse_command("window") == Command(action="window", window=None)
assert p._parse_command("window clear") == Command(action="window", window=None)
def test_parse_window_invalid_returns_none():
p = _make_poller()
assert p._parse_command("window 25:99-26:00") is None
assert p._parse_command("window foo") is None
assert p._parse_command("window 19:40") is None
assert p._parse_command("window 19:60-20:00") is None