2022-11-25 21:58:25 +00:00
|
|
|
#!/bin/bash
|
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
# ? ABOUT: Functions defined here should be used when initializing tests.
|
2022-11-25 21:58:25 +00:00
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
# ! 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.
|
2022-11-25 21:58:25 +00:00
|
|
|
function __initialize_variables() {
|
|
|
|
function __check_if_set() {
|
2023-05-24 07:06:59 +00:00
|
|
|
if [[ ${!1+set} != 'set' ]]; then
|
2022-11-25 21:58:25 +00:00
|
|
|
echo "ERROR: (helper/setup.sh) '${1:?No variable name given to __check_if_set}' is not set" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
local REQUIRED_VARIABLES_FOR_TESTS=(
|
|
|
|
'REPOSITORY_ROOT'
|
|
|
|
'IMAGE_NAME'
|
|
|
|
'CONTAINER_NAME'
|
|
|
|
)
|
|
|
|
|
2023-05-26 12:00:40 +00:00
|
|
|
for VARIABLE in "${REQUIRED_VARIABLES_FOR_TESTS[@]}"; do
|
2022-11-25 21:58:25 +00:00
|
|
|
__check_if_set "${VARIABLE}"
|
|
|
|
done
|
|
|
|
|
2023-01-03 06:00:13 +00:00
|
|
|
export SETUP_FILE_MARKER TEST_TIMEOUT_IN_SECONDS NUMBER_OF_LOG_LINES
|
|
|
|
SETUP_FILE_MARKER="${BATS_TMPDIR:?}/$(basename "${BATS_TEST_FILENAME:?}").setup_file"
|
2022-11-25 21:58:25 +00:00
|
|
|
TEST_TIMEOUT_IN_SECONDS=${TEST_TIMEOUT_IN_SECONDS:-120}
|
|
|
|
NUMBER_OF_LOG_LINES=${NUMBER_OF_LOG_LINES:-10}
|
|
|
|
}
|
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
# ? << Miscellaneous initialization functionality
|
|
|
|
# ! -------------------------------------------------------------------
|
|
|
|
# ? >> File setup
|
2022-11-25 21:58:25 +00:00
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
# 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}"
|
2022-11-25 21:58:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
# 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=$(_print_private_config_path "${2}")
|
|
|
|
|
2023-05-24 07:06:59 +00:00
|
|
|
if [[ -z ${OUTPUT_FOLDER} ]]; then
|
2023-01-21 23:05:28 +00:00
|
|
|
echo "'OUTPUT_FOLDER' in '_duplicate_config_for_container' is empty" >&2
|
|
|
|
return 1
|
2022-11-25 21:58:25 +00:00
|
|
|
fi
|
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
rm -rf "${OUTPUT_FOLDER:?}/"
|
|
|
|
mkdir -p "${OUTPUT_FOLDER}"
|
|
|
|
cp -r "${REPOSITORY_ROOT}/test/config/${1:?}/." "${OUTPUT_FOLDER}" || return $?
|
|
|
|
|
|
|
|
echo "${OUTPUT_FOLDER}"
|
2022-11-25 21:58:25 +00:00
|
|
|
}
|
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
# Common defaults appropriate for most tests.
|
2022-11-25 21:58:25 +00:00
|
|
|
#
|
2023-01-21 23:05:28 +00:00
|
|
|
# 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.
|
2023-01-16 07:39:46 +00:00
|
|
|
#
|
2023-01-21 23:05:28 +00:00
|
|
|
# ## 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}")`
|
|
|
|
function _init_with_defaults() {
|
2022-11-25 21:58:25 +00:00
|
|
|
__initialize_variables
|
|
|
|
|
|
|
|
export TEST_TMP_CONFIG
|
2023-01-21 23:05:28 +00:00
|
|
|
TEST_TMP_CONFIG=$(_duplicate_config_for_container . "${CONTAINER_NAME}")
|
2022-11-25 21:58:25 +00:00
|
|
|
|
|
|
|
# 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
|
2023-01-21 23:05:28 +00:00
|
|
|
#
|
2022-11-25 21:58:25 +00:00
|
|
|
# - two sed failures (unknown lines)
|
|
|
|
# - dovecot-quotas.cf (setup-stack.sh:_setup_dovecot_quotas)
|
|
|
|
# - postfix-aliases.cf (setup-stack.sh:_setup_postfix_aliases)
|
|
|
|
# TODO: Check how many tests need write access. Consider using `docker create` + `docker cp` for easier cleanup.
|
|
|
|
export TEST_CONFIG_VOLUME="${TEST_TMP_CONFIG}:/tmp/docker-mailserver"
|
|
|
|
|
|
|
|
# Default Root CA cert used in TLS tests with `openssl` commands:
|
|
|
|
export TEST_CA_CERT="${TEST_FILES_CONTAINER_PATH}/ssl/example.test/with_ca/ecdsa/ca-cert.ecdsa.pem"
|
|
|
|
}
|
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
|
|
|
|
# ? << 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}"
|
2022-11-25 21:58:25 +00:00
|
|
|
}
|
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
# Uses `docker create` to create a container with proper defaults without starting it instantly.
|
2022-11-25 21:58:25 +00:00
|
|
|
#
|
2023-01-21 23:05:28 +00:00
|
|
|
# @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]
|
2022-11-25 21:58:25 +00:00
|
|
|
#
|
2023-01-21 23:05:28 +00:00
|
|
|
# ## 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() {
|
2022-11-25 21:58:25 +00:00
|
|
|
[[ -n ${1} ]] && local -n X_EXTRA_ARGS=${1}
|
|
|
|
|
|
|
|
run docker create \
|
|
|
|
--tty \
|
|
|
|
--name "${CONTAINER_NAME}" \
|
2023-01-04 15:24:08 +00:00
|
|
|
--hostname "${TEST_FQDN:-mail.example.test}" \
|
2022-11-25 21:58:25 +00:00
|
|
|
--volume "${TEST_FILES_VOLUME}" \
|
|
|
|
--volume "${TEST_CONFIG_VOLUME}" \
|
|
|
|
--env ENABLE_AMAVIS=0 \
|
|
|
|
--env ENABLE_CLAMAV=0 \
|
|
|
|
--env ENABLE_UPDATE_CHECK=0 \
|
|
|
|
--env ENABLE_SPAMASSASSIN=0 \
|
|
|
|
--env ENABLE_FAIL2BAN=0 \
|
2023-01-03 06:00:13 +00:00
|
|
|
--env POSTFIX_INET_PROTOCOLS=ipv4 \
|
|
|
|
--env DOVECOT_INET_PROTOCOLS=ipv4 \
|
2022-11-25 21:58:25 +00:00
|
|
|
--env LOG_LEVEL=debug \
|
|
|
|
"${X_EXTRA_ARGS[@]}" \
|
|
|
|
"${IMAGE_NAME}"
|
|
|
|
|
|
|
|
assert_success
|
|
|
|
}
|
|
|
|
|
2023-01-21 23:05:28 +00:00
|
|
|
# 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}"
|
2022-11-25 21:58:25 +00:00
|
|
|
assert_success
|
2023-01-21 23:05:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# 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
|
tests(refactor): `open_dkim.bats` (#3060)
* tests(refactor): Make test cases for opendkim keysizes DRY
- These all do roughly the same logic that can be split into two separate methods.
- `_should_generate_dkim_key()` covers a bit more logic as it can be leveraged to handle other test cases that also perform the same logic.
- The `config/opendkim/` doesn't seem necessary for tests. Only the first few test cases here are testing against it, so we can conditionally make that available. `process_check_restart.bats` also depended on it to run OpenDKIM successfully, but this was due to the `setup-stack.sh` config defaults failing to find an "empty" file forcing `supervisord` to constantly restart the process..
- With this, there we inverse the default opendkim config, so we don't have to mount unique / empty subfolders for each test case, followed by copying over the two extra configs.
* tests(refactor): DRY up more test cases
All the remaining test cases but the last one were refactored here for a clean commit diff. The last test case will be refactored in the following commit.
Plenty of repeated logic spread across these test cases, now condensed into shared methods.
* tests(refactor): Make final test case DRY
* chore: Migrate to new testing helpers
* chore: Revise test case descriptions
* tests(refactor): Improve and simplify assertions
* tests(refactor): Use common container setup instead of `docker run`
- As the majority of test cases are only running `open-dkim` helper, we don't actually have to wait for a full container setup. So an alternative container start is called.
- Also improves assertions a bit more instead of just counting lines.
- Some test cases don't bind mount all of `/tmp/docker-mailserver` contents, thus don't raise permission errors on subsequent test runs.
- Instead of `rm -f` on some config files, have opted to mount them read-only instead, or alternatively mount an anonymous empty volume instead.
- Collapsed the first three test cases into one, thus no `setup_file()` necessary.
- Shift the `_wait_for_finished_setup_in_container()` method into `_common_container_setup()` instead since nothing else is using `_common_container_start()` yet, this allows for avoiding the wait.
* tests(refactor): Collapse dkim key size test cases into single test case
This makes these tests a bit more DRY, and enhances the raised quality issue with these tests. Now not only is the domain checked in the generated DNS dkim record, but we also verify the key size is corrected in the public and private keys via openssl.
* chore: Revise container names
* chore: Swap order of test case 1 and 2
* tests(refactor): Assert generated log output
- `__should_have_tables_trustedhosts_for_domain` shifted in each test case to just after generating the domains keys.
- Asserts `open-dkim` logs instead of just counting them.
- Added checks for domains that should not be present in a test case.
- Additional coverage and notes about the alias from vhost `@localdomain.com`
- Single assert statement with switch statement as all are using common args.
* chore: Minor changes
* tests(refactor): Share `find` logic in helpers and tests
* tests(fix): Listing file content does not need to match line order
The order printed from local system vs CI differed causing the CI to fail. The order of lines is irrelevant so `--index` is not required.
Additionally correct the prefix of the called method to be only one `_` now that it's a `common.bash` helper method.
* chore: Collapse custom DKIM selector test into custom DKIM domain test
These cover the same test logic for the most part, the first domain could also be testing the custom selector.
`special_use_folders.bats` + `mailbox_format_dbox` can assert lines instead, removing the need for `--partial`.
* Apply suggestions from code review
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
* chore: Split switch statement method into wrapper methods
---------
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2023-02-09 11:18:06 +00:00
|
|
|
|
|
|
|
_wait_for_finished_setup_in_container "${CONTAINER_NAME}"
|
2023-01-21 23:05:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# 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}"
|
2022-11-25 21:58:25 +00:00
|
|
|
}
|