test-lib.sh 8.79 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
PATH=$(pwd)/bin:${PATH}
13

14 15 16 17 18
# 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

19
# assert the `ipfs` we're using is the right one.
20
if test `which ipfs` != $(pwd)/bin/ipfs; then
21 22 23 24 25
	echo >&2 "Cannot find the tests' local ipfs tool."
	echo >&2 "Please check test and ipfs tool installation."
	exit 1
fi

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
26 27 28 29 30

# source the common hashes first.
. lib/test-lib-hashes.sh


31
SHARNESS_LIB="lib/sharness/sharness.sh"
32

33 34 35 36 37 38 39 40
. "$SHARNESS_LIB" || {
	echo >&2 "Cannot source: $SHARNESS_LIB"
	echo >&2 "Please check Sharness installation."
	exit 1
}

# Please put go-ipfs specific shell functions below

41
# grab + output options
42
test "$TEST_NO_FUSE" != 1 && test_set_prereq FUSE
43
test "$TEST_EXPENSIVE" = 1 && test_set_prereq EXPENSIVE
Christian Couder's avatar
Christian Couder committed
44
type docker && test_set_prereq DOCKER
45

46 47 48 49 50 51
if test "$TEST_VERBOSE" = 1; then
	echo '# TEST_VERBOSE='"$TEST_VERBOSE"
	echo '# TEST_NO_FUSE='"$TEST_NO_FUSE"
	echo '# TEST_EXPENSIVE='"$TEST_EXPENSIVE"
fi

52 53 54
# source our generic test lib
. ../../ipfs-test-lib.sh

55
test_cmp_repeat_10_sec() {
Christian Couder's avatar
Christian Couder committed
56
	for i in $(test_seq 1 100)
57
	do
58
		test_cmp "$1" "$2" >/dev/null && return
59
		go-sleep 100ms
60 61 62 63
	done
	test_cmp "$1" "$2"
}

64
test_run_repeat_60_sec() {
65
	for i in $(test_seq 1 600)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
66
	do
67 68
		(test_eval_ "$1") && return
		go-sleep 100ms
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69 70 71 72
	done
	return 1 # failed
}

73
test_wait_output_n_lines_60_sec() {
74
	for i in $(test_seq 1 600)
75
	do
76 77
		test $(cat "$1" | wc -l | tr -d " ") -ge $2 && return
		go-sleep 100ms
78
	done
79
	actual=$(cat "$1" | wc -l | tr -d " ")
80
	test_fsh "expected $2 lines of output. got $actual"
81 82
}

83
test_wait_open_tcp_port_10_sec() {
84 85
	for i in $(test_seq 1 100)
	do
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86 87 88 89 90
		# 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
91 92
			return 0
		fi
93
		go-sleep 100ms
94 95 96 97
	done
	return 1
}

98 99 100 101 102 103

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

Etienne Laurin's avatar
Etienne Laurin committed
104
	# grab flags (like --bool in "ipfs config --bool")
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
	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
}

122
test_init_ipfs() {
123

124 125 126 127 128 129 130 131 132 133 134
	# we have a problem where initializing daemons with the same api port
	# often fails-- it hangs indefinitely. The proper solution is to make
	# ipfs pick an unused port for the api on startup, and then use that.
	# Unfortunately, ipfs doesnt yet know how to do this-- the api port
	# must be specified. Until ipfs learns how to do this, we must use
	# specific port numbers, which may still fail but less frequently
	# if we at least use different ones.

	# Using RANDOM like this is clearly wrong-- it samples with replacement
	# and it doesnt even check the port is unused. this is a trivial stop gap
	# until the proper solution is implemented.
135
	RANDOM=$$
136 137 138 139 140
	PORT_API=$((RANDOM % 3000 + 5100))
	ADDR_API="/ip4/127.0.0.1/tcp/$PORT_API"

	PORT_GWAY=$((RANDOM % 3000 + 8100))
	ADDR_GWAY="/ip4/127.0.0.1/tcp/$PORT_GWAY"
141

142 143 144 145 146 147
	PORT_SWARM=$((RANDOM % 3000 + 12000))
	ADDR_SWARM="[
  \"/ip4/0.0.0.0/tcp/$PORT_SWARM\"
]"


148 149 150 151
	# 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?

152
	test_expect_success "ipfs init succeeds" '
153
		export IPFS_PATH="$(pwd)/.ipfs" &&
154
		ipfs init -b=1024 > /dev/null
155 156
	'

157
	test_expect_success "prepare config -- mounting and bootstrap rm" '
158
		mkdir mountdir ipfs ipns &&
159 160
		test_config_set Mounts.IPFS "$(pwd)/ipfs" &&
		test_config_set Mounts.IPNS "$(pwd)/ipns" &&
161
		test_config_set Addresses.API "$ADDR_API" &&
