complement.sh 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #!/usr/bin/env bash
  2. # This script is designed for developers who want to test their code
  3. # against Complement.
  4. #
  5. # It makes a Synapse image which represents the current checkout,
  6. # builds a synapse-complement image on top, then runs tests with it.
  7. #
  8. # By default the script will fetch the latest Complement main branch and
  9. # run tests with that. This can be overridden to use a custom Complement
  10. # checkout by setting the COMPLEMENT_DIR environment variable to the
  11. # filepath of a local Complement checkout or by setting the COMPLEMENT_REF
  12. # environment variable to pull a different branch or commit.
  13. #
  14. # By default Synapse is run in monolith mode. This can be overridden by
  15. # setting the WORKERS environment variable.
  16. #
  17. # You can optionally give a "-f" argument (for "fast") before any to skip
  18. # rebuilding the docker images, if you just want to rerun the tests.
  19. #
  20. # Remaining commandline arguments are passed through to `go test`. For example,
  21. # you can supply a regular expression of test method names via the "-run"
  22. # argument:
  23. #
  24. # ./complement.sh -run "TestOutboundFederation(Profile|Send)"
  25. #
  26. # Specifying TEST_ONLY_SKIP_DEP_HASH_VERIFICATION=1 will cause `poetry export`
  27. # to not emit any hashes when building the Docker image. This then means that
  28. # you can use 'unverifiable' sources such as git repositories as dependencies.
  29. # Exit if a line returns a non-zero exit code
  30. set -e
  31. # Helper to emit annotations that collapse portions of the log in GitHub Actions
  32. echo_if_github() {
  33. if [[ -n "$GITHUB_WORKFLOW" ]]; then
  34. echo $*
  35. fi
  36. }
  37. # Helper to print out the usage instructions
  38. usage() {
  39. cat >&2 <<EOF
  40. Usage: $0 [-f] <go test arguments>...
  41. Run the complement test suite on Synapse.
  42. -f, --fast
  43. Skip rebuilding the docker images, and just use the most recent
  44. 'complement-synapse:latest' image.
  45. Conflicts with --build-only.
  46. --build-only
  47. Only build the Docker images. Don't actually run Complement.
  48. Conflicts with -f/--fast.
  49. -e, --editable
  50. Use an editable build of Synapse, rebuilding the image if necessary.
  51. This is suitable for use in development where a fast turn-around time
  52. is important.
  53. Not suitable for use in CI in case the editable environment is impure.
  54. For help on arguments to 'go test', run 'go help testflag'.
  55. EOF
  56. }
  57. # parse our arguments
  58. skip_docker_build=""
  59. skip_complement_run=""
  60. while [ $# -ge 1 ]; do
  61. arg=$1
  62. case "$arg" in
  63. "-h")
  64. usage
  65. exit 1
  66. ;;
  67. "-f"|"--fast")
  68. skip_docker_build=1
  69. ;;
  70. "--build-only")
  71. skip_complement_run=1
  72. ;;
  73. "-e"|"--editable")
  74. use_editable_synapse=1
  75. ;;
  76. *)
  77. # unknown arg: presumably an argument to gotest. break the loop.
  78. break
  79. esac
  80. shift
  81. done
  82. # enable buildkit for the docker builds
  83. export DOCKER_BUILDKIT=1
  84. # Change to the repository root
  85. cd "$(dirname $0)/.."
  86. # Check for a user-specified Complement checkout
  87. if [[ -z "$COMPLEMENT_DIR" ]]; then
  88. COMPLEMENT_REF=${COMPLEMENT_REF:-main}
  89. echo "COMPLEMENT_DIR not set. Fetching Complement checkout from ${COMPLEMENT_REF}..."
  90. wget -Nq https://github.com/matrix-org/complement/archive/${COMPLEMENT_REF}.tar.gz
  91. tar -xzf ${COMPLEMENT_REF}.tar.gz
  92. COMPLEMENT_DIR=complement-${COMPLEMENT_REF}
  93. echo "Checkout available at 'complement-${COMPLEMENT_REF}'"
  94. fi
  95. if [ -n "$use_editable_synapse" ]; then
  96. if [[ -e synapse/synapse_rust.abi3.so ]]; then
  97. # In an editable install, back up the host's compiled Rust module to prevent
  98. # inconvenience; the container will overwrite the module with its own copy.
  99. mv -n synapse/synapse_rust.abi3.so synapse/synapse_rust.abi3.so~host
  100. # And restore it on exit:
  101. synapse_pkg=`realpath synapse`
  102. trap "mv -f '$synapse_pkg/synapse_rust.abi3.so~host' '$synapse_pkg/synapse_rust.abi3.so'" EXIT
  103. fi
  104. editable_mount="$(realpath .):/editable-src:z"
  105. if docker inspect complement-synapse-editable &>/dev/null; then
  106. # complement-synapse-editable already exists: see if we can still use it:
  107. # - The Rust module must still be importable; it will fail to import if the Rust source has changed.
  108. # - The Poetry lock file must be the same (otherwise we assume dependencies have changed)
  109. # First set up the module in the right place for an editable installation.
  110. docker run --rm -v $editable_mount --entrypoint 'cp' complement-synapse-editable -- /synapse_rust.abi3.so.bak /editable-src/synapse/synapse_rust.abi3.so
  111. if (docker run --rm -v $editable_mount --entrypoint 'python' complement-synapse-editable -c 'import synapse.synapse_rust' \
  112. && docker run --rm -v $editable_mount --entrypoint 'diff' complement-synapse-editable --brief /editable-src/poetry.lock /poetry.lock.bak); then
  113. skip_docker_build=1
  114. else
  115. echo "Editable Synapse image is stale. Will rebuild."
  116. unset skip_docker_build
  117. fi
  118. fi
  119. fi
  120. if [ -z "$skip_docker_build" ]; then
  121. if [ -n "$use_editable_synapse" ]; then
  122. # Build a special image designed for use in development with editable
  123. # installs.
  124. docker build -t synapse-editable \
  125. -f "docker/editable.Dockerfile" .
  126. docker build -t synapse-workers-editable \
  127. --build-arg FROM=synapse-editable \
  128. -f "docker/Dockerfile-workers" .
  129. docker build -t complement-synapse-editable \
  130. --build-arg FROM=synapse-workers-editable \
  131. -f "docker/complement/Dockerfile" "docker/complement"
  132. # Prepare the Rust module
  133. docker run --rm -v $editable_mount --entrypoint 'cp' complement-synapse-editable -- /synapse_rust.abi3.so.bak /editable-src/synapse/synapse_rust.abi3.so
  134. else
  135. # Build the base Synapse image from the local checkout
  136. echo_if_github "::group::Build Docker image: matrixdotorg/synapse"
  137. docker build -t matrixdotorg/synapse \
  138. --build-arg TEST_ONLY_SKIP_DEP_HASH_VERIFICATION \
  139. --build-arg TEST_ONLY_IGNORE_POETRY_LOCKFILE \
  140. -f "docker/Dockerfile" .
  141. echo_if_github "::endgroup::"
  142. # Build the workers docker image (from the base Synapse image we just built).
  143. echo_if_github "::group::Build Docker image: matrixdotorg/synapse-workers"
  144. docker build -t matrixdotorg/synapse-workers -f "docker/Dockerfile-workers" .
  145. echo_if_github "::endgroup::"
  146. # Build the unified Complement image (from the worker Synapse image we just built).
  147. echo_if_github "::group::Build Docker image: complement/Dockerfile"
  148. docker build -t complement-synapse \
  149. -f "docker/complement/Dockerfile" "docker/complement"
  150. echo_if_github "::endgroup::"
  151. fi
  152. fi
  153. if [ -n "$skip_complement_run" ]; then
  154. echo "Skipping Complement run as requested."
  155. exit
  156. fi
  157. export COMPLEMENT_BASE_IMAGE=complement-synapse
  158. if [ -n "$use_editable_synapse" ]; then
  159. export COMPLEMENT_BASE_IMAGE=complement-synapse-editable
  160. export COMPLEMENT_HOST_MOUNTS="$editable_mount"
  161. fi
  162. extra_test_args=()
  163. test_tags="synapse_blacklist,msc3787,msc3874,msc3890,msc3391,msc3930,faster_joins"
  164. # All environment variables starting with PASS_ will be shared.
  165. # (The prefix is stripped off before reaching the container.)
  166. export COMPLEMENT_SHARE_ENV_PREFIX=PASS_
  167. # It takes longer than 10m to run the whole suite.
  168. extra_test_args+=("-timeout=60m")
  169. if [[ -n "$WORKERS" ]]; then
  170. # Use workers.
  171. export PASS_SYNAPSE_COMPLEMENT_USE_WORKERS=true
  172. # Pass through the workers defined. If none, it will be an empty string
  173. export PASS_SYNAPSE_WORKER_TYPES="$WORKER_TYPES"
  174. # Workers can only use Postgres as a database.
  175. export PASS_SYNAPSE_COMPLEMENT_DATABASE=postgres
  176. # And provide some more configuration to complement.
  177. # It can take quite a while to spin up a worker-mode Synapse for the first
  178. # time (the main problem is that we start 14 python processes for each test,
  179. # and complement likes to do two of them in parallel).
  180. export COMPLEMENT_SPAWN_HS_TIMEOUT_SECS=120
  181. else
  182. export PASS_SYNAPSE_COMPLEMENT_USE_WORKERS=
  183. if [[ -n "$POSTGRES" ]]; then
  184. export PASS_SYNAPSE_COMPLEMENT_DATABASE=postgres
  185. else
  186. export PASS_SYNAPSE_COMPLEMENT_DATABASE=sqlite
  187. fi
  188. # The tests for importing historical messages (MSC2716)
  189. # only pass with monoliths, currently.
  190. test_tags="$test_tags,msc2716"
  191. fi
  192. if [[ -n "$SYNAPSE_TEST_LOG_LEVEL" ]]; then
  193. # Set the log level to what is desired
  194. export PASS_SYNAPSE_LOG_LEVEL="$SYNAPSE_TEST_LOG_LEVEL"
  195. # Allow logging sensitive things (currently SQL queries & parameters).
  196. # (This won't have any effect if we're not logging at DEBUG level overall.)
  197. # Since this is just a test suite, this is fine and won't reveal anyone's
  198. # personal information
  199. export PASS_SYNAPSE_LOG_SENSITIVE=1
  200. fi
  201. # Run the tests!
  202. echo "Images built; running complement"
  203. cd "$COMPLEMENT_DIR"
  204. go test -v -tags $test_tags -count=1 "${extra_test_args[@]}" "$@" ./tests/...