Small sh "framework" to test some server responses
sh
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

check.sh 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. #!/bin/sh
  2. #check.sh : functionnal check functions for various server
  3. #Copyright (C) 2016 Weber Yann
  4. #
  5. #This program is free software; you can redistribute it and/or modify
  6. #it under the terms of the GNU General Public License as published by
  7. #the Free Software Foundation; either version 3 of the License, or
  8. #any later version.
  9. #
  10. #This program is distributed in the hope that it will be useful,
  11. #but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. #GNU General Public License for more details.
  14. #
  15. #You should have received a copy of the GNU General Public License
  16. #along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. if [ -z "$color" ]
  18. then
  19. color=1
  20. fi
  21. if [ -z "$verbose" ]
  22. then
  23. verbose=1
  24. fi
  25. if [ -z "$exit_on_fail" ]
  26. then
  27. exit_on_fail=1
  28. fi
  29. alias echo="/bin/echo -e"
  30. col_reset() {
  31. if [ "$color" -gt 0 ]
  32. then
  33. tput sgr0
  34. fi
  35. }
  36. col_set() {
  37. if [ -z "$1" ]
  38. then
  39. return
  40. fi
  41. if [ "$color" -gt 0 ]
  42. then
  43. tput setaf $1
  44. fi
  45. }
  46. log() {
  47. echo "$(col_set $3)[$(printf "%7s" "$1")]$(col_reset) $2"
  48. }
  49. datetime() {
  50. date -Iseconds
  51. }
  52. logdate() {
  53. echo "$(date -Iseconds) $(col_set $3)[$(printf "%7s" "$1")]$(col_reset) $2"
  54. }
  55. fail() {
  56. if [ "$verbose" -lt 2 ]
  57. then
  58. echo "" #for the dot printed with -n
  59. fi
  60. test_msg="$1"
  61. test_status=1
  62. }
  63. err() {
  64. msg="$(log ERR "$1" 1)"
  65. test_msg="$1"
  66. test_status=-1
  67. }
  68. success() {
  69. msg="$(log OK "$1" 2)"
  70. test_msg="$1"
  71. test_status=0
  72. }
  73. #
  74. # Tests & testcase functions
  75. #
  76. tc_name=""
  77. tc_infos=""
  78. tc_fail=0
  79. tc_run=0
  80. total_fail=0
  81. total_run=0
  82. test_msg=""
  83. test_status=0
  84. _test_setup() {
  85. test_status=0
  86. test_msg=""
  87. }
  88. TC_INIT() {
  89. tc_name=$1
  90. tc_infos=$2
  91. tc_fail=0
  92. tc_run=0
  93. msg="Running testcase '$tc_name'"
  94. if [ -n "$tc_infos" ]
  95. then
  96. msg="${msg} ($tc_infos)"
  97. fi
  98. if [ "$verbose" -gt 0 ]
  99. then
  100. logdate TESTCASE "$msg" 4
  101. fi
  102. }
  103. TC_END() {
  104. if [ "$tc_fail" -gt 0 ]
  105. then
  106. if [ "$verbose" -gt 1 ]
  107. then
  108. logdate TESTCASE "-------------$tc_name END------------" 1
  109. fi
  110. logdate FAIL "Testcase '$tc_name' tests: ${tc_run} fails: $(col_set 1)${tc_fail}$(col_reset)" 1
  111. if [ "$exit_on_fail" -ne 0 ]
  112. then
  113. CHECK_REPORT
  114. fi
  115. elif [ "$verbose" -eq 1 ]
  116. then
  117. echo "" #for the dot printed with -n
  118. logdate TESTCASE "Testcase '$tc_name' tests:${tc_run} fails: $tc_fail" 2
  119. elif [ "$verbose" -gt 1 ]
  120. then
  121. logdate TESTCASE "-------------$tc_name END------------" 4
  122. fi
  123. tc_name=""
  124. tc_infos=""
  125. tc_fail=0
  126. tc_run=0
  127. }
  128. TC_RUN() {
  129. _test_setup
  130. cmd=$1
  131. shift
  132. args=""
  133. case $#
  134. in
  135. 1)$cmd "$1";;
  136. 2)$cmd "$1" "$2";;
  137. 3)$cmd "$1" "$2" "$3";;
  138. 4)$cmd "$1" "$2" "$3" "$4";;
  139. *)fail "To many arguments for $cmd"
  140. esac
  141. #$cmd $args
  142. tc_run=$(expr $tc_run + 1)
  143. total_run=$(expr $total_run + 1)
  144. if [ "$test_status" -ne 0 ]
  145. then
  146. err_type="FAIL"
  147. if [ "$test_status" -lt 0 ]
  148. then
  149. err_type="ERR"
  150. fi
  151. tc_fail=$(expr $tc_fail + 1)
  152. total_fail=$(expr $total_fail + 1)
  153. logdate $err_type "$tc_name: $test_msg" 1 >&2
  154. elif [ "$verbose" -gt 1 ]
  155. then
  156. logdate OK "$tc_name: $test_msg" 2
  157. else
  158. echo -n '.'
  159. fi
  160. }
  161. CHECK_START() {
  162. logdate STATUS "Starting tests" 3
  163. }
  164. CHECK_REPORT() {
  165. if [ "$verbose" -eq 0 -a "$tc_fail" -eq "0" ]
  166. then
  167. echo "" # for dot printed with -n
  168. fi
  169. if [ "$verbose" -gt 0 ]
  170. then
  171. logdate STATUS "All tests done" 3
  172. fi
  173. if [ "$total_fail" -gt 0 ]
  174. then
  175. logdate FAIL "Summary : tests: ${total_run} fails: $(col_set 1)${total_fail}$(col_reset)" 1
  176. exit 1
  177. else
  178. logdate OK "Summary : tests:${total_run} fails: $total_fail" 2
  179. exit 0
  180. fi
  181. }
  182. #
  183. # HTTP/HTTPS tests
  184. #
  185. _check_http_status() {
  186. # $1 url
  187. # $2 status
  188. # $* curl options
  189. url=$1
  190. shift 1
  191. expt=$1
  192. if [ -z "$1" ]
  193. then
  194. expt=200
  195. fi
  196. shift 1
  197. status=$(curl -s -o /dev/null -w "%{http_code}" $* $url)
  198. if [ "$status" -ne "$expt" ]
  199. then
  200. fail "Check http status $expt for $url : $status returned"
  201. elif [ "$verbose" -gt 0 ]
  202. then
  203. success "Check http status $status for $url"
  204. fi
  205. }
  206. check_http_status() {
  207. # $1 url
  208. # $2 status
  209. _check_http_status $1 $2
  210. }
  211. check_http_200() {
  212. _check_http_status $1 200
  213. }
  214. check_https_cert() {
  215. # Check that SSL Cert is valid
  216. # $1 URL
  217. status=$(curl -s -o /dev/null -w "%{http_code}" https://$1)
  218. rep=$?
  219. if [ "$rep" -eq 0 ]
  220. then
  221. success "https://$1 cert verified"
  222. return
  223. fi
  224. status=$(curl -k -s -o /dev/null -q "%{http_code}" https://$1)
  225. rep=$?
  226. if [ "$rep" -eq 0 ]
  227. then
  228. fail "https://$1 cert invalid"
  229. else
  230. err "Unable to curl https://$1"
  231. fi
  232. }
  233. check_html_title() {
  234. url="$1"
  235. expt="$2"
  236. tmpxsl=$(mktemp -t XSL.XXXXXXXXXXX)
  237. echo '<?xml version="1.0"?>
  238. <xsl:stylesheet version="1.0"
  239. xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  240. <xsl:output method = "text"/>
  241. <xsl:template match="/">
  242. <xsl:value-of select="/html/head/title"/>
  243. </xsl:template>
  244. </xsl:stylesheet>' > $tmpxsl
  245. tmphtml=$(mktemp -t html.XXXXXXXXX)
  246. curl --silent $url > $tmphtml
  247. title=$(xsltproc --html --novalid $tmpxsl $tmphtml 2>/dev/null)
  248. if [ "$?" -ne "0" ]
  249. then
  250. title=$(xsltproc --novalid $tmpxsl $tmphtml 2>/dev/null)
  251. fi
  252. if [ "$title" = "$expt" ]
  253. then
  254. success "$url HTML title is '$expt'"
  255. else
  256. fail "$url HTML title is '$title' but '$expt' expected"
  257. fi
  258. rm $tmpxsl $tmphtml 2>/dev/null
  259. }
  260. check_audiostream() {
  261. # Uses one of mplayer or mpv to retrieve a small amount of stream
  262. # and attempt to decode it.
  263. # $1 Stream URL
  264. MPLAYER="`which mplayer`"
  265. MPV="`which mpv`"
  266. if [ -x $MPLAYER ]
  267. then
  268. check_audiostream_mplayer "$1"
  269. elif [ -x $MPV ]
  270. then
  271. check_audiostream_mpv "$1"
  272. else
  273. fail "Unable to find mplayer nor mpv"
  274. fi
  275. }
  276. check_audiostream_mplayer() {
  277. # Uses mplayer to fetch 128Kb (by default) of stream
  278. # $1 Stream URL
  279. # $2 size in kb without the kb suffix
  280. # $3 mplayer path
  281. tmpfile=$(mktemp -t check_audiostream.XXXXXXXXX)
  282. sz="$2"
  283. if [ -z "$sz" ]
  284. then
  285. sz="128"
  286. fi
  287. MPLAYER="$3"
  288. if [ -z "$MPLAYER" ]
  289. then
  290. MPLAYER="`which mplayer`"
  291. fi
  292. sz_kb="${sz}kb"
  293. expt_sz="`expr $sz \* 8`"
  294. if [ "$verbose" -gt 1 ]
  295. then
  296. logdate INFO "$tc_name: Running mplayer on '$1' for $sz_kb" 3
  297. fi
  298. $MPLAYER -endpos $sz_kb -ao pcm:file=$tmpfile "$1" 1>/dev/null 2>/dev/null
  299. res=$?
  300. bytes=$(du -b $tmpfile | cut -f1)
  301. rm $tmpfile 2>/dev/null
  302. if [ "$bytes" -lt $expt_sz ]
  303. then
  304. fail "mplayer retrieved ${bytes}B of stream instead of expected $sz_kb"
  305. return
  306. fi
  307. if [ "$res" -eq 0 ]
  308. then
  309. success "mplayer retrieved $sz of stream on $1"
  310. else
  311. fail "mplayer failed to retrieve stream on $1"
  312. fi
  313. }
  314. check_audiostream_mpv() {
  315. # Uses mpv to fetch 4s of audio stream
  316. # $1 Stream URL
  317. # $2 time of stream to fetch
  318. # $3 mpv path
  319. time="$2"
  320. if [ -z "$time" ]
  321. then
  322. time="4"
  323. fi
  324. MPV="$3"
  325. if [ -z "$MPV" ]
  326. then
  327. MPV="`which mpv`"
  328. fi
  329. if [ "$verbose" -gt 1 ]
  330. then
  331. logdate INFO "$tc_name: Running mpv on '$1' for ${time}s" 3
  332. fi
  333. start_time=`date "+%s"`
  334. $MPV --vo=null --ao=null --o=/dev/null --of=wav --length $time "$1" 1> /dev/null 2>/dev/null
  335. res=$?
  336. stop_time=`date "+%s"`
  337. run_time=`expr $stop_time - $start_time`
  338. if [ $run_time -lt $time ]
  339. then
  340. fail "mpv stopped running ${run_time} after launch but ${time}s should be received"
  341. return
  342. fi
  343. if [ $res -eq 0 ]
  344. then
  345. success "mpv retrieved ${time}s of stream on $1"
  346. else
  347. fail "mpv failed to retrieve ${time}s of stream on $1"
  348. fi
  349. }
  350. check_ping() {
  351. ns=$1
  352. count=$2
  353. if [ -z "$count" ]
  354. then
  355. count=5
  356. fi
  357. ping -i 0.2 -c $count $ns 2>/dev/null >/dev/null
  358. res=$?
  359. if [ "$res" -ne 0 ]
  360. then
  361. fail "unable to ping '$ns'"
  362. else
  363. success "successfully send $count ping to '$ns'"
  364. fi
  365. }
  366. check_git_repo() {
  367. tmpdir=$(mktemp -d -t check_git.XXXXXXXXX)
  368. git clone $1 $tmpdir 2>/dev/null 1>/dev/null
  369. res=$?
  370. rm -Rf $tmpdir
  371. if [ "$res" -ne 0 ]
  372. then
  373. fail "unable to clone git repo '$1'"
  374. else
  375. success "git repo '$1' cloned'"
  376. fi
  377. }
  378. #
  379. # Jabber XMPP checks
  380. #
  381. __xmpp_probe() {
  382. serv=$1
  383. timeout=$2
  384. type=$3
  385. payload="<?xml version=\"1.0\"?>\n<stream:stream xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\" xmlns=\"jabber:$type\" to=\"${1}\" xml:lang=\"en\" xmlns:xml=\"http://www.w3.org/XML/1998/namespace\">\n"
  386. if [ "$verbose" -gt 2 ]
  387. then
  388. echo -e $payload | sed -e "s/^/$(datetime) [ DEBUG] Sent : /" >&2
  389. fi
  390. echo -e $payload
  391. sleep $timeout
  392. }
  393. _xmpp_probe() {
  394. serv=$1
  395. port=$2
  396. timeout=$3
  397. type=$4
  398. tmpres=$(mktemp -t xmpp_probe.XXXXXXXXX)
  399. echo "$(__xmpp_probe $serv $timeout $type| nc -q2 $serv $port)</stream:stream>" | xmllint --format - > $tmpres
  400. if [ "$verbose" -gt 2 ]
  401. then
  402. cat $tmpres | sed -e "s/^/$(datetime) [ DEBUG] Recv : /" >&2
  403. fi
  404. cat $tmpres
  405. rm $tmpres
  406. }
  407. _check_xmpp_ns() {
  408. ns1=$1
  409. expt_ns=$2
  410. expt_port=$3
  411. dnsq="_xmpp-${4}._tcp.$1"
  412. rep="$(dig $dnsq srv +short | cut -d" " -f3,4)"
  413. if [ "$rep" = "$expt_port ${expt_ns}." ]
  414. then
  415. success "$dnsq = '$rep'"
  416. else
  417. fail "$dnsq = '$rep' but '$expt_port ${expt_ns}.' expected"
  418. fi
  419. }
  420. check_xmpp_serv_ns() {
  421. _check_xmpp_ns "$1" "$2" "$3" "server"
  422. }
  423. check_xmpp_client_ns() {
  424. _check_xmpp_ns "$1" "$2" "$3" "client"
  425. }
  426. _check_xmpp_server() {
  427. serv=$1
  428. port=$2
  429. timeout=$3
  430. type=$4
  431. if [ -z "$port" ]
  432. then
  433. port=5222
  434. fi
  435. if [ -z "$timeout" ]
  436. then
  437. timeout=2
  438. fi
  439. if [ "$verbose" -gt 1 ]
  440. then
  441. tpe="client"
  442. if [ "$type" = "server" ]
  443. then
  444. tpe="S2S"
  445. fi
  446. logdate INFO "$tc_name: Connecting to XMPP $serv $tpe port $port (timeout=${timeout}s)" 3
  447. fi
  448. stream=$(_xmpp_probe $serv $port $timeout $type| head -n2 | tail -n1)
  449. if [ -z "$stream" ]
  450. then
  451. fail "Empty reply from $serv:$port"
  452. return
  453. fi
  454. if [ "$type" = "client" ]
  455. then
  456. infos=$(echo $stream | sed -E 's/^<([^ ]+).* xmlns="([^"]+)".* from="([^"]+)" .*$/\1 \2 \3/')
  457. else
  458. infos="$(echo $stream | sed -E 's/^<([^ ]+).* xmlns="([^"]+)" .*$/\1 \2/') $serv"
  459. fi
  460. if echo "$infos" | grep "jabber:$type" >/dev/null
  461. then
  462. success "Successfully connected to XMPP $type $serv:$port"
  463. else
  464. fail "Unexpected reply from $serv:$port : $infos"
  465. fi
  466. }
  467. check_xmpp_server_client() {
  468. _check_xmpp_server "$1" "$2" "$3" "client"
  469. }
  470. check_xmpp_server_s2s() {
  471. _check_xmpp_server "$1" "$2" "$3" "server"
  472. }
  473. check_xmpp_ssl() {
  474. serv=$1
  475. port=$2
  476. if [ -z "$port" ]
  477. then
  478. port=5222
  479. fi
  480. openssl s_client -connect $serv:$port </dev/null -starttls xmpp >/dev/null 2>/dev/null
  481. rep=$?
  482. if [ "$rep" -eq 0 ]
  483. then
  484. success "Openssl successfully negociating XMPP ssl with $serv:$port"
  485. else
  486. fail "Openssl failed negociating XMPP ssl with $serv:$port"
  487. fi
  488. }
  489. #
  490. # SSH checks
  491. #
  492. check_ssh_nc() {
  493. host=$1
  494. port=$2
  495. if [ -z "$port" ]
  496. then
  497. port=22
  498. fi
  499. rep="$(nc -w1 $host $port </dev/null)"
  500. res=$?
  501. if [ "$res" -ne "0" ]
  502. then
  503. fail "Netcat unable to connect to $host:$port"
  504. return
  505. fi
  506. if echo $rep | grep "^SSH-2.0-OpenSSH" >/dev/null
  507. then
  508. success "OpenSSH replied on $host:$port"
  509. else
  510. fail "Bad reply from $host:$port : '$rep'"
  511. fi
  512. }
  513. check_ssh_key() {
  514. host="$1"
  515. testkey="$2"
  516. keytype="$3"
  517. port="$4"
  518. if [ -z "$port" ]
  519. then
  520. port=22
  521. fi
  522. if [ -z "$keytype" ]
  523. then
  524. keytype="rsa"
  525. fi
  526. key=$(ssh-keyscan -p $port -t $keytype $host 2>/dev/null | cut -d " " -f3)
  527. if [ -z "$key" ]
  528. then
  529. fail "SSH server not responding"
  530. return
  531. elif [ "$key" = "$testkey" ]
  532. then
  533. success "OpenSSH $host:$port key is $testkey"
  534. return
  535. else
  536. fail "OpenSSH $host:$port missmatch : "
  537. logdate ERR "Expected : $testkey" 1
  538. logdate ERR "Received : $key" 1
  539. return
  540. fi
  541. }
  542. check_mpc() {
  543. # check_mpc [$host [$port] ]
  544. # tests if you can contact an MPD server in a client way
  545. # returns the current state of the server
  546. host=$1
  547. port=$2
  548. if [ -z "$host" ]
  549. then
  550. host=127.0.0.1
  551. fi
  552. if [ -z "$port" ]
  553. then
  554. port=6600
  555. fi
  556. if echo "status" | nc -w 1 "$host" "$port" | head -1 | grep "^OK MPD"
  557. then
  558. success "MPD server can be contacted on $host:$port"
  559. status=$(echo "status" | nc -w 1 "$host" "$port" | grep "^state:"|cut -d: -f2)
  560. success "It's state is : $status"
  561. fi
  562. }