Tenho minha própria implementação de um servidor Redis que gostaria de testar por meio de um script de shell.
A ideia geral é alimentá-lo com alguns comandos por meio de nc
, e como nc
imprime a saída do meu programa (resposta) para stdout
, capturar a resposta em uma variável de script e compará-la com a saída esperada.
Não consegui fazê-lo funcionar e não sei qual é o problema e como resolvê-lo.
Esta é uma parte do roteiro:
#!/bin/bash
set -eu
PORT=6380;
RUST_LOG=info ./run.sh --port $PORT 2>/dev/null & sleep 1; # Give it some time to start.
i=0;
i=$((i+1)); printf 'Running test #%d...' "$i";
response=$(printf "*1\r\n\$4\r\nPING\r\n" | nc localhost $PORT);
if [ "$response" = '+PONG\r\n' ]; then
printf ' PASSED'
else
printf ' FAILED\nGot:\n%s\n\n' "$response"
fi;
sleep 0.1;
pkill redis-server;
Este é apenas um exemplo de teste. Quando um usuário envia o PING
comando, a resposta esperada é PONG
, mas ela é codificada e enviada de volta como +PONG\r\n
.
A saída CLI deste teste ( $ ./test.sh
) é:
Running test #1... FAILED
Got:
+PONG
Então, parece que a variável $response
realmente contém o que deveria.
Tentei remover +
, \r
, \n
, \r\n
da saída de referência sem sucesso, só para ver se isso ajudaria.
Terei testes mais complicados que incluem um caractere que precisa ser escapado ( $
), como \$5\r\nHello
, na resposta.
A propósito, a configuração manual response
funciona conforme o esperado.
response='+PONG\r\n';
if [ "$response" = '+PONG\r\n' ]; then
echo Equal
else
echo Different
fi;
Isto imprime Equal
, como esperado.
Depois de adicionar a saída de depuração por meio de set -ex
, posso ver que $response
armazena +PONG\r
, ou seja, sem \n
.
Running test #1...++ printf '*1\r\n$4\r\nPING\r\n'
++ nc localhost 6380
+ response=$'+PONG\r'
+ '[' $'+PONG\r' = '+PONG\r\n' ']'
+ printf ' FAILED\nGot:\n%s\n\n' $'+PONG\r'
FAILED
Got:
+PONG
Certo, então definir a saída de referência +PONG\r
deve funcionar, certo?
Running test #1...++ printf '*1\r\n$4\r\nPING\r\n'
++ nc localhost 6380
+ response=$'+PONG\r'
+ '[' $'+PONG\r' = '+PONG\r' ']'
+ printf ' FAILED\nGot:\n%s\n\n' $'+PONG\r'
FAILED
Got:
+PONG
Claramente não.
Tentei encapsular response
em {}
, assim: if [ "${response}" = '+PONG\r' ]; then
, sem sucesso.
O que estou perdendo?
Também estou curioso para saber como e por que \n
me perdi.
Estou executando-o zsh
em um Mac, se isso for mencionado, mas o comando diz claramente para usar bash
.
Se eu executar ps -p $$
o script de teste, obtenho 51547 ttys003 0:00.02 /bin/bash ./test.sh
.
Seu teste de comparação não está funcionando como esperado por dois motivos:
A resposta real do servidor (pelo que entendi da sua postagem original e dos comentários) é a string
+PONG
seguida por um retorno de carro (também conhecido como CR, ^M, \r) seguido por uma quebra de linha (também conhecido como avanço de linha, LF, NL, ^J, \n). No entanto, seu teste tentou compará-la aos caracteres literais\r\n
. Em outras palavras, você tentou comparar os caracteres com seus equivalentes com barra invertida.O caractere de nova linha final capturado na sua
response
variável é removido devido ao comportamento de substituição de comando.Para corrigir seu teste, você pode:
Certifique-se de que a comparação seja entre os caracteres corretos. Em outras palavras, adote a sintaxe de @markp-fuso para
$'+PONG\r\n'
o seu valor de referência.Certifique-se de que a quebra de linha não seja removida. Uma solução é anexar um valor descartável ao final do valor desejado e removê-lo após a conclusão da substituição do comando. Alguns truques extras são necessários para preservar o status de saída. Isso é descrito em detalhes aqui .
Em conjunto, aqui está um exemplo de solução (sem o truque do código de saída):
Observe que a
$'...'
sintaxe, inicialmente do ksh93, embora agora seja padrãosh
desde a edição de 2024 da especificação POSIX, ainda não é suportada por algumassh
implementações, principalmentedash
dosh
Debian e derivados, então você pode querer mudar seu shebang para#! /usr/bin/env zsh
ou#! /usr/bin/env bash
por exemplo (ksh
não funcionaria em sistemas ondeksh
ainda há ksh88 ou pdksh) se quiser que seu script seja portável para outros sistemas.Observe também que você não precisa escapar do "
$
with"\
se usar aspas fortes ('...'
) no lugar de ""..."
inside", que ainda realiza a expansão de parâmetros. Você também pode usar$'...'
"(inside", que também não inclui expansões de parâmetros), nesse caso o "\r
,"\n
seria convertido para os caracteres de controle CR e LF por esse$'...'
operador antes de ser passado para ,printf
em vez deprintf
convertê-los ele mesmo.Usar
printf '%s\r\n' '*1' '$4' PING
também deixaria mais claro que você deseja gerar três linhas delimitadas por CRLF.