internal/checker: voice-quality + voice-srv tests for predictive voice diagnosis
Build / test (push) Has been cancelled
Build / build-windows (push) Has been cancelled

Replaces the single-packet `stun` test with two predictive voice tests:

  - voice-quality: 30-packet STUN burst through the SOCKS5 UDP relay.
    Computes loss%, jitter (RFC-3550-ish mean abs of inter-arrival
    delta), p50/p95 RTT. Three-tier gating: pass (loss≤5%, jitter≤30,
    p50≤250), warn (loss≤15%, jitter≤60, p50≤400 — voice glitches but
    works), fail (anything worse, including 100% loss).

  - voice-srv: parallel-DNS the 16-region <region>.discord.media
    hostnames, then SOCKS5 CONNECT to :443 on each through the proxy.
    Catches the very common Russian-DPI failure mode where the proxy
    passes generic Discord.com TCP but blocks the .discord.media voice
    CIDRs — a regression all 5 prior SOCKS5 sanity checks miss.

New StatusWarn = "warn" — soft pass with Hint kept visible. Counted as
passed in summary but flagged in UI.

Config gains VoiceBurstCount (default 30), VoiceBurstInterval (default
20ms), VoiceServerHostnames (default = built-in 16-region list).

Tests cover happy path, warn-tier (10% drop), fail-tier (100% drop),
voice-srv blocked, plus standalone unit tests on
runVoiceQualityBurst and runVoiceServerProbe with a fake UDP relay
and fake SOCKS5 server. Race + cover stays at 82.4%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 18:42:12 +03:00
parent ea4202d4a3
commit 0a85979142
6 changed files with 1264 additions and 137 deletions
+25 -18
View File
@@ -18,7 +18,7 @@ func TestHintFor(t *testing.T) {
t.Run("context_canceled_uniform", func(t *testing.T) {
// Cancellation is always reported as «Проверка отменена.» across
// all testIDs.
for _, id := range []string{"tcp", "greet", "auth", "connect", "udp", "stun", "api", "unknown"} {
for _, id := range []string{"tcp", "greet", "auth", "connect", "udp", "voice-quality", "voice-srv", "api", "unknown"} {
assert.Equal(t, "Проверка отменена.", hintFor(id, context.Canceled), "id=%s", id)
assert.Equal(t, "Проверка отменена.", hintFor(id, context.DeadlineExceeded), "id=%s", id)
}
@@ -42,8 +42,8 @@ func TestHintFor(t *testing.T) {
{"udp_unsupported_mentions_udp", "udp", ErrSocks5Reply{Code: 0x07}, "UDP"},
{"udp_unsupported_mentions_unsupported", "udp", ErrSocks5Reply{Code: 0x07}, "не поддерж"},
{"udp_atyp_ipv6", "udp", ErrUnsupportedRelayATYP, "IPv6"},
{"stun_no_mapped_xor", "stun", ErrSTUNNoMappedAddress, "XOR-MAPPED"},
{"stun_timeout_mentions_stun", "stun", &timeoutOnlyError{}, "STUN"},
{"voice_quality_no_mapped_xor", "voice-quality", ErrSTUNNoMappedAddress, "XOR-MAPPED"},
{"voice_quality_timeout_mentions_stun", "voice-quality", &timeoutOnlyError{}, "STUN"},
{"api_timeout_mentions_api_or_timeout", "api", &timeoutOnlyError{}, "таймаут"},
{"unknown_test_fallback_id", "unknown_test", errors.New("oops"), "unknown_test"},
{"unknown_test_fallback_err", "unknown_test", errors.New("oops"), "oops"},
@@ -111,13 +111,19 @@ func TestHintFor_PerStepBranches(t *testing.T) {
{"udp_unknown_rep", "udp", ErrSocks5Reply{Code: 0xFE}, "REP=FE"},
{"udp_fallback", "udp", errors.New("weird"), "UDP ASSOCIATE"},
// stun: every sentinel branch
{"stun_too_short", "stun", ErrSTUNTooShort, "20"},
{"stun_bad_magic", "stun", ErrSTUNBadMagicCookie, "magic"},
{"stun_not_success", "stun", ErrSTUNNotSuccess, "Binding"},
{"stun_txid_mismatch", "stun", ErrSTUNTxIDMismatch, "transaction"},
{"stun_unsupported_family", "stun", ErrSTUNUnsupportedFamily, "семейством"},
{"stun_fallback", "stun", errors.New("weird"), "STUN"},
// voice-quality: every sentinel branch (collapsed in 2026-05-01
// rewrite into a single user-visible message rather than
// per-error "магник cookie" / "семейство адресов" exposition)
{"voice_quality_too_short", "voice-quality", ErrSTUNTooShort, "мусор"},
{"voice_quality_bad_magic", "voice-quality", ErrSTUNBadMagicCookie, "мусор"},
{"voice_quality_not_success", "voice-quality", ErrSTUNNotSuccess, "мусор"},
{"voice_quality_txid_mismatch", "voice-quality", ErrSTUNTxIDMismatch, "мусор"},
{"voice_quality_unsupported_family", "voice-quality", ErrSTUNUnsupportedFamily, "мусор"},
{"voice_quality_fallback", "voice-quality", errors.New("weird"), "качество"},
// voice-srv: DNS error, timeout, generic
{"voice_srv_timeout", "voice-srv", &timeoutOnlyError{}, "таймаут"},
{"voice_srv_generic", "voice-srv", errors.New("boom"), "boom"},
// api: timeout vs generic
{"api_timeout", "api", &timeoutOnlyError{}, "таймаут"},
@@ -146,14 +152,15 @@ func TestSocks5ReplyHint_DefaultStep(t *testing.T) {
func TestTcpFriendlyName(t *testing.T) {
cases := map[string]string{
"tcp": "TCP",
"greet": "приветствие SOCKS5",
"auth": "авторизация SOCKS5",
"connect": "TCP-туннель к Discord",
"udp": "UDP ASSOCIATE",
"stun": "STUN round-trip",
"api": "Discord API",
"weirdo": "weirdo",
"tcp": "TCP",
"greet": "приветствие SOCKS5",
"auth": "авторизация SOCKS5",
"connect": "TCP-туннель к Discord",
"udp": "UDP ASSOCIATE",
"voice-quality": "качество UDP-канала",
"voice-srv": "доступность voice-серверов Discord",
"api": "Discord API",
"weirdo": "weirdo",
}
for in, want := range cases {
t.Run(in, func(t *testing.T) {