refactor: вынес сервисы и ui-компоненты
- вынес token/chat/update логику в services - вынес диалог и текст инструкции в ui - добавил и обновил тесты для нового слоя
This commit is contained in:
@@ -28,7 +28,10 @@ class AuthReloginSmokeTests(unittest.TestCase):
|
||||
self.assertIn("force_relogin", self.main_source)
|
||||
|
||||
def test_auth_error_paths_trigger_force_relogin(self):
|
||||
self.assertIn("def _handle_vk_api_error(self, context, exc, action_name=None, ui_message_prefix=None, disable_ui=False):", self.main_source)
|
||||
self.assertIn(
|
||||
"def _handle_vk_api_error(self, context, exc, action_name=None, ui_message_prefix=None, disable_ui=False):",
|
||||
self.main_source,
|
||||
)
|
||||
self.assertIn("self._force_relogin(exc, action_name or context)", self.main_source)
|
||||
self.assertIn('"load_chats",', self.main_source)
|
||||
self.assertIn('"execute_user_action",', self.main_source)
|
||||
@@ -42,17 +45,15 @@ class AuthReloginSmokeTests(unittest.TestCase):
|
||||
|
||||
def test_update_check_actions_exist(self):
|
||||
self.assertIn("from app_version import APP_VERSION", self.main_source)
|
||||
self.assertIn("from services import UpdateChecker, VkService, detect_update_repository_url", self.main_source)
|
||||
self.assertIn("from services import (", self.main_source)
|
||||
self.assertIn("UpdateChecker", self.main_source)
|
||||
self.assertIn("detect_update_repository_url", self.main_source)
|
||||
self.assertIn('QAction("Проверить обновления", self)', self.main_source)
|
||||
self.assertIn("def check_for_updates(self, silent_no_updates=False):", self.main_source)
|
||||
self.assertIn("class UpdateChecker(QObject):", self.update_source)
|
||||
self.assertIn('message_box.addButton("Обновить сейчас", QMessageBox.AcceptRole)', self.main_source)
|
||||
self.assertIn("def _start_auto_update(self, download_url, latest_version, checksum_url=\"\", download_name=\"\"):", self.main_source)
|
||||
self.assertIn("def _verify_update_checksum(self, zip_path, checksum_url, download_name):", self.main_source)
|
||||
self.assertIn("def _build_update_script(self, app_dir, source_dir, exe_name, target_pid):", self.main_source)
|
||||
self.assertIn("set TARGET_PID=", self.main_source)
|
||||
self.assertIn("set BACKUP_DIR=", self.main_source)
|
||||
self.assertIn(":rollback", self.main_source)
|
||||
self.assertIn("AutoUpdateService.prepare_update", self.main_source)
|
||||
self.assertIn("AutoUpdateService.build_update_script", self.main_source)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
50
tests/test_auto_update_service.py
Normal file
50
tests/test_auto_update_service.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
_SPEC = importlib.util.spec_from_file_location(
|
||||
"auto_update_service",
|
||||
Path("services/auto_update_service.py"),
|
||||
)
|
||||
_MODULE = importlib.util.module_from_spec(_SPEC)
|
||||
_SPEC.loader.exec_module(_MODULE)
|
||||
AutoUpdateService = _MODULE.AutoUpdateService
|
||||
|
||||
|
||||
class AutoUpdateServiceTests(unittest.TestCase):
|
||||
def test_extract_sha256_from_text(self):
|
||||
digest = "a" * 64
|
||||
text = f"{digest} AnabasisManager-1.0.0-win.zip\n"
|
||||
extracted = AutoUpdateService.extract_sha256_from_text(
|
||||
text,
|
||||
"AnabasisManager-1.0.0-win.zip",
|
||||
)
|
||||
self.assertEqual(extracted, digest)
|
||||
|
||||
def test_sha256_file(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
path = Path(td) / "payload.bin"
|
||||
payload = b"anabasis"
|
||||
path.write_bytes(payload)
|
||||
expected = hashlib.sha256(payload).hexdigest()
|
||||
self.assertEqual(AutoUpdateService.sha256_file(str(path)), expected)
|
||||
|
||||
def test_build_update_script_contains_core_vars(self):
|
||||
script = AutoUpdateService.build_update_script(
|
||||
app_dir=r"C:\Apps\AnabasisManager",
|
||||
source_dir=r"C:\Temp\Extracted",
|
||||
exe_name="AnabasisManager.exe",
|
||||
target_pid=1234,
|
||||
)
|
||||
script_text = Path(script).read_text(encoding="utf-8")
|
||||
self.assertIn("set APP_DIR=", script_text)
|
||||
self.assertIn("set SRC_DIR=", script_text)
|
||||
self.assertIn("set EXE_NAME=", script_text)
|
||||
self.assertIn("set TARGET_PID=", script_text)
|
||||
self.assertIn(":rollback", script_text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
65
tests/test_chat_actions.py
Normal file
65
tests/test_chat_actions.py
Normal file
@@ -0,0 +1,65 @@
|
||||
import unittest
|
||||
import importlib.util
|
||||
from types import SimpleNamespace
|
||||
from pathlib import Path
|
||||
|
||||
_SPEC = importlib.util.spec_from_file_location(
|
||||
"chat_actions",
|
||||
Path("services/chat_actions.py"),
|
||||
)
|
||||
_MODULE = importlib.util.module_from_spec(_SPEC)
|
||||
_SPEC.loader.exec_module(_MODULE)
|
||||
load_chat_conversations = _MODULE.load_chat_conversations
|
||||
resolve_user_ids = _MODULE.resolve_user_ids
|
||||
|
||||
|
||||
class ChatActionsTests(unittest.TestCase):
|
||||
def test_resolve_user_ids_mixed_results(self):
|
||||
mapping = {
|
||||
"id1": {"type": "user", "object_id": 1},
|
||||
"id2": {"type": "group", "object_id": 2},
|
||||
}
|
||||
|
||||
def call_with_retry(func, **kwargs):
|
||||
return func(**kwargs)
|
||||
|
||||
def resolve_screen_name(screen_name):
|
||||
if screen_name == "boom":
|
||||
raise RuntimeError("boom")
|
||||
return mapping.get(screen_name)
|
||||
|
||||
vk_api = SimpleNamespace(utils=SimpleNamespace(resolveScreenName=resolve_screen_name))
|
||||
links = [
|
||||
"https://vk.com/id1",
|
||||
"https://vk.com/id2",
|
||||
"https://vk.com/boom",
|
||||
"https://vk.com/",
|
||||
]
|
||||
resolved, failed = resolve_user_ids(call_with_retry, vk_api, links)
|
||||
|
||||
self.assertEqual(resolved, [1])
|
||||
self.assertEqual(len(failed), 3)
|
||||
self.assertEqual(failed[0][0], "https://vk.com/id2")
|
||||
self.assertIsNone(failed[0][1])
|
||||
|
||||
def test_load_chat_conversations_paginated(self):
|
||||
pages = [
|
||||
{"items": [{"id": 1}], "next_from": "page-2"},
|
||||
{"items": [{"id": 2}]},
|
||||
]
|
||||
|
||||
def get_conversations(**kwargs):
|
||||
if kwargs.get("start_from") == "page-2":
|
||||
return pages[1]
|
||||
return pages[0]
|
||||
|
||||
def call_with_retry(func, **kwargs):
|
||||
return func(**kwargs)
|
||||
|
||||
vk_api = SimpleNamespace(messages=SimpleNamespace(getConversations=get_conversations))
|
||||
items = load_chat_conversations(call_with_retry, vk_api)
|
||||
self.assertEqual(items, [{"id": 1}, {"id": 2}])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
53
tests/test_token_store.py
Normal file
53
tests/test_token_store.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import tempfile
|
||||
import unittest
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
_SPEC = importlib.util.spec_from_file_location(
|
||||
"token_store",
|
||||
Path("services/token_store.py"),
|
||||
)
|
||||
_MODULE = importlib.util.module_from_spec(_SPEC)
|
||||
_SPEC.loader.exec_module(_MODULE)
|
||||
load_token = _MODULE.load_token
|
||||
save_token = _MODULE.save_token
|
||||
|
||||
|
||||
class TokenStoreTests(unittest.TestCase):
|
||||
def test_save_and_load_non_expiring_token(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
token_file = Path(td) / "token.json"
|
||||
with patch.object(_MODULE.os, "name", "posix"):
|
||||
expiration = save_token(
|
||||
token="abc123",
|
||||
token_file=str(token_file),
|
||||
app_data_dir=td,
|
||||
expires_in=0,
|
||||
)
|
||||
token, loaded_expiration = load_token(str(token_file))
|
||||
|
||||
self.assertEqual(expiration, 0)
|
||||
self.assertEqual(token, "abc123")
|
||||
self.assertEqual(loaded_expiration, 0)
|
||||
|
||||
def test_expired_token_is_removed(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
token_file = Path(td) / "token.json"
|
||||
with patch.object(_MODULE.os, "name", "posix"):
|
||||
with patch.object(_MODULE.time, "time", return_value=1000):
|
||||
save_token(
|
||||
token="abc123",
|
||||
token_file=str(token_file),
|
||||
app_data_dir=td,
|
||||
expires_in=1,
|
||||
)
|
||||
with patch.object(_MODULE.time, "time", return_value=2000):
|
||||
token, expiration = load_token(str(token_file))
|
||||
|
||||
self.assertIsNone(token)
|
||||
self.assertIsNone(expiration)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user