mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-21 18:37:45 +08:00
* Create spellcheck.yml * Create .codespell-ignore --------- Co-authored-by: Marcin Rataj <lidel@lidel.org> Co-authored-by: Guillaume Michel <guillaumemichel@users.noreply.github.com>
545 lines
13 KiB
Bash
545 lines
13 KiB
Bash
# Test framework for go-ipfs
|
|
#
|
|
# Copyright (c) 2014 Christian Couder
|
|
# MIT Licensed; see the LICENSE file in this repository.
|
|
#
|
|
# We are using sharness (https://github.com/pl-strflt/sharness/tree/feat/junit)
|
|
# which was extracted from the Git test framework.
|
|
|
|
# use the ipfs tool to test against
|
|
|
|
# add current directory to path, for ipfs tool.
|
|
if test "$MAKE_SKIP_PATH" != "1"; then
|
|
BIN=$(cd .. && echo `pwd`/bin)
|
|
BIN2=$(cd ../.. && echo `pwd`/cmd/ipfs)
|
|
PATH=${BIN2}:${BIN}:${PATH}
|
|
|
|
# assert the `ipfs` we're using is the right one.
|
|
if test `which ipfs` != ${BIN2}/ipfs; then
|
|
echo >&2 "Cannot find the tests' local ipfs tool."
|
|
echo >&2 "Please check test and ipfs tool installation."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# set sharness verbosity. we set the env var directly as
|
|
# it's too late to pass in --verbose, and --verbose is harder
|
|
# to pass through in some cases.
|
|
test "$TEST_VERBOSE" = 1 && verbose=t
|
|
test "$TEST_IMMEDIATE" = 1 && immediate=t
|
|
test "$TEST_JUNIT" = 1 && junit=t
|
|
test "$TEST_NO_COLOR" = 1 && no_color=t
|
|
# source the common hashes first.
|
|
. lib/test-lib-hashes.sh
|
|
|
|
|
|
ln -sf lib/sharness/sharness.sh .
|
|
ln -sf lib/sharness/lib-sharness .
|
|
|
|
. "sharness.sh" || {
|
|
echo >&2 "Cannot source: sharness.sh"
|
|
echo >&2 "Please check Sharness installation."
|
|
exit 1
|
|
}
|
|
|
|
# Please put go-ipfs specific shell functions below
|
|
|
|
###
|
|
# BEGIN Check for pre-existing daemon being stuck
|
|
###
|
|
wait_prev_cleanup_tick_secs=1
|
|
wait_prev_cleanup_max_secs=5
|
|
cur_test_pwd="$(pwd)"
|
|
|
|
while true ; do
|
|
echo -n > stuck_cwd_list
|
|
|
|
lsof -c ipfs -Ffn 2>/dev/null | grep -A1 '^fcwd$' | grep '^n' | cut -b 2- | while read -r pwd_of_stuck ; do
|
|
case "$pwd_of_stuck" in
|
|
"$cur_test_pwd"*)
|
|
echo "$pwd_of_stuck" >> stuck_cwd_list
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
done
|
|
|
|
test -s stuck_cwd_list || break
|
|
|
|
test "$wait_prev_cleanup_max_secs" -le 0 && break
|
|
|
|
echo "Daemons still running, waiting for ${wait_prev_cleanup_max_secs}s"
|
|
sleep $wait_prev_cleanup_tick_secs
|
|
|
|
wait_prev_cleanup_max_secs="$(( $wait_prev_cleanup_max_secs - $wait_prev_cleanup_tick_secs ))"
|
|
done
|
|
|
|
if test -s stuck_cwd_list ; then
|
|
test_expect_success "ipfs daemon (s)seems to be running with CWDs of
|
|
$(cat stuck_cwd_list)
|
|
Almost certainly a leftover from a prior test, ABORTING" 'false'
|
|
|
|
test_done
|
|
fi
|
|
###
|
|
# END Check for pre-existing daemon being stuck
|
|
###
|
|
|
|
# Make sure the ipfs path is set, also set in test_init_ipfs but that
|
|
# is not always used.
|
|
export IPFS_PATH="$(pwd)/.ipfs"
|
|
# Ask programs to please not print ANSI codes
|
|
export TERM=dumb
|
|
|
|
TEST_OS="$(uname -s | tr '[a-z]' '[A-Z]')"
|
|
|
|
# grab + output options
|
|
test "$TEST_FUSE" = 1 && test_set_prereq FUSE
|
|
test "$TEST_EXPENSIVE" = 1 && test_set_prereq EXPENSIVE
|
|
test "$TEST_DOCKER" = 1 && type docker >/dev/null 2>&1 && groups | egrep "\bdocker\b" && test_set_prereq DOCKER
|
|
test "$TEST_PLUGIN" = 1 && test "$TEST_OS" = "LINUX" && test_set_prereq PLUGIN
|
|
|
|
# this may not be available, skip a few dependent tests
|
|
type socat >/dev/null 2>&1 && test_set_prereq SOCAT
|
|
type unzip >/dev/null 2>&1 && test_set_prereq UNZIP
|
|
|
|
|
|
# Set a prereq as error messages are often different on Windows/Cygwin
|
|
expr "$TEST_OS" : "CYGWIN_NT" >/dev/null || test_set_prereq STD_ERR_MSG
|
|
|
|
if test "$TEST_VERBOSE" = 1; then
|
|
echo '# TEST_VERBOSE='"$TEST_VERBOSE"
|
|
echo '# TEST_IMMEDIATE='"$TEST_IMMEDIATE"
|
|
echo '# TEST_FUSE='"$TEST_FUSE"
|
|
echo '# TEST_DOCKER='"$TEST_DOCKER"
|
|
echo '# TEST_PLUGIN='"$TEST_PLUGIN"
|
|
echo '# TEST_EXPENSIVE='"$TEST_EXPENSIVE"
|
|
echo '# TEST_OS='"$TEST_OS"
|
|
echo '# TEST_JUNIT='"$TEST_JUNIT"
|
|
echo '# TEST_NO_COLOR='"$TEST_NO_COLOR"
|
|
echo '# TEST_ULIMIT_PRESET='"$TEST_ULIMIT_PRESET"
|
|
fi
|
|
|
|
# source our generic test lib
|
|
. ../../ipfs-test-lib.sh
|
|
|
|
# source iptb lib
|
|
. ../lib/iptb-lib.sh
|
|
|
|
test_cmp_repeat_10_sec() {
|
|
for i in $(test_seq 1 100)
|
|
do
|
|
test_cmp "$1" "$2" >/dev/null && return
|
|
go-sleep 100ms
|
|
done
|
|
test_cmp "$1" "$2"
|
|
}
|
|
|
|
test_run_repeat_60_sec() {
|
|
for i in $(test_seq 1 600)
|
|
do
|
|
(test_eval_ "$1") && return
|
|
go-sleep 100ms
|
|
done
|
|
return 1 # failed
|
|
}
|
|
|
|
test_wait_output_n_lines() {
|
|
for i in $(test_seq 1 3600)
|
|
do
|
|
test $(cat "$1" | wc -l | tr -d " ") -ge $2 && return
|
|
go-sleep 100ms
|
|
done
|
|
actual=$(cat "$1" | wc -l | tr -d " ")
|
|
test_fsh "expected $2 lines of output. got $actual"
|
|
}
|
|
|
|
test_wait_open_tcp_port_10_sec() {
|
|
for i in $(test_seq 1 100)
|
|
do
|
|
# this is not a perfect check, but it's portable.
|
|
# can't count on ss. not installed everywhere.
|
|
# can't count on netstat using : or . as port delim. differ across platforms.
|
|
echo $(netstat -aln | egrep "^tcp.*LISTEN" | egrep "[.:]$1" | wc -l) -gt 0
|
|
if [ $(netstat -aln | egrep "^tcp.*LISTEN" | egrep "[.:]$1" | wc -l) -gt 0 ]; then
|
|
return 0
|
|
fi
|
|
go-sleep 100ms
|
|
done
|
|
return 1
|
|
}
|
|
|
|
|
|
# test_config_set helps us make sure _we really did set_ a config value.
|
|
# it sets it and then tests it. This became elaborate because ipfs config
|
|
# was setting really weird things and am not sure why.
|
|
test_config_set() {
|
|
|
|
# grab flags (like --bool in "ipfs config --bool")
|
|
test_cfg_flags="" # unset in case.
|
|
test "$#" = 3 && { test_cfg_flags=$1; shift; }
|
|
|
|
test_cfg_key=$1
|
|
test_cfg_val=$2
|
|
|
|
# when verbose, tell the user what config values are being set
|
|
test_cfg_cmd="ipfs config $test_cfg_flags \"$test_cfg_key\" \"$test_cfg_val\""
|
|
test "$TEST_VERBOSE" = 1 && echo "$test_cfg_cmd"
|
|
|
|
# ok try setting the config key/val pair.
|
|
ipfs config $test_cfg_flags "$test_cfg_key" "$test_cfg_val"
|
|
echo "$test_cfg_val" >cfg_set_expected
|
|
ipfs config "$test_cfg_key" >cfg_set_actual
|
|
test_cmp cfg_set_expected cfg_set_actual
|
|
}
|
|
|
|
test_init_ipfs() {
|
|
args=("$@")
|
|
|
|
# we set the Addresses.API config variable.
|
|
# the cli client knows to use it, so only need to set.
|
|
# todo: in the future, use env?
|
|
|
|
test_expect_success "ipfs init succeeds" '
|
|
export IPFS_PATH="$(pwd)/.ipfs" &&
|
|
ipfs init "${args[@]}" --profile=test > /dev/null
|
|
'
|
|
|
|
test_expect_success "prepare config -- mounting" '
|
|
mkdir mountdir ipfs ipns &&
|
|
test_config_set Mounts.IPFS "$(pwd)/ipfs" &&
|
|
test_config_set Mounts.IPNS "$(pwd)/ipns" ||
|
|
test_fsh cat "\"$IPFS_PATH/config\""
|
|
'
|
|
|
|
}
|
|
|
|
test_wait_for_file() {
|
|
loops=$1
|
|
delay=$2
|
|
file=$3
|
|
fwaitc=0
|
|
while ! test -f "$file"
|
|
do
|
|
if test $fwaitc -ge $loops
|
|
then
|
|
echo "Error: timed out waiting for file: $file"
|
|
return 1
|
|
fi
|
|
|
|
go-sleep $delay
|
|
fwaitc=`expr $fwaitc + 1`
|
|
done
|
|
}
|
|
|
|
test_set_address_vars() {
|
|
daemon_output="$1"
|
|
|
|
test_expect_success "set up address variables" '
|
|
API_MADDR=$(cat "$IPFS_PATH/api") &&
|
|
API_ADDR=$(convert_tcp_maddr $API_MADDR) &&
|
|
API_PORT=$(port_from_maddr $API_MADDR) &&
|
|
|
|
GWAY_MADDR=$(sed -n "s/^Gateway server listening on //p" "$daemon_output") &&
|
|
GWAY_ADDR=$(convert_tcp_maddr $GWAY_MADDR) &&
|
|
GWAY_PORT=$(port_from_maddr $GWAY_MADDR)
|
|
'
|
|
|
|
if ipfs swarm addrs local >/dev/null 2>&1; then
|
|
test_expect_success "get swarm addresses" '
|
|
ipfs swarm addrs local > addrs_out
|
|
'
|
|
|
|
test_expect_success "set swarm address vars" '
|
|
SWARM_MADDR=$(grep "127.0.0.1" addrs_out) &&
|
|
SWARM_PORT=$(port_from_maddr $SWARM_MADDR)
|
|
'
|
|
fi
|
|
}
|
|
|
|
test_launch_ipfs_daemon() {
|
|
|
|
args=("$@")
|
|
|
|
test "$TEST_ULIMIT_PRESET" != 1 && ulimit -n 2048
|
|
|
|
test_expect_success "'ipfs daemon' succeeds" '
|
|
ipfs daemon "${args[@]}" >actual_daemon 2>daemon_err &
|
|
IPFS_PID=$!
|
|
'
|
|
|
|
# wait for api file to show up
|
|
test_expect_success "api file shows up" '
|
|
test_wait_for_file 50 200ms "$IPFS_PATH/api"
|
|
'
|
|
|
|
test_set_address_vars actual_daemon
|
|
|
|
# we say the daemon is ready when the API server is ready.
|
|
test_expect_success "'ipfs daemon' is ready" '
|
|
pollEndpoint -host=$API_MADDR -v -tout=1s -tries=60 2>poll_apierr > poll_apiout ||
|
|
test_fsh cat actual_daemon || test_fsh cat daemon_err || test_fsh cat poll_apierr || test_fsh cat poll_apiout
|
|
'
|
|
}
|
|
|
|
test_launch_ipfs_daemon_without_network() {
|
|
test_launch_ipfs_daemon --offline "$@"
|
|
}
|
|
|
|
do_umount() {
|
|
if [ "$(uname -s)" = "Linux" ]; then
|
|
fusermount -z -u "$1"
|
|
else
|
|
umount "$1"
|
|
fi
|
|
}
|
|
|
|
test_mount_ipfs() {
|
|
|
|
# make sure stuff is unmounted first.
|
|
test_expect_success FUSE "'ipfs mount' succeeds" '
|
|
do_umount "$(pwd)/ipfs" || true &&
|
|
do_umount "$(pwd)/ipns" || true &&
|
|
ipfs mount >actual
|
|
'
|
|
|
|
test_expect_success FUSE "'ipfs mount' output looks good" '
|
|
echo "IPFS mounted at: $(pwd)/ipfs" >expected &&
|
|
echo "IPNS mounted at: $(pwd)/ipns" >>expected &&
|
|
test_cmp expected actual
|
|
'
|
|
|
|
}
|
|
|
|
test_launch_ipfs_daemon_and_mount() {
|
|
|
|
test_init_ipfs
|
|
test_launch_ipfs_daemon
|
|
test_mount_ipfs
|
|
|
|
}
|
|
|
|
test_kill_repeat_10_sec() {
|
|
# try to shut down once + wait for graceful exit
|
|
kill $1
|
|
for i in $(test_seq 1 100)
|
|
do
|
|
go-sleep 100ms
|
|
! kill -0 $1 2>/dev/null && return
|
|
done
|
|
|
|
# if not, try once more, which will skip graceful exit
|
|
kill $1
|
|
go-sleep 1s
|
|
! kill -0 $1 2>/dev/null && return
|
|
|
|
# ok, no hope. kill it to prevent it messing with other tests
|
|
kill -9 $1 2>/dev/null
|
|
return 1
|
|
}
|
|
|
|
test_kill_ipfs_daemon() {
|
|
|
|
test_expect_success "'ipfs daemon' is still running" '
|
|
kill -0 $IPFS_PID
|
|
'
|
|
|
|
test_expect_success "'ipfs daemon' can be killed" '
|
|
test_kill_repeat_10_sec $IPFS_PID
|
|
'
|
|
}
|
|
|
|
test_curl_resp_http_code() {
|
|
curl -I "$1" >curl_output || {
|
|
echo "curl error with url: '$1'"
|
|
echo "curl output was:"
|
|
cat curl_output
|
|
return 1
|
|
}
|
|
shift &&
|
|
RESP=$(head -1 curl_output) &&
|
|
while test "$#" -gt 0
|
|
do
|
|
expr "$RESP" : "$1" >/dev/null && return
|
|
shift
|
|
done
|
|
echo "curl response didn't match!"
|
|
echo "curl response was: '$RESP'"
|
|
echo "curl output was:"
|
|
cat curl_output
|
|
return 1
|
|
}
|
|
|
|
test_must_be_empty() {
|
|
if test -s "$1"
|
|
then
|
|
echo "'$1' is not empty, it contains:"
|
|
cat "$1"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_should_contain() {
|
|
test "$#" = 2 || error "bug in the test script: not 2 parameters to test_should_contain"
|
|
if ! grep -q "$1" "$2"
|
|
then
|
|
echo "'$2' does not contain '$1', it contains:"
|
|
cat "$2"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_should_not_contain() {
|
|
test "$#" = 2 || error "bug in the test script: not 2 parameters to test_should_not_contain"
|
|
if grep -q "$1" "$2"
|
|
then
|
|
echo "'$2' contains undesired value '$1'"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_str_contains() {
|
|
find=$1
|
|
shift
|
|
echo "$@" | egrep "\b$find\b" >/dev/null
|
|
}
|
|
|
|
disk_usage() {
|
|
# normalize du across systems
|
|
case $(uname -s) in
|
|
Linux)
|
|
DU="du -sb"
|
|
M=1
|
|
;;
|
|
FreeBSD)
|
|
DU="du -s -A -B 1"
|
|
M=512
|
|
;;
|
|
Darwin | DragonFly | *)
|
|
DU="du -s"
|
|
M=512
|
|
;;
|
|
esac
|
|
expr $($DU "$1" | awk "{print \$1}") "*" "$M"
|
|
}
|
|
|
|
# output a file's permission in human readable format
|
|
generic_stat() {
|
|
# normalize stat across systems
|
|
case $(uname -s) in
|
|
Linux)
|
|
_STAT="stat -c %A"
|
|
;;
|
|
FreeBSD | Darwin | DragonFly)
|
|
_STAT="stat -f %Sp"
|
|
;;
|
|
*)
|
|
echo "unsupported OS" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
$_STAT "$1" || echo "failed" # Avoid returning nothing.
|
|
}
|
|
|
|
# output a file's permission in human readable format
|
|
file_size() {
|
|
case $(uname -s) in
|
|
Linux)
|
|
_STAT="stat --format=%s"
|
|
;;
|
|
FreeBSD | Darwin | DragonFly)
|
|
_STAT="stat -f%z"
|
|
;;
|
|
*)
|
|
echo "unsupported OS" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
$_STAT "$1"
|
|
}
|
|
|
|
# len 46: 2048-bit RSA keys, b58mh-encoded
|
|
# len 52: ED25519 keys, b58mh-encoded
|
|
# len 56: 2048-bit RSA keys, base36-encoded
|
|
# len 62: ED25519 keys, base36-encoded
|
|
test_check_peerid() {
|
|
peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
|
|
test "$peeridlen" = "46" -o "$peeridlen" = "52" -o "$peeridlen" = "56" -o "$peeridlen" = "62" || {
|
|
echo "Bad peerid '$1' with len '$peeridlen'"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
test_check_rsa2048_b58mh_peerid() {
|
|
peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
|
|
test "$peeridlen" = "46" || {
|
|
echo "Bad RSA2048 B58MH peerid '$1' with len '$peeridlen'"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
test_check_ed25519_b58mh_peerid() {
|
|
peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
|
|
test "$peeridlen" = "52" || {
|
|
echo "Bad ED25519 B58MH peerid '$1' with len '$peeridlen'"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
test_check_rsa2048_base36_peerid() {
|
|
peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
|
|
test "$peeridlen" = "56" || {
|
|
echo "Bad RSA2048 B36CID peerid '$1' with len '$peeridlen'"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
test_check_ed25519_base36_peerid() {
|
|
peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
|
|
test "$peeridlen" = "62" || {
|
|
echo "Bad ED25519 B36CID peerid '$1' with len '$peeridlen'"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
convert_tcp_maddr() {
|
|
echo $1 | awk -F'/' '{ printf "%s:%s", $3, $5 }'
|
|
}
|
|
|
|
port_from_maddr() {
|
|
echo $1 | awk -F'/' '{ print $NF }'
|
|
}
|
|
|
|
findprovs_empty() {
|
|
test_expect_success 'findprovs '$1' succeeds' '
|
|
ipfsi 1 routing findprovs -n 1 '$1' > findprovsOut
|
|
'
|
|
|
|
test_expect_success "findprovs $1 output is empty" '
|
|
test_must_be_empty findprovsOut
|
|
'
|
|
}
|
|
|
|
findprovs_expect() {
|
|
test_expect_success 'findprovs '$1' succeeds' '
|
|
ipfsi 1 routing findprovs -n 1 '$1' > findprovsOut &&
|
|
echo '$2' > expected
|
|
'
|
|
|
|
test_expect_success "findprovs $1 output looks good" '
|
|
test_cmp findprovsOut expected
|
|
'
|
|
}
|
|
|
|
purge_blockstore() {
|
|
ipfs pin ls --quiet --type=recursive | ipfs pin rm &>/dev/null
|
|
ipfs repo gc --silent &>/dev/null
|
|
|
|
test_expect_success "pinlist empty" '
|
|
[[ -z "$( ipfs pin ls )" ]]
|
|
'
|
|
test_expect_success "nothing left to gc" '
|
|
[[ -z "$( ipfs repo gc )" ]]
|
|
'
|
|
}
|