You've already forked docker-mailserver
mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2025-08-08 23:06:49 +02:00
tests(refactor): Improve consistency and documentation for test helpers (#3012)
This commit is contained in:
@ -1,7 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# ? ABOUT: Functions defined here should be used when initializing tests.
|
||||
|
||||
# ! ATTENTION: Functions prefixed with `__` are intended for internal use within this file only, not in tests.
|
||||
# ! ATTENTION: This script must not use functions from `common.bash` to
|
||||
# ! avoid dependency hell.
|
||||
|
||||
# ! -------------------------------------------------------------------
|
||||
# ? >> Miscellaneous initialization functionality
|
||||
|
||||
# Does pre-flight checks for each test: check whether certain required variables
|
||||
# are set and exports other variables.
|
||||
#
|
||||
# ## Note
|
||||
#
|
||||
# This function is internal and should not be used in tests.
|
||||
function __initialize_variables() {
|
||||
function __check_if_set() {
|
||||
if [[ ${!1+set} != 'set' ]]
|
||||
@ -28,57 +41,70 @@ function __initialize_variables() {
|
||||
NUMBER_OF_LOG_LINES=${NUMBER_OF_LOG_LINES:-10}
|
||||
}
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# ? << Miscellaneous initialization functionality
|
||||
# ! -------------------------------------------------------------------
|
||||
# ? >> File setup
|
||||
|
||||
# @param ${1} relative source in test/config folder
|
||||
# @param ${2} (optional) container name, defaults to ${BATS_TEST_FILENAME}
|
||||
# @return path to the folder where the config is duplicated
|
||||
function duplicate_config_for_container() {
|
||||
# Print the private config path for the given container or test file,
|
||||
# if no container name was given.
|
||||
#
|
||||
# @param ${1} = container name [OPTIONAL]
|
||||
function _print_private_config_path() {
|
||||
local TARGET_NAME=${1:-$(basename "${BATS_TEST_FILENAME}")}
|
||||
echo "${REPOSITORY_ROOT}/test/duplicate_configs/${TARGET_NAME}"
|
||||
}
|
||||
|
||||
|
||||
# Create a dedicated configuration directory for a test file.
|
||||
#
|
||||
# @param ${1} = relative source in test/config folder
|
||||
# @param ${2} = (optional) container name, defaults to ${BATS_TEST_FILENAME}
|
||||
# @return = path to the folder where the config is duplicated
|
||||
function _duplicate_config_for_container() {
|
||||
local OUTPUT_FOLDER
|
||||
OUTPUT_FOLDER=$(private_config_path "${2}") || return $?
|
||||
OUTPUT_FOLDER=$(_print_private_config_path "${2}")
|
||||
|
||||
rm -rf "${OUTPUT_FOLDER:?}/" || return $? # cleanup
|
||||
mkdir -p "${OUTPUT_FOLDER}" || return $?
|
||||
cp -r "${PWD}/test/config/${1:?}/." "${OUTPUT_FOLDER}" || return $?
|
||||
if [[ -z ${OUTPUT_FOLDER} ]]
|
||||
then
|
||||
echo "'OUTPUT_FOLDER' in '_duplicate_config_for_container' is empty" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
rm -rf "${OUTPUT_FOLDER:?}/"
|
||||
mkdir -p "${OUTPUT_FOLDER}"
|
||||
cp -r "${REPOSITORY_ROOT}/test/config/${1:?}/." "${OUTPUT_FOLDER}" || return $?
|
||||
|
||||
echo "${OUTPUT_FOLDER}"
|
||||
}
|
||||
|
||||
# TODO: Should also fail early on "docker logs ${1} | egrep '^[ FATAL ]'"?
|
||||
# @param ${1} name of the postfix container
|
||||
function wait_for_finished_setup_in_container() {
|
||||
local STATUS=0
|
||||
repeat_until_success_or_timeout --fatal-test "container_is_running ${1}" "${TEST_TIMEOUT_IN_SECONDS}" sh -c "docker logs ${1} | grep 'is up and running'" || STATUS=1
|
||||
|
||||
if [[ ${STATUS} -eq 1 ]]; then
|
||||
echo "Last ${NUMBER_OF_LOG_LINES} lines of container \`${1}\`'s log"
|
||||
docker logs "${1}" | tail -n "${NUMBER_OF_LOG_LINES}"
|
||||
fi
|
||||
|
||||
return ${STATUS}
|
||||
}
|
||||
|
||||
# Common defaults appropriate for most tests, override vars in each test when necessary.
|
||||
# For all tests override in `setup_file()` via an `export` var.
|
||||
# For individual test override the var via `local` var instead.
|
||||
# Common defaults appropriate for most tests.
|
||||
#
|
||||
# Override variables in test cases within a file when necessary:
|
||||
# - Use `export <VARIABLE>` in `setup_file()` to overrides for all test cases.
|
||||
# - Use `local <VARIABLE>` to override within a specific test case.
|
||||
#
|
||||
# ## Attenton
|
||||
#
|
||||
# The ENV `CONTAINER_NAME` must be set before this method is called. It only affects the
|
||||
# `TEST_TMP_CONFIG` directory created, but will be used in `common_container_create()`
|
||||
# and implicitly in other helper methods.
|
||||
#
|
||||
# ## Example
|
||||
#
|
||||
# For example, if you need an immutable config volume that can't be affected by other tests
|
||||
# in the file, then use `local TEST_TMP_CONFIG=$(duplicate_config_for_container . "${UNIQUE_ID_HERE}")`
|
||||
#
|
||||
# REQUIRED: `CONTAINER_NAME` must be set before this method is called.
|
||||
# It only affects the `TEST_TMP_CONFIG` directory created,
|
||||
# but will be used in `common_container_create()` and implicitly in other helper methods.
|
||||
function init_with_defaults() {
|
||||
# in the file, then use `local TEST_TMP_CONFIG=$(_duplicate_config_for_container . "${UNIQUE_ID_HERE}")`
|
||||
function _init_with_defaults() {
|
||||
__initialize_variables
|
||||
|
||||
export TEST_TMP_CONFIG
|
||||
TEST_TMP_CONFIG=$(duplicate_config_for_container . "${CONTAINER_NAME}")
|
||||
TEST_TMP_CONFIG=$(_duplicate_config_for_container . "${CONTAINER_NAME}")
|
||||
|
||||
# Common complimentary test files, read-only safe to share across containers:
|
||||
export TEST_FILES_CONTAINER_PATH='/tmp/docker-mailserver-test'
|
||||
export TEST_FILES_VOLUME="${REPOSITORY_ROOT}/test/test-files:${TEST_FILES_CONTAINER_PATH}:ro"
|
||||
|
||||
# The config volume cannot be read-only as some data needs to be written at container startup
|
||||
#
|
||||
# - two sed failures (unknown lines)
|
||||
# - dovecot-quotas.cf (setup-stack.sh:_setup_dovecot_quotas)
|
||||
# - postfix-aliases.cf (setup-stack.sh:_setup_postfix_aliases)
|
||||
@ -89,22 +115,43 @@ function init_with_defaults() {
|
||||
export TEST_CA_CERT="${TEST_FILES_CONTAINER_PATH}/ssl/example.test/with_ca/ecdsa/ca-cert.ecdsa.pem"
|
||||
}
|
||||
|
||||
# Using `create` and `start` instead of only `run` allows to modify
|
||||
# the container prior to starting it. Otherwise use this combined method.
|
||||
# NOTE: Forwards all args to the create method at present.
|
||||
function common_container_setup() {
|
||||
common_container_create "${@}"
|
||||
common_container_start
|
||||
|
||||
# ? << File setup
|
||||
# ! -------------------------------------------------------------------
|
||||
# ? >> Container startup
|
||||
|
||||
# Waits until the container has finished starting up.
|
||||
#
|
||||
# @param ${1} = container name
|
||||
#
|
||||
# TODO: Should also fail early on "docker logs ${1} | egrep '^[ FATAL ]'"?
|
||||
function _wait_for_finished_setup_in_container() {
|
||||
local TARGET_CONTAINER_NAME=${1:?Container name must be provided}
|
||||
local STATUS=0
|
||||
_repeat_until_success_or_timeout \
|
||||
--fatal-test "_container_is_running ${1}" \
|
||||
"${TEST_TIMEOUT_IN_SECONDS}" \
|
||||
bash -c "docker logs ${TARGET_CONTAINER_NAME} | grep 'is up and running'" || STATUS=1
|
||||
|
||||
if [[ ${STATUS} -eq 1 ]]; then
|
||||
echo "Last ${NUMBER_OF_LOG_LINES} lines of container (${TARGET_CONTAINER_NAME}) log"
|
||||
docker logs "${1}" | tail -n "${NUMBER_OF_LOG_LINES}"
|
||||
fi
|
||||
|
||||
return "${STATUS}"
|
||||
}
|
||||
|
||||
# Common docker setup is centralized here.
|
||||
# Uses `docker create` to create a container with proper defaults without starting it instantly.
|
||||
#
|
||||
# `X_EXTRA_ARGS` - Optional: Pass an array by it's variable name as a string, it will
|
||||
# be used as a reference for appending extra config into the `docker create` below:
|
||||
# @param ${1} = Pass an array by it's variable name as a string; it will be used as a
|
||||
# reference for appending extra config into the `docker create` below [OPTIONAL]
|
||||
#
|
||||
# NOTE: Using array reference for a single input parameter, as this method is still
|
||||
# under development while adapting tests to it and requirements it must serve (eg: support base config matrix in CI)
|
||||
function common_container_create() {
|
||||
# ## Note
|
||||
#
|
||||
# Using array reference for a single input parameter, as this method is still
|
||||
# under development while adapting tests to it and requirements it must serve
|
||||
# (eg: support base config matrix in CI)
|
||||
function _common_container_create() {
|
||||
[[ -n ${1} ]] && local -n X_EXTRA_ARGS=${1}
|
||||
|
||||
run docker create \
|
||||
@ -127,9 +174,34 @@ function common_container_create() {
|
||||
assert_success
|
||||
}
|
||||
|
||||
function common_container_start() {
|
||||
run docker start "${CONTAINER_NAME}"
|
||||
# Starts a container given by it's name.
|
||||
# Uses `CONTAINER_NAME` as the name for the `docker start` command.
|
||||
#
|
||||
# ## Attenton
|
||||
#
|
||||
# The ENV `CONTAINER_NAME` must be set before this method is called.
|
||||
function _common_container_start() {
|
||||
run docker start "${CONTAINER_NAME:?Container name must be set}"
|
||||
assert_success
|
||||
|
||||
wait_for_finished_setup_in_container "${CONTAINER_NAME}"
|
||||
_wait_for_finished_setup_in_container "${CONTAINER_NAME}"
|
||||
}
|
||||
|
||||
# Using `create` and `start` instead of only `run` allows to modify
|
||||
# the container prior to starting it. Otherwise use this combined method.
|
||||
#
|
||||
# ## Note
|
||||
#
|
||||
# This function forwards all arguments to `_common_container_create` at present.
|
||||
function _common_container_setup() {
|
||||
_common_container_create "${@}"
|
||||
_common_container_start
|
||||
}
|
||||
|
||||
# Can be used in BATS' `teardown_file` function as a default value.
|
||||
#
|
||||
# @param ${1} = container name [OPTIONAL]
|
||||
function _default_teardown() {
|
||||
local TARGET_CONTAINER_NAME=${1:-${CONTAINER_NAME}}
|
||||
docker rm -f "${TARGET_CONTAINER_NAME}"
|
||||
}
|
||||
|
Reference in New Issue
Block a user