From c78b6d18475cd82dd07c11fa9bbfe846db06f4b8 Mon Sep 17 00:00:00 2001 From: georglauterbach <44545919+georglauterbach@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:12:25 +0100 Subject: [PATCH] simplify helpers for sending massively --- test/helper/sending.bash | 171 ++++++++---------- .../parallel/set1/spam_virus/fail2ban.bats | 2 +- .../set1/spam_virus/postgrey_enabled.bats | 2 +- .../parallel/set1/spam_virus/postscreen.bats | 2 +- .../parallel/set3/mta/smtp_delivery.bats | 4 +- test/tests/serial/mail_with_imap.bats | 2 +- test/tests/serial/mail_with_ldap.bats | 6 +- test/tests/serial/tests.bats | 2 +- 8 files changed, 82 insertions(+), 109 deletions(-) diff --git a/test/helper/sending.bash b/test/helper/sending.bash index 133bbec1..c36f06af 100644 --- a/test/helper/sending.bash +++ b/test/helper/sending.bash @@ -7,103 +7,19 @@ # ! ATTENTION: This file is loaded by `common.sh` - do not load it yourself! # ! ATTENTION: This file requires helper functions from `common.sh`! -# Parse the arguments given to `_send_email` and `_send_email_unchecked`. -# Outputs the `swaks` command to later be executed by the calling function. -# -# ## Note -# -# This is an internal support function, it should not be used directly by tests. -function __parse_swaks_arguments() { - [[ -v CONTAINER_NAME ]] || return 1 - - # Parameter defaults common to our testing needs: - local EHLO='mail.external.tld' - local FROM='user@external.tld' - local TO='user1@localhost.localdomain' - local SERVER='0.0.0.0' - local PORT=25 - # Extra options for `swaks` that aren't covered by the default options above: - local ADDITIONAL_SWAKS_OPTIONS=() - local DATA_WAS_SUPPLIED=0 - - while [[ ${#} -gt 0 ]]; do - case "${1}" in - ( '--ehlo' ) EHLO=${2:?--ehlo given but no argument} ; shift 2 ;; - ( '--from' ) FROM=${2:?--from given but no argument} ; shift 2 ;; - ( '--to' ) TO=${2:?--to given but no argument} ; shift 2 ;; - ( '--server' ) SERVER=${2:?--server given but no argument} ; shift 2 ;; - ( '--port' ) PORT=${2:?--port given but no argument} ; shift 2 ;; - ( '--data' ) - ADDITIONAL_SWAKS_OPTIONS+=('--data') - local FILE_PATH="/tmp/docker-mailserver-test/emails/${2:?--data given but no argument provided}" - if _exec_in_container_bash "[[ -e ${FILE_PATH} ]]"; then - ADDITIONAL_SWAKS_OPTIONS+=("@${FILE_PATH}") - else - ADDITIONAL_SWAKS_OPTIONS+=("'${2}'") - fi - shift 2 - DATA_WAS_SUPPLIED=1 - ;; - ( * ) ADDITIONAL_SWAKS_OPTIONS+=("'${1}'") ; shift 1 ;; - esac - done - - if [[ ${DATA_WAS_SUPPLIED} -eq 0 ]]; then - # Fallback template (without the implicit `Message-Id` + `X-Mailer` headers from swaks): - # NOTE: It is better to let Postfix generate and append the `Message-Id` header itself, - # as it will contain the Queue ID for tracking in logs (which is also returned in swaks output). - ADDITIONAL_SWAKS_OPTIONS+=('--data') - ADDITIONAL_SWAKS_OPTIONS+=("'Date: %DATE%\nTo: %TO_ADDRESS%\nFrom: %FROM_ADDRESS%\nSubject: test %DATE%\n%NEW_HEADERS%\n%BODY%\n'") - fi - - echo "swaks --server '${SERVER}' --port '${PORT}' --ehlo '${EHLO}' --from '${FROM}' --to '${TO}' ${ADDITIONAL_SWAKS_OPTIONS[*]}" -} - -# Sends a mail from the container named by the environment variable `CONTAINER_NAME` +# Sends an e-mail from the container named by the environment variable `CONTAINER_NAME` # to the same or another container. # -# To send a custom email: -# 1. Create a file at `test/files/` -# 2. Provide `` as an argument to this function. +# To send a custom email, you can # -# Parameters include all options that one can supply to `swaks` itself. -# The `--data` parameter expects a value of either: -# - A relative path from `test/files/emails/` -# - An "inline" data string (e.g., `Date: 1 Jan 2024\nSubject: This is a test`) +# 1. create a file at `test/files/` and provide `` via `--data` as an argument to this function; +# 2. use this function without the `--data` argument, in which case we provide a default; +# 3. provide data inline (`--data `). # -# ## Output +# The very first parameter **may** be `--expect-rejection` - use it of you expect the mail transaction to not finish +# successfully. All other (following) parameters include all options that one can supply to `swaks` itself. +# As mentioned before, the `--data` parameter expects a value of either: # -# This functions prints the output of the transaction that `swaks` prints. -# -# ## Attention -# -# This function assumes `CONTAINER_NAME` to be properly set (to the container -# name the command should be executed in)! -# -# This function will send the email in an "asynchronous" fashion, -# it will return without waiting for the Postfix mail queue to be emptied. -# -# This functions performs **no** implicit `assert_success` to check whether the -# e-mail transaction was successful. If this is not desirable, use `_send_email`. -# If you anticipate the sending to succeed, use `_send_email` instead. -function _send_email_unchecked() { - local COMMAND_STRING=$(__parse_swaks_arguments "${@}") - _run_in_container_bash "${COMMAND_STRING}" - local RETURN_VALUE=${?} - # shellcheck disable=SC2154 - echo "${output}" - return "${RETURN_VALUE}" -} - -# Sends a mail from the container named by the environment variable `CONTAINER_NAME` -# to the same or another container. -# -# To send a custom email: -# 1. Create a file at `test/files/` -# 2. Provide `` as an argument to this function. -# -# Parameters include all options that one can supply to `swaks` itself. -# The `--data` parameter expects a value of either: # - A relative path from `test/files/emails/` # - An "inline" data string (e.g., `Date: 1 Jan 2024\nSubject: This is a test`) # @@ -119,11 +35,69 @@ function _send_email_unchecked() { # This function will send the email in an "asynchronous" fashion, # it will return without waiting for the Postfix mail queue to be emptied. function _send_email() { - local COMMAND_STRING=$(__parse_swaks_arguments "${@}") - _run_in_container_bash "${COMMAND_STRING}" - assert_success + local RETURN_VALUE=0 + local COMMAND_STRING + + function __parse_arguments() { + [[ -v CONTAINER_NAME ]] || return 1 + + # Parameter defaults common to our testing needs: + local EHLO='mail.external.tld' + local FROM='user@external.tld' + local TO='user1@localhost.localdomain' + local SERVER='0.0.0.0' + local PORT=25 + # Extra options for `swaks` that aren't covered by the default options above: + local ADDITIONAL_SWAKS_OPTIONS=() + local DATA_WAS_SUPPLIED=0 + + while [[ ${#} -gt 0 ]]; do + case "${1}" in + ( '--ehlo' ) EHLO=${2:?--ehlo given but no argument} ; shift 2 ;; + ( '--from' ) FROM=${2:?--from given but no argument} ; shift 2 ;; + ( '--to' ) TO=${2:?--to given but no argument} ; shift 2 ;; + ( '--server' ) SERVER=${2:?--server given but no argument} ; shift 2 ;; + ( '--port' ) PORT=${2:?--port given but no argument} ; shift 2 ;; + ( '--data' ) + ADDITIONAL_SWAKS_OPTIONS+=('--data') + local FILE_PATH="/tmp/docker-mailserver-test/emails/${2:?--data given but no argument provided}" + if _exec_in_container_bash "[[ -e ${FILE_PATH} ]]"; then + ADDITIONAL_SWAKS_OPTIONS+=("@${FILE_PATH}") + else + ADDITIONAL_SWAKS_OPTIONS+=("'${2}'") + fi + shift 2 + DATA_WAS_SUPPLIED=1 + ;; + ( * ) ADDITIONAL_SWAKS_OPTIONS+=("'${1}'") ; shift 1 ;; + esac + done + + if [[ ${DATA_WAS_SUPPLIED} -eq 0 ]]; then + # Fallback template (without the implicit `Message-Id` + `X-Mailer` headers from swaks): + # NOTE: It is better to let Postfix generate and append the `Message-Id` header itself, + # as it will contain the Queue ID for tracking in logs (which is also returned in swaks output). + ADDITIONAL_SWAKS_OPTIONS+=('--data') + ADDITIONAL_SWAKS_OPTIONS+=("'Date: %DATE%\nTo: %TO_ADDRESS%\nFrom: %FROM_ADDRESS%\nSubject: test %DATE%\n%NEW_HEADERS%\n%BODY%\n'") + fi + + echo "swaks --server '${SERVER}' --port '${PORT}' --ehlo '${EHLO}' --from '${FROM}' --to '${TO}' ${ADDITIONAL_SWAKS_OPTIONS[*]}" + } + + if [[ ${1:-} == --expect-rejection ]]; then + shift 1 + COMMAND_STRING=$(__parse_arguments "${@}") + _run_in_container_bash "${COMMAND_STRING}" + assert_success + else + COMMAND_STRING=$(__parse_arguments "${@}") + _run_in_container_bash "${COMMAND_STRING}" + RETURN_VALUE=${?} + fi + # shellcheck disable=SC2154 echo "${output}" + return "${RETURN_VALUE}" } # Like `_send_email` with two major differences: @@ -172,9 +146,9 @@ function _send_email_and_get_id() { local MESSAGE_ID_REGEX="[0-9]{14}\\.${QUEUE_ID_REGEX}" _wait_for_empty_mail_queue_in_container - if [[ ${1} == --expect-rejection ]]; then - shift 1 - local OUTPUT=$(_send_email_unchecked "${@}") + local OUTPUT=$(_send_email "${@}") + + if [[ ${1:-} == --expect-rejection ]]; then # Because we expect the mail to be rejected, we have to query the mail log # instead of `swaks`, because `swaks` cannot provide us with a queue ID when # mail is rejected (we see something like this instead: `<** 554 5.7.1 Gtube pattern`). @@ -182,7 +156,6 @@ function _send_email_and_get_id() { | grep -E "postfix/smtpd.*: ${QUEUE_ID_REGEX}: client=" \ | grep -E -m 1 -o '[A-Z0-9]{9,12}' || :) else - local OUTPUT=$(_send_email "${@}") # When mail is expected to be delivered, we can use the output of `swaks` # to easily query the queue ID. QUEUE_ID=$(grep -F 'queued as' <<< "${OUTPUT}" | grep -E -o "${QUEUE_ID_REGEX}$") diff --git a/test/tests/parallel/set1/spam_virus/fail2ban.bats b/test/tests/parallel/set1/spam_virus/fail2ban.bats index 6760202b..f451befd 100644 --- a/test/tests/parallel/set1/spam_virus/fail2ban.bats +++ b/test/tests/parallel/set1/spam_virus/fail2ban.bats @@ -74,7 +74,7 @@ function teardown_file() { CONTAINER1_IP=$(_get_container_ip "${CONTAINER1_NAME}") # Trigger a ban by failing to login twice: for _ in {1..2}; do - CONTAINER_NAME=${CONTAINER2_NAME} _send_email_unchecked \ + CONTAINER_NAME=${CONTAINER2_NAME} _send_email --expect-rejection \ --server "${CONTAINER1_IP}" \ --port 465 \ --auth PLAIN \ diff --git a/test/tests/parallel/set1/spam_virus/postgrey_enabled.bats b/test/tests/parallel/set1/spam_virus/postgrey_enabled.bats index 950e70b7..5538d3bf 100644 --- a/test/tests/parallel/set1/spam_virus/postgrey_enabled.bats +++ b/test/tests/parallel/set1/spam_virus/postgrey_enabled.bats @@ -51,7 +51,7 @@ function teardown_file() { _default_teardown ; } _reload_postfix # Send test mail (it should fail to deliver): - _send_email_unchecked --from 'user@external.tld' --port 25 --data 'postgrey.txt' + _send_email --expect-rejection --from 'user@external.tld' --port 25 --data 'postgrey.txt' assert_failure assert_output --partial 'Recipient address rejected: Delayed by Postgrey' diff --git a/test/tests/parallel/set1/spam_virus/postscreen.bats b/test/tests/parallel/set1/spam_virus/postscreen.bats index e293c616..92333f98 100644 --- a/test/tests/parallel/set1/spam_virus/postscreen.bats +++ b/test/tests/parallel/set1/spam_virus/postscreen.bats @@ -57,7 +57,7 @@ function teardown_file() { # Configure `send_email()` to send from the mail client container (CONTAINER2_NAME) via ENV override, # mail is sent to the DMS server container (CONTAINER1_NAME) via `--server` parameter: # TODO: Use _send_email_and_get_id when proper resolution of domain names is possible: - CONTAINER_NAME=${CONTAINER2_NAME} _send_email_unchecked --server "${CONTAINER1_IP}" --port 25 --data 'postscreen.txt' + CONTAINER_NAME=${CONTAINER2_NAME} _send_email --expect-rejection --server "${CONTAINER1_IP}" --port 25 --data 'postscreen.txt' # CONTAINER_NAME=${CONTAINER2_NAME} _send_email_and_get_id MAIL_ID_POSTSCREEN --server "${CONTAINER1_IP}" --data 'postscreen.txt' # _print_mail_log_for_id "${MAIL_ID_POSTSCREEN}" # assert_output --partial "stored mail into mailbox 'INBOX'" diff --git a/test/tests/parallel/set3/mta/smtp_delivery.bats b/test/tests/parallel/set3/mta/smtp_delivery.bats index 87548aea..329f36b2 100644 --- a/test/tests/parallel/set3/mta/smtp_delivery.bats +++ b/test/tests/parallel/set3/mta/smtp_delivery.bats @@ -75,7 +75,7 @@ function setup_file() { _send_email --to test123@localhost.localdomain --header 'Subject: Test Message existing-regexp-alias-local' # Required for 'rejects mail to unknown user': - _send_email_unchecked --to nouser@localhost.localdomain + _send_email --expect-rejection --to nouser@localhost.localdomain assert_failure # Required for 'redirects mail to external aliases': _send_email --to bounce-always@localhost.localdomain @@ -99,7 +99,7 @@ function setup_file() { } function _unsuccessful() { - _send_email_unchecked --port 465 --auth "${1}" --auth-user "${2}" --auth-password wrongpassword --quit-after AUTH + _send_email --expect-rejection --port 465 --auth "${1}" --auth-user "${2}" --auth-password wrongpassword --quit-after AUTH assert_failure assert_output --partial 'authentication failed' assert_output --partial 'No authentication type succeeded' diff --git a/test/tests/serial/mail_with_imap.bats b/test/tests/serial/mail_with_imap.bats index 2b0ad083..94f1d519 100644 --- a/test/tests/serial/mail_with_imap.bats +++ b/test/tests/serial/mail_with_imap.bats @@ -31,7 +31,7 @@ function teardown_file() { _default_teardown ; } } @test '(SASLauthd) RIMAP SMTP authentication works' { - _send_email_unchecked \ + _send_email --expect-rejection \ --auth PLAIN \ --auth-user user1@localhost.localdomain \ --auth-password mypassword \ diff --git a/test/tests/serial/mail_with_ldap.bats b/test/tests/serial/mail_with_ldap.bats index 02028745..f3ee1cc1 100644 --- a/test/tests/serial/mail_with_ldap.bats +++ b/test/tests/serial/mail_with_ldap.bats @@ -326,7 +326,7 @@ function teardown() { @test "spoofing (with LDAP): rejects sender forging" { _wait_for_smtp_port_in_container_to_respond dms-test_ldap - _send_email_unchecked \ + _send_email --expect-rejection \ --port 465 -tlsc --auth PLAIN \ --auth-user some.user@localhost.localdomain \ --auth-password secret \ @@ -354,7 +354,7 @@ function teardown() { # Template used has invalid AUTH: https://github.com/docker-mailserver/docker-mailserver/pull/3006#discussion_r1073321432 skip 'TODO: This test seems to have been broken from the start (?)' - _send_email_unchecked \ + _send_email --expect-rejection \ --port 465 -tlsc --auth PLAIN \ --auth-user some.user.email@localhost.localdomain \ --auth-password secret \ @@ -367,7 +367,7 @@ function teardown() { } @test "saslauthd: ldap smtp authentication" { - _send_email_unchecked \ + _send_email --expect-rejection \ --auth PLAIN \ --auth-user some.user@localhost.localdomain \ --auth-password wrongpassword \ diff --git a/test/tests/serial/tests.bats b/test/tests/serial/tests.bats index aa8f6337..a344bd8d 100644 --- a/test/tests/serial/tests.bats +++ b/test/tests/serial/tests.bats @@ -293,7 +293,7 @@ EOF # An authenticated user cannot use an envelope sender (MAIL FROM) # address they do not own according to `main.cf:smtpd_sender_login_maps` lookup - _send_email_unchecked \ + _send_email --expect-rejection \ --port 465 -tlsc --auth PLAIN \ --auth-user added@localhost.localdomain \ --auth-password mypassword \