--parallel=auto e em diferentes sistemas operacionais.
Os padrões apresentados aqui se aplicam igualmente a extensões em C++ e Rust, pois ambos usam o MTR como executor de testes, que as extensões em Rust executam por meio de cargo vsql test.
Por que portas fixas falham
Dois modos de falha tornam as portas fixas não confiáveis no MTR: Conflitos de porta sob--parallel. O MTR atribui a cada worker uma faixa de portas em torno do seu valor @@port. Uma porta fixa fora dessa faixa (digamos, 18777) pode colidir com o bloco reservado de outro worker ou com um serviço do sistema, o que causa EADDRINUSE intermitente que só se reproduz em alto paralelismo.
Mudanças no nível do sistema operacional. Novas imagens de runner e versões de sistema operacional periodicamente reservam ou restringem portas que antes funcionavam. Uma porta que passa localmente e no CI hoje pode falhar silenciosamente ao vincular amanhã.
A solução em ambos os casos é a mesma: vincule à porta 0 e deixe o sistema operacional atribuir uma porta disponível, depois comunique a porta real de volta ao teste.
Padrão A: Listener integrado ao servidor
Use este quando o listener de rede é executado dentro do processo do MySQL (por exemplo, uma extensão que incorpora um servidor HTTP). Na extensão, exponha a porta vinculada como uma variável de status após a vinculação:wait_condition.inc do MTR para consultar a variável de status até que ela seja diferente de zero, depois capture a porta em uma variável do MTR. Releia após qualquer ciclo de UNINSTALL EXTENSION / INSTALL EXTENSION, pois uma porta efêmera muda a cada vinculação.
Padrão B: Listener em processo externo
Use este quando o listener é um processo independente — um servidor auxiliar em Python, uma API simulada ou qualquer programa externo que o MTR não controle diretamente.Este padrão requer
python3 no PATH. Os runners hospedados pelo GitHub o incluem; verifique a disponibilidade em runners auto-hospedados antes de usar.O lançador em primeiro plano
Em vez de colocar o servidor em segundo plano com--exec ... & e consultar uma porta, use um script de lançamento em primeiro plano que:
- Inicia o servidor em um subprocesso com
start_new_session=True - Bloqueia até que o servidor tenha vinculado e escrito um arquivo de prontidão
- Encerra, permitindo que o MTR continue
--exec em primeiro plano, então isso garante que o servidor esteja pronto antes que qualquer SQL seja executado, sem a necessidade de um poller ou sleep separado.
launcher.py — escreva isto com --write_file:
echo_server.py — o servidor em si, escrevendo sua porta antes de atender:
No teste
Inicie o lançador (em primeiro plano, já que o MTR bloqueia até que ele encerre), depois inclua o arquivo de porta:Mantendo a porta fora do arquivo de resultado
O arquivo de resultado registra o SQL conforme escrito. Se uma URL contiver o número da porta efêmera, o arquivo de resultado conteria um valor diferente a cada execução e o teste sempre falharia no registro/replay. Inclua o arquivo de porta e defina a variável de sessão do MySQL em conjunto sob--disable_query_log, para que nem a atribuição let nem a porta efêmera apareçam na saída. Use a variável de sessão em todos os lugares onde uma URL for necessária:
Gerenciamento de processos
Registre a saída do auxiliar e nunca a descarte. O padrão de lançador acima escreve o stderr do servidor emecho_server.log e o imprime em caso de falha. Descartar a saída do auxiliar torna as instabilidades inexplicáveis nos artefatos do CI.
Encerre por PID, não por nome. No Linux, pkill -f echo_server.py pode corresponder ao próprio processo do MTR via /proc/cmdline. Use o arquivo de PID escrito pelo lançador:
$MYSQLTEST_VARDIR/tmp/ como estado sujo e faz o teste falhar:
vsql-http/mysql-test/t/vsql_http_requests.test demonstra o mesmo objetivo — um processo auxiliar em segundo plano com um encerramento limpo e livre de condições de corrida — por meio de um mecanismo concreto diferente: um único arquivo Python que faz re-exec de si mesmo com uma flag --serve para se tornar o processo filho desanexado, em vez da divisão entre launcher.py e echo_server.py mostrada acima. Ele não escreve nenhum arquivo de PID; o processo filho escreve seu próprio script stop_echo.sh (kill <pid>) para o teste executar na limpeza.
Veja também
- Testes em C++ — configuração do MTR, execução de suítes, registro de resultados e depuração de falhas
- Criando Extensões em C++ — passos completos de compilação e configuração do CMake
- Desenvolvimento em C++ — criação de VDF, tipos de argumento e tratamento de resultados

