test-lib.sh 10.9 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
# Make sure the ipfs path is set, also set in test_init_ipfs but that
# is not always used.
export IPFS_PATH="$(pwd)/.ipfs"
47 48
# Ask programs to please not print ANSI codes
export TERM=dumb
49

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

52
# grab + output options
53
test "$TEST_NO_FUSE" != 1 && test_set_prereq FUSE
54
test "$TEST_EXPENSIVE" = 1 && test_set_prereq EXPENSIVE
55
test "$TEST_NO_DOCKER" != 1 && type docker >/dev/null 2>&1 && test_set_prereq DOCKER
56
test "$TEST_NO_PLUGIN" != 1 && test "$TEST_OS" = "LINUX" && test_set_prereq PLUGIN
57 58 59

# 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
60

61
if test "$TEST_VERBOSE" = 1; then
Łukasz Magiera's avatar
Łukasz Magiera committed
62 63 64 65 66
  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"
67 68
fi

69 70 71
# source our generic test lib
. ../../ipfs-test-lib.sh

72 73 74
# source iptb lib
. ../lib/iptb-lib.sh

75
test_cmp_repeat_10_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
76 77 78 79 80 81
  for i in $(test_seq 1 100)
  do
    test_cmp "$1" "$2" >/dev/null && return
    go-sleep 100ms
  done
  test_cmp "$1" "$2"
82 83
}

84
test_run_repeat_60_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
85 86 87 88 89 90
  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
91 92
}

93
test_wait_output_n_lines_60_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
94 95 96 97 98 99 100
  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"
101 102
}

103
test_wait_open_tcp_port_10_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
104 105 106 107 108 109 110 111 112 113 114 115
  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
116 117
}

118 119 120 121 122 123

# 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
124 125 126
  # grab flags (like --bool in "ipfs config --bool")
  test_cfg_flags="" # unset in case.
  test "$#" = 3 && { test_cfg_flags=$1; shift; }
127

Łukasz Magiera's avatar
Łukasz Magiera committed
128 129
  test_cfg_key=$1
  test_cfg_val=$2
130

Łukasz Magiera's avatar
Łukasz Magiera committed
131 132 133
  # 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"
134

Łukasz Magiera's avatar
Łukasz Magiera committed
135 136 137 138 139
  # 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
140 141
}

