Files
ems/backend/tests/test_discord_bot.py
Dusan Vojacek 0e7f7b69ae
All checks were successful
CI and deploy / migration-check (push) Successful in 21s
CI and deploy / deploy (push) Has been skipped
Discord bot fáze B: tlačítka na EV zprávě → patch session + okamžitý replan
services/discord_bot.py: gateway klient jako lifespan task (spojení ven,
žádný veřejný endpoint; bez DISCORD_BOT_TOKEN tiše spí). Tlačítka
[za 2h][za 4h][ráno][do plna][nenabíjet] s custom_id ev:<site>:<charger>:<akce>
(přežijí restart); whitelist DISCORD_ALLOWED_USER_IDS; akce = fn_ev_session_
apply_patch → run_rolling_replan → export_setpoints → edit zprávy novým plánem.

services/ev_notify.py: sdílený builder souhrnu (vyčleněno z collectoru),
send bot-first s webhook fallbackem. requirements: discord.py>=2.4.
7 testů helperů (parse, deadline akce vč. morning přes Prague TZ).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 11:41:05 +02:00

58 lines
1.9 KiB
Python

"""Discord bot — čisté helpery (custom_id, patch akcí), bez sítě/discord lib."""
from __future__ import annotations
import unittest
from datetime import datetime, timezone
from services.discord_bot import action_to_patch, parse_custom_id
_NOW = datetime(2026, 6, 12, 10, 0, tzinfo=timezone.utc) # 12:00 Prague
class ParseCustomIdTests(unittest.TestCase):
def test_valid(self) -> None:
self.assertEqual(
parse_custom_id("ev:2:ev-charger-1:h2"), (2, "ev-charger-1", "h2")
)
def test_invalid(self) -> None:
for bad in ("", "ev:2:x:jump", "foo:1:c:h2", "ev:abc:c:h2"):
self.assertIsNone(parse_custom_id(bad))
class ActionPatchTests(unittest.TestCase):
def _patch(self, action: str, **kw):
return action_to_patch(
action,
now=_NOW,
soc_at_connect=kw.get("soc", 55.0),
default_deadline_hour=kw.get("hour", 7),
)
def test_h2_deadline(self) -> None:
p = self._patch("h2")
self.assertIn("2026-06-12T12:00", p["target_deadline"])
def test_morning_next_occurrence(self) -> None:
p = self._patch("morning", hour=7)
# 12:00 Prague > 7:00 → zítra 7:00 Prague
self.assertIn("2026-06-13T07:00", p["target_deadline"])
def test_morning_today_if_before(self) -> None:
early = datetime(2026, 6, 12, 2, 0, tzinfo=timezone.utc) # 4:00 Prague
p = action_to_patch("morning", now=early, soc_at_connect=50, default_deadline_hour=7)
self.assertIn("2026-06-12T07:00", p["target_deadline"])
def test_full(self) -> None:
p = self._patch("full")
self.assertEqual(p["target_soc_pct"], 100)
def test_stop_targets_connect_soc(self) -> None:
p = self._patch("stop", soc=42.5)
self.assertEqual(p["target_soc_pct"], 42.5)
if __name__ == "__main__":
unittest.main()