zapretgui/tests/test_latest_worker_lane.py
loop-uh 3a95336d88
All checks were successful
Zapret source guards / validate (push) Successful in 7s
Windows-сборка / Dev Dev 21.1.6.31 опубликован
Настройка DNS: страница переписана с нуля — панель «Сейчас», плитки серверов и замер скорости
- Сверху панель «Сейчас»: какой DNS стоит на отмеченных адаптерах (или что
  на них разные DNS), адаптеры-таблетки и кнопки «Вернуть автоматически»,
  «Замерить скорость», «Сбросить кэш».
- Серверы — сетка плиток одной рисуемой поверхностью (быстро строится):
  значок в круге фирменного цвета, адрес, метки IPv6/DoH, скорость; фильтр
  по группам; плитка «Свой DNS» и меню правки своих серверов.
- Замер скорости: настоящий DNS-запрос каждому серверу, лучший из трёх;
  контрольный адрес 192.0.2.53 показывает, что провайдер перехватывает DNS.
- Фоновая работа через общий LatestWorkerLane (одна задача, побеждает
  последний запрос) вместо пяти вручную расписанных очередей.
- Удалены мёртвые принудительный DNS, «Тест соединения», ручной ввод DNS
  в строке и 18 старых вспомогательных модулей.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 21:42:54 +03:00

107 lines
3.2 KiB
Python

from __future__ import annotations
import os
import threading
import time
import unittest
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtCore import QThread, pyqtSignal
from PyQt6.QtWidgets import QApplication
from ui.latest_worker_lane import LatestWorkerLane
class _Worker(QThread):
completed = pyqtSignal(int, object)
failed = pyqtSignal(int, str)
def __init__(self, request_id: int, payload, gate: threading.Event, fail: bool = False) -> None:
super().__init__()
self._request_id = request_id
self._payload = payload
self._gate = gate
self._fail = fail
def run(self) -> None:
self._gate.wait(5)
if self._fail:
self.failed.emit(self._request_id, f"boom {self._payload}")
return
self.completed.emit(self._request_id, f"result {self._payload}")
def _spin(condition, timeout: float = 5.0) -> None:
deadline = time.monotonic() + timeout
while not condition() and time.monotonic() < deadline:
QApplication.processEvents()
time.sleep(0.005)
class LatestWorkerLaneTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls._app = QApplication.instance() or QApplication([])
def _lane(self, *, fail: bool = False):
gate = threading.Event()
created: list = []
results: list = []
errors: list = []
def create(request_id, payload):
worker = _Worker(request_id, payload, gate, fail=fail)
created.append(payload)
return worker
lane = LatestWorkerLane(
name="test_lane",
create_worker=create,
on_result=lambda payload, result: results.append((payload, result)),
on_error=lambda payload, error: errors.append((payload, error)),
)
return lane, gate, created, results, errors
def test_requests_during_running_task_keep_only_the_latest(self) -> None:
lane, gate, created, results, _errors = self._lane()
lane.request(1)
_spin(lambda: lane.runtime.is_running())
lane.request(2)
lane.request(3)
self.assertEqual(created, [1])
gate.set()
_spin(lambda: results)
_spin(lambda: not lane.is_busy())
# Результат первой задачи устарел (ждал новый запрос) и не отдан.
self.assertEqual(created, [1, 3])
self.assertEqual(results, [(3, "result 3")])
def test_errors_reach_page_with_their_payload(self) -> None:
lane, gate, _created, results, errors = self._lane(fail=True)
gate.set()
lane.request("x")
_spin(lambda: errors)
self.assertEqual(errors, [("x", "boom x")])
self.assertEqual(results, [])
def test_closed_lane_drops_results_and_new_requests(self) -> None:
lane, gate, created, results, _errors = self._lane()
lane.request(1)
_spin(lambda: lane.runtime.is_running())
lane.close()
lane.request(2)
gate.set()
_spin(lambda: False, timeout=0.2)
self.assertEqual(created, [1])
self.assertEqual(results, [])
if __name__ == "__main__":
unittest.main()