142
test_init_ipfs() {
143

144

Łukasz Magiera's avatar
Łukasz Magiera committed
145 146 147
  # 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?
148

Łukasz Magiera's avatar
Łukasz Magiera committed
149 150
  test_expect_success "ipfs init succeeds" '
    export IPFS_PATH="$(pwd)/.ipfs" &&
151
    ipfs init --profile=test -b=2048 > /dev/null
Łukasz Magiera's avatar
Łukasz Magiera committed
152
  '
153

Łukasz Magiera's avatar
Łukasz Magiera committed
154 155 156 157 158 159
  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\""
  '
160

161 162
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
163
test_config_ipfs_gateway_writable() {
Łukasz Magiera's avatar
Łukasz Magiera committed
164 165 166 167
  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
168 169
}

170
test_wait_for_file() {
Łukasz Magiera's avatar
Łukasz Magiera committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
  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
186 187
}

Jeromy's avatar
Jeromy committed
188
test_set_address_vars() {
Łukasz Magiera's avatar
Łukasz Magiera committed
189 190 191 192 193 194 195 196 197 198 199 200 201
  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
202 203 204 205
    test_expect_success "get swarm addresses" '
      ipfs swarm addrs local > addrs_out
    '

Łukasz Magiera's avatar
Łukasz Magiera committed
206 207 208 209 210
    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
211 212 213 214
}

test_launch_ipfs_daemon() {

Dominic Della Valle's avatar
Dominic Della Valle committed
215
  args=("$@")
Jeromy's avatar
Jeromy committed
216

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

Łukasz Magiera's avatar
Łukasz Magiera committed
219
  test_expect_success "'ipfs daemon' succeeds" '
Dominic Della Valle's avatar
Dominic Della Valle committed
220
    ipfs daemon "${args[@]}" >actual_daemon 2>daemon_err &
221
    IPFS_PID=$!
Łukasz Magiera's avatar
Łukasz Magiera committed
222
  '
Jeromy's avatar
Jeromy committed
223

Łukasz Magiera's avatar
Łukasz Magiera committed
224 225
  # wait for api file to show up
  test_expect_success "api file shows up" '
226
    test_wait_for_file 50 100ms "$IPFS_PATH/api"
Łukasz Magiera's avatar
Łukasz Magiera committed
227
  '
Jeromy's avatar
Jeromy committed
228

Łukasz Magiera's avatar
Łukasz Magiera committed
229
  test_set_address_vars actual_daemon
230

Łukasz Magiera's avatar
Łukasz Magiera committed
231 232 233 234 235
  # we say the daemon is ready when the API server is ready.
  test_expect_success "'ipfs daemon' is ready" '
    pollEndpoint -ep=/version -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
  '
236 237
}

238
do_umount() {
Łukasz Magiera's avatar
Łukasz Magiera committed
239 240 241 242 243
  if [ "$(uname -s)" = "Linux" ]; then
  fusermount -u "$1"
  else
  umount "$1"
  fi
244 245
}

246
test_mount_ipfs() {
247

Łukasz Magiera's avatar
Łukasz Magiera committed
248 249 250 251 252 253
  # 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
  '
254

Łukasz Magiera's avatar
Łukasz Magiera committed
255 256 257 258 259
  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
  '
260 261 262 263 264

}

test_launch_ipfs_daemon_and_mount() {

Łukasz Magiera's avatar
Łukasz Magiera committed
265 266 267
  test_init_ipfs
  test_launch_ipfs_daemon
  test_mount_ipfs
268

269 270 271
}

test_kill_repeat_10_sec() {
Łukasz Magiera's avatar
Łukasz Magiera committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
  # 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
288 289
}

290
test_kill_ipfs_daemon() {
291

Łukasz Magiera's avatar
Łukasz Magiera committed
292 293 294
  test_expect_success "'ipfs daemon' is still running" '
    kill -0 $IPFS_PID
  '
295

Łukasz Magiera's avatar
Łukasz Magiera committed
296 297 298
  test_expect_success "'ipfs daemon' can be killed" '
    test_kill_repeat_10_sec $IPFS_PID
  '
299
}
300 301

test_curl_resp_http_code() {
Łukasz Magiera's avatar
Łukasz Magiera committed
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
  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
320
}
321 322

test_must_be_empty() {
Łukasz Magiera's avatar
Łukasz Magiera committed
323 324 325 326 327 328
  if test -s "$1"
  then
    echo "'$1' is not empty, it contains:"
    cat "$1"
    return 1
  fi
329 330 331
}

test_should_contain() {
Łukasz Magiera's avatar
Łukasz Magiera committed
332 333 334 335 336 337 338
  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
339
}
Jeromy's avatar
Jeromy committed
340 341

test_str_contains() {
Łukasz Magiera's avatar
Łukasz Magiera committed
342 343 344
  find=$1
  shift
  echo "$@" | egrep "\b$find\b" >/dev/null
Jeromy's avatar
Jeromy committed
345
}
rht's avatar
rht committed
346 347

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

# output a file's permission in human readable format
generic_stat() {
Łukasz Magiera's avatar
Łukasz Magiera committed
368 369 370 371 372 373 374 375
  # normalize stat across systems
  case $(uname -s) in
    Linux)
      _STAT="stat -c %A"
      ;;
    FreeBSD | Darwin | DragonFly)
      _STAT="stat -f %Sp"
      ;;
376 377 378 379
    *)
        echo "unsupported OS" >&2
        exit 1
        ;;
Łukasz Magiera's avatar
Łukasz Magiera committed
380 381
  esac
  $_STAT "$1" || echo "failed" # Avoid returning nothing.
382
}
383

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
# 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"
}

Steven Allen's avatar
Steven Allen committed
401 402 403 404 405 406 407
directory_size() {
    local total=0
    local fsize=0
    local res=0
    find "$1" -type f | ( while read fname; do
        fsize=$(file_size "$fname")
        res=$?
Steven Allen's avatar
Steven Allen committed
408
        if ! test $res -eq 0; then
409 410 411
            if ! test -e "$fname"; then
                continue;
            fi
Steven Allen's avatar
Steven Allen committed
412 413 414 415 416
            echo "failed to get filesize" >&2
            return $res
        fi
        total=$(expr "$total" + "$fsize")
        res=$?
Steven Allen's avatar
Steven Allen committed
417
        if ! test $res -eq 0; then
Steven Allen's avatar
Steven Allen committed
418 419 420 421 422 423 424
            echo "filesize not a number: $fsize" >&2
            return $res
        fi
    done
    echo "$total" ) # do not remove this subshell
}

425
test_check_peerid() {
Łukasz Magiera's avatar
Łukasz Magiera committed
426 427 428 429 430
  peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
  test "$peeridlen" = "46" || {
    echo "Bad peerid '$1' with len '$peeridlen'"
    return 1
  }
431
}
432 433

convert_tcp_maddr() {
Łukasz Magiera's avatar
Łukasz Magiera committed
434
  echo $1 | awk -F'/' '{ printf "%s:%s", $3, $5 }'
435 436 437
}

port_from_maddr() {
Łukasz Magiera's avatar
Łukasz Magiera committed
438
  echo $1 | awk -F'/' '{ print $NF }'
439
}
Michael Avila's avatar
Michael Avila committed
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460

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
  '
}