fix(tests): мок-сервер переставал принимать соединения после одного обрыва - #84
Merged
Merged
Conversation
…брыва Причина флейка TestConcurrentChangeServerKeepsClientRecoverable: unit упал на push-прогоне dev, тогда как тот же коммит в PR-прогоне прошёл. Server.connectionCallback вызывал BeginAccept последней строкой try-блока, поэтому любое исключение выше по телу навсегда обрывало приём соединений. Пир, рвущий соединение во время handshake — ровно то, что порождают конкурентные ChangeServer/Disconnect — глушил мок именно так. Со стороны всё выглядело исправно: слушающий сокет оставался связан, порт числился занятым, TCP-соединения устанавливались ядром, и клиент видел сервер, который принял подключение и молчит. Отсюда 2m06s у упавшего прогона против 10s у обычного и сообщение, обвиняющее клиент в том, что он «не дошёл до живого сервера». - BeginAccept перезапускается безусловно после колбэка, чем бы тот ни кончился; ObjectDisposedException обрабатывается отдельно и без перезапуска — он означает, что Stop() закрыл listener - сокет, чей handshake упал, закрывается, а не течёт до конца процесса - TestUMockRippledAcceptLoop фиксирует поведение: обрыв на handshake (RST через LingerOption(true, 0)) поодиночке и десять подряд, затем обычный клиент, который обязан подключиться. На старом колбэке оба падают, после фикса проходят за 0.6s - TestUtils.MockCompletesHandshake: проба реальным WS-upgrade. Упавший reconnect-тест теперь сообщает, отвечает ли мок, — глухой сервер больше не будет прочитан как баг клиента. Проба покрыта на живом моке, свободном порту и слушающем сокете, который никогда не принимает
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Правка чисто в тестовой инфраструктуре: код SDK не менялся, потребителю пакета изменение не видно, поэтому в changelog релиза ему места нет. Разбор причины остаётся в описании PR и в комментариях к самому коду.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Чинит флейк
TestConcurrentChangeServerKeepsClientRecoverable, из-за которогоunitупал на push-прогонеdev(run 31613419252), тогда как тот же коммит в PR-прогоне прошёл. Это единственная красная галка, оставшаяся на релизном PR #76.Виноват не клиент, а мок-сервер.
Причина
Server.connectionCallbackперезапускал приём соединений последней строкой try-блока:Любое исключение выше по телу колбэка — и
BeginAcceptне вызывается уже никогда: приём соединений обрывается навсегда. Пир, рвущий соединение во время handshake, попадает ровно туда —clientSocket.ReceiveбросаетConnection reset by peer, а конкурентныеChangeServer/Disconnectв тесте такие обрывы и порождают.Почему это читалось как баг клиента: слушающий сокет остаётся связанным. Порт числится занятым, TCP-соединения ядро принимает в backlog, connect со стороны клиента успешен — и дальше тишина. Клиент ждёт handshake до своего таймаута и ретраится, пока не выйдет 30-секундное окно теста. Отсюда 2m06s у упавшего прогона против 10s у обычного и сообщение, обвиняющее клиент в том, что он «не дошёл до живого сервера», — при том что сервер к этому моменту оглох.
Строка
Connection reset by peer: An error has occured while trying to accept a connecting clientв CI-логе — это она и есть.Доказательство
Локально флейк не воспроизвёлся ни разу за 12 прогонов подряд, поэтому доказательство построено не на статистике, а на прямом тесте дефекта: соединение рвётся на handshake через
LingerOption(true, 0)(тот самый RST), после чего обычный клиент обязан подключиться.TestAbortedHandshakeLeavesTheMockAcceptingTestRepeatedAbortedHandshakesLeaveTheMockAcceptingОба падения — с той же строкой в выводе, что в CI. После фикса оба проходят за 0.6s суммарно.
Фикс
BeginAcceptперезапускается безусловно после колбэка, чем бы тот ни кончилсяObjectDisposedExceptionобрабатывается отдельно и без перезапуска: он означает, чтоStop()закрыл listener, и повторная попытка только бросит сноваЧтобы это не повторилось диагностически
TestUtils.MockCompletesHandshakeпробует настоящий WS-upgrade и проверяет ответ101; упавший reconnect-тест теперь вызывает её и пишет результат в сообщение — глухой мок больше не будет прочитан как баг клиента.Обычный TCP-connect для такой пробы не годится: против связанного, но не принимающего сокета он успешен и не доказывает ничего — ровно в эту ловушку всё и провалилось. Сама проба покрыта тремя случаями: живой мок, свободный порт и слушающий сокет, который никогда не принимает.
Проверка
TestUReconnectSessionRaces— 10 прогонов подряд без паденийЗатронута только тестовая инфраструктура — код SDK не менялся.