run.sh 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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 "--suites SUITE1,SUITE2: Comma separated SUITE names to run. e.g. apps/emqx/test/emqx_SUITE.erl"
  11. echo "--console: Start EMQX in console mode but do not run test cases"
  12. echo "--attach: Attach to the Erlang docker container without running any test case"
  13. echo "--stop: Stop running containers for the given app"
  14. echo "--only-up: Only start the testbed but do not run CT"
  15. echo "--keep-up: Keep the testbed running after CT"
  16. echo "--ci: Set this flag in GitHub action to enforce no tests are skipped"
  17. echo "--" If any, all args after '--' are passed to rebar3 ct
  18. echo " otherwise it runs the entire app's CT"
  19. }
  20. WHICH_APP='novalue'
  21. CONSOLE='no'
  22. KEEP_UP='no'
  23. ONLY_UP='no'
  24. ATTACH='no'
  25. STOP='no'
  26. IS_CI='no'
  27. while [ "$#" -gt 0 ]; do
  28. case $1 in
  29. -h|--help)
  30. help
  31. exit 0
  32. ;;
  33. --app)
  34. WHICH_APP="$2"
  35. shift 2
  36. ;;
  37. --only-up)
  38. ONLY_UP='yes'
  39. shift 1
  40. ;;
  41. --keep-up)
  42. KEEP_UP='yes'
  43. shift 1
  44. ;;
  45. --attach)
  46. ATTACH='yes'
  47. shift 1
  48. ;;
  49. --stop)
  50. STOP='yes'
  51. shift 1
  52. ;;
  53. --console)
  54. CONSOLE='yes'
  55. shift 1
  56. ;;
  57. --ci)
  58. IS_CI='yes'
  59. shift 1
  60. ;;
  61. --)
  62. shift 1
  63. REBAR3CT="$*"
  64. shift $#
  65. ;;
  66. *)
  67. echo "unknown option $1"
  68. exit 1
  69. ;;
  70. esac
  71. done
  72. if [ "${WHICH_APP}" = 'novalue' ]; then
  73. echo "must provide --app arg"
  74. help
  75. exit 1
  76. fi
  77. ERLANG_CONTAINER='erlang'
  78. DOCKER_CT_ENVS_FILE="${WHICH_APP}/docker-ct"
  79. case "${WHICH_APP}" in
  80. lib-ee*)
  81. ## ensure enterprise profile when testing lib-ee applications
  82. export PROFILE='emqx-enterprise'
  83. ;;
  84. *)
  85. export PROFILE="${PROFILE:-emqx}"
  86. ;;
  87. esac
  88. if [ -f "$DOCKER_CT_ENVS_FILE" ]; then
  89. # shellcheck disable=SC2002
  90. CT_DEPS="$(cat "$DOCKER_CT_ENVS_FILE" | xargs)"
  91. fi
  92. CT_DEPS="${ERLANG_CONTAINER} ${CT_DEPS:-}"
  93. FILES=( )
  94. for dep in ${CT_DEPS}; do
  95. case "${dep}" in
  96. erlang)
  97. FILES+=( '.ci/docker-compose-file/docker-compose.yaml' )
  98. ;;
  99. toxiproxy)
  100. FILES+=( '.ci/docker-compose-file/docker-compose-toxiproxy.yaml' )
  101. ;;
  102. influxdb)
  103. FILES+=( '.ci/docker-compose-file/docker-compose-influxdb-tcp.yaml'
  104. '.ci/docker-compose-file/docker-compose-influxdb-tls.yaml' )
  105. ;;
  106. mongo)
  107. FILES+=( '.ci/docker-compose-file/docker-compose-mongo-single-tcp.yaml'
  108. '.ci/docker-compose-file/docker-compose-mongo-single-tls.yaml' )
  109. ;;
  110. mongo_rs_sharded)
  111. FILES+=( '.ci/docker-compose-file/docker-compose-mongo-replicaset-tcp.yaml'
  112. '.ci/docker-compose-file/docker-compose-mongo-sharded-tcp.yaml' )
  113. ;;
  114. redis)
  115. FILES+=( '.ci/docker-compose-file/docker-compose-redis-single-tcp.yaml'
  116. '.ci/docker-compose-file/docker-compose-redis-single-tls.yaml'
  117. '.ci/docker-compose-file/docker-compose-redis-sentinel-tcp.yaml'
  118. '.ci/docker-compose-file/docker-compose-redis-sentinel-tls.yaml' )
  119. ;;
  120. redis_cluster)
  121. FILES+=( '.ci/docker-compose-file/docker-compose-redis-cluster-tcp.yaml'
  122. '.ci/docker-compose-file/docker-compose-redis-cluster-tls.yaml' )
  123. ;;
  124. mysql)
  125. FILES+=( '.ci/docker-compose-file/docker-compose-mysql-tcp.yaml'
  126. '.ci/docker-compose-file/docker-compose-mysql-tls.yaml' )
  127. ;;
  128. pgsql)
  129. FILES+=( '.ci/docker-compose-file/docker-compose-pgsql-tcp.yaml'
  130. '.ci/docker-compose-file/docker-compose-pgsql-tls.yaml' )
  131. ;;
  132. kafka)
  133. # Kafka container generates root owned ssl files
  134. # the files are shared with EMQX (with a docker volume)
  135. NEED_ROOT=yes
  136. FILES+=( '.ci/docker-compose-file/docker-compose-kafka.yaml' )
  137. ;;
  138. *)
  139. echo "unknown_ct_dependency $dep"
  140. exit 1
  141. ;;
  142. esac
  143. done
  144. F_OPTIONS=""
  145. for file in "${FILES[@]}"; do
  146. F_OPTIONS="$F_OPTIONS -f $file"
  147. done
  148. ORIG_UID_GID="$UID:$UID"
  149. if [[ "${NEED_ROOT:-}" == 'yes' ]]; then
  150. export UID_GID='root:root'
  151. else
  152. # Passing $UID to docker-compose to be used in erlang container
  153. # as owner of the main process to avoid git repo permissions issue.
  154. # Permissions issue happens because we are mounting local filesystem
  155. # where files are owned by $UID to docker container where it's using
  156. # root (UID=0) by default, and git is not happy about it.
  157. export UID_GID="$ORIG_UID_GID"
  158. fi
  159. if [ "$STOP" = 'no' ]; then
  160. # shellcheck disable=2086 # no quotes for F_OPTIONS
  161. docker-compose $F_OPTIONS up -d --build --remove-orphans
  162. fi
  163. # /emqx is where the source dir is mounted to the Erlang container
  164. # in .ci/docker-compose-file/docker-compose.yaml
  165. TTY=''
  166. if [[ -t 1 ]]; then
  167. TTY='-t'
  168. fi
  169. echo "Fixing file owners and permissions for $UID_GID"
  170. # rebar and hex cache directory need to be writable by $UID
  171. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "mkdir -p /.cache && chown $UID_GID /.cache && chown -R $UID_GID /emqx"
  172. # need to initialize .erlang.cookie manually here because / is not writable by $UID
  173. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "openssl rand -base64 16 > /.erlang.cookie && chown $UID_GID /.erlang.cookie && chmod 0400 /.erlang.cookie"
  174. restore_ownership() {
  175. if [[ "$ORIG_UID_GID" != "$UID_GID" ]]; then
  176. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c "chown -R $ORIG_UID_GID /emqx"
  177. fi
  178. }
  179. if [ "$ONLY_UP" = 'yes' ]; then
  180. exit 0
  181. fi
  182. set +e
  183. if [ "$STOP" = 'yes' ]; then
  184. # shellcheck disable=2086 # no quotes for F_OPTIONS
  185. docker-compose $F_OPTIONS down --remove-orphans
  186. elif [ "$ATTACH" = 'yes' ]; then
  187. docker exec -it "$ERLANG_CONTAINER" bash
  188. restore_ownership
  189. elif [ "$CONSOLE" = 'yes' ]; then
  190. docker exec -e PROFILE="$PROFILE" -i $TTY "$ERLANG_CONTAINER" bash -c "make run"
  191. restore_ownership
  192. else
  193. if [ -z "${REBAR3CT:-}" ]; then
  194. docker exec -e IS_CI="$IS_CI" -e PROFILE="$PROFILE" -i $TTY "$ERLANG_CONTAINER" bash -c "BUILD_WITHOUT_QUIC=1 make ${WHICH_APP}-ct"
  195. else
  196. docker exec -e IS_CI="$IS_CI" -e PROFILE="$PROFILE" -i $TTY "$ERLANG_CONTAINER" bash -c "./rebar3 ct $REBAR3CT"
  197. fi
  198. RESULT=$?
  199. restore_ownership
  200. if [ $RESULT -ne 0 ]; then
  201. LOG='_build/test/logs/docker-compose.log'
  202. echo "Dumping docker-compose log to $LOG"
  203. # shellcheck disable=2086 # no quotes for F_OPTIONS
  204. docker-compose $F_OPTIONS logs --no-color --timestamps > "$LOG"
  205. fi
  206. if [ "$KEEP_UP" != 'yes' ]; then
  207. # shellcheck disable=2086 # no quotes for F_OPTIONS
  208. docker-compose $F_OPTIONS down
  209. fi
  210. exit $RESULT
  211. fi