-
-
Notifications
You must be signed in to change notification settings - Fork 3k
/
test-lib.sh
355 lines (291 loc) · 8.76 KB
/
test-lib.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# 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.
# use the ipfs tool to test against
# add current directory to path, for ipfs tool.
PATH=$(pwd)/bin:${PATH}
# 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
# assert the `ipfs` we're using is the right one.
if test `which ipfs` != $(pwd)/bin/ipfs; then
echo >&2 "Cannot find the tests' local ipfs tool."
echo >&2 "Please check test and ipfs tool installation."
exit 1
fi
# source the common hashes first.
. lib/test-lib-hashes.sh
SHARNESS_LIB="lib/sharness/sharness.sh"
. "$SHARNESS_LIB" || {
echo >&2 "Cannot source: $SHARNESS_LIB"
echo >&2 "Please check Sharness installation."
exit 1
}
# Please put go-ipfs specific shell functions below
# grab + output options
test "$TEST_NO_FUSE" != 1 && test_set_prereq FUSE
test "$TEST_EXPENSIVE" = 1 && test_set_prereq EXPENSIVE
if test "$TEST_VERBOSE" = 1; then
echo '# TEST_VERBOSE='"$TEST_VERBOSE"
echo '# TEST_NO_FUSE='"$TEST_NO_FUSE"
echo '# TEST_EXPENSIVE='"$TEST_EXPENSIVE"
fi
# source our generic test lib
. ../../ipfs-test-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_60_sec() {
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"
}
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.
# 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
}
# 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() {
# 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.
RANDOM=$$
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"
PORT_SWARM=$((RANDOM % 3000 + 12000))
ADDR_SWARM="[
\"/ip4/0.0.0.0/tcp/$PORT_SWARM\"
]"
# 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 -b=1024 > /dev/null
'
test_expect_success "prepare config -- mounting and bootstrap rm" '
mkdir mountdir ipfs ipns &&
test_config_set Mounts.IPFS "$(pwd)/ipfs" &&
test_config_set Mounts.IPNS "$(pwd)/ipns" &&
test_config_set Addresses.API "$ADDR_API" &&
test_config_set Addresses.Gateway "$ADDR_GWAY" &&
test_config_set --json Addresses.Swarm "$ADDR_SWARM" &&
ipfs bootstrap rm --all ||
test_fsh cat "\"$IPFS_PATH/config\""
'
}
test_config_ipfs_gateway_readonly() {
ADDR_GWAY=$1
test_expect_success "prepare config -- gateway address" '
test "$ADDR_GWAY" != "" &&
test_config_set "Addresses.Gateway" "$ADDR_GWAY"
'
# 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
}
test_config_ipfs_gateway_writable() {
test_config_ipfs_gateway_readonly $1
test_expect_success "prepare config -- gateway writable" '
test_config_set --bool Gateway.Writable true ||
test_fsh cat "\"$IPFS_PATH/config\""
'
}
test_launch_ipfs_daemon() {
args="$@"
test_expect_success "'ipfs daemon' succeeds" '
ipfs daemon $args >actual_daemon 2>daemon_err &
'
# we say the daemon is ready when the API server is ready.
test_expect_success "'ipfs daemon' is ready" '
IPFS_PID=$! &&
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
'
if test "$ADDR_GWAY" != ""; then
test_expect_success "'ipfs daemon' output includes Gateway address" '
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
'
fi
}
test_mount_ipfs() {
# make sure stuff is unmounted first.
test_expect_success FUSE "'ipfs mount' succeeds" '
umount "$(pwd)/ipfs" || true &&
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_str_contains() {
find=$1
shift
echo "$@" | grep "$find" >/dev/null
}
disk_usage() {
# normalize du across systems
case $(uname -s) in
Linux)
DU="du -sb"
;;
FreeBSD)
DU="du -s -A -B 1"
;;
Darwin | DragonFly | *)
DU="du -s"
;;
esac
$DU "$1" | awk "{print \$1}"
}
# 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"
}
test_check_peerid() {
peeridlen=$(echo "$1" | tr -dC "[:alnum:]" | wc -c | tr -d " ") &&
test "$peeridlen" = "46" || {
echo "Bad peerid '$1' with len '$peeridlen'"
return 1
}
}