162
		test_config_set Addresses.Gateway "$ADDR_GWAY" &&
163
		test_config_set --json Addresses.Swarm "$ADDR_SWARM" &&
164
		ipfs bootstrap rm --all ||
165
		test_fsh cat "\"$IPFS_PATH/config\""
166 167
	'

168 169
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
170
test_config_ipfs_gateway_readonly() {
171
	ADDR_GWAY=$1
172
	test_expect_success "prepare config -- gateway address" '
173 174
		test "$ADDR_GWAY" != "" &&
		test_config_set "Addresses.Gateway" "$ADDR_GWAY"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
175
	'
176 177 178 179 180 181 182

	# tell the user what's going on if they messed up the call.
	if test "$#" = 0; then
		echo "#			Error: must call with an address, for example:"
		echo '#			test_config_ipfs_gateway_readonly "/ip4/0.0.0.0/tcp/5002"'
		echo '#'
	fi
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
183 184 185
}

test_config_ipfs_gateway_writable() {
186 187 188

	test_config_ipfs_gateway_readonly $1

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
189
	test_expect_success "prepare config -- gateway writable" '
Etienne Laurin's avatar
Etienne Laurin committed
190
		test_config_set --bool Gateway.Writable true ||
191
		test_fsh cat "\"$IPFS_PATH/config\""
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
192 193 194
	'
}

195 196
test_launch_ipfs_daemon() {

197
	args="$@"
198

199
	test_expect_success "'ipfs daemon' succeeds" '
200
		ipfs daemon $args >actual_daemon 2>daemon_err &
201 202
	'

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
203 204
	# we say the daemon is ready when the API server is ready.
	test_expect_success "'ipfs daemon' is ready" '
205
		IPFS_PID=$! &&
Henry's avatar
Henry committed
206 207
		pollEndpoint -ep=/version -host=$ADDR_API -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
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
208 209 210 211
	'

	if test "$ADDR_GWAY" != ""; then
		test_expect_success "'ipfs daemon' output includes Gateway address" '
Henry's avatar
Henry committed
212 213
			pollEndpoint -ep=/version -host=$ADDR_GWAY -v -tout=1s -tries=60 2>poll_gwerr > poll_gwout ||
			test_fsh cat daemon_err || test_fsh cat poll_gwerr || test_fsh cat poll_gwout
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
214 215
		'
	fi
216 217 218
}

test_mount_ipfs() {
219

220
	# make sure stuff is unmounted first.
221
	test_expect_success FUSE "'ipfs mount' succeeds" '
222 223
		umount "$(pwd)/ipfs" || true &&
		umount "$(pwd)/ipns" || true &&
224 225 226 227 228 229 230 231
		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
	'
232 233 234 235 236 237 238 239 240

}

test_launch_ipfs_daemon_and_mount() {

	test_init_ipfs
	test_launch_ipfs_daemon
	test_mount_ipfs

241 242 243
}

test_kill_repeat_10_sec() {
244 245
	# try to shut down once + wait for graceful exit
	kill $1
Christian Couder's avatar
Christian Couder committed
246
	for i in $(test_seq 1 100)
247
	do
248
		go-sleep 100ms
249 250
		! kill -0 $1 2>/dev/null && return
	done
251 252 253

	# if not, try once more, which will skip graceful exit
	kill $1
254
	go-sleep 1s
255 256 257 258 259
	! 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
260 261
}

262
test_kill_ipfs_daemon() {
263

264
	test_expect_success "'ipfs daemon' is still running" '
265 266 267
		kill -0 $IPFS_PID
	'

268
	test_expect_success "'ipfs daemon' can be killed" '
269
		test_kill_repeat_10_sec $IPFS_PID
270 271
	'
}
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292

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
}
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

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
}
Jeromy's avatar
Jeromy committed
312 313 314 315 316 317

test_str_contains() {
	find=$1
	shift
	echo "$@" | grep "$find" >/dev/null
}
rht's avatar
rht committed
318 319 320 321 322 323 324 325 326 327

disk_usage() {
    # normalize du across systems
    case $(uname -s) in
        Linux)
            DU="du -sb"
            ;;
        FreeBSD)
            DU="du -s -A -B 1"
            ;;
rht's avatar
rht committed
328 329
        Darwin | DragonFly | *)
            DU="du -s"
rht's avatar
rht committed
330 331 332 333
            ;;
    esac
        $DU "$1" | awk "{print \$1}"
}
334 335 336 337 338 339 340 341 342 343 344 345 346 347

# 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"
            ;;
    esac
    $_STAT "$1"
}
348 349

test_check_peerid() {
350 351 352 353 354
	peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
	test "$peeridlen" = "46" || {
		echo "Bad peerid '$1' with len '$peeridlen'"
		return 1
	}
355 356
}