test-lib.sh 11.4 KB
Newer Older
1 2 3 4 5 6 7 8
# 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/mlafeldt/sharness)
# which was extracted from the Git test framework.

9 10 11
# use the ipfs tool to test against

# add current directory to path, for ipfs tool.
12
if test "$MAKE_SKIP_PATH" != "1"; then
Łukasz Magiera's avatar
Łukasz Magiera committed
13 14 15 16 17 18 19 20 21 22
  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
23
fi
24

25 26 27 28
# 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
keks's avatar
keks committed
29
test "$TEST_IMMEDIATE" = 1 && immediate=t
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
30 31 32 33
# source the common hashes first.
. lib/test-lib-hashes.sh


34
SHARNESS_LIB="lib/sharness/sharness.sh"
35

36
. "$SHARNESS_LIB" || {
Łukasz Magiera's avatar
Łukasz Magiera committed
37 38 39
  echo >&2 "Cannot source: $SHARNESS_LIB"
  echo >&2 "Please check Sharness installation."
  exit 1
40 41 42 43
}

# Please put go-ipfs specific shell functions below

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
###
# 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
###

85 86 87
# Make sure the ipfs path is set, also set in test_init_ipfs but that
# is not always used.
export IPFS_PATH="$(pwd)/.ipfs"
88 89
# Ask programs to please not print ANSI codes
export TERM=dumb
90

91 92
TEST_OS="$(uname -s | tr '[a-z]' '[A-Z]')"

93
# grab + output options
94
test "$TEST_NO_FUSE" != 1 && test_set_prereq FUSE
95
test "$TEST_EXPENSIVE" = 1 && test_set_prereq EXPENSIVE
96
test "$TEST_NO_DOCKER" != 1 && type docker >/dev/null 2>&1 && groups | egrep "\bdocker\b" && test_set_prereq DOCKER
97
test "$TEST_NO_PLUGIN" != 1 && test "$TEST_OS" = "LINUX" && test_set_prereq PLUGIN
98

99 100 101 102
# this may not be available, skip a few dependent tests
type socat >/dev/null 2>&1 && test_set_prereq SOCAT


103 104
# 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
105

106
if test "$TEST_VERBOSE" = 1; then
Łukasz Magiera's avatar
Łukasz Magiera committed
107 108 109 110 111
  echo '# TEST_VERBOSE='"$TEST_VERBOSE"
  echo '# TEST_NO_FUSE='"$TEST_NO_FUSE"
  echo '# TEST_NO_PLUGIN='"$TEST_NO_PLUGIN"
  echo '# TEST_EXPENSIVE='"$TEST_EXPENSIVE"
  echo '# TEST_OS='"$TEST_OS"
112 113
fi

114 115 116
# source our generic test lib
. ../../ipfs-test-lib.sh

117 118 119
# source iptb lib
. ../lib/iptb-lib.sh

120
test_cmp_repeat_10_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
121 122 123 124 125 126
  for i in $(test_seq 1 100)
  do
    test_cmp "$1" "$2" >/dev/null && return
    go-sleep 100ms
  done
  test_cmp "$1" "$2"
127 128
}

129
test_run_repeat_60_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
130 131 132 133 134 135
  for i in $(test_seq 1 600)
  do
    (test_eval_ "$1") && return
    go-sleep 100ms
  done
  return 1 # failed
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
136 137
}

138
test_wait_output_n_lines_60_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
139 140 141 142 143 144 145
  for i in $(test_seq 1 600)
  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"
146 147
}

148
test_wait_open_tcp_port_10_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
149 150 151 152 153 154 155 156 157 158 159 160
  for i in $(test_seq 1 100)
  do
    # this is not a perfect check, but it's portable.
    # cant count on ss. not installed everywhere.
    # cant 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
161 162
}

163 164 165 166 167 168

# 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() {

Łukasz Magiera's avatar
Łukasz Magiera committed
169 170 171
  # grab flags (like --bool in "ipfs config --bool")
  test_cfg_flags="" # unset in case.
  test "$#" = 3 && { test_cfg_flags=$1; shift; }
