run.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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. UP='up'
  38. while [ "$#" -gt 0 ]; do
  39. case $1 in
  40. -h|--help)
  41. help
  42. exit 0
  43. ;;
  44. --app)
  45. WHICH_APP="${2%/}"
  46. shift 2
  47. ;;
  48. --only-up)
  49. ONLY_UP='yes'
  50. shift 1
  51. ;;
  52. --keep-up)
  53. KEEP_UP='yes'
  54. shift 1
  55. ;;
  56. --attach)
  57. ATTACH='yes'
  58. shift 1
  59. ;;
  60. --stop)
  61. STOP='yes'
  62. shift 1
  63. ;;
  64. --console)
  65. CONSOLE='yes'
  66. shift 1
  67. ;;
  68. --ci)
  69. IS_CI='yes'
  70. UP='up --quiet-pull'
  71. shift 1
  72. ;;
  73. --)
  74. shift 1
  75. REBAR3CT="$*"
  76. shift $#
  77. ;;
  78. *)
  79. echo "unknown option $1"
  80. exit 1
  81. ;;
  82. esac
  83. done
  84. if [ "${WHICH_APP}" = 'novalue' ]; then
  85. echo "must provide --app arg"
  86. help
  87. exit 1
  88. fi
  89. if [ ! -d "${WHICH_APP}" ]; then
  90. echo "must provide an existing path for --app arg"
  91. help
  92. exit 1
  93. fi
  94. ERLANG_CONTAINER='erlang'
  95. DOCKER_CT_ENVS_FILE="${WHICH_APP}/docker-ct"
  96. if [ -f "${WHICH_APP}/BSL.txt" ]; then
  97. if [ -n "${PROFILE:-}" ] && [ "${PROFILE}" != 'emqx-enterprise' ]; then
  98. echo "bad_profile: PROFILE=${PROFILE} will not work for app ${WHICH_APP}"
  99. exit 1
  100. fi
  101. fi
  102. if [ -z "${PROFILE+x}" ]; then
  103. case "${WHICH_APP}" in
  104. apps/emqx)
  105. export PROFILE='emqx-enterprise'
  106. ;;
  107. apps/emqx_bridge)
  108. export PROFILE='emqx-enterprise'
  109. ;;
  110. # emqx_connector test suite is using kafka bridge which is only available in emqx-enterprise
  111. apps/emqx_connector)
  112. export PROFILE='emqx-enterprise'
  113. ;;
  114. apps/emqx_dashboard)
  115. export PROFILE='emqx-enterprise'
  116. ;;
  117. apps/emqx_rule_engine)
  118. export PROFILE='emqx-enterprise'
  119. ;;
  120. apps/*)
  121. if [[ -f "${WHICH_APP}/BSL.txt" ]]; then
  122. export PROFILE='emqx-enterprise'
  123. else
  124. export PROFILE='emqx'
  125. fi
  126. ;;
  127. *)
  128. export PROFILE="${PROFILE:-emqx}"
  129. ;;
  130. esac
  131. fi
  132. if [ -f "$DOCKER_CT_ENVS_FILE" ]; then
  133. # shellcheck disable=SC2002
  134. CT_DEPS="$(cat "$DOCKER_CT_ENVS_FILE" | xargs)"
  135. fi
  136. CT_DEPS="${ERLANG_CONTAINER} ${CT_DEPS:-}"
  137. FILES=( )
  138. for dep in ${CT_DEPS}; do
  139. case "${dep}" in
  140. erlang)
  141. FILES+=( '.ci/docker-compose-file/docker-compose.yaml' )
  142. ;;
  143. toxiproxy)
  144. FILES+=( '.ci/docker-compose-file/docker-compose-toxiproxy.yaml' )
  145. ;;
  146. influxdb)
  147. FILES+=( '.ci/docker-compose-file/docker-compose-influxdb-tcp.yaml'
  148. '.ci/docker-compose-file/docker-compose-influxdb-tls.yaml' )
  149. ;;
  150. mongo)
  151. FILES+=( '.ci/docker-compose-file/docker-compose-mongo-single-tcp.yaml'
  152. '.ci/docker-compose-file/docker-compose-mongo-single-tls.yaml' )
  153. ;;
  154. mongo_rs_sharded)
  155. FILES+=( '.ci/docker-compose-file/docker-compose-mongo-replicaset-tcp.yaml'
  156. '.ci/docker-compose-file/docker-compose-mongo-sharded-tcp.yaml' )
  157. ;;
  158. redis)
  159. FILES+=( '.ci/docker-compose-file/docker-compose-redis-single-tcp.yaml'
  160. '.ci/docker-compose-file/docker-compose-redis-single-tls.yaml'
  161. '.ci/docker-compose-file/docker-compose-redis-sentinel-tcp.yaml'
  162. '.ci/docker-compose-file/docker-compose-redis-sentinel-tls.yaml' )
  163. ;;
  164. redis_cluster)
  165. FILES+=( '.ci/docker-compose-file/docker-compose-redis-cluster-tcp.yaml'
  166. '.ci/docker-compose-file/docker-compose-redis-cluster-tls.yaml' )
  167. ;;
  168. mysql)
  169. FILES+=( '.ci/docker-compose-file/docker-compose-mysql-tcp.yaml'
  170. '.ci/docker-compose-file/docker-compose-mysql-tls.yaml' )
  171. ;;
  172. pgsql)
  173. FILES+=( '.ci/docker-compose-file/docker-compose-pgsql-tcp.yaml'
  174. '.ci/docker-compose-file/docker-compose-pgsql-tls.yaml' )
  175. ;;
  176. kafka)
  177. FILES+=( '.ci/docker-compose-file/docker-compose-kafka.yaml' )
  178. ;;
  179. tdengine)
  180. FILES+=( '.ci/docker-compose-file/docker-compose-tdengine-restful.yaml' )
  181. ;;
  182. clickhouse)
  183. FILES+=( '.ci/docker-compose-file/docker-compose-clickhouse.yaml' )
  184. ;;
  185. dynamo)
  186. FILES+=( '.ci/docker-compose-file/docker-compose-dynamo.yaml' )
  187. ;;
  188. rocketmq)
  189. FILES+=( '.ci/docker-compose-file/docker-compose-rocketmq.yaml' )
  190. ;;
  191. cassandra)
  192. FILES+=( '.ci/docker-compose-file/docker-compose-cassandra.yaml' )
  193. ;;
  194. sqlserver)
  195. ODBC_REQUEST='yes'
  196. FILES+=( '.ci/docker-compose-file/docker-compose-sqlserver.yaml' )
  197. ;;
  198. opents)
  199. FILES+=( '.ci/docker-compose-file/docker-compose-opents.yaml' )
  200. ;;
  201. pulsar)
  202. FILES+=( '.ci/docker-compose-file/docker-compose-pulsar.yaml' )
  203. ;;
  204. oracle)
  205. FILES+=( '.ci/docker-compose-file/docker-compose-oracle.yaml' )
  206. ;;
  207. iotdb)
  208. FILES+=( '.ci/docker-compose-file/docker-compose-iotdb.yaml' )
  209. ;;
  210. rabbitmq)
  211. FILES+=( '.ci/docker-compose-file/docker-compose-rabbitmq.yaml' )
  212. ;;
  213. minio)
  214. FILES+=( '.ci/docker-compose-file/docker-compose-minio-tcp.yaml'
  215. '.ci/docker-compose-file/docker-compose-minio-tls.yaml' )
  216. ;;
  217. gcp_emulator)
  218. FILES+=( '.ci/docker-compose-file/docker-compose-gcp-emulator.yaml' )
  219. ;;
  220. hstreamdb)
  221. FILES+=( '.ci/docker-compose-file/docker-compose-hstreamdb.yaml' )
  222. ;;
  223. kinesis)
  224. FILES+=( '.ci/docker-compose-file/docker-compose-kinesis.yaml' )
  225. ;;
  226. greptimedb)
  227. FILES+=( '.ci/docker-compose-file/docker-compose-greptimedb.yaml' )
  228. ;;
  229. ldap)
  230. FILES+=( '.ci/docker-compose-file/docker-compose-ldap.yaml' )
  231. ;;
  232. otel)
  233. FILES+=( '.ci/docker-compose-file/docker-compose-otel.yaml' )
  234. ;;
  235. elasticsearch)
  236. FILES+=( '.ci/docker-compose-file/docker-compose-elastic-search-tls.yaml' )
  237. ;;
  238. *)
  239. echo "unknown_ct_dependency $dep"
  240. exit 1
  241. ;;
  242. esac
  243. done
  244. if [ "$ODBC_REQUEST" = 'yes' ]; then
  245. INSTALL_ODBC="./scripts/install-msodbc-driver.sh"
  246. else
  247. INSTALL_ODBC="echo 'msodbc driver not requested'"
  248. fi
  249. for file in "${FILES[@]}"; do
  250. DC="$DC -f $file"
  251. done
  252. DOCKER_USER="$(id -u)"
  253. export DOCKER_USER
  254. TTY=''
  255. if [[ -t 1 ]]; then
  256. TTY='-t'
  257. fi
  258. # ensure directory with secrets is created by current user before running compose
  259. mkdir -p /tmp/emqx-ci/emqx-shared-secret
  260. if [ "$STOP" = 'no' ]; then
  261. # some left-over log file has to be deleted before a new docker-compose up
  262. rm -f '.ci/docker-compose-file/redis/*.log'
  263. set +e
  264. # shellcheck disable=2086 # no quotes for UP
  265. $DC $UP -d --build --remove-orphans
  266. RESULT=$?
  267. if [ $RESULT -ne 0 ]; then
  268. mkdir -p _build/test/logs
  269. LOG='_build/test/logs/docker-compose.log'
  270. echo "Dumping docker-compose log to $LOG"
  271. $DC logs --no-color --timestamps > "$LOG"
  272. exit 1
  273. fi
  274. set -e
  275. fi
  276. if [ "$DOCKER_USER" != "root" ]; then
  277. # the user must exist inside the container for `whoami` to work
  278. docker exec -i $TTY -u root:root "$ERLANG_CONTAINER" bash -c \
  279. "useradd --uid $DOCKER_USER -M -d / emqx && \
  280. mkdir -p /.cache /.hex /.mix && \
  281. chown $DOCKER_USER /.cache /.hex /.mix && \
  282. openssl rand -base64 -hex 16 > /.erlang.cookie && \
  283. chown $DOCKER_USER /.erlang.cookie && \
  284. chmod 0400 /.erlang.cookie && \
  285. chown -R $DOCKER_USER /var/lib/secret && \
  286. $INSTALL_ODBC" || true
  287. fi
  288. if [ "$ONLY_UP" = 'yes' ]; then
  289. exit 0
  290. fi
  291. set +e
  292. if [ "$STOP" = 'yes' ]; then
  293. $DC down --remove-orphans
  294. elif [ "$ATTACH" = 'yes' ]; then
  295. docker exec -it "$ERLANG_CONTAINER" bash
  296. elif [ "$CONSOLE" = 'yes' ]; then
  297. docker exec -e PROFILE="$PROFILE" -i $TTY "$ERLANG_CONTAINER" bash -c "make run"
  298. else
  299. if [ -z "${REBAR3CT:-}" ]; then
  300. docker exec -e IS_CI="$IS_CI" \
  301. -e PROFILE="$PROFILE" \
  302. -e SUITEGROUP="${SUITEGROUP:-}" \
  303. -e ENABLE_COVER_COMPILE="${ENABLE_COVER_COMPILE:-}" \
  304. -e CT_COVER_EXPORT_PREFIX="${CT_COVER_EXPORT_PREFIX:-}" \
  305. -i $TTY "$ERLANG_CONTAINER" \
  306. bash -c "BUILD_WITHOUT_QUIC=1 make ${WHICH_APP}-ct"
  307. else
  308. # this is an ad-hoc run
  309. docker exec -e IS_CI="$IS_CI" \
  310. -e PROFILE="$PROFILE" \
  311. -i $TTY "$ERLANG_CONTAINER" \
  312. bash -c "./rebar3 ct $REBAR3CT"
  313. fi
  314. RESULT=$?
  315. if [ "$RESULT" -ne 0 ]; then
  316. LOG='_build/test/logs/docker-compose.log'
  317. echo "Dumping docker-compose log to $LOG"
  318. $DC logs --no-color --timestamps > "$LOG"
  319. fi
  320. if [ "$KEEP_UP" != 'yes' ]; then
  321. $DC down
  322. fi
  323. exit "$RESULT"
  324. fi