zapret-kvn/tests/test_probe_gate.py
loop-uh 54ac4b0251
Some checks failed
Windows project source guards / test (push) Has been cancelled
Шлюз проверок: по одному серверу с паузой, кандидат замены в бюджете
Требование незаметности: пачка соединений к разным серверам или ровный
ритм проверок выдаёт провайдеру (ТСПУ) весь список подписки.

- network/probe_gate.py — одно место с правилами: пауза прохода «все»
  10–20 с со случайным разбросом, не больше 3 автоматических проверок
  других серверов в скользящий час, журнал всех проверок для тестов.
- «Пинг всех» — одно соединение за раз (было до 8) и пауза шлюза между
  серверами; отмена будит паузу, одиночный пинг после прохода не ждёт.
- «Скорость всех» — пауза 10–20 с между серверами вместо 0,4–1,6 с.
- Умная замена мерит одного кандидата (было до 3 прямых рукопожатий с
  другими серверами каждые ~5 мин) и только в бюджете шлюза.
- Тест-список сетевых вызовов: create_connection/getaddrinfo/urlopen и т. п.
  в новом модуле роняют тест, пока не решено, по какому правилу шлюза
  идёт проверка.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:06:17 +03:00

41 lines
1.6 KiB
Python

"""Шлюз проверок (xray_fluent/network/probe_gate.py): бюджет и журнал."""
from __future__ import annotations
import random
import unittest
from xray_fluent.network import probe_gate
class ProbeGateTests(unittest.TestCase):
def setUp(self) -> None:
self.now = 1000.0
self.gate = probe_gate.ProbeGate(clock=lambda: self.now)
def test_candidate_budget_is_a_sliding_hour(self) -> None:
for _ in range(probe_gate.CANDIDATE_PROBES_PER_HOUR):
self.assertTrue(self.gate.try_candidate("a.example"))
self.assertFalse(self.gate.try_candidate("b.example"))
self.now += 3599.0
self.assertFalse(self.gate.try_candidate("b.example"))
self.now += 2.0
self.assertTrue(self.gate.try_candidate("b.example"))
def test_refused_candidate_is_not_journaled(self) -> None:
for _ in range(probe_gate.CANDIDATE_PROBES_PER_HOUR + 2):
self.gate.try_candidate("a.example")
kinds = [record.kind for record in self.gate.journal()]
self.assertEqual(kinds, [probe_gate.CANDIDATE] * probe_gate.CANDIDATE_PROBES_PER_HOUR)
def test_sweep_pause_stays_in_range(self) -> None:
rng = random.Random(7)
low, high = probe_gate.SWEEP_PAUSE_SEC
self.assertGreaterEqual(low, 10.0)
pauses = [probe_gate.sweep_pause(rng) for _ in range(200)]
self.assertTrue(all(low <= pause <= high for pause in pauses))
self.assertGreater(max(pauses) - min(pauses), 5.0) # разброс, не ровный ритм
if __name__ == "__main__":
unittest.main()