172

Łukasz Magiera's avatar
Łukasz Magiera committed
173 174
  test_cfg_key=$1
  test_cfg_val=$2
175

Łukasz Magiera's avatar
Łukasz Magiera committed
176 177 178
  # 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"
179

Łukasz Magiera's avatar
Łukasz Magiera committed
180 181 182 183 184
  # 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
185 186
}

187
test_init_ipfs() {
188

189

Łukasz Magiera's avatar
Łukasz Magiera committed
190 191 192
  # 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?
193

Łukasz Magiera's avatar
Łukasz Magiera committed
194 195
  test_expect_success "ipfs init succeeds" '
    export IPFS_PATH="$(pwd)/.ipfs" &&
196
    ipfs init --profile=test -b=2048 > /dev/null
Łukasz Magiera's avatar
Łukasz Magiera committed
197
  '
198

Łukasz Magiera's avatar
Łukasz Magiera committed
199 200 201 202 203 204
  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\""
  '
205

206 207
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
208
test_config_ipfs_gateway_writable() {
Łukasz Magiera's avatar
Łukasz Magiera committed
209 210 211 212
  test_expect_success "prepare config -- gateway writable" '
    test_config_set --bool Gateway.Writable true ||
    test_fsh cat "\"$IPFS_PATH/config\""
  '
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
213 214
}

215
test_wait_for_file() {
Łukasz Magiera's avatar
Łukasz Magiera committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
  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
231 232
}

Jeromy's avatar
Jeromy committed
233
test_set_address_vars() {
Łukasz Magiera's avatar
Łukasz Magiera committed
234 235 236 237 238 239 240 241 242 243 244 245 246
  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
247 248 249 250
    test_expect_success "get swarm addresses" '
      ipfs swarm addrs local > addrs_out
    '

Łukasz Magiera's avatar
Łukasz Magiera committed
251 252 253 254 255
    test_expect_success "set swarm address vars" '
      SWARM_MADDR=$(grep "127.0.0.1" addrs_out) &&
      SWARM_PORT=$(port_from_maddr $SWARM_MADDR)
    '
  fi
Jeromy's avatar
Jeromy committed
256 257 258 259
}

test_launch_ipfs_daemon() {

Dominic Della Valle's avatar
Dominic Della Valle committed
260
  args=("$@")
Jeromy's avatar
Jeromy committed
261

Łukasz Magiera's avatar
Łukasz Magiera committed
262
  test "$TEST_ULIMIT_PRESET" != 1 && ulimit -n 2048
Jeromy's avatar
Jeromy committed
263

Łukasz Magiera's avatar
Łukasz Magiera committed
264
  test_expect_success "'ipfs daemon' succeeds" '
Dominic Della Valle's avatar
Dominic Della Valle committed
265
    ipfs daemon "${args[@]}" >actual_daemon 2>daemon_err &
266
    IPFS_PID=$!
Łukasz Magiera's avatar
Łukasz Magiera committed
267
  '
Jeromy's avatar
Jeromy committed
268

Łukasz Magiera's avatar
Łukasz Magiera committed
269 270
  # wait for api file to show up
  test_expect_success "api file shows up" '
271
    test_wait_for_file 50 100ms "$IPFS_PATH/api"
Łukasz Magiera's avatar
Łukasz Magiera committed
272
  '
Jeromy's avatar
Jeromy committed
273

Łukasz Magiera's avatar
Łukasz Magiera committed
274
  test_set_address_vars actual_daemon
275

Łukasz Magiera's avatar
Łukasz Magiera committed
276 277
  # we say the daemon is ready when the API server is ready.
  test_expect_success "'ipfs daemon' is ready" '
278
    pollEndpoint -host=$API_MADDR -v -tout=1s -tries=60 2>poll_apierr > poll_apiout ||
Łukasz Magiera's avatar
Łukasz Magiera committed
279 280
    test_fsh cat actual_daemon || test_fsh cat daemon_err || test_fsh cat poll_apierr || test_fsh cat poll_apiout
  '
281 282
}

283
do_umount() {
Łukasz Magiera's avatar
Łukasz Magiera committed
284 285 286 287 288
  if [ "$(uname -s)" = "Linux" ]; then
  fusermount -u "$1"
  else
  umount "$1"
  fi
289 290
}

291
test_mount_ipfs() {
292

Łukasz Magiera's avatar
Łukasz Magiera committed
293 294 295 296 297 298
  # 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
  '
299

Łukasz Magiera's avatar
Łukasz Magiera committed
300 301 302 303 304
  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
  '
305 306 307 308 309

}

test_launch_ipfs_daemon_and_mount() {

Łukasz Magiera's avatar
Łukasz Magiera committed
310 311 312
  test_init_ipfs
  test_launch_ipfs_daemon
  test_mount_ipfs
313

314 315 316
}

test_kill_repeat_10_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
  # 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
333 334
}

