zapretgui/tests/test_premium_worker_architecture.py
loop-uh 3a331518c6
All checks were successful
Zapret source guards / validate (push) Successful in 10s
Windows-сборка / Dev Dev 21.1.7.154 опубликован
Страница Premium: зачем нужен код, инструкция из 4 шагов и кнопка «Как это работает»
На странице Premium добавлен блок «зачем код»: Premium входит в любой тариф бота @zapretvpns_bot, даже «Запретик»; код не ключ и не оплата, он один раз связывает компьютер с Telegram-аккаунтом; VPN — отдельная часть тарифов бота. Инструкция теперь из 4 шагов, начинается с покупки тарифа и говорит, что код живёт 10 минут. Кнопка «Как это работает» открывает https://wiki2.zapret.moe/Zapret/premium. Подпись «device token: ✅/❌» заменена на «Привязка: есть/нет». На странице «О программе» убрано неверное обещание, что Premium открывает VPN.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 21:03:39 +03:00

648 lines
30 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
import inspect
import importlib.util
import unittest
from types import SimpleNamespace
from unittest.mock import Mock, patch
from app.feature_facades.premium import PremiumFeature
import donater.commands as premium_commands
import donater.open_bot_worker as open_bot_worker
import donater.status_runtime as status_runtime
import donater.status_worker as status_worker
from donater.ui.page import PremiumPage
class PremiumWorkerArchitectureTests(unittest.TestCase):
def test_manual_status_check_is_delegated_to_status_owner(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
# Идущее действие страницы (создание кода) не должно задерживать
# проверку: у владельца статуса свой фоновый поток.
page._premium_action_runtime = SimpleNamespace(is_running=Mock(return_value=True))
page._pending_premium_action = ""
page._premium = SimpleNamespace(request_status_refresh=Mock())
page._start_worker_thread = Mock()
page.refresh_btn = Mock()
page._set_status_badge = Mock()
with patch("donater.ui.page.apply_status_check_start_ui") as start_ui:
PremiumPage._check_status(page)
start_ui.assert_called_once()
page._premium.request_status_refresh.assert_called_once_with(force=True)
page._start_worker_thread.assert_not_called()
self.assertEqual(page._pending_premium_action, "")
def test_page_has_no_own_status_network_path_or_polling(self) -> None:
page_source = inspect.getsource(PremiumPage)
feature_source = inspect.getsource(PremiumFeature)
self.assertNotIn("check_device_activation", page_source)
self.assertNotIn("autopoll", page_source)
self.assertNotIn("_pairing_status_timer", page_source)
self.assertNotIn("on_page_hidden", page_source)
self.assertNotIn("check_device_activation", feature_source)
self.assertIsNone(importlib.util.find_spec("donater.pairing_workflow"))
self.assertIsNone(importlib.util.find_spec("donater.subscription_manager"))
self.assertIsNone(importlib.util.find_spec("donater.subscription_worker"))
def test_created_pair_code_wakes_status_owner(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._activation_in_progress = True
page._premium = SimpleNamespace(request_status_refresh=Mock())
page.activate_btn = Mock()
page.key_input = Mock()
page._tr = Mock(side_effect=lambda _key, default, **kwargs: default)
page._set_activation_status = Mock()
page._update_device_info = Mock()
page._set_activation_section_visible = Mock()
with patch("donater.ui.pairing_workflow.QApplication"), patch(
"donater.ui.pairing_workflow.apply_premium_button_accessibility"
), patch("donater.ui.pairing_workflow.apply_premium_pair_code_accessibility"):
PremiumPage._on_pair_code_created(page, (True, "ok", "ABCD12EF"))
page._premium.request_status_refresh.assert_called_once_with(force=True)
# Раздел с кодом виден, даже если фоновая проверка успела его скрыть.
page._set_activation_section_visible.assert_called_once_with(True)
page._premium.request_status_refresh.reset_mock()
page._set_activation_section_visible.reset_mock()
PremiumPage._on_pair_code_created(page, (False, "нет сети", None))
page._premium.request_status_refresh.assert_not_called()
page._set_activation_section_visible.assert_not_called()
def test_failed_reset_asks_status_owner_to_show_closed_access(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._reset_storage_runtime = SimpleNamespace(is_current=Mock(return_value=True))
page._reset_storage_state = SimpleNamespace(has_pending=Mock(return_value=False))
page._premium = SimpleNamespace(request_status_refresh=Mock())
with patch("donater.ui.page.InfoBar", None):
PremiumPage._on_reset_storage_failed(page, 1, "сервер не подтвердил")
page._premium.request_status_refresh.assert_called_once_with(force=True)
def test_open_bot_worker_receives_feature_action_not_feature_object(self) -> None:
feature_source = inspect.getsource(PremiumFeature.create_open_extend_bot_worker)
worker_source = inspect.getsource(open_bot_worker.PremiumOpenBotWorker)
self.assertNotIn("premium_feature=self", feature_source)
self.assertNotIn("self._premium", worker_source)
self.assertIn("open_extend_bot=self.open_extend_bot", feature_source)
self.assertIn("_open_extend_bot", worker_source)
self.assertNotIn("premium_commands.open_extend_bot", worker_source)
self.assertNotIn("import donater.commands", worker_source)
self.assertIn("open_extend_bot", inspect.getsource(premium_commands.open_extend_bot))
def test_status_worker_receives_command_actions_from_runtime(self) -> None:
command_source = inspect.getsource(premium_commands.create_status_runtime)
runtime_init_source = inspect.getsource(status_runtime.PremiumStatusRuntime.__init__)
runtime_start_source = inspect.getsource(status_runtime.PremiumStatusRuntime._start_check)
worker_source = inspect.getsource(status_worker.PremiumStatusCheckWorker)
self.assertIn("get_premium_checker=get_premium_checker", command_source)
self.assertIn("check_device_activation=check_device_activation", command_source)
self.assertIn("_get_premium_checker", runtime_init_source)
self.assertIn("_check_device_activation", runtime_init_source)
self.assertIn("get_premium_checker=self._get_premium_checker", runtime_start_source)
self.assertIn("check_device_activation=self._check_device_activation", runtime_start_source)
self.assertIn("_get_premium_checker", worker_source)
self.assertIn("_check_device_activation", worker_source)
self.assertNotIn("import donater.commands", worker_source)
def test_status_runtime_uses_shared_worker_runtime(self) -> None:
runtime_init_source = inspect.getsource(status_runtime.PremiumStatusRuntime.__init__)
runtime_start_source = inspect.getsource(status_runtime.PremiumStatusRuntime._start_check)
runtime_cleanup_source = inspect.getsource(status_runtime.PremiumStatusRuntime.cleanup)
self.assertIn("_worker_runtime = OneShotWorkerRuntime()", runtime_init_source)
self.assertIn("_worker_runtime.start_qobject_worker", runtime_start_source)
self.assertIn("bind_worker=", runtime_start_source)
self.assertIn("_worker_runtime.stop", runtime_cleanup_source)
self.assertNotIn("QThread(", runtime_start_source)
self.assertNotIn("moveToThread", runtime_start_source)
def test_premium_page_action_tasks_use_shared_worker_runtime(self) -> None:
page_init_source = inspect.getsource(PremiumPage.__init__)
start_source = inspect.getsource(PremiumPage._start_worker_thread)
page_source = inspect.getsource(PremiumPage)
lifecycle_source = inspect.getsource(__import__("donater.ui.page_lifecycle", fromlist=["cleanup_premium_page"]))
self.assertIn("_premium_action_runtime = OneShotWorkerRuntime()", page_init_source)
self.assertIn("_premium_action_runtime.start_qthread_worker", start_source)
self.assertIn("loaded_signal_name=\"result_ready\"", start_source)
self.assertIn("failed_signal_name=\"error_occurred\"", start_source)
self.assertIn("_is_premium_action_running", page_source)
self.assertIn("premium_action_runtime.stop", lifecycle_source)
self.assertNotIn("start_premium_worker_task", page_source)
self.assertNotIn("current_thread", page_source)
self.assertNotIn("is_premium_task_running", page_source)
self.assertIsNone(importlib.util.find_spec("donater.premium_page_tasks"))
def test_pair_code_action_is_remembered_while_checker_initializes(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._premium_action_runtime = SimpleNamespace(is_running=Mock(return_value=False))
page._premium = SimpleNamespace(is_checker_ready=Mock(return_value=False))
page._pending_premium_action = ""
page._pending_premium_action_start_scheduled = False
page._start_premium_init_worker = Mock()
page._set_activation_status = Mock()
PremiumPage._create_pair_code(page)
self.assertEqual(page._pending_premium_action, "pair_code")
page._start_premium_init_worker.assert_called_once_with()
def test_pending_premium_action_restarts_after_event_loop_turn(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._pending_premium_action = "test_connection"
page._pending_premium_action_start_scheduled = False
page._test_connection = Mock()
single_shot = Mock(side_effect=lambda _delay, _callback: None)
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._schedule_pending_premium_action_start(page)
single_shot.assert_called_once()
self.assertEqual(single_shot.call_args.args[0], 0)
page._test_connection.assert_not_called()
single_shot.call_args.args[1]()
page._test_connection.assert_called_once_with()
self.assertEqual(page._pending_premium_action, "")
def test_premium_worker_finished_replays_pending_action_later(self) -> None:
import donater.ui.page as premium_page
worker = object()
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._premium_action_runtime_worker = worker
page._pending_premium_action = "test_connection"
page._pending_premium_action_start_scheduled = False
page._test_connection = Mock()
single_shot = Mock(side_effect=lambda _delay, _callback: None)
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._on_worker_thread_finished(page, worker)
single_shot.assert_called_once()
page._test_connection.assert_not_called()
single_shot.call_args.args[1]()
page._test_connection.assert_called_once_with()
self.assertEqual(page._pending_premium_action, "")
def test_stale_premium_worker_finished_does_not_replay_pending_action(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._premium_action_runtime_worker = object()
page._pending_premium_action = "test_connection"
page._schedule_pending_premium_action_start = Mock()
PremiumPage._on_worker_thread_finished(page, object())
page._schedule_pending_premium_action_start.assert_not_called()
self.assertEqual(page._pending_premium_action, "test_connection")
def test_stale_premium_action_result_is_ignored(self) -> None:
worker = object()
start_kwargs = {}
result_handler = Mock()
error_handler = Mock()
runtime = SimpleNamespace(
start_qthread_worker=Mock(side_effect=lambda **kwargs: start_kwargs.update(kwargs) or (2, worker)),
is_current=Mock(return_value=False),
)
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._premium_action_runtime = runtime
page._premium = SimpleNamespace(
create_premium_worker_thread=Mock(return_value=worker),
)
PremiumPage._start_worker_thread(page, Mock(), result_handler, error_handler)
start_kwargs["on_loaded"](1, "old-result")
start_kwargs["on_failed"](1, "old-error")
result_handler.assert_not_called()
error_handler.assert_not_called()
runtime.is_current.assert_any_call(1, cleanup_in_progress=False)
def test_pending_premium_action_is_cleared_when_init_fails(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._pending_premium_action = "pair_code"
page._pending_premium_action_start_scheduled = True
PremiumPage._on_premium_init_error(page, "boom")
self.assertEqual(page._pending_premium_action, "")
self.assertFalse(page._pending_premium_action_start_scheduled)
def test_device_info_pending_restarts_after_event_loop_turn(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._device_info_pending = True
page._cleanup_in_progress = False
page._start_device_info_load_worker = Mock()
single_shot = Mock(side_effect=lambda _delay, _callback: None)
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._on_device_info_worker_finished(page, object())
single_shot.assert_called_once()
self.assertEqual(single_shot.call_args.args[0], 0)
page._start_device_info_load_worker.assert_not_called()
single_shot.call_args.args[1]()
page._start_device_info_load_worker.assert_called_once_with()
def test_device_info_load_uses_shared_latest_worker_state(self) -> None:
from ui.latest_value_worker_state import LatestValueWorkerState
page = PremiumPage.__new__(PremiumPage)
page._device_info_runtime = SimpleNamespace(is_running=Mock(return_value=False))
init_source = inspect.getsource(PremiumPage.__init__)
request_source = inspect.getsource(PremiumPage._request_device_info_load)
schedule_source = inspect.getsource(PremiumPage._schedule_device_info_load_worker_start)
cleanup_source = inspect.getsource(PremiumPage.cleanup)
self.assertIsInstance(PremiumPage._device_info_state_obj(page), LatestValueWorkerState)
self.assertIn("_device_info_state", init_source)
self.assertNotIn("self._device_info_pending = False", init_source)
self.assertNotIn("self._device_info_start_scheduled = False", init_source)
self.assertIn("_device_info_state_obj()", request_source)
self.assertIn("_device_info_state_obj()", schedule_source)
self.assertIn("_device_info_state_obj().reset()", cleanup_source)
def test_stale_device_info_worker_finished_does_not_restart_pending_load(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._device_info_runtime = SimpleNamespace(worker=object())
page._device_info_pending = True
page._cleanup_in_progress = False
page._start_device_info_load_worker = Mock()
single_shot = Mock()
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._on_device_info_worker_finished(page, object())
single_shot.assert_not_called()
page._start_device_info_load_worker.assert_not_called()
self.assertTrue(page._device_info_pending)
def test_device_info_result_is_ignored_when_new_load_is_pending(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._device_info_runtime = SimpleNamespace(is_current=Mock(return_value=True))
page._device_info_pending = True
page._set_pairing_autopoll_snapshot_from_device_info = Mock()
page._tr = Mock(side_effect=lambda _key, default, **_kwargs: default)
page.device_id_label = Mock()
page.saved_key_label = Mock()
page.last_check_label = Mock()
with patch.object(premium_page, "apply_device_info_snapshot_labels") as apply_labels:
PremiumPage._on_device_info_loaded(page, 4, {"device_id": "old"})
page._set_pairing_autopoll_snapshot_from_device_info.assert_not_called()
apply_labels.assert_not_called()
def test_open_bot_pending_restarts_after_event_loop_turn(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._open_bot_pending = True
page._cleanup_in_progress = False
page._request_open_extend_bot = Mock()
single_shot = Mock(side_effect=lambda _delay, _callback: None)
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._on_open_extend_bot_worker_finished(page, object())
single_shot.assert_called_once()
self.assertEqual(single_shot.call_args.args[0], 0)
page._request_open_extend_bot.assert_not_called()
single_shot.call_args.args[1]()
page._request_open_extend_bot.assert_called_once_with()
def test_open_bot_uses_shared_latest_worker_state(self) -> None:
from ui.latest_value_worker_state import LatestValueWorkerState
page = PremiumPage.__new__(PremiumPage)
page._open_bot_runtime = SimpleNamespace(is_running=Mock(return_value=False))
init_source = inspect.getsource(PremiumPage.__init__)
request_source = inspect.getsource(PremiumPage._request_open_extend_bot)
schedule_source = inspect.getsource(PremiumPage._schedule_open_extend_bot_worker_start)
cleanup_source = inspect.getsource(PremiumPage.cleanup)
self.assertIsInstance(PremiumPage._open_bot_state_obj(page), LatestValueWorkerState)
self.assertIn("_open_bot_state", init_source)
self.assertNotIn("self._open_bot_pending = False", init_source)
self.assertNotIn("self._open_bot_start_scheduled = False", init_source)
self.assertIn("_open_bot_state_obj()", request_source)
self.assertIn("_open_bot_state_obj()", schedule_source)
self.assertIn("_open_bot_state_obj().reset()", cleanup_source)
def test_stale_open_bot_worker_finished_does_not_restart_pending_open(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._open_bot_runtime = SimpleNamespace(worker=object())
page._open_bot_pending = True
page._cleanup_in_progress = False
page._request_open_extend_bot = Mock()
single_shot = Mock()
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._on_open_extend_bot_worker_finished(page, object())
single_shot.assert_not_called()
page._request_open_extend_bot.assert_not_called()
self.assertTrue(page._open_bot_pending)
def test_open_bot_result_is_ignored_when_new_open_is_pending(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._open_bot_runtime = SimpleNamespace(is_current=Mock(return_value=True))
page._open_bot_pending = True
page._show_open_extend_bot_error = Mock()
PremiumPage._on_open_extend_bot_finished(
page,
4,
SimpleNamespace(ok=False, message="old error"),
)
page._show_open_extend_bot_error.assert_not_called()
def test_open_bot_error_is_ignored_when_new_open_is_pending(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._open_bot_runtime = SimpleNamespace(is_current=Mock(return_value=True))
page._open_bot_pending = True
page._show_open_extend_bot_error = Mock()
PremiumPage._on_open_extend_bot_failed(page, 4, "old error")
page._show_open_extend_bot_error.assert_not_called()
def test_cleanup_stops_open_bot_worker_without_blocking_gui(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._premium_action_runtime = Mock()
page._open_bot_runtime = Mock()
page._open_guide_runtime = Mock()
page._device_info_runtime = Mock()
page._reset_storage_runtime = Mock()
page._open_bot_pending = True
page._open_bot_start_scheduled = True
page._device_info_pending = True
page._device_info_start_scheduled = True
page._reset_storage_pending = True
page._reset_storage_start_scheduled = True
page._premium_action_runtime_worker = object()
page._pending_premium_action = "activate"
page._pending_premium_action_start_scheduled = True
unsubscribe_ui_state = Mock()
page._ui_state_unsubscribe = unsubscribe_ui_state
unsubscribe_status_checks = Mock()
page._status_checks_unsubscribe = unsubscribe_status_checks
PremiumPage.cleanup(page)
self.assertTrue(page._cleanup_in_progress)
unsubscribe_ui_state.assert_called_once_with()
self.assertIsNone(page._ui_state_unsubscribe)
unsubscribe_status_checks.assert_called_once_with()
self.assertIsNone(page._status_checks_unsubscribe)
self.assertFalse(page._open_bot_pending)
self.assertFalse(page._open_bot_start_scheduled)
self.assertFalse(page._device_info_pending)
self.assertFalse(page._device_info_start_scheduled)
page._open_bot_runtime.stop.assert_called_once_with(
blocking=False,
warning_prefix="Premium open bot worker",
)
page._open_bot_runtime.cancel.assert_called_once()
page._open_guide_runtime.stop.assert_called_once_with(
blocking=False,
warning_prefix="Premium open guide worker",
)
page._open_guide_runtime.cancel.assert_called_once()
page._device_info_runtime.stop.assert_called_once_with(
blocking=False,
warning_prefix="Premium device info worker",
)
page._device_info_runtime.cancel.assert_called_once()
page._premium_action_runtime.stop.assert_called_once_with(
blocking=False,
wait_timeout_ms=1000,
warning_prefix="Premium action worker",
)
page._reset_storage_runtime.stop.assert_called_once_with(
blocking=False,
warning_prefix="Premium reset storage worker",
)
def test_close_event_stops_premium_action_worker_without_blocking_gui(self) -> None:
from donater.ui.page_lifecycle import close_premium_page
runtime = SimpleNamespace(is_running=Mock(return_value=True), stop=Mock())
event = SimpleNamespace(accept=Mock())
cleanup_values = []
close_premium_page(
set_cleanup_in_progress_fn=cleanup_values.append,
build_close_plan_fn=Mock(
return_value=SimpleNamespace(
should_quit_thread=True,
wait_timeout_ms=750,
)
),
premium_action_runtime=runtime,
event=event,
)
self.assertEqual(cleanup_values, [True])
runtime.stop.assert_called_once_with(
blocking=False,
wait_timeout_ms=750,
warning_prefix="Premium action worker",
)
event.accept.assert_called_once_with()
def test_device_info_pending_restart_is_coalesced_while_scheduled(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._device_info_start_scheduled = False
page._cleanup_in_progress = False
page._device_info_pending = False
page._start_device_info_load_worker = Mock()
single_shot = Mock(side_effect=lambda _delay, _callback: None)
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._schedule_device_info_load_worker_start(page)
PremiumPage._schedule_device_info_load_worker_start(page)
single_shot.assert_called_once()
self.assertTrue(page._device_info_pending)
single_shot.call_args.args[1]()
page._start_device_info_load_worker.assert_called_once_with()
self.assertTrue(page._device_info_pending)
def test_open_bot_pending_restart_is_coalesced_while_scheduled(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._open_bot_start_scheduled = False
page._cleanup_in_progress = False
page._open_bot_pending = False
page._request_open_extend_bot = Mock()
single_shot = Mock(side_effect=lambda _delay, _callback: None)
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._schedule_open_extend_bot_worker_start(page)
PremiumPage._schedule_open_extend_bot_worker_start(page)
single_shot.assert_called_once()
self.assertTrue(page._open_bot_pending)
single_shot.call_args.args[1]()
page._request_open_extend_bot.assert_called_once_with()
self.assertTrue(page._open_bot_pending)
def test_reset_storage_request_is_remembered_while_worker_runs(self) -> None:
page = PremiumPage.__new__(PremiumPage)
page._reset_storage_runtime = SimpleNamespace(is_running=Mock(return_value=True), start_qthread_worker=Mock())
page._reset_storage_pending = False
page._reset_storage_start_scheduled = False
PremiumPage._request_reset_storage(page)
page._reset_storage_runtime.start_qthread_worker.assert_not_called()
self.assertTrue(page._reset_storage_pending)
def test_reset_storage_pending_restarts_after_event_loop_turn(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._reset_storage_pending = True
page._reset_storage_start_scheduled = False
page._start_reset_storage_worker = Mock()
single_shot = Mock(side_effect=lambda _delay, _callback: None)
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._on_reset_storage_worker_finished(page, object())
single_shot.assert_called_once()
self.assertEqual(single_shot.call_args.args[0], 0)
page._start_reset_storage_worker.assert_not_called()
single_shot.call_args.args[1]()
page._start_reset_storage_worker.assert_called_once_with()
self.assertFalse(page._reset_storage_pending)
def test_reset_storage_uses_shared_latest_worker_state(self) -> None:
from ui.latest_value_worker_state import LatestValueWorkerState
page = PremiumPage.__new__(PremiumPage)
page._reset_storage_runtime = SimpleNamespace(is_running=Mock(return_value=False))
init_source = inspect.getsource(PremiumPage.__init__)
request_source = inspect.getsource(PremiumPage._request_reset_storage)
schedule_source = inspect.getsource(PremiumPage._schedule_reset_storage_worker_start)
cleanup_source = inspect.getsource(PremiumPage.cleanup)
self.assertIsInstance(PremiumPage._reset_storage_state_obj(page), LatestValueWorkerState)
self.assertIn("_reset_storage_state", init_source)
self.assertNotIn("self._reset_storage_pending = False", init_source)
self.assertNotIn("self._reset_storage_start_scheduled = False", init_source)
self.assertIn("_reset_storage_state_obj()", request_source)
self.assertIn("_reset_storage_state_obj()", schedule_source)
self.assertIn("_reset_storage_state_obj().reset()", cleanup_source)
def test_stale_reset_storage_worker_finished_does_not_restart_pending_reset(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._reset_storage_runtime = SimpleNamespace(worker=object())
page._cleanup_in_progress = False
page._reset_storage_pending = True
page._reset_storage_start_scheduled = False
page._start_reset_storage_worker = Mock()
single_shot = Mock()
with patch.object(premium_page, "QTimer", SimpleNamespace(singleShot=single_shot), create=True):
PremiumPage._on_reset_storage_worker_finished(page, object())
single_shot.assert_not_called()
page._start_reset_storage_worker.assert_not_called()
self.assertTrue(page._reset_storage_pending)
def test_reset_storage_result_is_ignored_when_new_reset_is_pending(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._reset_storage_runtime = SimpleNamespace(is_current=Mock(return_value=True))
page._reset_storage_pending = True
page.key_input = Mock()
page._set_activation_status = Mock()
page._update_device_info = Mock()
page._set_status_badge = Mock()
page._render_days_label = Mock()
page._set_activation_section_visible = Mock()
page._stop_pairing_status_autopoll = Mock()
page._apply_subscription_state = Mock()
with patch.object(premium_page, "apply_reset_plan_ui", return_value=("idle", "")) as apply_reset:
PremiumPage._on_reset_storage_finished(page, 4, object())
apply_reset.assert_not_called()
page._render_days_label.assert_not_called()
def test_reset_storage_error_is_ignored_when_new_reset_is_pending(self) -> None:
import donater.ui.page as premium_page
page = PremiumPage.__new__(PremiumPage)
page._cleanup_in_progress = False
page._reset_storage_runtime = SimpleNamespace(is_current=Mock(return_value=True))
page._reset_storage_pending = True
page._tr = Mock(side_effect=lambda _key, default, **kwargs: default.format(**kwargs) if kwargs else default)
page.window = Mock(return_value=object())
with patch.object(premium_page.InfoBar, "warning") as warning:
PremiumPage._on_reset_storage_failed(page, 4, "old error")
warning.assert_not_called()
if __name__ == "__main__":
unittest.main()