run.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #!/usr/bin/env bash
  2. ## This script runs CT (and necessary dependencies) in docker container(s)
  3. set -euo pipefail
  4. # ensure dir
  5. cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")/../.."
  6. help() {
  7. echo
  8. echo "-h|--help: To display this usage info"
  9. echo "--app lib_dir/app_name: For which app to run start docker-compose, and run common tests"
  10. echo "--console: Start EMQX in console mode but do not run test cases"
  11. echo "--attach: Attach to the Erlang docker container without running any test case"
  12. echo "--stop: Stop running containers for the given app"
  13. echo "--only-up: Only start the testbed but do not run CT"
  14. echo "--keep-up: Keep the testbed running after CT"
  15. echo "--ci: Set this flag in GitHub action to enforce no tests are skipped"
  16. echo "--: If any, all args after '--' are passed to rebar3 ct"
  17. echo " otherwise it runs the entire app's CT"
  18. }
  19. set +e
  20. if docker compose version; then
  21. DC='docker compose'
  22. elif command -v docker-compose; then
  23. DC='docker-compose'
  24. else
  25. echo 'Neither "docker compose" or "docker-compose" are available, stop.'
  26. exit 1
  27. fi
  28. set -e
  29. WHICH_APP='novalue'
  30. CONSOLE='no'
  31. KEEP_UP='no'
  32. ONLY_UP='no'
  33. ATTACH='no'
  34. STOP='no'
  35. IS_CI='no'
  36. ODBC_REQUEST='no'
  37. while [ "$#" -gt 0 ]; do
  38. case $1 in
  39. -h|--help)
  40. help
  41. exit 0
  42. ;;
  43. --app)
  44. WHICH_APP="${2%/}"
  45. shift 2
  46. ;;
  47. --only-up)
  48. ONLY_UP='yes'
  49. shift 1
  50. ;;
  51. --keep-up)
  52. KEEP_UP='yes'
  53. shift 1
  54. ;;
  55. --attach)
  56. ATTACH='yes'
  57. shift 1
  58. ;;
  59. --stop)
  60. STOP='yes'
  61. shift 1
  62. ;;
  63. --console)
  64. CONSOLE='yes'
  65. shift 1
  66. ;;
  67. --ci)
  68. IS_CI='yes'
  69. shift 1
  70. ;;
  71. --)
  72. shift 1
  73. REBAR3CT="$*"
  74. shift $#
  75. ;;
  76. *)
  77. echo "unknown option $1"
  78. exit 1
  79. ;;
  80. esac
  81. done
  82. if [ "${WHICH_APP}" = 'novalue' ]; then
  83. echo "must provide --app arg"
  84. help
  85. exit 1
  86. fi
  87. if [ ! -d "${WHICH_APP}" ]; then
  88. echo "must provide an existing path for --app arg"
  89. help
  90. exit 1
  91. fi
  92. if [[ "${WHICH_APP}" == lib-ee* && (-z "${PROFILE+x}" || "${PROFILE}" != emqx-enterprise) ]]; then
  93. echo 'You are trying to run an enterprise test case without the emqx-enterprise profile.'
  94. echo 'This will most likely not work.'
  95. echo ''
  96. echo 'Run "export PROFILE=emqx-enterprise" and "make" to fix this'
  97. exit 1
  98. fi
  99. ERLANG_CONTAINER='erlang'
  100. DOCKER_CT_ENVS_FILE="${WHICH_APP}/docker-ct"
  101. case "${WHICH_APP}" in
  102. lib-ee*)
  103. ## ensure enterprise profile when testing lib-ee applications
  104. export PROFILE='emqx-enterprise'
  105. ;;
  106. apps/*)
  107. if [[ -f "${WHICH_APP}/BSL.txt" ]]; then
  108. export PROFILE='emqx-enterprise'
  109. else
  110. export PROFILE='emqx'
  111. fi
  112. ;;
  113. *)
  114. export PROFILE="${PROFILE:-emqx}"
  115. ;;
  116. esac
  117. if [ -f "$DOCKER_CT_ENVS_FILE" ]; then
  118. # shellcheck disable=SC2002
  119. CT_DEPS="$(cat "$DOCKER_CT_ENVS_FILE" | xargs)"
  120. fi
  121. CT_DEPS="${ERLANG_CONTAINER} ${CT_DEPS:-}"
  122. FILES=( )
  123. for dep in ${CT_DEPS}; do
  124. case "${dep}" in
  125. erlang)
  126. FILES+=( '.ci/docker-compose-file/docker-compose.yaml' )
  127. ;;
  128. toxiproxy)
  129. FILES+=( '.ci/docker-compose-file/docker-compose-toxiproxy.yaml' )
  130. ;;
  131. influxdb)
  132. FILES+=( '.ci/docker-compose-file/docker-compose-influxdb-tcp.yaml'
  133. '.ci/docker-compose-file/docker-compose-influxdb-tls.yaml' )
  134. ;;
  135. mongo)
  136. FILES+=( '.ci/docker-compose-file/docker-compose-mongo-single-tcp.yaml'
  137. '.ci/docker-compose-file/docker-compose-mongo-single-tls.yaml' )
  138. ;;
  139. mongo_rs_sharded)
  140. FILES+=( '.ci/docker-compose-file/docker-compose-mongo-replicaset-tcp.yaml'
  141. '.ci/docker-compose-file/docker-compose-mongo-sharded-tcp.yaml' )
  142. ;;
  143. redis)
  144. FILES+=( '.ci/docker-compose-file/docker-compose-redis-single-tcp.yaml'
  145. '.ci/docker-compose-file/docker-compose-redis-single-tls.yaml'
  146. '.ci/docker-compose-file/docker-compose-redis-sentinel-tcp.yaml'
  147. '.ci/docker-compose-file/docker-compose-redis-sentinel-tls.yaml' )
  148. ;;
  149. redis_cluster)
  150. FILES+=( '.ci/docker-compose-file/docker-compose-redis-cluster-tcp.yaml'
  151. '.ci/docker-compose-file/docker-compose-redis-cluster-tls.yaml' )
  152. ;;
  153. mysql)
  154. FILES+=( '.ci/docker-compose-file/docker-compose-mysql-tcp.yaml'
  155. '.ci/docker-compose-file/docker-compose-mysql-tls.yaml' )
  156. ;;
  157. pgsql)
  158. FILES+=( '.ci/docker-compose-file/docker-compose-pgsql-tcp.yaml'
  159. '.ci/docker-compose-file/docker-compose-pgsql-tls.yaml' )
  160. ;;
  161. kafka)
  162. FILES+=( '.ci/docker-compose-file/docker-compose-kafka.yaml' )
  163. ;;
  164. tdengine)
  165. FILES+=( '.ci/docker-compose-file/docker-compose-tdengine-restful.yaml' )
  166. ;;
  167. clickhouse)
  168. FILES+=( '.ci/docker-compose-file/docker-compose-clickhouse.yaml' )
  169. ;;
  170. dynamo)
  171. FILES+=( '.ci/docker-compose-file/docker-compose-dynamo.yaml' )
  172. ;;
  173. rocketmq)
  174. FILES+=( '.ci/docker-compose-file/docker-compose-rocketmq.yaml' )
  175. ;;
  176. cassandra)
  177. FILES+=( '.ci/docker-compose-file/docker-compose-cassandra.yaml' )
  178. ;;
  179. sqlserver)
  180. ODBC_REQUEST='yes'
  181. FILES+=( '.ci/docker-compose-file/docker-compose-sqlserver.yaml' )
  182. ;;
  183. opents)
  184. FILES+=( '.ci/docker-compose-file/docker-compose-opents.yaml' )
  185. ;;
  186. pulsar)
  187. FILES+=( '.ci/docker-compose-file/docker-compose-pulsar.yaml' )
  188. ;;
  189. oracle)
  190. FILES+=( '.ci/docker-compose-file/docker-compose-oracle.yaml' )
  191. ;;
  192. iotdb)
  193. FILES+=( '.ci/docker-compose-file/docker-compose-iotdb.yaml' )
  194. ;;
  195. rabbitmq)
  196. FILES+=( '.ci/docker-compose-file/docker-compose-rabbitmq.yaml' )
  197. ;;
  198. minio)
  199. FILES+=( '.ci/docker-compose-file/docker-compose-minio-tcp.yaml'
  200. '.ci/docker-compose-file/docker-compose-minio-tls.yaml' )
  201. ;;
  202. gcp_emulator)
  203. FILES+=( '.ci/docker-compose-file/docker-compose-gcp-emulator.yaml' )
  204. ;;
  205. hstreamdb)
  206. FILES+=( '.ci/docker-compose-file/docker-compose-hstreamdb.yaml' )
  207. ;;
  208. kinesis)
  209. FILES+=( '.ci/docker-compose-file/docker-compose-kinesis.yaml' )
  210. ;;
  211. greptimedb)
  212. FILES+=( '.ci/docker-compose-file/docker-compose-greptimedb.yaml' )
  213. ;;
  214. ldap)
  215. FILES+=( '.ci/docker-compose-file/docker-compose-ldap.yaml' )
  216. ;;
  217. *)
  218. echo "unknown_ct_dependency $dep"
  219. exit 1
  220. ;;
  221. esac
  222. done
  223. if [ "$ODBC_REQUEST" = 'yes' ]; then
  224. INSTALL_ODBC="./scripts/install-msodbc-driver.sh"
  225. else
  226. INSTALL_ODBC="echo 'msodbc driver not requested'"
  227. fi
  228. F_OPTIONS=""
  229. for file in "${FILES[@]}"; do
  230. F_OPTIONS="$F_OPTIONS -f $file"
  231. done
  232. DOCKER_USER="$(id -u)"
  233. export DOCKER_USER
  234. TTY=''
  235. if [[ -t 1 ]]; then
  236. TTY='-t'
  237. fi
  238. # ensure directory with secrets is created by current user before running compose
  239. mkdir -p /tmp/emqx-ci/emqx-shared-secret
  240. if [ "$STOP" = 'no' ]; then
  241. # some left-over log file has to be deleted before a new docker-compose up
  242. rm -f '.ci/docker-compose-file/redis/*.log'
  243. set +e
  244. # shellcheck disable=2086 # no quotes for F_OPTIONS
  245. $DC $F_OPTIONS up -d --build --remove-orphans
  246. RESULT=$?
  247. if [ $RESULT -ne 0 ]; then
  248. mkdir -p _build/test/logs
  249. LOG='_build/test/logs/docker-compose.log'
  250. echo "Dumping docker-compose log to $LOG"
  251. # shellcheck disable=2086 # no quotes for F_OPTIONS
  252. $DC $F_OPTIONS logs --no-color --timestamps > "$LOG"
  253. exit 1
  254. fi
  255. set -e
  256. fi
  257. # rebar, mix and hex cache directory need to be writable by $DOCKER_USER
  258. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "mkdir -p /.cache /.hex /.mix && chown $DOCKER_USER /.cache /.hex /.mix"
  259. # need to initialize .erlang.cookie manually here because / is not writable by $DOCKER_USER
  260. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "openssl rand -base64 -hex 16 > /.erlang.cookie && chown $DOCKER_USER /.erlang.cookie && chmod 0400 /.erlang.cookie"
  261. # the user must exist inside the container for `whoami` to work
  262. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "useradd --uid $DOCKER_USER -M -d / emqx" || true
  263. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "chown -R $DOCKER_USER /var/lib/secret" || true
  264. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "$INSTALL_ODBC" || true
  265. if [ "$ONLY_UP" = 'yes' ]; then
  266. exit 0
  267. fi
  268. set +e
  269. if [ "$STOP" = 'yes' ]; then
  270. # shellcheck disable=2086 # no quotes for F_OPTIONS
  271. $DC $F_OPTIONS down --remove-orphans
  272. elif [ "$ATTACH" = 'yes' ]; then
  273. docker exec -it "$ERLANG_CONTAINER" bash
  274. elif [ "$CONSOLE" = 'yes' ]; then
  275. docker exec -e PROFILE="$PROFILE" -i $TTY "$ERLANG_CONTAINER" bash -c "make run"
  276. else
  277. if [ -z "${REBAR3CT:-}" ]; then
  278. docker exec -e IS_CI="$IS_CI" \
  279. -e PROFILE="$PROFILE" \
  280. -e SUITEGROUP="${SUITEGROUP:-}" \
  281. -e CT_COVER_EXPORT_PREFIX="${CT_COVER_EXPORT_PREFIX:-}" \
  282. -i $TTY "$ERLANG_CONTAINER" \
  283. bash -c "BUILD_WITHOUT_QUIC=1 make ${WHICH_APP}-ct"
  284. else
  285. # this is an ad-hoc run
  286. docker exec -e IS_CI="$IS_CI" \
  287. -e PROFILE="$PROFILE" \
  288. -i $TTY "$ERLANG_CONTAINER" \
  289. bash -c "./rebar3 ct $REBAR3CT"
  290. fi
  291. RESULT=$?
  292. if [ "$RESULT" -ne 0 ]; then
  293. LOG='_build/test/logs/docker-compose.log'
  294. echo "Dumping docker-compose log to $LOG"
  295. # shellcheck disable=2086 # no quotes for F_OPTIONS
  296. $DC $F_OPTIONS logs --no-color --timestamps > "$LOG"
  297. fi
  298. if [ "$KEEP_UP" != 'yes' ]; then
  299. # shellcheck disable=2086 # no quotes for F_OPTIONS
  300. $DC $F_OPTIONS down
  301. fi
  302. exit "$RESULT"
  303. fi