335
test_kill_ipfs_daemon() {
336

Łukasz Magiera's avatar
Łukasz Magiera committed
337 338 339
  test_expect_success "'ipfs daemon' is still running" '
    kill -0 $IPFS_PID
  '
340

Łukasz Magiera's avatar
Łukasz Magiera committed
341 342 343
  test_expect_success "'ipfs daemon' can be killed" '
    test_kill_repeat_10_sec $IPFS_PID
  '
344
}
345 346

test_curl_resp_http_code() {
Łukasz Magiera's avatar
Łukasz Magiera committed
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
  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
365
}
366 367

test_must_be_empty() {
Łukasz Magiera's avatar
Łukasz Magiera committed
368 369 370 371 372 373
  if test -s "$1"
  then
    echo "'$1' is not empty, it contains:"
    cat "$1"
    return 1
  fi
374 375 376
}

test_should_contain() {
Łukasz Magiera's avatar
Łukasz Magiera committed
377 378 379 380 381 382 383
  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
384
}
Jeromy's avatar
Jeromy committed
385 386

test_str_contains() {
Łukasz Magiera's avatar
Łukasz Magiera committed
387 388 389
  find=$1
  shift
  echo "$@" | egrep "\b$find\b" >/dev/null
Jeromy's avatar
Jeromy committed
390
}
rht's avatar
rht committed
391 392

disk_usage() {
Łukasz Magiera's avatar
Łukasz Magiera committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
  # 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"
rht's avatar
rht committed
409
}
410 411 412

# output a file's permission in human readable format
generic_stat() {
Łukasz Magiera's avatar
Łukasz Magiera committed
413 414 415 416 417 418 419 420
  # normalize stat across systems
  case $(uname -s) in
    Linux)
      _STAT="stat -c %A"
      ;;
    FreeBSD | Darwin | DragonFly)
      _STAT="stat -f %Sp"
      ;;
421 422 423 424
    *)
        echo "unsupported OS" >&2
        exit 1
        ;;
Łukasz Magiera's avatar
Łukasz Magiera committed
425 426
  esac
  $_STAT "$1" || echo "failed" # Avoid returning nothing.
427
}
428

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
# 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"
}

446
test_check_peerid() {
Łukasz Magiera's avatar
Łukasz Magiera committed
447 448 449 450 451
  peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
  test "$peeridlen" = "46" || {
    echo "Bad peerid '$1' with len '$peeridlen'"
    return 1
  }
452
}
453 454

convert_tcp_maddr() {
Łukasz Magiera's avatar
Łukasz Magiera committed
455
  echo $1 | awk -F'/' '{ printf "%s:%s", $3, $5 }'
456 457 458
}

port_from_maddr() {
Łukasz Magiera's avatar
Łukasz Magiera committed
459
  echo $1 | awk -F'/' '{ print $NF }'
460
}
Michael Avila's avatar
Michael Avila committed
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481

findprovs_empty() {
  test_expect_success 'findprovs '$1' succeeds' '
    ipfsi 1 dht 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 dht findprovs -n 1 '$1' > findprovsOut &&
    echo '$2' > expected
  '

  test_expect_success "findprovs $1 output looks good" '
    test_cmp findprovsOut expected
  '
}