diff --git a/test/tests/parallel/set3/process-check-restart.bats b/test/tests/parallel/set3/process-check-restart.bats index d30fc34e..6a743bf8 100644 --- a/test/tests/parallel/set3/process-check-restart.bats +++ b/test/tests/parallel/set3/process-check-restart.bats @@ -127,6 +127,8 @@ ENV_PROCESS_LIST=( assert_success pgrep --full 'fetchmail-2.rc' assert_success + + _should_stop_cleanly } # Split into separate test case for the benefit of minimizing CPU + RAM overhead of clamd. @@ -140,6 +142,7 @@ ENV_PROCESS_LIST=( _common_container_setup 'CONTAINER_ARGS_ENV_CUSTOM' _should_restart_when_killed 'clamd' + _should_stop_cleanly } function _should_restart_when_killed() { @@ -190,3 +193,16 @@ function _check_if_process_is_running() { # Original output (if any) for assertions echo "${IS_RUNNING}" } + +# The process manager (supervisord) should perform a graceful shutdown: +# NOTE: Time limit should never be below these configured values: +# - supervisor-app.conf:stopwaitsecs +# - docker-compose.yml:stop_grace_period +function _should_stop_cleanly() { + run docker stop -t 60 "${CONTAINER_NAME}" + assert_success + + # Running `docker rm -f` too soon after `docker stop` can result in failure during teardown with: + # "Error response from daemon: removal of container "${CONTAINER_NAME}" is already in progress" + sleep 1 +} diff --git a/test/tests/serial/mail_hostname.bats b/test/tests/serial/mail_hostname.bats index d12df582..ceebe0f6 100644 --- a/test/tests/serial/mail_hostname.bats +++ b/test/tests/serial/mail_hostname.bats @@ -1,213 +1,260 @@ -load "${REPOSITORY_ROOT}/test/test_helper/common" +load "${REPOSITORY_ROOT}/test/helper/common" +load "${REPOSITORY_ROOT}/test/helper/setup" +BATS_TEST_NAME_PREFIX='[Network - Hostname] ' +CONTAINER1_NAME='dms-test_hostname_fqdn-with-subdomain' +CONTAINER2_NAME='dms-test_hostname_bare-domain' +CONTAINER3_NAME='dms-test_hostname_env-override-hostname' +CONTAINER4_NAME='dms-test_hostname_with-nis-domain' +CONTAINER5_NAME='dms-test_hostname_env-srs-domainname' -function setup_file() { - local PRIVATE_CONFIG +# NOTE: Required until postsrsd package updated: +# `--ulimit` is a workaround for some environments when using ENABLE_SRS=1: +# PR 2730: https://github.com/docker-mailserver/docker-mailserver/commit/672e9cf19a3bb1da309e8cea6ee728e58f905366 - PRIVATE_CONFIG=$(duplicate_config_for_container . mail_override_hostname) - docker run --rm -d --name mail_override_hostname \ - -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ - -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ - -e PERMIT_DOCKER=network \ - -e ENABLE_SRS=1 \ - -e OVERRIDE_HOSTNAME=mail.my-domain.com \ - --hostname unknown.domain.tld \ - --tty \ - --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \ - "${NAME}" +function teardown() { _default_teardown ; } - PRIVATE_CONFIG_TWO=$(duplicate_config_for_container . mail_non_subdomain_hostname) - docker run --rm -d --name mail_non_subdomain_hostname \ - -v "${PRIVATE_CONFIG_TWO}":/tmp/docker-mailserver \ - -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ - -e PERMIT_DOCKER=network \ - -e ENABLE_SRS=1 \ - --hostname domain.com \ - --tty \ - --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \ - "${NAME}" +@test "should update configuration correctly (Standard FQDN setup)" { + export CONTAINER_NAME="${CONTAINER1_NAME}" - PRIVATE_CONFIG_THREE=$(duplicate_config_for_container . mail_srs_domainname) - docker run --rm -d --name mail_srs_domainname \ - -v "${PRIVATE_CONFIG_THREE}":/tmp/docker-mailserver \ - -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ - -e PERMIT_DOCKER=network \ - -e ENABLE_SRS=1 \ - -e SRS_DOMAINNAME='srs.my-domain.com' \ - --domainname 'my-domain.com' \ - --hostname 'mail' \ - --tty \ - --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \ - "${NAME}" + # Should be using the default `--hostname mail.example.test` + local CUSTOM_SETUP_ARGUMENTS=( + --env ENABLE_AMAVIS=1 + --env ENABLE_SRS=1 + --env PERMIT_DOCKER='container' + --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" + ) + _init_with_defaults + _common_container_setup 'CUSTOM_SETUP_ARGUMENTS' + _wait_for_smtp_port_in_container - PRIVATE_CONFIG_FOUR=$(duplicate_config_for_container . mail_domainname) - docker run --rm -d --name mail_domainname \ - -v "${PRIVATE_CONFIG_FOUR}":/tmp/docker-mailserver \ - -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ - -e PERMIT_DOCKER=network \ - -e ENABLE_SRS=1 \ - --domainname 'my-domain.com' \ - --hostname 'mail' \ - --tty \ - --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" \ - "${NAME}" + _should_have_expected_hostname 'mail.example.test' - wait_for_smtp_port_in_container mail_override_hostname - wait_for_smtp_port_in_container mail_non_subdomain_hostname - wait_for_smtp_port_in_container mail_srs_domainname - wait_for_smtp_port_in_container mail_domainname + _should_be_configured_to_domainname 'example.test' + _should_be_configured_to_fqdn 'mail.example.test' - docker exec mail_override_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt" - docker exec mail_non_subdomain_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt" + _should_have_correct_mail_headers 'mail.example.test' 'example.test' } -function teardown_file() { - # Running `docker rm -f` too soon after `docker stop` can result in failure during teardown with: - # "Error response from daemon: removal of container mail_domainname is already in progress" - sleep 1 +@test "should update configuration correctly (Bare Domain)" { + export CONTAINER_NAME="${CONTAINER2_NAME}" - docker rm -f mail_override_hostname mail_non_subdomain_hostname mail_srs_domainname mail_domainname + local CUSTOM_SETUP_ARGUMENTS=( + --hostname 'bare-domain.test' + --env ENABLE_AMAVIS=1 + --env ENABLE_SRS=1 + --env PERMIT_DOCKER='container' + --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" + ) + _init_with_defaults + _common_container_setup 'CUSTOM_SETUP_ARGUMENTS' + _wait_for_smtp_port_in_container + + _should_have_expected_hostname 'bare-domain.test' + + _should_be_configured_to_domainname 'bare-domain.test' + # Bare domain configured, thus no subdomain: + _should_be_configured_to_fqdn 'bare-domain.test' + + _should_have_correct_mail_headers 'bare-domain.test' } -@test "checking SRS: SRS_DOMAINNAME is used correctly" { - repeat_until_success_or_timeout 15 docker exec mail_srs_domainname grep "SRS_DOMAIN=srs.my-domain.com" /etc/default/postsrsd -} +@test "should update configuration correctly (ENV OVERRIDE_HOSTNAME)" { + export CONTAINER_NAME="${CONTAINER3_NAME}" -@test "checking SRS: DOMAINNAME is handled correctly" { - repeat_until_success_or_timeout 15 docker exec mail_domainname grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd -} + local CUSTOM_SETUP_ARGUMENTS=( + --hostname 'original.example.test' + --env OVERRIDE_HOSTNAME='mail.override.test' + --env ENABLE_AMAVIS=1 + --env ENABLE_SRS=1 + --env PERMIT_DOCKER='container' + --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" + ) + _init_with_defaults + _common_container_setup 'CUSTOM_SETUP_ARGUMENTS' + _wait_for_smtp_port_in_container -@test "checking configuration: hostname/domainname override: check container hostname is applied correctly" { - run docker exec mail_override_hostname /bin/bash -c "hostname | grep unknown.domain.tld" - assert_success -} + # Should be the original `--hostname` (`hostname -f`), not `OVERRIDE_HOSTNAME`: + _should_have_expected_hostname 'original.example.test' -@test "checking configuration: hostname/domainname override: check overriden hostname is applied to all configs" { - run docker exec mail_override_hostname /bin/bash -c "cat /etc/mailname | grep my-domain.com" - assert_success + _should_be_configured_to_domainname 'override.test' + _should_be_configured_to_fqdn 'mail.override.test' - run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep mydomain | grep my-domain.com" - assert_success - - run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep myhostname | grep mail.my-domain.com" - assert_success - - run docker exec mail_override_hostname /bin/bash -c "doveconf | grep hostname | grep mail.my-domain.com" - assert_success - - run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep mail.my-domain.com" - assert_success - - run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep mail.my-domain.com" - assert_success - - run docker exec mail_override_hostname /bin/bash -c "cat /etc/amavis/conf.d/05-node_id | grep myhostname | grep mail.my-domain.com" - assert_success -} - -@test "checking configuration: hostname/domainname override: check hostname in postfix HELO message" { - run docker exec mail_override_hostname /bin/bash -c "nc -w 1 0.0.0.0 25 | grep mail.my-domain.com" - assert_success -} - -@test "checking configuration: hostname/domainname override: check headers of received mail" { - run docker exec mail_override_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1" - assert_success - - run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep mail.my-domain.com" - assert_success - - # test whether the container hostname is not found in received mail - run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep unknown.domain.tld" + _should_have_correct_mail_headers 'mail.override.test' 'override.test' 'original.example.test' + # Container hostname should not be found in received mail (due to `OVERRIDE_HOSTNAME`): + _run_in_container grep -R 'original.example.test' /var/mail/localhost.localdomain/user1/new/ assert_failure } -@test "checking SRS: OVERRIDE_HOSTNAME is handled correctly" { - run docker exec mail_override_hostname grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd +@test "should update configuration correctly (--hostname + --domainname)" { + export CONTAINER_NAME="${CONTAINER4_NAME}" + + local CUSTOM_SETUP_ARGUMENTS=( + --hostname 'mail' + --domainname 'example.test' + --env ENABLE_AMAVIS=1 + --env ENABLE_SRS=1 + --env PERMIT_DOCKER='container' + --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" + ) + _init_with_defaults + _common_container_setup 'CUSTOM_SETUP_ARGUMENTS' + _wait_for_smtp_port_in_container + + # Differs from the first test case, matches exact `--hostname` value: + _should_have_expected_hostname 'mail' + + _should_be_configured_to_domainname 'example.test' + _should_be_configured_to_fqdn 'mail.example.test' + + # Likewise `--hostname` value will always match the third parameter: + _should_have_correct_mail_headers 'mail.example.test' 'example.test' 'mail' +} + +# This test is purely for testing the ENV `SRS_DOMAINNAME` (not relevant to these tests?) +@test "should give priority to ENV in postsrsd config (ENV SRS_DOMAINNAME)" { + export CONTAINER_NAME="${CONTAINER5_NAME}" + + local CUSTOM_SETUP_ARGUMENTS=( + --hostname 'mail' + --domainname 'example.test' + --env ENABLE_SRS=1 + --env SRS_DOMAINNAME='srs.example.test' + --env PERMIT_DOCKER='container' + --ulimit "nofile=$(ulimit -Sn):$(ulimit -Hn)" + ) + _init_with_defaults + _common_container_setup 'CUSTOM_SETUP_ARGUMENTS' + + # PostSRSd should be configured correctly: + _run_in_container grep '^SRS_DOMAIN=' /etc/default/postsrsd + assert_output "SRS_DOMAIN=srs.example.test" assert_success } -@test "checking dovecot: postmaster address" { - run docker exec mail_override_hostname /bin/sh -c "grep 'postmaster_address = postmaster@my-domain.com' /etc/dovecot/conf.d/15-lda.conf" +function _should_have_expected_hostname() { + local EXPECTED_FQDN=${1} + + _run_in_container "hostname" + assert_output "${EXPECTED_FQDN}" + assert_success + + _run_in_container grep -E "[[:space:]]+${EXPECTED_FQDN}" /etc/hosts assert_success } -# -# non-subdomain tests -# +function _should_be_configured_to_domainname() { + local EXPECTED_DOMAIN=${1} -@test "checking configuration: non-subdomain: check container hostname is applied correctly" { - run docker exec mail_non_subdomain_hostname /bin/bash -c "hostname | grep domain.com" + # setup-stack.sh:_setup_mailname + _run_in_container cat /etc/mailname + assert_output "${EXPECTED_DOMAIN}" + assert_success + + # Postfix + _run_in_container postconf mydomain + assert_output "mydomain = ${EXPECTED_DOMAIN}" + assert_success + + # PostSRSd + _run_in_container grep '^SRS_DOMAIN=' /etc/default/postsrsd + assert_output "SRS_DOMAIN=${EXPECTED_DOMAIN}" + assert_success + + # Dovecot + _run_in_container grep '^postmaster_address' /etc/dovecot/conf.d/15-lda.conf + assert_output "postmaster_address = postmaster@${EXPECTED_DOMAIN}" assert_success } -@test "checking configuration: non-subdomain: check overriden hostname is applied to all configs" { - run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/mailname | grep domain.com" +function _should_be_configured_to_fqdn() { + local EXPECTED_FQDN=${1} + + # Postfix + _run_in_container postconf myhostname + assert_output "myhostname = ${EXPECTED_FQDN}" + assert_success + # Postfix HELO message should contain FQDN (hostname) + _run_in_container nc -w 1 0.0.0.0 25 + assert_output --partial "220 ${EXPECTED_FQDN} ESMTP" assert_success - run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep mydomain | grep domain.com" + # Dovecot + _run_in_container doveconf hostname + assert_output "hostname = ${EXPECTED_FQDN}" assert_success - run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep myhostname | grep domain.com" + # OpenDMARC + _run_in_container grep '^AuthservID' /etc/opendmarc.conf + assert_output --partial " ${EXPECTED_FQDN}" + assert_success + _run_in_container grep '^TrustedAuthservIDs' /etc/opendmarc.conf + assert_output --partial " ${EXPECTED_FQDN}" assert_success - run docker exec mail_non_subdomain_hostname /bin/bash -c "doveconf | grep hostname | grep domain.com" - assert_success - - run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep domain.com" - assert_success - - run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep domain.com" - assert_success - - run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/amavis/conf.d/05-node_id | grep myhostname | grep domain.com" + # Amavis + _run_in_container grep '^\$myhostname' /etc/amavis/conf.d/05-node_id + assert_output "\$myhostname = \"${EXPECTED_FQDN}\";" assert_success } -@test "checking configuration: non-subdomain: check hostname in postfix HELO message" { - run docker exec mail_non_subdomain_hostname /bin/bash -c "nc -w 1 0.0.0.0 25 | grep domain.com" - assert_success -} - -@test "checking configuration: non-subdomain: check headers of received mail" { - run docker exec mail_non_subdomain_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1" - assert_success - - run docker exec mail_non_subdomain_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep domain.com" - assert_success -} - -@test "checking SRS: non-subdomain is handled correctly" { - docker exec mail_non_subdomain_hostname cat /etc/default/postsrsd - run docker exec mail_non_subdomain_hostname grep "SRS_DOMAIN=domain.com" /etc/default/postsrsd - assert_success -} - -@test "checking dovecot: non-subdomain postmaster address" { - run docker exec mail_non_subdomain_hostname /bin/sh -c "grep 'postmaster_address = postmaster@domain.com' /etc/dovecot/conf.d/15-lda.conf" - assert_success -} - -# -# clean exit -# - -@test "checking that the container stops cleanly: mail_override_hostname" { - run docker stop -t 60 mail_override_hostname - assert_success -} - -@test "checking that the container stops cleanly: mail_non_subdomain_hostname" { - run docker stop -t 60 mail_non_subdomain_hostname - assert_success -} - -@test "checking that the container stops cleanly: mail_srs_domainname" { - run docker stop -t 60 mail_srs_domainname - assert_success -} - -@test "checking that the container stops cleanly: mail_domainname" { - run docker stop -t 60 mail_domainname +function _should_have_correct_mail_headers() { + local EXPECTED_FQDN=${1} + # NOTE: The next two params should not differ for bare domains: + local EXPECTED_DOMAINPART=${2:-${EXPECTED_FQDN}} + # Required when EXPECTED_FQDN would not match the container hostname: + # (eg: OVERRIDE_HOSTNAME or `--hostname mail --domainname example.test`) + local EXPECTED_HOSTNAME=${3:-${EXPECTED_FQDN}} + + _run_in_container_bash "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt" assert_success + + _wait_for_empty_mail_queue_in_container + _count_files_in_directory_in_container '/var/mail/localhost.localdomain/user1/new/' '1' + + # MTA hostname (sender?) is used in filename of stored mail: + local MAIL_FILEPATH=$(_exec_in_container find /var/mail/localhost.localdomain/user1/new -maxdepth 1 -type f) + + run echo "${MAIL_FILEPATH}" + assert_success + assert_output --partial ".${EXPECTED_HOSTNAME}," + + # Mail headers should contain EXPECTED_FQDN for lines Received + by + Message-Id + # For `ENABLE_SRS=1`, EXPECTED_DOMAINPART should match lines Return-Path + envelope-from + _run_in_container cat "${MAIL_FILEPATH}" + assert_success + assert_line --index 0 --partial 'Return-Path: " + # Passed on from Postfix to Dovecot via LMTP: + assert_line --index 2 --partial "Received: from ${EXPECTED_FQDN}" + assert_line --index 3 --partial "by ${EXPECTED_FQDN} with LMTP" + assert_line --index 5 --partial '(envelope-from " + # Arrived via Postfix: + # NOTE: The first `localhost` in this line would actually be `mail.external.tld`, + # but Amavis is changing that. It also changes protocol from SMTP to ESMTP. + assert_line --index 7 --partial 'Received: from localhost (localhost [127.0.0.1])' + assert_line --index 8 --partial "by ${EXPECTED_FQDN} (Postfix) with ESMTP id" + assert_line --index 14 --partial 'Message-Id:' + assert_line --index 14 --partial "@${EXPECTED_FQDN}>" + + # Mail contents example: + # + # Return-Path: + # Delivered-To: user1@localhost.localdomain + # Received: from mail.example.test + # by mail.example.test with LMTP + # id jvJfJk23zGPeBgAAUi6ngw + # (envelope-from ) + # for ; Sun, 22 Jan 2023 04:10:53 +0000 + # Received: from localhost (localhost [127.0.0.1]) + # by mail.example.test (Postfix) with ESMTP id 8CFC4C30F9C4 + # for ; Sun, 22 Jan 2023 04:10:53 +0000 (UTC) + # From: Docker Mail Server + # To: Existing Local User + # Date: Sat, 22 May 2010 07:43:25 -0400 + # Subject: Test Message existing-user1.txt + # Message-Id: <20230122041053.5A5F1C2F608E@mail.example.test> + # + # This is a test mail. } diff --git a/test/tests/serial/tests.bats b/test/tests/serial/tests.bats index 1aa83abf..e91f70bd 100644 --- a/test/tests/serial/tests.bats +++ b/test/tests/serial/tests.bats @@ -244,18 +244,6 @@ function teardown_file() { _default_teardown ; } assert_failure } -@test "system: sets the server fqdn" { - _run_in_container hostname - assert_success - assert_output "mail.example.test" -} - -@test "system: sets the server domain name in /etc/mailname" { - _run_in_container cat /etc/mailname - assert_success - assert_output "example.test" -} - @test "system: postfix should not log to syslog" { _run_in_container grep 'postfix' /var/log/syslog assert_failure