- Исправлен перезапуск приложения после замены файлов и добавлено подтверждение запуска новой версии. - Обеспечены откат при ошибке и корректное завершение фоновых задач. - Исключены посторонние DLL из Windows-сборки, обновлены тесты и инструкция ручного перехода с v2.0.1.
161 lines
5.5 KiB
Python
161 lines
5.5 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
|
|
|
from PySide6.QtWidgets import QApplication
|
|
|
|
from app.services.update_service import UpdateError, UpdateInfo
|
|
from app.widgets.start_tab import StartTab, _UpdateCheckThread, _UpdateDownloadThread
|
|
|
|
|
|
class StartTabUpdateTests(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls) -> None:
|
|
cls._app = QApplication.instance() or QApplication([])
|
|
|
|
def test_update_button_is_below_settings_and_hidden_initially(self) -> None:
|
|
tab = StartTab(lambda: None)
|
|
|
|
self.assertTrue(tab._update_btn.isHidden())
|
|
self.assertLess(
|
|
tab._settings_column_layout.indexOf(tab._settings_btn),
|
|
tab._settings_column_layout.indexOf(tab._update_btn),
|
|
)
|
|
tab.shutdown()
|
|
|
|
def test_available_update_shows_download_button(self) -> None:
|
|
tab = StartTab(lambda: None)
|
|
info = UpdateInfo(
|
|
tag="v2.1.0",
|
|
version="2.1.0",
|
|
asset_name="plate_config_app-windows-x86_64.zip",
|
|
download_url="https://git.robotail.pro/download/test",
|
|
)
|
|
|
|
tab._on_update_check_done(info)
|
|
|
|
self.assertFalse(tab._update_btn.isHidden())
|
|
self.assertEqual("Скачать обновление", tab._update_btn.text())
|
|
self.assertIn("v2.1.0", tab._update_btn.toolTip())
|
|
tab.shutdown()
|
|
|
|
def test_no_update_hides_previously_visible_button(self) -> None:
|
|
tab = StartTab(lambda: None)
|
|
tab._on_update_check_done(self._update_info())
|
|
|
|
tab._on_update_check_done(None)
|
|
|
|
self.assertTrue(tab._update_btn.isHidden())
|
|
self.assertIsNone(tab._available_update)
|
|
tab.shutdown()
|
|
|
|
def test_progress_updates_button_text(self) -> None:
|
|
tab = StartTab(lambda: None)
|
|
|
|
tab._on_update_progress(57)
|
|
|
|
self.assertEqual("Скачивание 57%", tab._update_btn.text())
|
|
tab.shutdown()
|
|
|
|
def test_download_failure_resets_button_and_warns(self) -> None:
|
|
tab = StartTab(lambda: None)
|
|
tab._update_btn.setEnabled(False)
|
|
tab._update_btn.setText("Скачивание 42%")
|
|
|
|
with patch("app.widgets.start_tab.QMessageBox.warning") as warning:
|
|
tab._on_update_failed("ошибка сети")
|
|
|
|
self.assertTrue(tab._update_btn.isEnabled())
|
|
self.assertEqual("Скачать обновление", tab._update_btn.text())
|
|
warning.assert_called_once()
|
|
self.assertIn("ошибка сети", warning.call_args.args[2])
|
|
tab.shutdown()
|
|
|
|
def test_launch_failure_removes_download_and_warns(self) -> None:
|
|
tab = StartTab(lambda: None)
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
downloaded = Path(directory) / ".downloaded-update"
|
|
downloaded.write_bytes(b"MZupdate")
|
|
|
|
with (
|
|
patch(
|
|
"app.widgets.start_tab.launch_update",
|
|
side_effect=UpdateError("не удалось запустить helper"),
|
|
),
|
|
patch("app.widgets.start_tab.QMessageBox.warning") as warning,
|
|
):
|
|
tab._on_update_downloaded(downloaded)
|
|
|
|
self.assertFalse(downloaded.exists())
|
|
self.assertEqual("Скачать обновление", tab._update_btn.text())
|
|
self.assertTrue(tab._update_btn.isEnabled())
|
|
warning.assert_called_once()
|
|
tab.shutdown()
|
|
|
|
def test_successful_download_launches_update_and_closes_window(self) -> None:
|
|
tab = StartTab(lambda: None)
|
|
downloaded = Path("downloaded-update")
|
|
|
|
with (
|
|
patch("app.widgets.start_tab.launch_update") as launcher,
|
|
patch.object(tab, "close") as close_window,
|
|
):
|
|
tab._on_update_downloaded(downloaded)
|
|
|
|
launcher.assert_called_once_with(downloaded)
|
|
close_window.assert_called_once_with()
|
|
self.assertEqual("Перезапуск…", tab._update_btn.text())
|
|
tab.shutdown()
|
|
|
|
def test_update_check_thread_hides_network_errors(self) -> None:
|
|
thread = _UpdateCheckThread()
|
|
results: list[UpdateInfo | None] = []
|
|
thread.result_ready.connect(results.append)
|
|
|
|
with patch(
|
|
"app.widgets.start_tab.check_for_update",
|
|
side_effect=UpdateError("offline"),
|
|
):
|
|
thread.run()
|
|
|
|
self.assertEqual([None], results)
|
|
|
|
def test_download_thread_emits_progress_and_result(self) -> None:
|
|
info = self._update_info()
|
|
result_path = Path("downloaded-update")
|
|
thread = _UpdateDownloadThread(info, Path("."))
|
|
progress_values: list[int] = []
|
|
results: list[Path] = []
|
|
thread.progress_changed.connect(progress_values.append)
|
|
thread.result_ready.connect(results.append)
|
|
|
|
def fake_download(_info, _directory, *, progress, cancelled):
|
|
self.assertFalse(cancelled())
|
|
progress(75)
|
|
return result_path
|
|
|
|
with patch("app.widgets.start_tab.download_update", side_effect=fake_download):
|
|
thread.run()
|
|
|
|
self.assertEqual([75], progress_values)
|
|
self.assertEqual([result_path], results)
|
|
|
|
@staticmethod
|
|
def _update_info() -> UpdateInfo:
|
|
return UpdateInfo(
|
|
tag="v2.1.0",
|
|
version="2.1.0",
|
|
asset_name="plate_config_app-windows-x86_64.zip",
|
|
download_url="https://git.robotail.pro/download/test",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|