I have my own implementation of a Redis server which I'd like to test through a shell script.
The general idea is to feed it with some commands through nc
, and since nc
prints the output of my program (response) to stdout
, to capture the response in a script variable and compare it with the expected output.
I haven't been able to get it to work and I don't know what the issue is and how to solve it.
This is a part of the script:
#!/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;
That's just one example of a test. When a user sends the PING
command, the expected response is PONG
, but it is encoded and sent back as +PONG\r\n
.
The CLI output of this test run ($ ./test.sh
) is:
Running test #1... FAILED
Got:
+PONG
So, it seems that the variable $response
indeed contains what it should.
I tried removing +
, \r
, \n
, \r\n
from the reference output to no avail, just to see if that would help.
I'll have more complicated tests that include a character that needs to be escaped ($
), such as \$5\r\nHello
, in the response.
By the way, manually setting response
works as expected.
response='+PONG\r\n';
if [ "$response" = '+PONG\r\n' ]; then
echo Equal
else
echo Different
fi;
This prints Equal
, as expected.
After adding debug output through set -ex
, I can see that $response
stores +PONG\r
, i.e., without \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
Okay, so then setting the reference output to +PONG\r
should work, right?
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
Clearly not.
I tried wrapping response
in {}
, like this: if [ "${response}" = '+PONG\r' ]; then
, to no avail.
What am I missing?
I'm also curious to know how and why \n
got lost.
I'm running it from zsh
on a mac if that should be noted, but the shebang clearly tells it to use bash
.
If I execute ps -p $$
from the test script, I get 51547 ttys003 0:00.02 /bin/bash ./test.sh
.
+PONG\r\n
), but then say+PONG
(as output after runningtest.sh
) is correct. Shouldn't a working version print out+PONG\r\n
instead? Why do you think otherwise?typeset -p response
to see what's actually stored in the variable\r\n
are you actually looking for the 4 literal characters '\', \r', '\' and 'n', or are you looking for the 2 characters\r
(carriage return) and\n
(linefeed)? if the latter then consider[ "$response" = $'+PONG\r\n' ]
response=$'+PONG\r'
=> the$
prefix says to treat\r
as the single carriage return character; without the$
prefix you end up dealing with 2 separate characters '\' and 'r'; consider updating your code to match what's shown in thetypeset -p
output, namely:[ "$response" = $'+PONG\r' ]
sh
compliance you can adopt the recommendations in SC3003 -- in other words, allowprintf
to convert escape sequences to the intended character before assigning to a variable. The newline character got lost because shell command substitution trims trailing newlines. See: pubs.opengroup.org/onlinepubs/9699919799/utilities/…