-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_nodebuilder
More file actions
executable file
·339 lines (306 loc) · 11.2 KB
/
test_nodebuilder
File metadata and controls
executable file
·339 lines (306 loc) · 11.2 KB
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
#!/bin/sh
#
# A console output functional test script for nodebuilder
# shellcheck disable=SC2155
set -o errexit
set -o nounset
get_operating_system()
{
case "${TARGET_KERNEL}" in
Darwin | FreeBSD | NetBSD | OpenBSD)
printf '%s\n' "${TARGET_KERNEL}"
;;
*)
readonly OS_RELEASE_ID_LIKE="$(grep '^ID_LIKE=' /etc/os-release | cut -d= -f2)"
readonly OS_RELEASE_ID="$(grep '^ID=' /etc/os-release | cut -d= -f2)"
if [ -n "${OS_RELEASE_ID_LIKE}" ] || [ -n "${OS_RELEASE_ID}" ]; then
printf '%s\n' "${OS_RELEASE_ID_LIKE:-${OS_RELEASE_ID}}"
else
throw_error 'Failed to determine OS release type'
fi
;;
esac
}
handle_exit()
{
kill_tail_process
if [ -f nodebuilder ]; then
rm nodebuilder
fi
if [ -f "${STDOUT_TEST_FILENAME}" ]; then
rm "${STDOUT_TEST_FILENAME}"
fi
if [ -f "${STDERR_TEST_FILENAME}" ]; then
rm "${STDERR_TEST_FILENAME}"
fi
}
handle_error()
{
handle_exit
printf '%s\n' 'Test failed.'
}
is_valid_bitcoin_version()
{
[ -z "$1" ] && throw_error 'No arguemnt passed into is_valid_bitcoin_version().'
readonly BITCOIN_VERSION_TO_CHECK="$1"
for version in ${VALID_BITCOIN_VERSION_LIST}; do
[ "${BITCOIN_VERSION_TO_CHECK}" = "${version}" ] &&
return 0
done
return 1
}
kill_tail_process()
{
if kill -0 "${tail_pid}" > /dev/null 2>&1; then
kill -TERM "${tail_pid}" ||
kill -INT "${tail_pid}" ||
kill -HUP "${tail_pid}" ||
kill -KILL "${tail_pid}"
fi
}
print_usage()
{
printf '%s\n\n' "Usage: $0 [options]"
printf '%s\n' 'Options:'
printf '%s\n' '-b, --bitcoin-version Specify the Bitcoin version'
printf '%s\n' '-c, --compile Build Bitcoin from source'
printf '%s\n' '-h, --help Display this help message'
printf '%s\n' '-r, --ref Choose a git tef to test'
}
throw_error()
{
if [ -z "${2:-}" ]; then
echo "ERROR: $1" >&2
else
echo "ERROR at line $2: $1" >&2
fi
exit 1
}
validate_bitcoin_version()
{
[ -z "$1" ] && throw_error 'No arguemnt passed into validate_bitcoin_version().'
readonly BITCOIN_VERSION_TO_VALIDATE="$1"
if ! is_valid_bitcoin_version "${BITCOIN_VERSION_TO_VALIDATE}"; then
throw_error "The Bitcoin version '${BITCOIN_VERSION_TO_VALIDATE}' is invalid. Please use a value such as '27.0' from https-bitcoincore-dot-org/bin/"
fi
}
validate_git_ref_short_name()
{
if command -v git > /dev/null 2>&1; then
[ "$(git rev-parse --is-inside-work-tree 2> /dev/null)" = 'true' ] ||
throw_error 'Not inside a Git repository.' "${LINENO}"
[ "$(basename "$(git rev-parse --show-toplevel)")" = 'nodebuilder' ] ||
throw_error 'Not in the nodebuilder repository.' "${LINENO}"
git rev-parse --quiet --verify "$1" ||
throw_error "$1 is not a valid branch, tag, or commit." "${LINENO}"
fi
}
readonly VALID_BITCOIN_VERSION_LIST='0.9.5 0.10.0 0.10.1 0.10.2 0.10.3 0.10.4 \
0.11.0 0.11.1 0.11.2 0.12.0 0.12.1 0.13.0 0.13.1 0.13.2 \0.14.3 0.15.2 \
0.16.3 0.17.0 0.17.0.1 0.17.1 0.17.2 0.18.0 0.18.1 0.19.0 0.19.0.1 0.19.1 \
0.20.0 0.20.1 0.20.2 0.21.0 0.21.1 0.21.2 22.0 22.1 23.0 23.1 23.2 24.0 \
24.0.1 24.1 24.2 25.0 25.1 25.2 26.0 26.1 27.0'
while [ $# -gt 0 ]; do
case "$1" in
-b | --bitcoin-version)
[ -z "$2" ] && throw_error 'No argument supplied for -b|--bitcoin-version.' "${LINENO}"
readonly TARGET_BITCOIN_VERSION="$2"
validate_bitcoin_version "${TARGET_BITCOIN_VERSION}"
shift
;;
-c | --compile)
readonly COMPILE_BITCOIN='true'
;;
-h | --help)
print_usage
exit 0
;;
-r | --ref)
[ -z "$2" ] && throw_error 'No argument supplied for -r|--ref.' "${LINENO}"
readonly GIT_REF_SHORT_NAME="$2"
case "$(uname -s)" in
FreeBSD | NetBSD | OpenBSD) ;;
*)
validate_git_ref_short_name "${GIT_REF_SHORT_NAME}"
;;
esac
shift
;;
*)
throw_error "'$1' is invalid. Use -h or --help for available options."
;;
esac
shift
done
[ -z "${GIT_REF_SHORT_NAME:-}" ] && readonly GIT_REF_SHORT_NAME=''
[ -z "${TARGET_BITCOIN_VERSION:-}" ] && readonly TARGET_BITCOIN_VERSION=''
[ "${COMPILE_BITCOIN:-false}" != "true" ] && readonly COMPILE_BITCOIN="false"
readonly STDOUT_TEST_FILENAME='test_output_stdout.txt'
readonly STDERR_TEST_FILENAME='test_output_stderr.txt'
readonly TARGET_KERNEL="$(uname -s)"
readonly TARGET_OPERATING_SYSTEM="$(get_operating_system)"
[ -f "${STDOUT_TEST_FILENAME}" ] || touch "${STDOUT_TEST_FILENAME}"
tail -f "${STDOUT_TEST_FILENAME}" &
tail_pid=$!
trap 'if [ $? -eq 0 ]; then handle_exit; else handle_error; fi' EXIT
readonly NODEBUILDER_REPO_URL='https://github.com/bitcoin-tools/nodebuilder'
readonly NODEBUILDER_BINARY_URL="${NODEBUILDER_REPO_URL}/raw/${GIT_REF_SHORT_NAME:-master}/nodebuilder"
case "${TARGET_KERNEL}" in
Darwin) bitcoin_data_directory="${HOME}/Library/Application Support/Bitcoin" ;;
Linux | FreeBSD | NetBSD | OpenBSD) bitcoin_data_directory="${HOME}/.bitcoin" ;;
MINGW*) throw_error 'Windows is not supported.' ;;
*) throw_error 'Your operating system is not supported.' ;;
esac
bitcoind_pid_path="${bitcoin_data_directory}/bitcoind.pid"
[ -f nodebuilder ] || wget --no-verbose "${NODEBUILDER_BINARY_URL}"
[ -x nodebuilder ] || chmod u+x nodebuilder
nodebuilder_args=""
[ -n "${TARGET_BITCOIN_VERSION}" ] && nodebuilder_args="${nodebuilder_args} --bitcoin-version ${TARGET_BITCOIN_VERSION}"
[ "${COMPILE_BITCOIN}" = 'true' ] && nodebuilder_args="${nodebuilder_args} --compile"
if [ -n "${nodebuilder_args}" ]; then
readonly NODEBUILDER_ARGS_TRIMMED="$(printf '%s' "${nodebuilder_args}" | sed -e 's/^[[:space:]]*//')"
printf "Running nodebuilder with '%s' args\n" "${NODEBUILDER_ARGS_TRIMMED}"
readonly RUN_NODEBUILDER_COMMAND="./nodebuilder ${NODEBUILDER_ARGS_TRIMMED:-}"
else
readonly RUN_NODEBUILDER_COMMAND="./nodebuilder"
fi
# Execute the script with optional command line arguments
printf 'Executing command: %s\n' "${RUN_NODEBUILDER_COMMAND}"
if ! ${RUN_NODEBUILDER_COMMAND} \
> "${STDOUT_TEST_FILENAME}"; then
throw_error "Failed to execute nodebuilder command."
fi
# After the script runs successfully
rm nodebuilder
kill_tail_process
# Stop Bitcoin Core
if [ -f "${bitcoind_pid_path}" ]; then
read -r bitcoind_pid < "${bitcoind_pid_path}"
if command -v bitcoin-cli > /dev/null 2>&1; then
bitcoin-cli stop
bitcoind_stop_sleep_seconds=2
bitcoind_stop_sleep_counter=0
while [ -f "${bitcoind_pid_path}" ]; do
sleep "${bitcoind_stop_sleep_seconds}"
# TODO: debug intermittent stalled stop issue
# shellcheck disable=SC2009
ps aux | grep "${bitcoind_pid}"
bitcoind_stop_sleep_counter=$((bitcoind_stop_sleep_counter + 1))
if [ "$((bitcoind_stop_sleep_seconds * bitcoind_stop_sleep_counter))" -ge 3600 ]; then
throw_error 'Stopping Bitcoin Core took over an hour.'
fi
done
else
throw_error 'Unable to find bitcoin-cli in PATH.'
fi
fi
if [ -s "${STDERR_TEST_FILENAME}" ]; then
printf '%s\n' 'Printing the contents of stderr:'
cat "${STDERR_TEST_FILENAME}"
printf '\n%s\n' 'FAILURE: Detected runtime errors.'
exit 1
fi
# Positve matches for all environments
for message in \
'INFO: Detected: running (Linux|macOS|FreeBSD|NetBSD|OpenBSD).$' \
'INFO: Checking for internet.$' \
'INFO: Internet checks passed.$' \
'INFO: Bitcoin Core [1-9][0-9]*\.[0-9]+(\.[0-9]+)?(rc[1-9])? (not|was) found.$' \
'INFO: Installing Bitcoin Core [1-9][0-9]*\.[0-9]+(\.[0-9]+)?(rc[1-9])?.$' \
'INFO: Setting the default node behavior.$' \
'INFO: Found data already synced... [0-9]+ GiB.$' \
'INFO: Found free space available... [0-9]+ [GM]iB.$' \
'INFO: Starting Bitcoin Core.$' \
'INFO: Checking the RPC status.$' \
'INFO: This screen will refresh in 10 seconds.' \
'INFO: Syncing the block headers \((first|second) pass\).$' \
'INFO: Syncing the blockchain. Please be patient.$' \
'Sync progress: [0-9]+\.[0-9]{3} %$' \
'Blocks remaining: [0-9]*$' \
'Current chain tip: (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [ 1-3][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} UTC 2[0-9]{3}$' \
'Chain sync size: [0-9]+ [GM]iB$' \
'Disk free space: [0-9]+ GiB$'; do
if ! grep -Eq "${message}" "${STDOUT_TEST_FILENAME}" > /dev/null 2>&1; then
printf '%s\n' "FAILURE: Expected message ${message} not found."
exit 1
fi
done
# Negative matches for all environments
for message in \
'apt-utils' \
'libzmq' \
'BDB' \
'Berkeley DB' \
'Installing Bitcoin Core.$' \
"TERM variable '[0-9A-Za-z]*' is not recognized. Disabling color." \
'Checking system memory... 0 of 0 GiB free.' \
'Checking system memory... 0.0 of 0.0 GiB free.' \
'INFO: Found free space available... 0 GiB.' \
'Sync progress: [0-9]+\.[0-9]{4} %' \
'Disk free space: (0 G|[0-9]+ M)iB'; do
if grep -Eq "${message}" "${STDOUT_TEST_FILENAME}" > /dev/null 2>&1; then
printf '%s\n' "FAILURE: Unexpected message ${message} found."
exit 1
fi
done
# Positve matches when compiling from source
if [ "${COMPILE_BITCOIN}" = 'true' ] ||
[ "${TARGET_KERNEL}" = 'FreeBSD' ] ||
[ "${TARGET_KERNEL}" = 'NetBSD' ] ||
[ "${TARGET_KERNEL}" = 'OpenBSD' ] ||
{
[ -f /etc/os-release ] && [ "${TARGET_OPERATING_SYSTEM}" = 'alpine' ]
}; then
for message in \
'INFO: Ensuring compile dependencies.$' \
'INFO: Downloading Bitcoin source code.$' \
'INFO: Analyzing hardware configuration.$' \
'INFO: Configuring the build environment.$' \
'INFO: Compiling source code. Please wait.$'; do
if ! grep -Eq "${message}" "${STDOUT_TEST_FILENAME}" > /dev/null 2>&1; then
printf '%s\n' "FAILURE: Expected message ${message} not found."
exit 1
fi
done
# Positive matches when downloading package
else
for message in \
'INFO: Downloading Bitcoin Core.$' \
'INFO: Validated the checksum.$' \
'INFO: Found [0-9]+ good signatures.$' \
'INFO: Extracting Bitcoin Core.$' \
'INFO: Running the unit tests.$' \
'INFO: Removing installation files.$' \
'INFO: Bitcoin Core installation complete.$'; do
if ! grep -Eq "${message}" "${STDOUT_TEST_FILENAME}" > /dev/null 2>&1; then
printf '%s\n' "FAILURE: Expected message ${message} not found."
exit 1
fi
done
# from nodebuilder, gpg_good_signatures_required='7'
message='Found [0-6] good signatures.$'
if grep -Eq "${message}" "${STDOUT_TEST_FILENAME}" > /dev/null 2>&1; then
printf '%s\n' "FAILURE: Unexpected message ${message} found."
exit 1
fi
fi
# Positive matches for all environments except macOS
if [ "${TARGET_KERNEL}" != 'Darwin' ]; then
for message in \
'INFO: Ensuring base dependencies.$' \
'INFO: Creating application shortcuts.$'; do
if ! grep -Eq "${message}" "${STDOUT_TEST_FILENAME}" > /dev/null 2>&1; then
printf '%s\n' "FAILURE: Expected message ${message} not found."
exit 1
fi
done
fi
# Positve matches for Linux kernel environments
if [ "${TARGET_KERNEL}" = 'Linux' ]; then
message='Checking system memory... [0-9]+\.[0-9] of [0-9]+\.[0-9] GiB free.$'
if ! grep -Eq "${message}" "${STDOUT_TEST_FILENAME}" > /dev/null 2>&1; then
printf '%s\n' "FAILURE: Expected message ${message} not found."
exit 1
fi
fi
printf '%s\n' 'PASS: All console output tests passed.'