test-release.sh 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #!/bin/bash
  2. #
  3. # mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
  4. # Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen-wallet
  9. # https://gitlab.com/mmgen/mmgen-wallet
  10. # Tested on Linux, Armbian, Raspbian, MSYS2
  11. # cfg.sh must implement:
  12. # list_avail_tests()
  13. # init_groups()
  14. # init_tests()
  15. . 'test/test-release.d/cfg.sh'
  16. run_test() {
  17. set +x
  18. tests="t_$1"
  19. skips="t_$1_skip"
  20. while read skip test; do
  21. [ "$test" ] || continue
  22. echo "${!skips}" | grep -q $skip && continue
  23. if [ "$LIST_CMDS" ]; then
  24. echo $test
  25. else
  26. test_disp=$YELLOW${test/\#/$RESET$MAGENTA\#}$RESET
  27. if [ "${test:0:1}" == '#' ]; then
  28. echo -e "$test_disp"
  29. else
  30. echo -e "${GREEN}Running:$RESET $test_disp"
  31. eval "$test" || {
  32. echo -e $RED"test-release.sh: test '$CUR_TEST' failed at command '$test'"$RESET
  33. exit 1
  34. }
  35. fi
  36. fi
  37. done <<<${!tests}
  38. }
  39. prompt_skip() {
  40. echo -n "Enter 's' to skip, or ENTER to continue: "; read -n1; echo
  41. [ "$REPLY" == 's' ] && return 0
  42. return 1
  43. }
  44. list_avail_tests() {
  45. echo "AVAILABLE TESTS:"
  46. init_tests
  47. for i in $all_tests; do
  48. z="d_$i"
  49. printf " %-8s - %s\n" $i "${!z}"
  50. done
  51. echo
  52. echo "AVAILABLE TEST GROUPS:"
  53. while read a b c; do
  54. [ "$a" ] && printf " %-8s - %s\n" $a "$c"
  55. done <<<$groups_desc
  56. echo
  57. echo "By default, all tests are run"
  58. }
  59. run_tests() {
  60. [ "$LIST_CMDS" ] || echo "Running tests: $1"
  61. for t in $1; do
  62. desc_id="d_$t" desc=${!desc_id}
  63. if [ "$SKIP_ALT_DEP" ]; then
  64. ok=$(for a in $noalt_tests; do if [ $t == $a ]; then echo 'ok'; fi; done)
  65. if [ ! "$ok" ]; then
  66. echo -e "${BLUE}Skipping altcoin test '$t'$RESET"
  67. continue
  68. fi
  69. fi
  70. if [ "$LIST_CMDS" ]; then
  71. echo -e "\n### $t: $desc"
  72. else
  73. echo -e "\n${BLUE}Testing:$RESET $GREEN$desc$RESET"
  74. fi
  75. [ "$PAUSE" ] && prompt_skip && continue
  76. CUR_TEST=$t
  77. run_test $t
  78. [ "$LIST_CMDS" ] || echo -e "${BLUE}Finished testing:$RESET $GREEN$desc$RESET"
  79. done
  80. }
  81. check_tests() {
  82. for i in $tests; do
  83. echo "$dfl_tests $extra_tests" | grep -q "\<$i\>" || {
  84. echo "$i: unrecognized argument"
  85. exit 1
  86. }
  87. done
  88. }
  89. remove_skipped_tests() {
  90. tests=$(for t in $tests; do
  91. [ "$(for s in $SKIP_LIST; do [ $t == $s ] && echo y; done)" ] && continue
  92. echo $t
  93. done)
  94. tests=$(echo $tests)
  95. }
  96. list_group_symbols() {
  97. echo -e "Default tests:\n $dfl_tests"
  98. echo -e "Extra tests:\n $extra_tests"
  99. echo -e "'noalt' test group:\n $noalt_tests"
  100. echo -e "'quick' test group:\n $quick_tests"
  101. echo -e "'qskip' test group:\n $qskip_tests"
  102. }
  103. print_ver_hash() {
  104. python3 -m pip freeze | grep "^$repo\>" | sed 's/.*sha256=//' | cut -c 1-12
  105. }
  106. install_package() {
  107. echo -e "${BLUE}Installing package$YELLOW $repo$RESET"
  108. rm -rf build dist *.egg-info
  109. ver=$(print_ver_hash)
  110. echo -e "${BLUE}Currently installed version is$MAGENTA $ver$RESET"
  111. cmd="python3 -m build --no-isolation --wheel --config-setting=quiet $STDOUT_DEVNULL"
  112. echo -e "${BLUE}Executing:$CYAN $cmd$RESET"
  113. eval $cmd
  114. cmd="python3 -m pip $QUIET install --break-system-packages dist/*.whl"
  115. echo -e "${BLUE}Executing:$CYAN $cmd$RESET"
  116. eval $cmd
  117. new_ver=$(print_ver_hash)
  118. if [ "$ver" == "$new_ver" ]; then
  119. echo -ne "${YELLOW}Version hash is unchanged. Force install? (y/N):$RESET "
  120. read -n1
  121. if [ "$REPLY" == 'y' ]; then
  122. echo
  123. cmd="python3 -m pip $QUIET install --break-system-packages --force --no-deps dist/*.whl"
  124. echo -e "${BLUE}Executing:$CYAN $cmd$RESET"
  125. eval $cmd
  126. elif [ "$REPLY" ]; then
  127. echo; return
  128. else
  129. return
  130. fi
  131. fi
  132. new_ver=$(print_ver_hash)
  133. if [ "$ver" == "$new_ver" ]; then
  134. echo -e "${RED}ERROR: version hash is unchanged$RESET"
  135. exit 1
  136. else
  137. echo -e "${GREEN}OK$RESET"
  138. fi
  139. }
  140. # start execution
  141. trap 'echo -e "${GREEN}Exiting at user request$RESET"; exit' INT
  142. umask 0022
  143. if [ "$(uname -m)" == 'armv7l' ]; then
  144. ARM32=1
  145. elif [ "$(uname -m)" == 'aarch64' ]; then
  146. ARM64=1
  147. elif [ "$MSYSTEM" ] && uname -a | grep -qi 'msys'; then
  148. MSYS2=1
  149. fi
  150. if [ "$MSYS2" ]; then
  151. DISTRO='MSYS2'
  152. else
  153. DISTRO=$(grep '^ID=' '/etc/os-release' | cut -c 4-)
  154. [ "$DISTRO" ] || { echo 'Unable to determine distro. Aborting'; exit 1; }
  155. fi
  156. cmdtest_py='test/cmdtest.py -n'
  157. objtest_py='test/objtest.py'
  158. objattrtest_py='test/objattrtest.py'
  159. unit_tests_py='test/unit_tests.py --names --quiet'
  160. tooltest_py='test/tooltest.py'
  161. tooltest2_py='test/tooltest2.py --names --quiet'
  162. gentest_py='test/gentest.py --quiet'
  163. scrambletest_py='test/scrambletest.py'
  164. altcoin_mod_opts='--quiet'
  165. mmgen_tool='cmds/mmgen-tool'
  166. pylint='PYTHONPATH=. pylint' # PYTHONPATH required by older Pythons (e.g. v3.9)
  167. python='python3'
  168. rounds=10
  169. ORIG_ARGS=$@
  170. PROGNAME=$(basename $0)
  171. init_groups
  172. while getopts hAbcdDfFILlNOps:StvV OPT
  173. do
  174. case "$OPT" in
  175. h) printf " %-16s Test MMGen release\n" "${PROGNAME}:"
  176. echo " USAGE: $PROGNAME [options] [tests or test group]"
  177. echo " OPTIONS: -h Print this help message"
  178. echo " -A Skip tests requiring altcoin modules or daemons"
  179. echo " -b Buffer keypresses for all invocations of 'test/cmdtest.py'"
  180. echo " -c Run tests in coverage mode"
  181. echo " -d Enable Python Development Mode"
  182. echo " -D Run tests in deterministic mode"
  183. echo " -f Speed up the tests by using fewer rounds"
  184. echo " -F Reduce rounds even further"
  185. echo " -I Install the package"
  186. echo " -L List available tests and test groups with description"
  187. echo " -l List the test name symbols"
  188. echo " -N Pass the --no-timings switch to test/cmdtest.py"
  189. echo " -O Use pexpect.spawn rather than popen_spawn where applicable"
  190. echo " -p Pause between tests"
  191. echo " -s LIST Skip tests in LIST (space-separated)"
  192. echo " -S Build sdist distribution, unpack, and run test"
  193. echo " -t Print the tests without running them"
  194. echo " -v Run test/cmdtest.py with '--exact-output' and other commands"
  195. echo " with '--verbose' switch"
  196. echo " -V Run test/cmdtest.py and other commands with '--verbose' switch"
  197. echo
  198. echo " For traceback output and error file support, set the EXEC_WRAPPER_TRACEBACK"
  199. echo " environment variable"
  200. exit ;;
  201. A) SKIP_ALT_DEP=1
  202. cmdtest_py+=" --no-altcoin"
  203. unit_tests_py+=" --no-altcoin-deps"
  204. scrambletest_py+=" --no-altcoin"
  205. tooltest2_py+=" --no-altcoin" ;;
  206. b) cmdtest_py+=" --buf-keypress" ;;
  207. c) mkdir -p 'test/trace'
  208. touch 'test/trace.acc'
  209. cmdtest_py+=" --coverage"
  210. tooltest_py+=" --coverage"
  211. tooltest2_py+=" --fork --coverage"
  212. scrambletest_py+=" --coverage"
  213. python="python3 -m trace --count --file=test/trace.acc --coverdir=test/trace"
  214. unit_tests_py="$python $unit_tests_py"
  215. objtest_py="$python $objtest_py"
  216. objattrtest_py="$python $objattrtest_py"
  217. gentest_py="$python $gentest_py"
  218. mmgen_tool="$python $mmgen_tool" ;&
  219. d) export PYTHONDEVMODE=1
  220. export PYTHONWARNINGS='error' ;;
  221. D) export MMGEN_TEST_SUITE_DETERMINISTIC=1
  222. export MMGEN_DISABLE_COLOR=1 ;;
  223. f) rounds=6 FAST=1 fast_opt='--fast' unit_tests_py+=" --fast" ;;
  224. F) rounds=3 FAST=1 fast_opt='--fast' unit_tests_py+=" --fast" ;;
  225. I) INSTALL_PACKAGE=1 ;;
  226. L) list_avail_tests; exit ;;
  227. l) list_group_symbols; exit ;;
  228. N) cmdtest_py+=" --no-timings" ;;
  229. O) cmdtest_py+=" --pexpect-spawn" ;;
  230. p) PAUSE=1 ;;
  231. s) SKIP_LIST+=" $OPTARG" ;;
  232. S) SDIST_TEST=1 ;;
  233. t) LIST_CMDS=1 ;;
  234. v) EXACT_OUTPUT=1 cmdtest_py+=" --exact-output" ;&
  235. V) VERBOSE='--verbose'
  236. [ "$EXACT_OUTPUT" ] || cmdtest_py+=" --verbose"
  237. unit_tests_py="${unit_tests_py/--quiet/--verbose}"
  238. altcoin_mod_opts="${altcoin_mod_opts/--quiet/--verbose}"
  239. tooltest2_py="${tooltest2_py/--quiet/--verbose}"
  240. gentest_py="${gentest_py/--quiet/--verbose}"
  241. tooltest_py+=" --verbose"
  242. mmgen_tool+=" --verbose"
  243. objattrtest_py+=" --verbose"
  244. scrambletest_py+=" --verbose"
  245. pylint+=" --verbose" ;;
  246. *) exit ;;
  247. esac
  248. done
  249. [ "$MMGEN_DISABLE_COLOR" ] || {
  250. RED="\e[31;1m" GREEN="\e[32;1m" YELLOW="\e[33;1m" BLUE="\e[34;1m" MAGENTA="\e[35;1m" CYAN="\e[36;1m"
  251. RESET="\e[0m"
  252. }
  253. [ "$INSTALL_PACKAGE" ] && { install_package; exit; }
  254. [ "$MSYS2" -a ! "$FAST" ] && tooltest2_py+=' --fork'
  255. [ "$EXACT_OUTPUT" -o "$VERBOSE" ] || objtest_py+=" -S"
  256. shift $((OPTIND-1))
  257. set -e
  258. [ "$SDIST_TEST" -a -z "$TEST_RELEASE_IN_SDIST" ] && {
  259. test_dir='.sdist-test'
  260. rm -rf build dist *.egg-info $test_dir
  261. python3 -m build --no-isolation --sdist
  262. mkdir $test_dir
  263. tar -C $test_dir -axf dist/*.tar.gz
  264. cd $test_dir/mmgen-*
  265. python3 setup.py build_ext --inplace
  266. echo -e "\n${BLUE}Running 'test/test-release $ORIG_ARGS'$RESET $YELLOW[PWD=$PWD]$RESET\n"
  267. export TEST_RELEASE_IN_SDIST=1
  268. test/test-release.sh $ORIG_ARGS
  269. exit
  270. }
  271. case $1 in
  272. '') tests=$dfl_tests ;;
  273. 'default') tests=$dfl_tests ;;
  274. 'extra') tests=$extra_tests ;;
  275. 'noalt') tests=$noalt_tests
  276. SKIP_ALT_DEP=1
  277. cmdtest_py+=" --no-altcoin"
  278. unit_tests_py+=" --no-altcoin-deps"
  279. scrambletest_py+=" --no-altcoin" ;;
  280. 'quick') tests=$quick_tests ;;
  281. 'qskip') tests=$qskip_tests ;;
  282. *) tests="$*" ;;
  283. esac
  284. rounds_min=$((rounds / 2))
  285. for n in 2 5 10 20 50 100 200 500 1000; do
  286. eval "rounds${n}x=$((rounds*n))"
  287. done
  288. init_tests
  289. remove_skipped_tests
  290. check_tests
  291. test/cmdtest.py clean
  292. start_time=$(date +%s)
  293. run_tests "$tests"
  294. elapsed=$(($(date +%s)-start_time))
  295. elapsed_fmt=$(printf %02d:%02d $((elapsed/60)) $((elapsed%60)))
  296. [ "$LIST_CMDS" ] || {
  297. if [ "$MMGEN_TEST_SUITE_DETERMINISTIC" ]; then
  298. echo -e "\n${GREEN}All OK"
  299. else
  300. echo -e "\n${GREEN}All OK. Total elapsed time: $elapsed_fmt$RESET"
  301. fi
  302. }