run.sh 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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. while [ "$#" -gt 0 ]; do
  37. case $1 in
  38. -h|--help)
  39. help
  40. exit 0
  41. ;;
  42. --app)
  43. WHICH_APP="$2"
  44. shift 2
  45. ;;
  46. --only-up)
  47. ONLY_UP='yes'
  48. shift 1
  49. ;;
  50. --keep-up)
  51. KEEP_UP='yes'
  52. shift 1
  53. ;;
  54. --attach)
  55. ATTACH='yes'
  56. shift 1
  57. ;;
  58. --stop)
  59. STOP='yes'
  60. shift 1
  61. ;;
  62. --console)
  63. CONSOLE='yes'
  64. shift 1
  65. ;;
  66. --ci)
  67. IS_CI='yes'
  68. shift 1
  69. ;;
  70. --)
  71. shift 1
  72. REBAR3CT="$*"
  73. shift $#
  74. ;;
  75. *)
  76. echo "unknown option $1"
  77. exit 1
  78. ;;
  79. esac
  80. done
  81. if [ "${WHICH_APP}" = 'novalue' ]; then
  82. echo "must provide --app arg"
  83. help
  84. exit 1
  85. fi
  86. if [[ "${WHICH_APP}" == lib-ee* && (-z "${PROFILE+x}" || "${PROFILE}" != emqx-enterprise) ]]; then
  87. echo 'You are trying to run an enterprise test case without the emqx-enterprise profile.'
  88. echo 'This will most likely not work.'
  89. echo ''
  90. echo 'Run "export PROFILE=emqx-enterprise" and "make" to fix this'
  91. exit 1
  92. fi
  93. ERLANG_CONTAINER='erlang'
  94. DOCKER_CT_ENVS_FILE="${WHICH_APP}/docker-ct"
  95. case "${WHICH_APP}" in
  96. lib-ee*)
  97. ## ensure enterprise profile when testing lib-ee applications
  98. export PROFILE='emqx-enterprise'
  99. ;;
  100. apps/emqx_bridge_kafka)
  101. ## ensure enterprise profile when testing ee applications
  102. export PROFILE='emqx-enterprise'
  103. ;;
  104. *)
  105. export PROFILE="${PROFILE:-emqx}"
  106. ;;
  107. esac
  108. if [ -f "$DOCKER_CT_ENVS_FILE" ]; then
  109. # shellcheck disable=SC2002
  110. CT_DEPS="$(cat "$DOCKER_CT_ENVS_FILE" | xargs)"
  111. fi
  112. CT_DEPS="${ERLANG_CONTAINER} ${CT_DEPS:-}"
  113. FILES=( )
  114. for dep in ${CT_DEPS}; do
  115. case "${dep}" in
  116. erlang)
  117. FILES+=( '.ci/docker-compose-file/docker-compose.yaml' )
  118. ;;
  119. toxiproxy)
  120. FILES+=( '.ci/docker-compose-file/docker-compose-toxiproxy.yaml' )
  121. ;;
  122. influxdb)
  123. FILES+=( '.ci/docker-compose-file/docker-compose-influxdb-tcp.yaml'
  124. '.ci/docker-compose-file/docker-compose-influxdb-tls.yaml' )
  125. ;;
  126. mongo)
  127. FILES+=( '.ci/docker-compose-file/docker-compose-mongo-single-tcp.yaml'
  128. '.ci/docker-compose-file/docker-compose-mongo-single-tls.yaml' )
  129. ;;
  130. mongo_rs_sharded)
  131. FILES+=( '.ci/docker-compose-file/docker-compose-mongo-replicaset-tcp.yaml'
  132. '.ci/docker-compose-file/docker-compose-mongo-sharded-tcp.yaml' )
  133. ;;
  134. redis)
  135. FILES+=( '.ci/docker-compose-file/docker-compose-redis-single-tcp.yaml'
  136. '.ci/docker-compose-file/docker-compose-redis-single-tls.yaml'
  137. '.ci/docker-compose-file/docker-compose-redis-sentinel-tcp.yaml'
  138. '.ci/docker-compose-file/docker-compose-redis-sentinel-tls.yaml' )
  139. ;;
  140. redis_cluster)
  141. FILES+=( '.ci/docker-compose-file/docker-compose-redis-cluster-tcp.yaml'
  142. '.ci/docker-compose-file/docker-compose-redis-cluster-tls.yaml' )
  143. ;;
  144. mysql)
  145. FILES+=( '.ci/docker-compose-file/docker-compose-mysql-tcp.yaml'
  146. '.ci/docker-compose-file/docker-compose-mysql-tls.yaml' )
  147. ;;
  148. pgsql)
  149. FILES+=( '.ci/docker-compose-file/docker-compose-pgsql-tcp.yaml'
  150. '.ci/docker-compose-file/docker-compose-pgsql-tls.yaml' )
  151. ;;
  152. kafka)
  153. FILES+=( '.ci/docker-compose-file/docker-compose-kafka.yaml' )
  154. ;;
  155. tdengine)
  156. FILES+=( '.ci/docker-compose-file/docker-compose-tdengine-restful.yaml' )
  157. ;;
  158. clickhouse)
  159. FILES+=( '.ci/docker-compose-file/docker-compose-clickhouse.yaml' )
  160. ;;
  161. dynamo)
  162. FILES+=( '.ci/docker-compose-file/docker-compose-dynamo.yaml' )
  163. ;;
  164. rocketmq)
  165. FILES+=( '.ci/docker-compose-file/docker-compose-rocketmq.yaml' )
  166. ;;
  167. cassandra)
  168. FILES+=( '.ci/docker-compose-file/docker-compose-cassandra.yaml' )
  169. ;;
  170. *)
  171. echo "unknown_ct_dependency $dep"
  172. exit 1
  173. ;;
  174. esac
  175. done
  176. F_OPTIONS=""
  177. for file in "${FILES[@]}"; do
  178. F_OPTIONS="$F_OPTIONS -f $file"
  179. done
  180. DOCKER_USER="$(id -u)"
  181. export DOCKER_USER
  182. TTY=''
  183. if [[ -t 1 ]]; then
  184. TTY='-t'
  185. fi
  186. # ensure directory with secrets is created by current user before running compose
  187. mkdir -p /tmp/emqx-ci/emqx-shared-secret
  188. if [ "$STOP" = 'no' ]; then
  189. # some left-over log file has to be deleted before a new docker-compose up
  190. rm -f '.ci/docker-compose-file/redis/*.log'
  191. set +e
  192. # shellcheck disable=2086 # no quotes for F_OPTIONS
  193. $DC $F_OPTIONS up -d --build --remove-orphans
  194. RESULT=$?
  195. if [ $RESULT -ne 0 ]; then
  196. mkdir -p _build/test/logs
  197. LOG='_build/test/logs/docker-compose.log'
  198. echo "Dumping docker-compose log to $LOG"
  199. # shellcheck disable=2086 # no quotes for F_OPTIONS
  200. $DC $F_OPTIONS logs --no-color --timestamps > "$LOG"
  201. exit 1
  202. fi
  203. set -e
  204. fi
  205. # rebar, mix and hex cache directory need to be writable by $DOCKER_USER
  206. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "mkdir -p /.cache /.hex /.mix && chown $DOCKER_USER /.cache /.hex /.mix"
  207. # need to initialize .erlang.cookie manually here because / is not writable by $DOCKER_USER
  208. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "openssl rand -base64 16 > /.erlang.cookie && chown $DOCKER_USER /.erlang.cookie && chmod 0400 /.erlang.cookie"
  209. # the user must exist inside the container for `whoami` to work
  210. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "useradd --uid $DOCKER_USER -M -d / emqx" || true
  211. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "chown -R $DOCKER_USER /var/lib/secret" || true
  212. if [ "$ONLY_UP" = 'yes' ]; then
  213. exit 0
  214. fi
  215. set +e
  216. if [ "$STOP" = 'yes' ]; then
  217. # shellcheck disable=2086 # no quotes for F_OPTIONS
  218. $DC $F_OPTIONS down --remove-orphans
  219. elif [ "$ATTACH" = 'yes' ]; then
  220. docker exec -it "$ERLANG_CONTAINER" bash
  221. elif [ "$CONSOLE" = 'yes' ]; then
  222. docker exec -e PROFILE="$PROFILE" -i $TTY "$ERLANG_CONTAINER" bash -c "make run"
  223. else
  224. if [ -z "${REBAR3CT:-}" ]; then
  225. docker exec -e IS_CI="$IS_CI" -e PROFILE="$PROFILE" -i $TTY "$ERLANG_CONTAINER" bash -c "BUILD_WITHOUT_QUIC=1 make ${WHICH_APP}-ct"
  226. else
  227. docker exec -e IS_CI="$IS_CI" -e PROFILE="$PROFILE" -i $TTY "$ERLANG_CONTAINER" bash -c "./rebar3 ct $REBAR3CT"
  228. fi
  229. RESULT=$?
  230. if [ "$RESULT" -ne 0 ]; then
  231. LOG='_build/test/logs/docker-compose.log'
  232. echo "Dumping docker-compose log to $LOG"
  233. # shellcheck disable=2086 # no quotes for F_OPTIONS
  234. $DC $F_OPTIONS logs --no-color --timestamps > "$LOG"
  235. fi
  236. if [ "$KEEP_UP" != 'yes' ]; then
  237. # shellcheck disable=2086 # no quotes for F_OPTIONS
  238. $DC $F_OPTIONS down
  239. fi
  240. exit "$RESULT"
  241. fi