From c814eca5961306055231d67da28397fdef1e84c0 Mon Sep 17 00:00:00 2001 From: Kenik Date: Sat, 5 Sep 2026 14:51:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D0=BF=D0=BE=D0=BC=D0=B8=D0=BD?= =?UTF-8?q?=D0=B0=D0=BB=D0=BA=D0=B8:=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20?= =?UTF-8?q?=D0=B3=D0=B5=D0=B9=D1=82=D0=B0=20=D1=87=D0=B0=D1=81=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D0=BF=D0=BE=D1=8F=D1=81=D0=B0,=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D0=B2=D0=B5=D1=80=D1=82=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=B8=20=D0=BF=D0=B0=D1=83=D0=B7=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- tests/test_flow.py | 89 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tests/test_flow.py b/tests/test_flow.py index 7d95564..a49a29d 100644 --- a/tests/test_flow.py +++ b/tests/test_flow.py @@ -1,4 +1,6 @@ import bot +import reminders +from datetime import datetime, timedelta def _state(uid): @@ -356,6 +358,7 @@ def test_stats_runs(app): def test_admin_reminder_wizard_creates_reminder(app, monkeypatch): admin = 80001 monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin]) + bot.db.set_admin_tz_offset(admin, 3) # пояс уже задан — гейт не должен мешать app.handle_message(admin, "Админка ⚙️") app.handle_message(admin, "⏰ Напоминалки") @@ -387,6 +390,7 @@ def test_admin_reminder_wizard_creates_reminder(app, monkeypatch): def test_admin_reminder_wizard_specific_recipients(app, monkeypatch): admin, other = 80003, 80004 monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin, other]) + bot.db.set_admin_tz_offset(admin, 0) app.handle_message(admin, "⏰ Напоминалки") app.handle_message(admin, "➕ Добавить") @@ -406,6 +410,7 @@ def test_admin_reminder_wizard_specific_recipients(app, monkeypatch): def test_admin_reminder_delete(app, monkeypatch): admin = 80002 monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin]) + bot.db.set_admin_tz_offset(admin, 0) rid = bot.db.add_reminder("Тест", "2099-01-01 09:00:00", "once", [admin], created_by=admin) app.handle_message(admin, f"напоминалка удалить {rid}") @@ -423,6 +428,7 @@ def test_admin_reminder_delete_via_picker_button(app, monkeypatch): """Удаление через кнопку «🗑 Удалить напоминание» + выбор из списка (без ввода id вручную).""" admin = 80005 monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin]) + bot.db.set_admin_tz_offset(admin, 0) rid = bot.db.add_reminder("Продлить хостинг", "2099-01-01 09:00:00", "once", [admin], created_by=admin) app.handle_message(admin, "⏰ Напоминалки") @@ -432,3 +438,86 @@ def test_admin_reminder_delete_via_picker_button(app, monkeypatch): app.handle_message(admin, f"{rid}. Продлить хостинг") # клик по кнопке пикера assert _state(admin) == "FREE_CHAT" assert not bot.db.get_active_reminders() + + +def test_reminder_tz_gate_before_list(app, monkeypatch): + """Без заданного часового пояса раздел не открывается — сначала гейт.""" + admin = 80006 + monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin]) + + app.handle_message(admin, "⏰ Напоминалки") + assert _state(admin) == "ADMIN_REMINDER_TZ_SETUP" + + app.handle_message(admin, "не число") # невалидный формат — остаёмся на шаге + assert _state(admin) == "ADMIN_REMINDER_TZ_SETUP" + + app.handle_message(admin, "+3") + assert _state(admin) == "FREE_CHAT" + assert bot.db.get_admin_tz_offset(admin) == 3 + + # повторный вход — пояс уже задан, гейт больше не срабатывает + app.handle_message(admin, "⏰ Напоминалки") + assert _state(admin) == "FREE_CHAT" + + +def test_reminder_creation_converts_author_local_time_to_server(app, monkeypatch): + admin = 80007 + monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin]) + bot.db.set_admin_tz_offset(admin, 3) # пояс уже задан — гейт не мешает + + app.handle_message(admin, "⏰ Напоминалки") + app.handle_message(admin, "➕ Добавить") + app.handle_message(admin, "01.06.2099 09:00") # 09:00 по времени автора (UTC+3) + app.handle_message(admin, "Тест конвертации") + app.handle_message(admin, "0") + app.handle_message(admin, "Разово") + + rows = bot.db.get_active_reminders() + stored = datetime.strptime(rows[0]["remind_at"], "%Y-%m-%d %H:%M:%S") + server_offset = reminders.server_utc_offset_hours() + expected = datetime(2099, 6, 1, 9, 0) + timedelta(hours=(server_offset - 3)) + assert stored == expected + + +def test_reminder_pause_and_resume_via_picker(app, monkeypatch): + admin = 80008 + monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin]) + bot.db.set_admin_tz_offset(admin, 0) + rid = bot.db.add_reminder("Продлить хостинг", "2020-01-01 09:00:00", "once", [admin], created_by=admin) + + app.handle_message(admin, "⏰ Напоминалки") + app.handle_message(admin, "⏸/▶ Пауза") + assert _state(admin) == "ADMIN_REMINDER_PAUSE_PICK" + app.handle_message(admin, f"{rid}. Продлить хостинг") + assert _state(admin) == "FREE_CHAT" + row = next(r for r in bot.db.get_active_reminders() if r["id"] == rid) + assert row["paused"] == 1 + + # напоминание давно просрочено, но на паузе — планировщик не должен его отправить + app._sent.clear() + app._check_due_reminders() + assert not app._sent + assert bot.db.get_active_reminders() # всё ещё активно (не деактивировалось) + + # возобновляем через тот же пикер + app.handle_message(admin, "⏸/▶ Пауза") + app.handle_message(admin, f"{rid}. Продлить хостинг") + row = next(r for r in bot.db.get_active_reminders() if r["id"] == rid) + assert row["paused"] == 0 + + # теперь просроченное разовое напоминание должно уйти при следующей проверке + app._check_due_reminders() + assert app._sent + assert not bot.db.get_active_reminders() # once — деактивировалось после отправки + + +def test_timezone_change_command(app, monkeypatch): + admin = 80009 + monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin]) + bot.db.set_admin_tz_offset(admin, 3) + + app.handle_message(admin, "часовой пояс -5") + assert bot.db.get_admin_tz_offset(admin) == -5 + + app.handle_message(admin, "часовой пояс много") + assert bot.db.get_admin_tz_offset(admin) == -5 # невалидный ввод не поменял значение