tests(fix): Adjust for local testing conditions (#2606)

* tests(fix): Increase some timeouts

Running tests locally via a VM these tests would fail sometimes due to the time from being queued and Amavis actually processing being roughly around 30 seconds.

There should be no harm in raising this to 60 seconds, other than delaying a failure case which will ripple through other time sensitive tests.

It's better to pass when functionality is actually correct but just needs a bit longer to complete.



* tests(fix): Don't setup an invalid hostname

During container startup `helpers/dns.sh` would panic with `hostname -f` failing.

Dropping `--domainname` for this container is fine and does not affect the point of it's test.

---

It's unclear why this does not occur in CI. Possibly changes within the docker daemon since as CI runs docker on Ubuntu 20.04? (2020).

For clarity, this may be equivalent to setting a hostname of `domain.com.domain.com`, or `--hostname` value truncated the NIS domain (`--domainname`) of the same value.

IIRC, it would still fail with both options using different values if `--hostname` was multi-label. I believe I've documented how non-deterministic these options can be across different environments.

`--hostname` should be preferred. There doesn't seem to be any reason to actually need `--domainname` (which is NIS domain name, unrelated to the DNS domain name). We still need to properly investigate reworking our ENV support that `dns.sh` manages.

---

Containers were also not removing themselves after failures either (missing teardown). Which would cause problems when running tests again.



* chore: Normalize white-space

Sets a consistent indent size of 2 spaces. Previously this varied a fair bit, sometimes with tabs or mixed tabs and spaces.

Some formatting with blank lines.

Easier to review with white-space in diff ignored. Some minor edits besides blank lines, but no change in functionality.



* fix: `setup.sh` target container under test

Some of the `setup.sh` commands did not specify the container which was problematic if another `docker-mailserver` container was running, causing test failures.

This probably doesn't help with `test/no_container.bats`, but at least prevents `test/tests.bats` failing at this point.
This commit is contained in:
Brennan Kinney 2022-05-30 12:53:30 +12:00 committed by GitHub
parent 05e45c349a
commit 3b4f44e837
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1166 additions and 998 deletions

View File

@ -1,15 +1,17 @@
load 'test_helper/common' load 'test_helper/common'
function setup() { function setup() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container relay-hosts) PRIVATE_CONFIG=$(duplicate_config_for_container relay-hosts)
docker run -d --name mail_with_default_relay \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run -d --name mail_with_default_relay \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e DEFAULT_RELAY_HOST=default.relay.host.invalid:25 \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
--cap-add=SYS_PTRACE \ -e DEFAULT_RELAY_HOST=default.relay.host.invalid:25 \
-e PERMIT_DOCKER=host \ --cap-add=SYS_PTRACE \
-h mail.my-domain.com -t "${NAME}" -e PERMIT_DOCKER=host \
-h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_with_default_relay wait_for_finished_setup_in_container mail_with_default_relay
} }

View File

@ -9,23 +9,23 @@ function setup_file() {
IPV4="mail_dovecot_ipv4" IPV4="mail_dovecot_ipv4"
IPV6="mail_dovecot_ipv6" IPV6="mail_dovecot_ipv6"
docker run --rm -d --name "${ALL}" \ docker run --rm -d --name "${ALL}" \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e DOVECOT_INET_PROTOCOLS= \ -e DOVECOT_INET_PROTOCOLS= \
-h mail.my-domain.com \ -h mail.my-domain.com \
-t "${NAME}" -t "${NAME}"
docker run --rm -d --name "${IPV4}" \ docker run --rm -d --name "${IPV4}" \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e DOVECOT_INET_PROTOCOLS=ipv4 \ -e DOVECOT_INET_PROTOCOLS=ipv4 \
-h mail.my-domain.com \ -h mail.my-domain.com \
-t "${NAME}" -t "${NAME}"
docker run --rm -d --name "${IPV6}" \ docker run --rm -d --name "${IPV6}" \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e DOVECOT_INET_PROTOCOLS=ipv6 \ -e DOVECOT_INET_PROTOCOLS=ipv6 \
-h mail.my-domain.com \ -h mail.my-domain.com \
-t "${NAME}" -t "${NAME}"
} }
@test 'checking dovecot IP configuration' { @test 'checking dovecot IP configuration' {

View File

@ -1,15 +1,17 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_helper_functions \
--cap-add=NET_ADMIN \ docker run -d --name mail_helper_functions \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ --cap-add=NET_ADMIN \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e ENABLE_FETCHMAIL=1 \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-h mail.my-domain.com -t "${NAME}" -e ENABLE_FETCHMAIL=1 \
wait_for_finished_setup_in_container mail_helper_functions -h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_helper_functions
} }
function teardown_file() { function teardown_file() {
@ -19,8 +21,10 @@ function teardown_file() {
@test "check helper functions (network.sh): _sanitize_ipv4_to_subnet_cidr" { @test "check helper functions (network.sh): _sanitize_ipv4_to_subnet_cidr" {
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 255.255.255.255/0" run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 255.255.255.255/0"
assert_output "0.0.0.0/0" assert_output "0.0.0.0/0"
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/20" run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/20"
assert_output "192.168.240.0/20" assert_output "192.168.240.0/20"
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/32" run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/32"
assert_output "192.168.255.14/32" assert_output "192.168.255.14/32"
} }

View File

@ -9,17 +9,18 @@ function setup_file() {
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_changedetector_one) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_changedetector_one)
docker run -d --name mail_changedetector_one \ docker run -d --name mail_changedetector_one \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e LOG_LEVEL=trace \ -e LOG_LEVEL=trace \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_changedetector_one
docker run -d --name mail_changedetector_two \ docker run -d --name mail_changedetector_two \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e LOG_LEVEL=trace \ -e LOG_LEVEL=trace \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_changedetector_one
wait_for_finished_setup_in_container mail_changedetector_two wait_for_finished_setup_in_container mail_changedetector_two
} }
@ -36,11 +37,13 @@ function teardown_file() {
@test "checking changedetector: can detect changes & between two containers using same config" { @test "checking changedetector: can detect changes & between two containers using same config" {
echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf" echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf"
sleep 25 sleep 25
run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail -3000 changedetector" run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail -3000 changedetector"
assert_output --partial "postfix: stopped" assert_output --partial "postfix: stopped"
assert_output --partial "postfix: started" assert_output --partial "postfix: started"
assert_output --partial "Change detected" assert_output --partial "Change detected"
assert_output --partial "Removed lock" assert_output --partial "Removed lock"
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl tail -3000 changedetector" run docker exec mail_changedetector_two /bin/bash -c "supervisorctl tail -3000 changedetector"
assert_output --partial "postfix: stopped" assert_output --partial "postfix: stopped"
assert_output --partial "postfix: started" assert_output --partial "postfix: started"
@ -54,10 +57,12 @@ function teardown_file() {
echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf" echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf"
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl start changedetector" run docker exec mail_changedetector_two /bin/bash -c "supervisorctl start changedetector"
sleep 15 sleep 15
run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail changedetector" run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail changedetector"
assert_output --partial "another execution of 'check-for-changes.sh' is happening" assert_output --partial "another execution of 'check-for-changes.sh' is happening"
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl tail changedetector" run docker exec mail_changedetector_two /bin/bash -c "supervisorctl tail changedetector"
assert_output --partial "another execution of 'check-for-changes.sh' is happening" assert_output --partial "another execution of 'check-for-changes.sh' is happening"
# Ensure starting a new check-for-changes.sh instance (restarting here) doesn't delete the lock # Ensure starting a new check-for-changes.sh instance (restarting here) doesn't delete the lock
docker exec mail_changedetector_two /bin/bash -c "rm -f /var/log/supervisor/changedetector.log" docker exec mail_changedetector_two /bin/bash -c "rm -f /var/log/supervisor/changedetector.log"
run docker exec mail_changedetector_two /bin/bash -c "supervisorctl restart changedetector" run docker exec mail_changedetector_two /bin/bash -c "supervisorctl restart changedetector"
@ -72,9 +77,11 @@ function teardown_file() {
docker exec mail_changedetector_one /bin/bash -c "touch /tmp/docker-mailserver/check-for-changes.sh.lock" docker exec mail_changedetector_one /bin/bash -c "touch /tmp/docker-mailserver/check-for-changes.sh.lock"
echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf" echo "" >> "$(private_config_path mail_changedetector_one)/postfix-accounts.cf"
sleep 15 sleep 15
run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail changedetector" run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail changedetector"
assert_output --partial "another execution of 'check-for-changes.sh' is happening" assert_output --partial "another execution of 'check-for-changes.sh' is happening"
sleep 65 sleep 65
run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail -3000 changedetector" run docker exec mail_changedetector_one /bin/bash -c "supervisorctl tail -3000 changedetector"
assert_output --partial "removing stale lock file" assert_output --partial "removing stale lock file"
} }

View File

@ -1,15 +1,17 @@
load 'test_helper/common' load 'test_helper/common'
setup_file() { setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run --rm -d --name mail_disabled_clamav_spamassassin \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run --rm -d --name mail_disabled_clamav_spamassassin \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e ENABLE_CLAMAV=0 \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_SPAMASSASSIN=0 \ -e ENABLE_CLAMAV=0 \
-e AMAVIS_LOGLEVEL=2 \ -e ENABLE_SPAMASSASSIN=0 \
-h mail.my-domain.com -t "${NAME}" -e AMAVIS_LOGLEVEL=2 \
-h mail.my-domain.com -t "${NAME}"
# TODO: find a better way to know when we have waited long enough # TODO: find a better way to know when we have waited long enough
# for ClamAV to should have come up, if it were enabled # for ClamAV to should have come up, if it were enabled
wait_for_smtp_port_in_container mail_disabled_clamav_spamassassin wait_for_smtp_port_in_container mail_disabled_clamav_spamassassin

View File

@ -7,20 +7,20 @@ function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . "${CONTAINER}") PRIVATE_CONFIG=$(duplicate_config_for_container . "${CONTAINER}")
docker run --rm -d --name "${CONTAINER}" \ docker run --rm -d --name "${CONTAINER}" \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e ENABLE_DNSBL=1 \ -e ENABLE_DNSBL=1 \
-h mail.my-domain.com \ -h mail.my-domain.com \
-t "${NAME}" -t "${NAME}"
docker run --rm -d --name "${CONTAINER2}" \ docker run --rm -d --name "${CONTAINER2}" \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e ENABLE_DNSBL=0 \ -e ENABLE_DNSBL=0 \
-h mail.my-domain.com \ -h mail.my-domain.com \
-t "${NAME}" -t "${NAME}"
wait_for_smtp_port_in_container "${CONTAINER}" wait_for_smtp_port_in_container "${CONTAINER}"
wait_for_smtp_port_in_container "${CONTAINER2}" wait_for_smtp_port_in_container "${CONTAINER2}"
} }
# ENABLE_DNSBL=1 # ENABLE_DNSBL=1

View File

@ -1,29 +1,28 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run --rm -d --name mail_fail2ban \ docker run --rm -d --name mail_fail2ban \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_FAIL2BAN=1 \ -e ENABLE_FAIL2BAN=1 \
-e POSTSCREEN_ACTION=ignore \ -e POSTSCREEN_ACTION=ignore \
--cap-add=NET_ADMIN \ --cap-add=NET_ADMIN \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
# Create a container which will send wrong authentications and should get banned # Create a container which will send wrong authentications and should get banned
docker run --name fail-auth-mailer \ docker run --name fail-auth-mailer \
-e MAIL_FAIL2BAN_IP="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_fail2ban)" \ -e MAIL_FAIL2BAN_IP="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_fail2ban)" \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test \
-d "${NAME}" \ -d "${NAME}" \
tail -f /var/log/faillog tail -f /var/log/faillog
wait_for_finished_setup_in_container mail_fail2ban
wait_for_finished_setup_in_container mail_fail2ban
} }
function teardown_file() { function teardown_file() {
docker rm -f mail_fail2ban fail-auth-mailer docker rm -f mail_fail2ban fail-auth-mailer
} }
# #
@ -102,7 +101,6 @@ function teardown_file() {
} }
@test "checking fail2ban: unban ip works" { @test "checking fail2ban: unban ip works" {
FAIL_AUTH_MAILER_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' fail-auth-mailer) FAIL_AUTH_MAILER_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' fail-auth-mailer)
docker exec mail_fail2ban fail2ban-client set postfix-sasl unbanip "${FAIL_AUTH_MAILER_IP}" docker exec mail_fail2ban fail2ban-client set postfix-sasl unbanip "${FAIL_AUTH_MAILER_IP}"
@ -131,7 +129,6 @@ function teardown_file() {
} }
@test "checking setup.sh: setup.sh fail2ban" { @test "checking setup.sh: setup.sh fail2ban" {
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.4" run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.4"
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.5" run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.5"

View File

@ -1,19 +1,21 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_fetchmail \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run -d --name mail_fetchmail \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e ENABLE_FETCHMAIL=1 \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
--cap-add=NET_ADMIN \ -e ENABLE_FETCHMAIL=1 \
-h mail.my-domain.com -t "${NAME}" --cap-add=NET_ADMIN \
wait_for_finished_setup_in_container mail_fetchmail -h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_fetchmail
} }
function teardown_file() { function teardown_file() {
docker rm -f mail_fetchmail docker rm -f mail_fetchmail
} }
# #

View File

@ -1,20 +1,22 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_fetchmail_parallel \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run -d --name mail_fetchmail_parallel \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e ENABLE_FETCHMAIL=1 \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e FETCHMAIL_PARALLEL=1 \ -e ENABLE_FETCHMAIL=1 \
--cap-add=NET_ADMIN \ -e FETCHMAIL_PARALLEL=1 \
-h mail.my-domain.com -t "${NAME}" --cap-add=NET_ADMIN \
wait_for_finished_setup_in_container mail_fetchmail_parallel -h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_fetchmail_parallel
} }
function teardown_file() { function teardown_file() {
docker rm -f mail_fetchmail_parallel docker rm -f mail_fetchmail_parallel
} }
# #

View File

@ -3,25 +3,25 @@ load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_override_hostname) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_override_hostname)
docker run --rm -d --name mail_override_hostname \ docker run --rm -d --name mail_override_hostname \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e PERMIT_DOCKER=network \ -e PERMIT_DOCKER=network \
-e ENABLE_SRS=1 \ -e ENABLE_SRS=1 \
-e OVERRIDE_HOSTNAME=mail.my-domain.com \ -e OVERRIDE_HOSTNAME=mail.my-domain.com \
-h unknown.domain.tld \ -h unknown.domain.tld \
-t "${NAME}" -t "${NAME}"
PRIVATE_CONFIG_TWO=$(duplicate_config_for_container . mail_non_subdomain_hostname) PRIVATE_CONFIG_TWO=$(duplicate_config_for_container . mail_non_subdomain_hostname)
docker run --rm -d --name mail_non_subdomain_hostname \ docker run --rm -d --name mail_non_subdomain_hostname \
-v "${PRIVATE_CONFIG_TWO}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG_TWO}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e PERMIT_DOCKER=network \ -e PERMIT_DOCKER=network \
-e ENABLE_SRS=1 \ -e ENABLE_SRS=1 \
--hostname domain.com \ --hostname domain.com \
--domainname domain.com \ -t "${NAME}"
-t "${NAME}"
PRIVATE_CONFIG_THREE=$(duplicate_config_for_container . mail_srs_domainname) PRIVATE_CONFIG_THREE=$(duplicate_config_for_container . mail_srs_domainname)
docker run --rm -d --name mail_srs_domainname \ docker run --rm -d --name mail_srs_domainname \
@ -45,11 +45,8 @@ function setup_file() {
-t "${NAME}" -t "${NAME}"
wait_for_smtp_port_in_container mail_override_hostname 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_non_subdomain_hostname
wait_for_smtp_port_in_container mail_srs_domainname wait_for_smtp_port_in_container mail_srs_domainname
wait_for_smtp_port_in_container mail_domainname wait_for_smtp_port_in_container mail_domainname
# postfix virtual transport lmtp # postfix virtual transport lmtp
@ -57,6 +54,10 @@ function setup_file() {
docker exec mail_non_subdomain_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"
} }
function teardown_file() {
docker rm -f mail_override_hostname mail_non_subdomain_hostname mail_srs_domainname mail_domainname
}
@test "checking SRS: SRS_DOMAINNAME is used correctly" { @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 repeat_until_success_or_timeout 15 docker exec mail_srs_domainname grep "SRS_DOMAIN=srs.my-domain.com" /etc/default/postsrsd
} }
@ -73,16 +74,22 @@ function setup_file() {
@test "checking configuration: hostname/domainname override: check overriden hostname is applied to all configs" { @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" run docker exec mail_override_hostname /bin/bash -c "cat /etc/mailname | grep my-domain.com"
assert_success assert_success
run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep mydomain | grep my-domain.com" run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep mydomain | grep my-domain.com"
assert_success assert_success
run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep myhostname | grep mail.my-domain.com" run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep myhostname | grep mail.my-domain.com"
assert_success assert_success
run docker exec mail_override_hostname /bin/bash -c "doveconf | grep hostname | grep mail.my-domain.com" run docker exec mail_override_hostname /bin/bash -c "doveconf | grep hostname | grep mail.my-domain.com"
assert_success assert_success
run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep mail.my-domain.com" run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep mail.my-domain.com"
assert_success assert_success
run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep mail.my-domain.com" run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep mail.my-domain.com"
assert_success 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" 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 assert_success
} }
@ -95,6 +102,7 @@ function setup_file() {
@test "checking configuration: hostname/domainname override: check headers of received mail" { @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" run docker exec mail_override_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1"
assert_success assert_success
run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep mail.my-domain.com" run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep mail.my-domain.com"
assert_success assert_success
@ -125,16 +133,22 @@ function setup_file() {
@test "checking configuration: non-subdomain: check overriden hostname is applied to all configs" { @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" run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/mailname | grep domain.com"
assert_success assert_success
run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep mydomain | grep domain.com" run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep mydomain | grep domain.com"
assert_success assert_success
run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep myhostname | grep domain.com" run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep myhostname | grep domain.com"
assert_success assert_success
run docker exec mail_non_subdomain_hostname /bin/bash -c "doveconf | grep hostname | grep domain.com" run docker exec mail_non_subdomain_hostname /bin/bash -c "doveconf | grep hostname | grep domain.com"
assert_success assert_success
run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep domain.com" run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep domain.com"
assert_success assert_success
run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep domain.com" run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep domain.com"
assert_success 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" run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/amavis/conf.d/05-node_id | grep myhostname | grep domain.com"
assert_success assert_success
} }
@ -147,6 +161,7 @@ function setup_file() {
@test "checking configuration: non-subdomain: check headers of received mail" { @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" run docker exec mail_non_subdomain_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1"
assert_success assert_success
run docker exec mail_non_subdomain_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep domain.com" run docker exec mail_non_subdomain_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep domain.com"
assert_success assert_success
} }

View File

@ -1,10 +1,11 @@
load 'test_helper/common' load 'test_helper/common'
setup_file() { setup_file() {
local PRIVATE_CONFIG PRIVATE_ETC local PRIVATE_CONFIG PRIVATE_ETC
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
PRIVATE_ETC=$(duplicate_config_for_container dovecot-lmtp/ mail_lmtp_ip_dovecot-lmtp) PRIVATE_ETC=$(duplicate_config_for_container dovecot-lmtp/ mail_lmtp_ip_dovecot-lmtp)
docker run -d --name mail_lmtp_ip \
docker run -d --name mail_lmtp_ip \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "${PRIVATE_ETC}":/etc/dovecot \ -v "${PRIVATE_ETC}":/etc/dovecot \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
@ -12,12 +13,12 @@ setup_file() {
-e POSTFIX_DAGENT=lmtp:127.0.0.1:24 \ -e POSTFIX_DAGENT=lmtp:127.0.0.1:24 \
-e PERMIT_DOCKER=container \ -e PERMIT_DOCKER=container \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_lmtp_ip
wait_for_finished_setup_in_container mail_lmtp_ip
} }
teardown_file() { teardown_file() {
docker rm -f mail_lmtp_ip docker rm -f mail_lmtp_ip
} }
# #

View File

@ -1,16 +1,17 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_pop3 \
docker run -d --name mail_pop3 \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_POP3=1 \ -e ENABLE_POP3=1 \
-e PERMIT_DOCKER=container \ -e PERMIT_DOCKER=container \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_pop3 wait_for_finished_setup_in_container mail_pop3
} }
function teardown_file() { function teardown_file() {
@ -43,10 +44,13 @@ function teardown_file() {
@test "checking spamassassin: docker env variables are set correctly (default)" { @test "checking spamassassin: docker env variables are set correctly (default)" {
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'"
assert_success assert_success
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'" run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'"
assert_success assert_success
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'" run docker exec mail_pop3 /bin/sh -c "grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'"
assert_success assert_success
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= .\*\*\*SPAM\*\*\* .'" run docker exec mail_pop3 /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= .\*\*\*SPAM\*\*\* .'"
assert_success assert_success
} }
@ -58,6 +62,7 @@ function teardown_file() {
@test "checking system: /var/log/mail/mail.log is error free" { @test "checking system: /var/log/mail/mail.log is error free" {
run docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail/mail.log run docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail/mail.log
assert_failure assert_failure
run docker exec mail_pop3 grep ': error:' /var/log/mail/mail.log run docker exec mail_pop3 grep ': error:' /var/log/mail/mail.log
assert_failure assert_failure
} }

View File

@ -7,10 +7,11 @@ load 'test_helper/common'
@test "checking postfix: inet default" { @test "checking postfix: inet default" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . ) PRIVATE_CONFIG=$(duplicate_config_for_container . )
docker run -d --name mail_postfix_inet_default \ docker run -d --name mail_postfix_inet_default \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
teardown() { docker rm -f mail_postfix_inet_default; } teardown() { docker rm -f mail_postfix_inet_default; }
@ -24,11 +25,12 @@ load 'test_helper/common'
@test "checking postfix: inet all" { @test "checking postfix: inet all" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . ) PRIVATE_CONFIG=$(duplicate_config_for_container . )
docker run -d --name mail_postfix_inet_all \ docker run -d --name mail_postfix_inet_all \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e POSTFIX_INET_PROTOCOLS=all \ -e POSTFIX_INET_PROTOCOLS=all \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
teardown() { docker rm -f mail_postfix_inet_all; } teardown() { docker rm -f mail_postfix_inet_all; }
@ -42,11 +44,12 @@ load 'test_helper/common'
@test "checking postfix: inet ipv4" { @test "checking postfix: inet ipv4" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . ) PRIVATE_CONFIG=$(duplicate_config_for_container . )
docker run -d --name mail_postfix_inet_ipv4 \ docker run -d --name mail_postfix_inet_ipv4 \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e POSTFIX_INET_PROTOCOLS=ipv4 \ -e POSTFIX_INET_PROTOCOLS=ipv4 \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
teardown() { docker rm -f mail_postfix_inet_ipv4; } teardown() { docker rm -f mail_postfix_inet_ipv4; }
@ -60,11 +63,12 @@ load 'test_helper/common'
@test "checking postfix: inet ipv6" { @test "checking postfix: inet ipv6" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . ) PRIVATE_CONFIG=$(duplicate_config_for_container . )
docker run -d --name mail_postfix_inet_ipv6 \ docker run -d --name mail_postfix_inet_ipv6 \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e POSTFIX_INET_PROTOCOLS=ipv6 \ -e POSTFIX_INET_PROTOCOLS=ipv6 \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
teardown() { docker rm -f mail_postfix_inet_ipv6; } teardown() { docker rm -f mail_postfix_inet_ipv6; }

View File

@ -1,30 +1,31 @@
load 'test_helper/common' load 'test_helper/common'
setup() { setup() {
# Getting mail container IP # Getting mail container IP
MAIL_POSTSCREEN_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_postscreen) MAIL_POSTSCREEN_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_postscreen)
} }
setup_file() { setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_postscreen \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e POSTSCREEN_ACTION=enforce \
--cap-add=NET_ADMIN \
-h mail.my-domain.com -t "${NAME}"
docker run --name mail_postscreen_sender \ docker run -d --name mail_postscreen \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-d "${NAME}" \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
tail -f /var/log/faillog -e POSTSCREEN_ACTION=enforce \
--cap-add=NET_ADMIN \
-h mail.my-domain.com -t "${NAME}"
wait_for_smtp_port_in_container mail_postscreen docker run --name mail_postscreen_sender \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-d "${NAME}" \
tail -f /var/log/faillog
wait_for_smtp_port_in_container mail_postscreen
} }
teardown_file() { teardown_file() {
docker rm -f mail_postscreen mail_postscreen_sender docker rm -f mail_postscreen mail_postscreen_sender
} }
@test "checking postscreen: talk too fast" { @test "checking postscreen: talk too fast" {

View File

@ -3,6 +3,7 @@ load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_privacy \ docker run -d --name mail_privacy \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
@ -29,9 +30,11 @@ function teardown_file() {
# shellcheck disable=SC2016 # shellcheck disable=SC2016
repeat_until_success_or_timeout 120 docker exec mail_privacy /bin/bash -c '[[ $(ls /var/mail/localhost.localdomain/user1/new | wc -l) -eq 1 ]]' repeat_until_success_or_timeout 120 docker exec mail_privacy /bin/bash -c '[[ $(ls /var/mail/localhost.localdomain/user1/new | wc -l) -eq 1 ]]'
docker logs mail_privacy docker logs mail_privacy
run docker exec mail_privacy /bin/sh -c "ls /var/mail/localhost.localdomain/user1/new | wc -l" run docker exec mail_privacy /bin/sh -c "ls /var/mail/localhost.localdomain/user1/new | wc -l"
assert_success assert_success
assert_output 1 assert_output 1
run docker exec mail_privacy /bin/sh -c 'grep -rE "^User-Agent:" /var/mail/localhost.localdomain/user1/new | wc -l' run docker exec mail_privacy /bin/sh -c 'grep -rE "^User-Agent:" /var/mail/localhost.localdomain/user1/new | wc -l'
assert_success assert_success
assert_output 0 assert_output 0

View File

@ -6,30 +6,34 @@ load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_no_quotas \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_QUOTAS=0 \
-h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_no_quotas docker run -d --name mail_no_quotas \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_QUOTAS=0 \
-h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_no_quotas
} }
function teardown_file() { function teardown_file() {
docker rm -f mail_no_quotas docker rm -f mail_no_quotas
} }
@test "checking dovecot: (ENABLE_QUOTAS=0) quota plugin is disabled" { @test "checking dovecot: (ENABLE_QUOTAS=0) quota plugin is disabled" {
run docker exec mail_no_quotas /bin/sh -c "grep '\$mail_plugins quota' /etc/dovecot/conf.d/10-mail.conf" run docker exec mail_no_quotas /bin/sh -c "grep '\$mail_plugins quota' /etc/dovecot/conf.d/10-mail.conf"
assert_failure assert_failure
run docker exec mail_no_quotas /bin/sh -c "grep '\$mail_plugins imap_quota' /etc/dovecot/conf.d/20-imap.conf"
assert_failure run docker exec mail_no_quotas /bin/sh -c "grep '\$mail_plugins imap_quota' /etc/dovecot/conf.d/20-imap.conf"
run docker exec mail_no_quotas ls /etc/dovecot/conf.d/90-quota.conf assert_failure
assert_failure
run docker exec mail_no_quotas ls /etc/dovecot/conf.d/90-quota.conf.disab run docker exec mail_no_quotas ls /etc/dovecot/conf.d/90-quota.conf
assert_success assert_failure
run docker exec mail_no_quotas ls /etc/dovecot/conf.d/90-quota.conf.disab
assert_success
} }
@test "checking postfix: (ENABLE_QUOTAS=0) dovecot quota absent in postconf" { @test "checking postfix: (ENABLE_QUOTAS=0) dovecot quota absent in postconf" {

View File

@ -1,21 +1,22 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run --rm -d --name mail_smtponly \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e SMTP_ONLY=1 \
-e PERMIT_DOCKER=network \
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
-t "${NAME}"
wait_for_finished_setup_in_container mail_smtponly docker run --rm -d --name mail_smtponly \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e SMTP_ONLY=1 \
-e PERMIT_DOCKER=network \
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
-t "${NAME}"
wait_for_finished_setup_in_container mail_smtponly
} }
function teardown_file() { function teardown_file() {
docker rm -f mail_smtponly docker rm -f mail_smtponly
} }
# #
@ -65,6 +66,7 @@ function teardown_file() {
@test "checking PERMIT_DOCKER=network: opendmarc/opendkim config" { @test "checking PERMIT_DOCKER=network: opendmarc/opendkim config" {
run docker exec mail_smtponly /bin/sh -c "cat /etc/opendmarc/ignore.hosts | grep '172.16.0.0/12'" run docker exec mail_smtponly /bin/sh -c "cat /etc/opendmarc/ignore.hosts | grep '172.16.0.0/12'"
assert_success assert_success
run docker exec mail_smtponly /bin/sh -c "cat /etc/opendkim/TrustedHosts | grep '172.16.0.0/12'" run docker exec mail_smtponly /bin/sh -c "cat /etc/opendkim/TrustedHosts | grep '172.16.0.0/12'"
assert_success assert_success
} }

View File

@ -43,6 +43,7 @@ function _should_bounce_spam() {
run docker exec "${TEST_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt" run docker exec "${TEST_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
assert_success assert_success
run repeat_until_success_or_timeout 20 sh -c "docker logs ${TEST_NAME} | grep 'Blocked SPAM {NoBounceInbound,Quarantined}'" # message will be added to a queue with varying delay until amavis receives it
run repeat_until_success_or_timeout 60 sh -c "docker logs ${TEST_NAME} | grep 'Blocked SPAM {NoBounceInbound,Quarantined}'"
assert_success assert_success
} }

View File

@ -5,17 +5,18 @@ load 'test_helper/common'
# When SPAMASSASSIN_SPAM_TO_INBOX=1, spam messages must be delivered and eventually (MOVE_SPAM_TO_JUNK=1) moved to the Junk folder. # When SPAMASSASSIN_SPAM_TO_INBOX=1, spam messages must be delivered and eventually (MOVE_SPAM_TO_JUNK=1) moved to the Junk folder.
@test "checking amavis: spam message is delivered and moved to the Junk folder (MOVE_SPAM_TO_JUNK=1)" { @test "checking amavis: spam message is delivered and moved to the Junk folder (MOVE_SPAM_TO_JUNK=1)" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_spam_moved_junk) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_spam_moved_junk)
docker run -d --name mail_spam_moved_junk \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run -d --name mail_spam_moved_junk \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e ENABLE_SPAMASSASSIN=1 \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e MOVE_SPAM_TO_JUNK=1 \ -e ENABLE_SPAMASSASSIN=1 \
-e PERMIT_DOCKER=container \ -e MOVE_SPAM_TO_JUNK=1 \
-e SA_SPAM_SUBJECT="SPAM: " \ -e PERMIT_DOCKER=container \
-e SPAMASSASSIN_SPAM_TO_INBOX=1 \ -e SA_SPAM_SUBJECT="SPAM: " \
-h mail.my-domain.com -t "${NAME}" -e SPAMASSASSIN_SPAM_TO_INBOX=1 \
-h mail.my-domain.com -t "${NAME}"
teardown() { docker rm -f mail_spam_moved_junk; } teardown() { docker rm -f mail_spam_moved_junk; }
@ -25,7 +26,8 @@ load 'test_helper/common'
run docker exec mail_spam_moved_junk /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt" run docker exec mail_spam_moved_junk /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
assert_success assert_success
run repeat_until_success_or_timeout 20 sh -c "docker logs mail_spam_moved_junk | grep 'Passed SPAM {RelayedTaggedInbound,Quarantined}'" # message will be added to a queue with varying delay until amavis receives it
run repeat_until_success_or_timeout 60 sh -c "docker logs mail_spam_moved_junk | grep 'Passed SPAM {RelayedTaggedInbound,Quarantined}'"
assert_success assert_success
# spam moved to Junk folder # spam moved to Junk folder
@ -36,15 +38,16 @@ load 'test_helper/common'
@test "checking amavis: spam message is delivered to INBOX (MOVE_SPAM_TO_JUNK=0)" { @test "checking amavis: spam message is delivered to INBOX (MOVE_SPAM_TO_JUNK=0)" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_spam_moved_new) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_spam_moved_new)
docker run -d --name mail_spam_moved_new \ docker run -d --name mail_spam_moved_new \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_SPAMASSASSIN=1 \ -e ENABLE_SPAMASSASSIN=1 \
-e MOVE_SPAM_TO_JUNK=0 \ -e MOVE_SPAM_TO_JUNK=0 \
-e PERMIT_DOCKER=container \ -e PERMIT_DOCKER=container \
-e SA_SPAM_SUBJECT="SPAM: " \ -e SA_SPAM_SUBJECT="SPAM: " \
-e SPAMASSASSIN_SPAM_TO_INBOX=1 \ -e SPAMASSASSIN_SPAM_TO_INBOX=1 \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
teardown() { docker rm -f mail_spam_moved_new; } teardown() { docker rm -f mail_spam_moved_new; }
@ -54,7 +57,8 @@ load 'test_helper/common'
run docker exec mail_spam_moved_new /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt" run docker exec mail_spam_moved_new /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-spam.txt"
assert_success assert_success
run repeat_until_success_or_timeout 20 sh -c "docker logs mail_spam_moved_new | grep 'Passed SPAM {RelayedTaggedInbound,Quarantined}'" # message will be added to a queue with varying delay until amavis receives it
run repeat_until_success_or_timeout 60 sh -c "docker logs mail_spam_moved_new | grep 'Passed SPAM {RelayedTaggedInbound,Quarantined}'"
assert_success assert_success
# spam moved to INBOX # spam moved to INBOX

View File

@ -1,22 +1,24 @@
load 'test_helper/common' load 'test_helper/common'
setup_file() { setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_special_use_folders \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run -d --name mail_special_use_folders \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e SASL_PASSWD="external-domain.com username:password" \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_CLAMAV=0 \ -e SASL_PASSWD="external-domain.com username:password" \
-e ENABLE_SPAMASSASSIN=0 \ -e ENABLE_CLAMAV=0 \
--cap-add=SYS_PTRACE \ -e ENABLE_SPAMASSASSIN=0 \
-e PERMIT_DOCKER=host \ --cap-add=SYS_PTRACE \
-h mail.my-domain.com -t "${NAME}" -e PERMIT_DOCKER=host \
wait_for_smtp_port_in_container mail_special_use_folders -h mail.my-domain.com -t "${NAME}"
wait_for_smtp_port_in_container mail_special_use_folders
} }
teardown_file() { teardown_file() {
docker rm -f mail_special_use_folders docker rm -f mail_special_use_folders
} }
@test "checking normal delivery" { @test "checking normal delivery" {

View File

@ -2,108 +2,110 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
# Internal copies made by `start-mailserver.sh`: # Internal copies made by `start-mailserver.sh`:
export PRIMARY_KEY='/etc/dms/tls/key' export PRIMARY_KEY='/etc/dms/tls/key'
export PRIMARY_CERT='/etc/dms/tls/cert' export PRIMARY_CERT='/etc/dms/tls/cert'
export FALLBACK_KEY='/etc/dms/tls/fallback_key' export FALLBACK_KEY='/etc/dms/tls/fallback_key'
export FALLBACK_CERT='/etc/dms/tls/fallback_cert' export FALLBACK_CERT='/etc/dms/tls/fallback_cert'
# Volume mounted certs: # Volume mounted certs:
export SSL_KEY_PATH='/config/ssl/key.ecdsa.pem' export SSL_KEY_PATH='/config/ssl/key.ecdsa.pem'
export SSL_CERT_PATH='/config/ssl/cert.ecdsa.pem' export SSL_CERT_PATH='/config/ssl/cert.ecdsa.pem'
export SSL_ALT_KEY_PATH='/config/ssl/key.rsa.pem' export SSL_ALT_KEY_PATH='/config/ssl/key.rsa.pem'
export SSL_ALT_CERT_PATH='/config/ssl/cert.rsa.pem' export SSL_ALT_CERT_PATH='/config/ssl/cert.rsa.pem'
local PRIVATE_CONFIG local PRIVATE_CONFIG
export DOMAIN_SSL_MANUAL='example.test' export DOMAIN_SSL_MANUAL='example.test'
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_manual_ssl \ docker run -d --name mail_manual_ssl \
--volume "${PRIVATE_CONFIG}/:/tmp/docker-mailserver/" \ --volume "${PRIVATE_CONFIG}/:/tmp/docker-mailserver/" \
--volume "$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/:/config/ssl/:ro" \ --volume "$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/:/config/ssl/:ro" \
--env LOG_LEVEL='trace' \ --env LOG_LEVEL='trace' \
--env SSL_TYPE='manual' \ --env SSL_TYPE='manual' \
--env TLS_LEVEL='modern' \ --env TLS_LEVEL='modern' \
--env SSL_KEY_PATH="${SSL_KEY_PATH}" \ --env SSL_KEY_PATH="${SSL_KEY_PATH}" \
--env SSL_CERT_PATH="${SSL_CERT_PATH}" \ --env SSL_CERT_PATH="${SSL_CERT_PATH}" \
--env SSL_ALT_KEY_PATH="${SSL_ALT_KEY_PATH}" \ --env SSL_ALT_KEY_PATH="${SSL_ALT_KEY_PATH}" \
--env SSL_ALT_CERT_PATH="${SSL_ALT_CERT_PATH}" \ --env SSL_ALT_CERT_PATH="${SSL_ALT_CERT_PATH}" \
--hostname "mail.${DOMAIN_SSL_MANUAL}" \ --hostname "mail.${DOMAIN_SSL_MANUAL}" \
--tty \ --tty \
"${NAME}" # Image name "${NAME}" # Image name
wait_for_finished_setup_in_container mail_manual_ssl
wait_for_finished_setup_in_container mail_manual_ssl
} }
function teardown_file() { function teardown_file() {
docker rm -f mail_manual_ssl docker rm -f mail_manual_ssl
} }
@test "checking ssl: ENV vars provided are valid files" { @test "checking ssl: ENV vars provided are valid files" {
assert docker exec mail_manual_ssl [ -f "${SSL_CERT_PATH}" ] assert docker exec mail_manual_ssl [ -f "${SSL_CERT_PATH}" ]
assert docker exec mail_manual_ssl [ -f "${SSL_KEY_PATH}" ] assert docker exec mail_manual_ssl [ -f "${SSL_KEY_PATH}" ]
assert docker exec mail_manual_ssl [ -f "${SSL_ALT_CERT_PATH}" ] assert docker exec mail_manual_ssl [ -f "${SSL_ALT_CERT_PATH}" ]
assert docker exec mail_manual_ssl [ -f "${SSL_ALT_KEY_PATH}" ] assert docker exec mail_manual_ssl [ -f "${SSL_ALT_KEY_PATH}" ]
} }
@test "checking ssl: manual configuration is correct" { @test "checking ssl: manual configuration is correct" {
local DOVECOT_CONFIG_SSL='/etc/dovecot/conf.d/10-ssl.conf' local DOVECOT_CONFIG_SSL='/etc/dovecot/conf.d/10-ssl.conf'
run docker exec mail_manual_ssl grep '^smtpd_tls_chain_files =' '/etc/postfix/main.cf' run docker exec mail_manual_ssl grep '^smtpd_tls_chain_files =' '/etc/postfix/main.cf'
assert_success assert_success
assert_output "smtpd_tls_chain_files = ${PRIMARY_KEY} ${PRIMARY_CERT} ${FALLBACK_KEY} ${FALLBACK_CERT}" assert_output "smtpd_tls_chain_files = ${PRIMARY_KEY} ${PRIMARY_CERT} ${FALLBACK_KEY} ${FALLBACK_CERT}"
run docker exec mail_manual_ssl grep '^ssl_key =' "${DOVECOT_CONFIG_SSL}" run docker exec mail_manual_ssl grep '^ssl_key =' "${DOVECOT_CONFIG_SSL}"
assert_success assert_success
assert_output "ssl_key = <${PRIMARY_KEY}" assert_output "ssl_key = <${PRIMARY_KEY}"
run docker exec mail_manual_ssl grep '^ssl_cert =' "${DOVECOT_CONFIG_SSL}" run docker exec mail_manual_ssl grep '^ssl_cert =' "${DOVECOT_CONFIG_SSL}"
assert_success assert_success
assert_output "ssl_cert = <${PRIMARY_CERT}" assert_output "ssl_cert = <${PRIMARY_CERT}"
run docker exec mail_manual_ssl grep '^ssl_alt_key =' "${DOVECOT_CONFIG_SSL}" run docker exec mail_manual_ssl grep '^ssl_alt_key =' "${DOVECOT_CONFIG_SSL}"
assert_success assert_success
assert_output "ssl_alt_key = <${FALLBACK_KEY}" assert_output "ssl_alt_key = <${FALLBACK_KEY}"
run docker exec mail_manual_ssl grep '^ssl_alt_cert =' "${DOVECOT_CONFIG_SSL}" run docker exec mail_manual_ssl grep '^ssl_alt_cert =' "${DOVECOT_CONFIG_SSL}"
assert_success assert_success
assert_output "ssl_alt_cert = <${FALLBACK_CERT}" assert_output "ssl_alt_cert = <${FALLBACK_CERT}"
} }
@test "checking ssl: manual configuration copied files correctly " { @test "checking ssl: manual configuration copied files correctly " {
run docker exec mail_manual_ssl cmp -s "${PRIMARY_KEY}" "${SSL_KEY_PATH}" run docker exec mail_manual_ssl cmp -s "${PRIMARY_KEY}" "${SSL_KEY_PATH}"
assert_success assert_success
run docker exec mail_manual_ssl cmp -s "${PRIMARY_CERT}" "${SSL_CERT_PATH}" run docker exec mail_manual_ssl cmp -s "${PRIMARY_CERT}" "${SSL_CERT_PATH}"
assert_success assert_success
# Fallback cert # Fallback cert
run docker exec mail_manual_ssl cmp -s "${FALLBACK_KEY}" "${SSL_ALT_KEY_PATH}" run docker exec mail_manual_ssl cmp -s "${FALLBACK_KEY}" "${SSL_ALT_KEY_PATH}"
assert_success assert_success
run docker exec mail_manual_ssl cmp -s "${FALLBACK_CERT}" "${SSL_ALT_CERT_PATH}" run docker exec mail_manual_ssl cmp -s "${FALLBACK_CERT}" "${SSL_ALT_CERT_PATH}"
assert_success assert_success
} }
@test "checking ssl: manual cert works correctly" { @test "checking ssl: manual cert works correctly" {
wait_for_tcp_port_in_container 587 mail_manual_ssl wait_for_tcp_port_in_container 587 mail_manual_ssl
local TEST_COMMAND=(timeout 1 openssl s_client -connect mail.example.test:587 -starttls smtp)
local RESULT
# Should fail as a chain of trust is required to verify successfully: local TEST_COMMAND=(timeout 1 openssl s_client -connect mail.example.test:587 -starttls smtp)
RESULT=$(docker exec mail_manual_ssl "${TEST_COMMAND[@]}" | grep 'Verification error:') local RESULT
assert_equal "${RESULT}" 'Verification error: unable to verify the first certificate'
# Provide the Root CA cert for successful verification: # Should fail as a chain of trust is required to verify successfully:
local CA_CERT='/config/ssl/ca-cert.ecdsa.pem' RESULT=$(docker exec mail_manual_ssl "${TEST_COMMAND[@]}" | grep 'Verification error:')
assert docker exec mail_manual_ssl [ -f "${CA_CERT}" ] assert_equal "${RESULT}" 'Verification error: unable to verify the first certificate'
RESULT=$(docker exec mail_manual_ssl "${TEST_COMMAND[@]}" -CAfile "${CA_CERT}" | grep 'Verification: OK')
assert_equal "${RESULT}" 'Verification: OK' # Provide the Root CA cert for successful verification:
local CA_CERT='/config/ssl/ca-cert.ecdsa.pem'
assert docker exec mail_manual_ssl [ -f "${CA_CERT}" ]
RESULT=$(docker exec mail_manual_ssl "${TEST_COMMAND[@]}" -CAfile "${CA_CERT}" | grep 'Verification: OK')
assert_equal "${RESULT}" 'Verification: OK'
} }
@test "checking ssl: manual cert changes are picked up by check-for-changes" { @test "checking ssl: manual cert changes are picked up by check-for-changes" {
printf '%s' 'someThingsChangedHere' \ printf '%s' 'someThingsChangedHere' \
>>"$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/key.ecdsa.pem" >>"$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/key.ecdsa.pem"
run timeout 15 docker exec mail_manual_ssl bash -c "tail -F /var/log/supervisor/changedetector.log | sed '/Manual certificates have changed/ q'" run timeout 15 docker exec mail_manual_ssl bash -c "tail -F /var/log/supervisor/changedetector.log | sed '/Manual certificates have changed/ q'"
assert_success assert_success
sed -i '/someThingsChangedHere/d' "$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/key.ecdsa.pem" sed -i '/someThingsChangedHere/d' "$(pwd)/test/test-files/ssl/${DOMAIN_SSL_MANUAL}/with_ca/ecdsa/key.ecdsa.pem"
} }

View File

@ -15,7 +15,7 @@ setup_file() {
} }
teardown_file() { teardown_file() {
docker rm -f mail_time docker rm -f mail_time
} }
@test "checking time: setting the time with TZ works correctly" { @test "checking time: setting the time with TZ works correctly" {

View File

@ -14,7 +14,7 @@ load 'test_helper/common'
# - A warning is raised about usage of potentially insecure parameters. # - A warning is raised about usage of potentially insecure parameters.
function teardown() { function teardown() {
docker rm -f mail_dhparams docker rm -f mail_dhparams
} }
function setup_file() { function setup_file() {
@ -33,7 +33,6 @@ function setup_file() {
export DH_CUSTOM_PARAMS export DH_CUSTOM_PARAMS
export DH_CUSTOM_CHECKSUM export DH_CUSTOM_CHECKSUM
DH_DEFAULT_PARAMS="$(pwd)/target/shared/ffdhe4096.pem" DH_DEFAULT_PARAMS="$(pwd)/target/shared/ffdhe4096.pem"
DH_DEFAULT_CHECKSUM=$(sha512sum "${DH_DEFAULT_PARAMS}" | awk '{print $1}') DH_DEFAULT_CHECKSUM=$(sha512sum "${DH_DEFAULT_PARAMS}" | awk '{print $1}')
@ -46,83 +45,83 @@ function setup_file() {
# } # }
@test "testing tls: DH Parameters - Verify integrity of Default (ffdhe4096)" { @test "testing tls: DH Parameters - Verify integrity of Default (ffdhe4096)" {
# Reference used (22/04/2020): # Reference used (22/04/2020):
# https://english.ncsc.nl/publications/publications/2019/juni/01/it-security-guidelines-for-transport-layer-security-tls # https://english.ncsc.nl/publications/publications/2019/juni/01/it-security-guidelines-for-transport-layer-security-tls
run echo "${DH_DEFAULT_CHECKSUM}" run echo "${DH_DEFAULT_CHECKSUM}"
refute_output '' # checksum must not be empty refute_output '' # checksum must not be empty
# Verify the FFDHE params file has not been modified (equivalent to `target/shared/ffdhe4096.pem.sha512sum`): # Verify the FFDHE params file has not been modified (equivalent to `target/shared/ffdhe4096.pem.sha512sum`):
local DH_MOZILLA_CHECKSUM local DH_MOZILLA_CHECKSUM
DH_MOZILLA_CHECKSUM=$(curl https://ssl-config.mozilla.org/ffdhe4096.txt -s | sha512sum | awk '{print $1}') DH_MOZILLA_CHECKSUM=$(curl https://ssl-config.mozilla.org/ffdhe4096.txt -s | sha512sum | awk '{print $1}')
assert_equal "${DH_DEFAULT_CHECKSUM}" "${DH_MOZILLA_CHECKSUM}" assert_equal "${DH_DEFAULT_CHECKSUM}" "${DH_MOZILLA_CHECKSUM}"
} }
@test "testing tls: DH Parameters - Default [ONE_DIR=0]" { @test "testing tls: DH Parameters - Default [ONE_DIR=0]" {
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_default_0) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_default_0)
DMS_ONE_DIR=0 DMS_ONE_DIR=0
common_container_setup common_container_setup
should_have_valid_checksum "${DH_DEFAULT_CHECKSUM}" should_have_valid_checksum "${DH_DEFAULT_CHECKSUM}"
} }
@test "testing tls: DH Parameters - Default [ONE_DIR=1]" { @test "testing tls: DH Parameters - Default [ONE_DIR=1]" {
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_default_1) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_default_1)
common_container_setup common_container_setup
should_have_valid_checksum "${DH_DEFAULT_CHECKSUM}" should_have_valid_checksum "${DH_DEFAULT_CHECKSUM}"
} }
@test "testing tls: DH Parameters - Custom [ONE_DIR=0]" { @test "testing tls: DH Parameters - Custom [ONE_DIR=0]" {
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_custom_0) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_custom_0)
# shellcheck disable=SC2030 # shellcheck disable=SC2030
DMS_ONE_DIR=0 DMS_ONE_DIR=0
cp "${DH_CUSTOM_PARAMS}" "${PRIVATE_CONFIG}/dhparams.pem" cp "${DH_CUSTOM_PARAMS}" "${PRIVATE_CONFIG}/dhparams.pem"
common_container_setup common_container_setup
should_have_valid_checksum "${DH_CUSTOM_CHECKSUM}" should_have_valid_checksum "${DH_CUSTOM_CHECKSUM}"
should_emit_warning should_emit_warning
} }
@test "testing tls: DH Parameters - Custom [ONE_DIR=1]" { @test "testing tls: DH Parameters - Custom [ONE_DIR=1]" {
# shellcheck disable=SC2030 # shellcheck disable=SC2030
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_custom_1) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dhparams_custom_1)
cp "${DH_CUSTOM_PARAMS}" "${PRIVATE_CONFIG}/dhparams.pem" cp "${DH_CUSTOM_PARAMS}" "${PRIVATE_CONFIG}/dhparams.pem"
common_container_setup common_container_setup
should_have_valid_checksum "${DH_CUSTOM_CHECKSUM}" should_have_valid_checksum "${DH_CUSTOM_CHECKSUM}"
should_emit_warning should_emit_warning
} }
function common_container_setup() { function common_container_setup() {
# shellcheck disable=SC2031 # shellcheck disable=SC2031
docker run -d --name mail_dhparams \ docker run -d --name mail_dhparams \
-v "${PRIVATE_CONFIG}:/tmp/docker-mailserver" \ -v "${PRIVATE_CONFIG}:/tmp/docker-mailserver" \
-v "$(pwd)/test/test-files:/tmp/docker-mailserver-test:ro" \ -v "$(pwd)/test/test-files:/tmp/docker-mailserver-test:ro" \
-e ONE_DIR="${DMS_ONE_DIR}" \ -e ONE_DIR="${DMS_ONE_DIR}" \
-h mail.my-domain.com \ -h mail.my-domain.com \
--tty \ --tty \
"${NAME}" "${NAME}"
wait_for_finished_setup_in_container mail_dhparams wait_for_finished_setup_in_container mail_dhparams
} }
# Ensures the docker image services (Postfix and Dovecot) have the intended DH files # Ensures the docker image services (Postfix and Dovecot) have the intended DH files
function should_have_valid_checksum() { function should_have_valid_checksum() {
local DH_CHECKSUM=$1 local DH_CHECKSUM=$1
local DH_CHECKSUM_DOVECOT local DH_CHECKSUM_DOVECOT
DH_CHECKSUM_DOVECOT=$(docker exec mail_dhparams sha512sum /etc/dovecot/dh.pem | awk '{print $1}') DH_CHECKSUM_DOVECOT=$(docker exec mail_dhparams sha512sum /etc/dovecot/dh.pem | awk '{print $1}')
assert_equal "${DH_CHECKSUM_DOVECOT}" "${DH_CHECKSUM}" assert_equal "${DH_CHECKSUM_DOVECOT}" "${DH_CHECKSUM}"
local DH_CHECKSUM_POSTFIX local DH_CHECKSUM_POSTFIX
DH_CHECKSUM_POSTFIX=$(docker exec mail_dhparams sha512sum /etc/postfix/dhparams.pem | awk '{print $1}') DH_CHECKSUM_POSTFIX=$(docker exec mail_dhparams sha512sum /etc/postfix/dhparams.pem | awk '{print $1}')
assert_equal "${DH_CHECKSUM_POSTFIX}" "${DH_CHECKSUM}" assert_equal "${DH_CHECKSUM_POSTFIX}" "${DH_CHECKSUM}"
} }
function should_emit_warning() { function should_emit_warning() {
run sh -c "docker logs mail_dhparams | grep 'Using self-generated dhparams is considered insecure.'" run sh -c "docker logs mail_dhparams | grep 'Using self-generated dhparams is considered insecure.'"
assert_success assert_success
} }

View File

@ -1,53 +1,59 @@
load 'test_helper/common' load 'test_helper/common'
function setup() { function setup() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_undef_spam_subject \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_SPAMASSASSIN=1 \
-e SA_SPAM_SUBJECT="undef" \
-h mail.my-domain.com -t "${NAME}"
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_undef_spam_subject_2) PRIVATE_CONFIG=$(duplicate_config_for_container .)
CONTAINER=$(docker run -d \ docker run -d --name mail_undef_spam_subject \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-v "$(pwd)/test/onedir":/var/mail-state \ -e ENABLE_SPAMASSASSIN=1 \
-e ENABLE_CLAMAV=1 \ -e SA_SPAM_SUBJECT="undef" \
-e SPOOF_PROTECTION=1 \ -h mail.my-domain.com -t "${NAME}"
-e ENABLE_SPAMASSASSIN=1 \
-e REPORT_RECIPIENT=user1@localhost.localdomain \ PRIVATE_CONFIG=$(duplicate_config_for_container . mail_undef_spam_subject_2)
-e REPORT_SENDER=report1@mail.my-domain.com \ CONTAINER=$(docker run -d \
-e SA_TAG=-5.0 \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e SA_TAG2=2.0 \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e SA_KILL=3.0 \ -v "$(pwd)/test/onedir":/var/mail-state \
-e SA_SPAM_SUBJECT="SPAM: " \ -e ENABLE_CLAMAV=1 \
-e VIRUSMAILS_DELETE_DELAY=7 \ -e SPOOF_PROTECTION=1 \
-e ENABLE_SRS=1 \ -e ENABLE_SPAMASSASSIN=1 \
-e SASL_PASSWD="external-domain.com username:password" \ -e REPORT_RECIPIENT=user1@localhost.localdomain \
-e ENABLE_MANAGESIEVE=1 \ -e REPORT_SENDER=report1@mail.my-domain.com \
--cap-add=SYS_PTRACE \ -e SA_TAG=-5.0 \
-e PERMIT_DOCKER=host \ -e SA_TAG2=2.0 \
-h mail.my-domain.com -t "${NAME}") -e SA_KILL=3.0 \
wait_for_finished_setup_in_container mail_undef_spam_subject -e SA_SPAM_SUBJECT="SPAM: " \
wait_for_finished_setup_in_container "${CONTAINER}" -e VIRUSMAILS_DELETE_DELAY=7 \
-e ENABLE_SRS=1 \
-e SASL_PASSWD="external-domain.com username:password" \
-e ENABLE_MANAGESIEVE=1 \
--cap-add=SYS_PTRACE \
-e PERMIT_DOCKER=host \
-h mail.my-domain.com -t "${NAME}")
wait_for_finished_setup_in_container mail_undef_spam_subject
wait_for_finished_setup_in_container "${CONTAINER}"
} }
function teardown() { function teardown() {
docker rm -f mail_undef_spam_subject "${CONTAINER}" docker rm -f mail_undef_spam_subject "${CONTAINER}"
} }
@test "checking spamassassin: docker env variables are set correctly (custom)" { @test "checking spamassassin: docker env variables are set correctly (custom)" {
run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= -5.0'" run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= -5.0'"
assert_success assert_success
run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'"
assert_success assert_success
run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 3.0'" run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 3.0'"
assert_success assert_success
run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= .SPAM: .'" run docker exec "${CONTAINER}" /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= .SPAM: .'"
assert_success assert_success
run docker exec mail_undef_spam_subject /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= undef'" run docker exec mail_undef_spam_subject /bin/sh -c "grep '\$sa_spam_subject_tag' /etc/amavis/conf.d/20-debian_defaults | grep '= undef'"
assert_success assert_success
} }

View File

@ -1,10 +1,10 @@
load 'test_helper/common' load 'test_helper/common'
setup_file() { setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_with_imap \
docker run -d --name mail_with_imap \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_SASLAUTHD=1 \ -e ENABLE_SASLAUTHD=1 \
@ -13,11 +13,12 @@ setup_file() {
-e SASLAUTHD_MECHANISMS=rimap \ -e SASLAUTHD_MECHANISMS=rimap \
-e PERMIT_DOCKER=container \ -e PERMIT_DOCKER=container \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
wait_for_smtp_port_in_container mail_with_imap
wait_for_smtp_port_in_container mail_with_imap
} }
teardown_file() { teardown_file() {
docker rm -f mail_with_imap docker rm -f mail_with_imap
} }
# #

View File

@ -101,41 +101,52 @@ function teardown_file() {
} }
@test "checking postfix: ldap custom config files copied" { @test "checking postfix: ldap custom config files copied" {
run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-users.cf" run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-users.cf"
assert_success assert_success
run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-groups.cf"
assert_success run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-groups.cf"
run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-aliases.cf" assert_success
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep '# Testconfig for ldap integration' /etc/postfix/ldap-aliases.cf"
assert_success
} }
@test "checking postfix: ldap config overwrites success" { @test "checking postfix: ldap config overwrites success" {
run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-users.cf" run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-users.cf"
assert_success assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-users.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-users.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-users.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-groups.cf" run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-users.cf"
assert_success assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-groups.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-groups.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-groups.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-aliases.cf" run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-users.cf"
assert_success assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-aliases.cf"
assert_success run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-users.cf"
run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-aliases.cf" assert_success
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-aliases.cf" run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-groups.cf"
assert_success assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-groups.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-groups.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-groups.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'server_host = ldap' /etc/postfix/ldap-aliases.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'start_tls = no' /etc/postfix/ldap-aliases.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'search_base = ou=people,dc=localhost,dc=localdomain' /etc/postfix/ldap-aliases.cf"
assert_success
run docker exec mail_with_ldap /bin/sh -c "grep 'bind_dn = cn=admin,dc=localhost,dc=localdomain' /etc/postfix/ldap-aliases.cf"
assert_success
} }
# dovecot # dovecot

View File

@ -1,19 +1,21 @@
load 'test_helper/common' load 'test_helper/common'
setup_file() { setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_with_mdbox_format \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run -d --name mail_with_mdbox_format \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e SASL_PASSWD="external-domain.com username:password" \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_CLAMAV=0 \ -e SASL_PASSWD="external-domain.com username:password" \
-e ENABLE_SPAMASSASSIN=0 \ -e ENABLE_CLAMAV=0 \
-e DOVECOT_MAILBOX_FORMAT=mdbox \ -e ENABLE_SPAMASSASSIN=0 \
--cap-add=SYS_PTRACE \ -e DOVECOT_MAILBOX_FORMAT=mdbox \
-e PERMIT_DOCKER=host \ --cap-add=SYS_PTRACE \
-h mail.my-domain.com -t "${NAME}" -e PERMIT_DOCKER=host \
wait_for_smtp_port_in_container mail_with_mdbox_format -h mail.my-domain.com -t "${NAME}"
wait_for_smtp_port_in_container mail_with_mdbox_format
} }
teardown_file() { teardown_file() {

View File

@ -1,25 +1,27 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_with_postgrey \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run -d --name mail_with_postgrey \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e ENABLE_DNSBL=1 \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_POSTGREY=1 \ -e ENABLE_DNSBL=1 \
-e PERMIT_DOCKER=container \ -e ENABLE_POSTGREY=1 \
-e POSTGREY_AUTO_WHITELIST_CLIENTS=5 \ -e PERMIT_DOCKER=container \
-e POSTGREY_DELAY=15 \ -e POSTGREY_AUTO_WHITELIST_CLIENTS=5 \
-e POSTGREY_MAX_AGE=35 \ -e POSTGREY_DELAY=15 \
-e POSTGREY_TEXT="Delayed by Postgrey" \ -e POSTGREY_MAX_AGE=35 \
-h mail.my-domain.com -t "${NAME}" -e POSTGREY_TEXT="Delayed by Postgrey" \
# using postfix availability as start indicator, this might be insufficient for postgrey -h mail.my-domain.com -t "${NAME}"
wait_for_smtp_port_in_container mail_with_postgrey
# using postfix availability as start indicator, this might be insufficient for postgrey
wait_for_smtp_port_in_container mail_with_postgrey
} }
function teardown_file() { function teardown_file() {
docker rm -f mail_with_postgrey docker rm -f mail_with_postgrey
} }
@test "checking postgrey: /etc/postfix/main.cf correctly edited" { @test "checking postgrey: /etc/postfix/main.cf correctly edited" {
@ -32,6 +34,7 @@ function teardown_file() {
run docker exec mail_with_postgrey /bin/bash -c "grep '^POSTGREY_OPTS=\"--inet=127.0.0.1:10023 --delay=15 --max-age=35 --auto-whitelist-clients=5\"$' /etc/default/postgrey | wc -l" run docker exec mail_with_postgrey /bin/bash -c "grep '^POSTGREY_OPTS=\"--inet=127.0.0.1:10023 --delay=15 --max-age=35 --auto-whitelist-clients=5\"$' /etc/default/postgrey | wc -l"
assert_success assert_success
assert_output 1 assert_output 1
run docker exec mail_with_postgrey /bin/bash -c "grep '^POSTGREY_TEXT=\"Delayed by Postgrey\"$' /etc/default/postgrey | wc -l" run docker exec mail_with_postgrey /bin/bash -c "grep '^POSTGREY_TEXT=\"Delayed by Postgrey\"$' /etc/default/postgrey | wc -l"
assert_success assert_success
assert_output 1 assert_output 1
@ -61,6 +64,7 @@ function teardown_file() {
sleep 20 #wait 20 seconds so that postgrey would accept the message sleep 20 #wait 20 seconds so that postgrey would accept the message
run docker exec mail_with_postgrey /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/postgrey.txt" run docker exec mail_with_postgrey /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/postgrey.txt"
sleep 8 sleep 8
run docker exec mail_with_postgrey /bin/sh -c "grep -i 'action=pass, reason=triplet found.*user@external\.tld' /var/log/mail/mail.log | wc -l" run docker exec mail_with_postgrey /bin/sh -c "grep -i 'action=pass, reason=triplet found.*user@external\.tld' /var/log/mail/mail.log | wc -l"
assert_success assert_success
assert_output 1 assert_output 1

View File

@ -1,18 +1,20 @@
load 'test_helper/common' load 'test_helper/common'
function setup() { function setup() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
CONTAINER=$(docker run -d \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ CONTAINER=$(docker run -d \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com -t "${NAME}") -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
# using postfix availability as start indicator, this might be insufficient for postgrey -h mail.my-domain.com -t "${NAME}")
wait_for_smtp_port_in_container "${CONTAINER}"
# using postfix availability as start indicator, this might be insufficient for postgrey
wait_for_smtp_port_in_container "${CONTAINER}"
} }
function teardown() { function teardown() {
docker rm -f "${CONTAINER}" docker rm -f "${CONTAINER}"
} }
@test "checking process: postgrey (disabled in default configuration)" { @test "checking process: postgrey (disabled in default configuration)" {

View File

@ -1,27 +1,28 @@
load 'test_helper/common' load 'test_helper/common'
function setup_file() { function setup_file() {
# We use a temporary config directory since we'll be dynamically editing # We use a temporary config directory since we'll be dynamically editing
# it with setup.sh. # it with setup.sh.
tmp_confdir=$(mktemp -d /tmp/docker-mailserver-config-relay-hosts-XXXXX) tmp_confdir=$(mktemp -d /tmp/docker-mailserver-config-relay-hosts-XXXXX)
cp -a test/config/relay-hosts/* "${tmp_confdir}/" cp -a test/config/relay-hosts/* "${tmp_confdir}/"
docker run -d --name mail_with_relays \ docker run -d --name mail_with_relays \
-v "${tmp_confdir}":/tmp/docker-mailserver \ -v "${tmp_confdir}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e RELAY_HOST=default.relay.com \ -e RELAY_HOST=default.relay.com \
-e RELAY_PORT=2525 \ -e RELAY_PORT=2525 \
-e RELAY_USER=smtp_user \ -e RELAY_USER=smtp_user \
-e RELAY_PASSWORD=smtp_password \ -e RELAY_PASSWORD=smtp_password \
--cap-add=SYS_PTRACE \ --cap-add=SYS_PTRACE \
-e PERMIT_DOCKER=host \ -e PERMIT_DOCKER=host \
-h mail.my-domain.com -t "${NAME}" -h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_with_relays
wait_for_finished_setup_in_container mail_with_relays
} }
function teardown_file() { function teardown_file() {
docker rm -f mail_with_relays docker rm -f mail_with_relays
rm -rf "${tmp_confdir}" rm -rf "${tmp_confdir}"
} }
@test "checking relay hosts: default mapping is added from env vars" { @test "checking relay hosts: default mapping is added from env vars" {
@ -37,6 +38,7 @@ function teardown_file() {
@test "checking relay hosts: default mapping is added from env vars for new user entry" { @test "checking relay hosts: default mapping is added from env vars for new user entry" {
run docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map run docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map
assert_output '' assert_output ''
run ./setup.sh -c mail_with_relays email add user0@domainzero.tld password123 run ./setup.sh -c mail_with_relays email add user0@domainzero.tld password123
run_until_success_or_timeout 10 docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map run_until_success_or_timeout 10 docker exec mail_with_relays grep -e domainzero.tld /etc/postfix/relayhost_map
assert_output -e '^@domainzero.tld[[:space:]]+\[default.relay.com\]:2525$' assert_output -e '^@domainzero.tld[[:space:]]+\[default.relay.com\]:2525$'
@ -45,6 +47,7 @@ function teardown_file() {
@test "checking relay hosts: default mapping is added from env vars for new virtual user entry" { @test "checking relay hosts: default mapping is added from env vars for new virtual user entry" {
run docker exec mail_with_relays grep -e domain2.tld /etc/postfix/relayhost_map run docker exec mail_with_relays grep -e domain2.tld /etc/postfix/relayhost_map
assert_output '' assert_output ''
run ./setup.sh -c mail_with_relays alias add user2@domain2.tld user2@domaintwo.tld run ./setup.sh -c mail_with_relays alias add user2@domain2.tld user2@domaintwo.tld
run_until_success_or_timeout 10 docker exec mail_with_relays grep -e domain2.tld /etc/postfix/relayhost_map run_until_success_or_timeout 10 docker exec mail_with_relays grep -e domain2.tld /etc/postfix/relayhost_map
assert_output -e '^@domain2.tld[[:space:]]+\[default.relay.com\]:2525$' assert_output -e '^@domain2.tld[[:space:]]+\[default.relay.com\]:2525$'

View File

@ -1,23 +1,25 @@
load 'test_helper/common' load 'test_helper/common'
setup_file() { setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
docker run -d --name mail_with_sdbox_format \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ docker run -d --name mail_with_sdbox_format \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-e SASL_PASSWD="external-domain.com username:password" \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_CLAMAV=0 \ -e SASL_PASSWD="external-domain.com username:password" \
-e ENABLE_SPAMASSASSIN=0 \ -e ENABLE_CLAMAV=0 \
-e DOVECOT_MAILBOX_FORMAT=sdbox \ -e ENABLE_SPAMASSASSIN=0 \
--cap-add=SYS_PTRACE \ -e DOVECOT_MAILBOX_FORMAT=sdbox \
-e PERMIT_DOCKER=host \ --cap-add=SYS_PTRACE \
-h mail.my-domain.com -t "${NAME}" -e PERMIT_DOCKER=host \
wait_for_smtp_port_in_container mail_with_sdbox_format -h mail.my-domain.com -t "${NAME}"
wait_for_smtp_port_in_container mail_with_sdbox_format
} }
teardown_file() { teardown_file() {
docker rm -f mail_with_sdbox_format docker rm -f mail_with_sdbox_format
} }
@test "checking dovecot mailbox format: sdbox file created" { @test "checking dovecot mailbox format: sdbox file created" {

View File

@ -9,18 +9,18 @@ TEST_FILE='checking OpenDKIM: '
# WHY IS THIS CONTAINER EVEN CREATED WHEN MOST TESTS DO NOT USE IT? # WHY IS THIS CONTAINER EVEN CREATED WHEN MOST TESTS DO NOT USE IT?
function setup_file function setup_file
{ {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . "${CONTAINER_NAME}") PRIVATE_CONFIG=$(duplicate_config_for_container . "${CONTAINER_NAME}")
docker run -d \ docker run -d \
--name "${CONTAINER_NAME}" \ --name "${CONTAINER_NAME}" \
--cap-add=SYS_PTRACE \ --cap-add=SYS_PTRACE \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "${PWD}/test/test-files":/tmp/docker-mailserver-test:ro \ -v "${PWD}/test/test-files":/tmp/docker-mailserver-test:ro \
-e DEFAULT_RELAY_HOST=default.relay.host.invalid:25 \ -e DEFAULT_RELAY_HOST=default.relay.host.invalid:25 \
-e PERMIT_DOCKER=host \ -e PERMIT_DOCKER=host \
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-h mail.my-domain.com \ -h mail.my-domain.com \
-t "${IMAGE_NAME}" -t "${IMAGE_NAME}"
wait_for_finished_setup_in_container "${CONTAINER_NAME}" wait_for_finished_setup_in_container "${CONTAINER_NAME}"
@ -92,20 +92,21 @@ function teardown_file
# TODO Needs complete re-write # TODO Needs complete re-write
@test "${TEST_FILE}generator creates key size 4096" { @test "${TEST_FILE}generator creates key size 4096" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_4096) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_4096)
rm -rf "${PRIVATE_CONFIG}/key4096" rm -rf "${PRIVATE_CONFIG}/key4096"
mkdir -p "${PRIVATE_CONFIG}/config/key4096" mkdir -p "${PRIVATE_CONFIG}/config/key4096"
run docker run --rm \ run docker run --rm \
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/key2048/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/key2048/":/tmp/docker-mailserver/ \
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \ -v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \ -v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 4096 | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 4096 | wc -l'
assert_success
assert_output 6 assert_success
assert_output 6
run docker run --rm \ run docker run --rm \
-v "${PRIVATE_CONFIG}/key2048/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/key2048/opendkim":/etc/opendkim \
@ -121,20 +122,21 @@ function teardown_file
# TODO Needs complete re-write # TODO Needs complete re-write
@test "${TEST_FILE}generator creates key size 2048" { @test "${TEST_FILE}generator creates key size 2048" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_2048) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_2048)
rm -rf "${PRIVATE_CONFIG}/key2048" rm -rf "${PRIVATE_CONFIG}/key2048"
mkdir -p "${PRIVATE_CONFIG}/config/key2048" mkdir -p "${PRIVATE_CONFIG}/config/key2048"
run docker run --rm \ run docker run --rm \
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/key2048/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/key2048/":/tmp/docker-mailserver/ \
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \ -v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \ -v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 | wc -l'
assert_success
assert_output 6 assert_success
assert_output 6
run docker run --rm \ run docker run --rm \
-v "${PRIVATE_CONFIG}/key2048/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/key2048/opendkim":/etc/opendkim \
@ -150,20 +152,21 @@ function teardown_file
# TODO Needs complete re-write # TODO Needs complete re-write
@test "${TEST_FILE}generator creates key size 1024" { @test "${TEST_FILE}generator creates key size 1024" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_1024) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_key_size_1024)
rm -rf "${PRIVATE_CONFIG}/key1024" rm -rf "${PRIVATE_CONFIG}/key1024"
mkdir -p "${PRIVATE_CONFIG}/key1024" mkdir -p "${PRIVATE_CONFIG}/key1024"
run docker run --rm \ run docker run --rm \
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/key1024/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/key1024/":/tmp/docker-mailserver/ \
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \ -v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \ -v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 1024 | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 1024 | wc -l'
assert_success
assert_output 6 assert_success
assert_output 6
run docker run --rm \ run docker run --rm \
-v "${PRIVATE_CONFIG}/key1024/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/key1024/opendkim":/etc/opendkim \
@ -177,14 +180,17 @@ function teardown_file
@test "${TEST_FILE}generator creates keys, tables and TrustedHosts" { @test "${TEST_FILE}generator creates keys, tables and TrustedHosts" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dkim_generator_creates_keys_tables_TrustedHosts) PRIVATE_CONFIG=$(duplicate_config_for_container . mail_dkim_generator_creates_keys_tables_TrustedHosts)
rm -rf "${PRIVATE_CONFIG}/empty" rm -rf "${PRIVATE_CONFIG}/empty"
mkdir -p "${PRIVATE_CONFIG}/empty" mkdir -p "${PRIVATE_CONFIG}/empty"
run docker run --rm \ run docker run --rm \
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/empty/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/empty/":/tmp/docker-mailserver/ \
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \ -v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \ -v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l'
assert_success assert_success
assert_output 6 assert_output 6
@ -192,6 +198,7 @@ function teardown_file
run docker run --rm \ run docker run --rm \
-v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -199,6 +206,7 @@ function teardown_file
run docker run --rm \ run docker run --rm \
-v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -206,6 +214,7 @@ function teardown_file
run docker run --rm \ run docker run --rm \
-v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/empty/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l" "${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l"
assert_success assert_success
assert_output 4 assert_output 4
} }
@ -213,13 +222,16 @@ function teardown_file
@test "${TEST_FILE}generator creates keys, tables and TrustedHosts without postfix-accounts.cf" { @test "${TEST_FILE}generator creates keys, tables and TrustedHosts without postfix-accounts.cf" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . ) PRIVATE_CONFIG=$(duplicate_config_for_container . )
rm -rf "${PRIVATE_CONFIG}/without-accounts" rm -rf "${PRIVATE_CONFIG}/without-accounts"
mkdir -p "${PRIVATE_CONFIG}/without-accounts" mkdir -p "${PRIVATE_CONFIG}/without-accounts"
run docker run --rm \ run docker run --rm \
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/without-accounts/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/without-accounts/":/tmp/docker-mailserver/ \
-v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \ -v "${PRIVATE_CONFIG}/postfix-virtual.cf":/tmp/docker-mailserver/postfix-virtual.cf \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l'
assert_success assert_success
assert_output 5 assert_output 5
@ -228,6 +240,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/without-accounts/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/without-accounts/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -237,11 +250,13 @@ function teardown_file
# "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l' # "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l'
# assert_success # assert_success
# [ "${output}" -eq 0 ] # [ "${output}" -eq 0 ]
# check presence of tables and TrustedHosts # check presence of tables and TrustedHosts
run docker run --rm \ run docker run --rm \
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/without-accounts/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/without-accounts/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l" "${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l"
assert_success assert_success
assert_output 4 assert_output 4
} }
@ -249,13 +264,16 @@ function teardown_file
@test "${TEST_FILE}generator creates keys, tables and TrustedHosts without postfix-virtual.cf" { @test "${TEST_FILE}generator creates keys, tables and TrustedHosts without postfix-virtual.cf" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . "${BATS_TEST_NAME}") PRIVATE_CONFIG=$(duplicate_config_for_container . "${BATS_TEST_NAME}")
rm -rf "${PRIVATE_CONFIG}/without-virtual" rm -rf "${PRIVATE_CONFIG}/without-virtual"
mkdir -p "${PRIVATE_CONFIG}/without-virtual" mkdir -p "${PRIVATE_CONFIG}/without-virtual"
run docker run --rm \ run docker run --rm \
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/without-virtual/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/without-virtual/":/tmp/docker-mailserver/ \
-v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \ -v "${PRIVATE_CONFIG}/postfix-accounts.cf":/tmp/docker-mailserver/postfix-accounts.cf \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim | wc -l'
assert_success assert_success
assert_output 5 assert_output 5
@ -264,6 +282,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/localhost.localdomain/ | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -272,6 +291,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/otherdomain.tld | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -280,6 +300,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/without-virtual/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l" "${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys'|wc -l"
assert_success assert_success
assert_output 4 assert_output 4
} }
@ -294,6 +315,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain domain1.tld | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain domain1.tld | wc -l'
assert_success assert_success
assert_output 4 assert_output 4
@ -302,6 +324,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain "domain2.tld,domain3.tld" | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain "domain2.tld,domain3.tld" | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -310,6 +333,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/with-domain/":/tmp/docker-mailserver/ \
"${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain "domain3.tld,domain4.tld" | wc -l' "${IMAGE_NAME}" /bin/bash -c 'open-dkim keysize 2048 domain "domain3.tld,domain4.tld" | wc -l'
assert_success assert_success
assert_output 1 assert_output 1
@ -318,6 +342,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain1.tld/ | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain1.tld/ | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -326,6 +351,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain2.tld | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain2.tld | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -334,6 +360,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain3.tld | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain3.tld | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -342,6 +369,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain4.tld | wc -l' "${IMAGE_NAME}" /bin/bash -c 'ls -1 /etc/opendkim/keys/domain4.tld | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -350,6 +378,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys' | wc -l" "${IMAGE_NAME}" /bin/bash -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys' | wc -l"
assert_success assert_success
assert_output 4 assert_output 4
@ -359,6 +388,7 @@ function teardown_file
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c \ "${IMAGE_NAME}" /bin/bash -c \
"egrep 'domain1.tld|domain2.tld|domain3.tld|domain4.tld' /etc/opendkim/KeyTable | wc -l" "egrep 'domain1.tld|domain2.tld|domain3.tld|domain4.tld' /etc/opendkim/KeyTable | wc -l"
assert_success assert_success
assert_output 4 assert_output 4
@ -368,6 +398,7 @@ function teardown_file
-v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-domain/opendkim":/etc/opendkim \
"${IMAGE_NAME}" /bin/bash -c \ "${IMAGE_NAME}" /bin/bash -c \
"egrep 'domain1.tld|domain2.tld|domain3.tld|domain4.tld' /etc/opendkim/SigningTable | wc -l" "egrep 'domain1.tld|domain2.tld|domain3.tld|domain4.tld' /etc/opendkim/SigningTable | wc -l"
assert_success assert_success
assert_output 4 assert_output 4
} }
@ -382,6 +413,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-selector/":/tmp/docker-mailserver/ \ -v "${PRIVATE_CONFIG}/with-selector/":/tmp/docker-mailserver/ \
"${IMAGE_NAME:?}" /bin/sh -c "open-dkim keysize 2048 domain 'domain1.tld' selector mailer| wc -l" "${IMAGE_NAME:?}" /bin/sh -c "open-dkim keysize 2048 domain 'domain1.tld' selector mailer| wc -l"
assert_success assert_success
assert_output 4 assert_output 4
@ -390,6 +422,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
"${IMAGE_NAME:?}" /bin/sh -c 'ls -1 /etc/opendkim/keys/domain1.tld/ | wc -l' "${IMAGE_NAME:?}" /bin/sh -c 'ls -1 /etc/opendkim/keys/domain1.tld/ | wc -l'
assert_success assert_success
assert_output 2 assert_output 2
@ -398,6 +431,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
"${IMAGE_NAME:?}" /bin/sh -c "ls -1 /etc/opendkim/keys/domain1.tld | grep -E 'mailer.private|mailer.txt' | wc -l" "${IMAGE_NAME:?}" /bin/sh -c "ls -1 /etc/opendkim/keys/domain1.tld | grep -E 'mailer.private|mailer.txt' | wc -l"
assert_success assert_success
assert_output 2 assert_output 2
@ -406,6 +440,7 @@ function teardown_file
-e LOG_LEVEL='trace' \ -e LOG_LEVEL='trace' \
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
"${IMAGE_NAME:?}" /bin/sh -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys' | wc -l" "${IMAGE_NAME:?}" /bin/sh -c "ls -1 /etc/opendkim | grep -E 'KeyTable|SigningTable|TrustedHosts|keys' | wc -l"
assert_success assert_success
assert_output 4 assert_output 4
@ -415,6 +450,7 @@ function teardown_file
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
"${IMAGE_NAME:?}" /bin/sh -c \ "${IMAGE_NAME:?}" /bin/sh -c \
"grep 'domain1.tld' /etc/opendkim/KeyTable | wc -l" "grep 'domain1.tld' /etc/opendkim/KeyTable | wc -l"
assert_success assert_success
assert_output 1 assert_output 1
@ -424,6 +460,7 @@ function teardown_file
-v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \ -v "${PRIVATE_CONFIG}/with-selector/opendkim":/etc/opendkim \
"${IMAGE_NAME:?}" /bin/sh -c \ "${IMAGE_NAME:?}" /bin/sh -c \
"grep 'domain1.tld' /etc/opendkim/SigningTable | wc -l" "grep 'domain1.tld' /etc/opendkim/SigningTable | wc -l"
assert_success assert_success
assert_output 1 assert_output 1
} }

View File

@ -2,55 +2,57 @@ load 'test_helper/common'
NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME=non-default-docker-mail-network NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME=non-default-docker-mail-network
setup_file() { setup_file() {
docker network create --driver bridge "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}" docker network create --driver bridge "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}"
docker network create --driver bridge "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2" docker network create --driver bridge "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2"
# use two networks (default ("bridge") and our custom network) to recreate problematic test case where PERMIT_DOCKER=host would not help
# currently we cannot use --network in `docker run` multiple times, it will just use the last one
# instead we need to use create, network connect and start (see https://success.docker.com/article/multiple-docker-networks)
local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_smtponly_second_network)
docker create --name mail_smtponly_second_network \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e SMTP_ONLY=1 \
-e PERMIT_DOCKER=connected-networks \
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
--network "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}" \
-t "${NAME}"
docker network connect "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2" mail_smtponly_second_network
docker start mail_smtponly_second_network
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_smtponly_second_network_sender)
docker run -d --name mail_smtponly_second_network_sender \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e SMTP_ONLY=1 \
-e PERMIT_DOCKER=connected-networks \
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
--network "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2" \
-t "${NAME}"
# wait until postfix is up # use two networks (default ("bridge") and our custom network) to recreate problematic test case where PERMIT_DOCKER=host would not help
wait_for_smtp_port_in_container mail_smtponly_second_network # currently we cannot use --network in `docker run` multiple times, it will just use the last one
# instead we need to use create, network connect and start (see https://success.docker.com/article/multiple-docker-networks)
local PRIVATE_CONFIG
# create another container that enforces authentication even on local connections PRIVATE_CONFIG=$(duplicate_config_for_container . mail_smtponly_second_network)
docker run -d --name mail_smtponly_force_authentication \ docker create --name mail_smtponly_second_network \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e SMTP_ONLY=1 \ -e SMTP_ONLY=1 \
-e PERMIT_DOCKER=none \ -e PERMIT_DOCKER=connected-networks \
-e OVERRIDE_HOSTNAME=mail.my-domain.com \ -e OVERRIDE_HOSTNAME=mail.my-domain.com \
-t "${NAME}" --network "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}" \
-t "${NAME}"
# wait until postfix is up docker network connect "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2" mail_smtponly_second_network
wait_for_smtp_port_in_container mail_smtponly_force_authentication docker start mail_smtponly_second_network
PRIVATE_CONFIG=$(duplicate_config_for_container . mail_smtponly_second_network_sender)
docker run -d --name mail_smtponly_second_network_sender \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e SMTP_ONLY=1 \
-e PERMIT_DOCKER=connected-networks \
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
--network "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2" \
-t "${NAME}"
# wait until postfix is up
wait_for_smtp_port_in_container mail_smtponly_second_network
# create another container that enforces authentication even on local connections
docker run -d --name mail_smtponly_force_authentication \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e SMTP_ONLY=1 \
-e PERMIT_DOCKER=none \
-e OVERRIDE_HOSTNAME=mail.my-domain.com \
-t "${NAME}"
# wait until postfix is up
wait_for_smtp_port_in_container mail_smtponly_force_authentication
} }
teardown_file() { teardown_file() {
docker logs mail_smtponly_second_network docker logs mail_smtponly_second_network
docker rm -f mail_smtponly_second_network \ docker rm -f mail_smtponly_second_network mail_smtponly_second_network_sender mail_smtponly_force_authentication
mail_smtponly_second_network_sender \ docker network rm "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}" "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2"
mail_smtponly_force_authentication
docker network rm "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}" "${NON_DEFAULT_DOCKER_MAIL_NETWORK_NAME}2"
} }
@test "checking PERMIT_DOCKER: connected-networks" { @test "checking PERMIT_DOCKER: connected-networks" {
@ -62,8 +64,10 @@ teardown_file() {
run docker exec mail_smtponly_second_network /bin/sh -c "postconf -e smtp_host_lookup=no" run docker exec mail_smtponly_second_network /bin/sh -c "postconf -e smtp_host_lookup=no"
assert_success assert_success
run docker exec mail_smtponly_second_network /bin/sh -c "/etc/init.d/postfix reload" run docker exec mail_smtponly_second_network /bin/sh -c "/etc/init.d/postfix reload"
assert_success assert_success
# we should be able to send from the other container on the second network! # we should be able to send from the other container on the second network!
run docker exec mail_smtponly_second_network_sender /bin/sh -c "nc mail_smtponly_second_network 25 < /tmp/docker-mailserver-test/email-templates/smtp-only.txt" run docker exec mail_smtponly_second_network_sender /bin/sh -c "nc mail_smtponly_second_network 25 < /tmp/docker-mailserver-test/email-templates/smtp-only.txt"
assert_output --partial "250 2.0.0 Ok: queued as " assert_output --partial "250 2.0.0 Ok: queued as "
@ -74,8 +78,10 @@ teardown_file() {
@test "checking PERMIT_DOCKER: none" { @test "checking PERMIT_DOCKER: none" {
run docker exec mail_smtponly_force_authentication /bin/sh -c "postconf -e smtp_host_lookup=no" run docker exec mail_smtponly_force_authentication /bin/sh -c "postconf -e smtp_host_lookup=no"
assert_success assert_success
run docker exec mail_smtponly_force_authentication /bin/sh -c "/etc/init.d/postfix reload" run docker exec mail_smtponly_force_authentication /bin/sh -c "/etc/init.d/postfix reload"
assert_success assert_success
# the mailserver should require authentication and a protocol error should occur when using TLS # the mailserver should require authentication and a protocol error should occur when using TLS
run docker exec mail_smtponly_force_authentication /bin/sh -c "nc localhost 25 < /tmp/docker-mailserver-test/email-templates/smtp-only.txt" run docker exec mail_smtponly_force_authentication /bin/sh -c "nc localhost 25 < /tmp/docker-mailserver-test/email-templates/smtp-only.txt"
assert_output --partial "550 5.5.1 Protocol error" assert_output --partial "550 5.5.1 Protocol error"

View File

@ -4,170 +4,176 @@ load 'test_helper/common'
# `${NAME}` defaults to `mailserver-testing:ci` # `${NAME}` defaults to `mailserver-testing:ci`
function teardown() { function teardown() {
docker rm -f tls_test_cipherlists docker rm -f tls_test_cipherlists
} }
function setup_file() { function setup_file() {
export DOMAIN="example.test" export DOMAIN="example.test"
export NETWORK="test-network" export NETWORK="test-network"
# Shared config for TLS testing (read-only) # Shared config for TLS testing (read-only)
export TLS_CONFIG_VOLUME export TLS_CONFIG_VOLUME
TLS_CONFIG_VOLUME="$(pwd)/test/test-files/ssl/${DOMAIN}/:/config/ssl/:ro" TLS_CONFIG_VOLUME="$(pwd)/test/test-files/ssl/${DOMAIN}/:/config/ssl/:ro"
# `${BATS_TMPDIR}` maps to `/tmp` # `${BATS_TMPDIR}` maps to `/tmp`
export TLS_RESULTS_DIR="${BATS_TMPDIR}/results" export TLS_RESULTS_DIR="${BATS_TMPDIR}/results"
# NOTE: If the network already exists, test will fail to start. # NOTE: If the network already exists, test will fail to start.
docker network create "${NETWORK}" docker network create "${NETWORK}"
# Copies all of `./test/config/` to specific directory for testing # Copies all of `./test/config/` to specific directory for testing
# `${PRIVATE_CONFIG}` becomes `$(pwd)/test/duplicate_configs/<bats test filename>` # `${PRIVATE_CONFIG}` becomes `$(pwd)/test/duplicate_configs/<bats test filename>`
export PRIVATE_CONFIG export PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
# Pull `testssl.sh` image in advance to avoid it interfering with the `run` captured output. # Pull `testssl.sh` image in advance to avoid it interfering with the `run` captured output.
# Only interferes (potential test failure) with `assert_output` not `assert_success`? # Only interferes (potential test failure) with `assert_output` not `assert_success`?
docker pull drwetter/testssl.sh:3.1dev docker pull drwetter/testssl.sh:3.1dev
} }
function teardown_file() { function teardown_file() {
docker network rm "${NETWORK}" docker network rm "${NETWORK}"
} }
@test "checking tls: cipher list - rsa intermediate" { @test "checking tls: cipher list - rsa intermediate" {
check_ports 'rsa' 'intermediate' check_ports 'rsa' 'intermediate'
} }
@test "checking tls: cipher list - rsa modern" { @test "checking tls: cipher list - rsa modern" {
check_ports 'rsa' 'modern' check_ports 'rsa' 'modern'
} }
@test "checking tls: cipher list - ecdsa intermediate" { @test "checking tls: cipher list - ecdsa intermediate" {
check_ports 'ecdsa' 'intermediate' check_ports 'ecdsa' 'intermediate'
} }
@test "checking tls: cipher list - ecdsa modern" { @test "checking tls: cipher list - ecdsa modern" {
check_ports 'ecdsa' 'modern' check_ports 'ecdsa' 'modern'
} }
# Only ECDSA with RSA fallback is tested. # Only ECDSA with RSA fallback is tested.
# There isn't a situation where RSA with ECDSA fallback would make sense. # There isn't a situation where RSA with ECDSA fallback would make sense.
@test "checking tls: cipher list - ecdsa intermediate, with rsa fallback" { @test "checking tls: cipher list - ecdsa intermediate, with rsa fallback" {
check_ports 'ecdsa' 'intermediate' 'rsa' check_ports 'ecdsa' 'intermediate' 'rsa'
} }
@test "checking tls: cipher list - ecdsa modern, with rsa fallback" { @test "checking tls: cipher list - ecdsa modern, with rsa fallback" {
check_ports 'ecdsa' 'modern' 'rsa' check_ports 'ecdsa' 'modern' 'rsa'
} }
function check_ports() { function check_ports() {
local KEY_TYPE=$1 local KEY_TYPE=$1
local TLS_LEVEL=$2 local TLS_LEVEL=$2
local ALT_KEY_TYPE=$3 # Optional parameter local ALT_KEY_TYPE=$3 # Optional parameter
local KEY_TYPE_LABEL="${KEY_TYPE}" local KEY_TYPE_LABEL="${KEY_TYPE}"
# This is just to add a `_` delimiter between the two key types for readability # This is just to add a `_` delimiter between the two key types for readability
if [[ -n ${ALT_KEY_TYPE} ]] if [[ -n ${ALT_KEY_TYPE} ]]
then then
KEY_TYPE_LABEL="${KEY_TYPE}_${ALT_KEY_TYPE}" KEY_TYPE_LABEL="${KEY_TYPE}_${ALT_KEY_TYPE}"
fi fi
local RESULTS_PATH="${KEY_TYPE_LABEL}/${TLS_LEVEL}" local RESULTS_PATH="${KEY_TYPE_LABEL}/${TLS_LEVEL}"
collect_cipherlist_data collect_cipherlist_data
# SMTP: Opportunistic STARTTLS Explicit(25) # SMTP: Opportunistic STARTTLS Explicit(25)
# Needs to test against cipher lists specific to Port 25 ('_p25' parameter) # Needs to test against cipher lists specific to Port 25 ('_p25' parameter)
check_cipherlists "${RESULTS_PATH}/port_25.json" '_p25' check_cipherlists "${RESULTS_PATH}/port_25.json" '_p25'
# SMTP Submission: Mandatory STARTTLS Explicit(587) and Implicit(465) TLS
check_cipherlists "${RESULTS_PATH}/port_587.json" # SMTP Submission: Mandatory STARTTLS Explicit(587) and Implicit(465) TLS
check_cipherlists "${RESULTS_PATH}/port_465.json" check_cipherlists "${RESULTS_PATH}/port_587.json"
# IMAP: Mandatory STARTTLS Explicit(143) and Implicit(993) TLS check_cipherlists "${RESULTS_PATH}/port_465.json"
check_cipherlists "${RESULTS_PATH}/port_143.json"
check_cipherlists "${RESULTS_PATH}/port_993.json" # IMAP: Mandatory STARTTLS Explicit(143) and Implicit(993) TLS
# POP3: Mandatory STARTTLS Explicit(110) and Implicit(995) check_cipherlists "${RESULTS_PATH}/port_143.json"
check_cipherlists "${RESULTS_PATH}/port_110.json" check_cipherlists "${RESULTS_PATH}/port_993.json"
check_cipherlists "${RESULTS_PATH}/port_995.json"
# POP3: Mandatory STARTTLS Explicit(110) and Implicit(995)
check_cipherlists "${RESULTS_PATH}/port_110.json"
check_cipherlists "${RESULTS_PATH}/port_995.json"
} }
function collect_cipherlist_data() { function collect_cipherlist_data() {
local ALT_CERT=() local ALT_CERT=()
local ALT_KEY=() local ALT_KEY=()
if [[ -n ${ALT_KEY_TYPE} ]] if [[ -n ${ALT_KEY_TYPE} ]]
then then
ALT_CERT=(--env SSL_ALT_CERT_PATH="/config/ssl/cert.${ALT_KEY_TYPE}.pem") ALT_CERT=(--env SSL_ALT_CERT_PATH="/config/ssl/cert.${ALT_KEY_TYPE}.pem")
ALT_KEY=(--env SSL_ALT_KEY_PATH="/config/ssl/key.${ALT_KEY_TYPE}.pem") ALT_KEY=(--env SSL_ALT_KEY_PATH="/config/ssl/key.${ALT_KEY_TYPE}.pem")
fi fi
run docker run -d --name tls_test_cipherlists \ run docker run -d --name tls_test_cipherlists \
--volume "${PRIVATE_CONFIG}/:/tmp/docker-mailserver/" \ --volume "${PRIVATE_CONFIG}/:/tmp/docker-mailserver/" \
--volume "${TLS_CONFIG_VOLUME}" \ --volume "${TLS_CONFIG_VOLUME}" \
--env ENABLE_POP3=1 \ --env ENABLE_POP3=1 \
--env SSL_TYPE="manual" \ --env SSL_TYPE="manual" \
--env SSL_CERT_PATH="/config/ssl/cert.${KEY_TYPE}.pem" \ --env SSL_CERT_PATH="/config/ssl/cert.${KEY_TYPE}.pem" \
--env SSL_KEY_PATH="/config/ssl/key.${KEY_TYPE}.pem" \ --env SSL_KEY_PATH="/config/ssl/key.${KEY_TYPE}.pem" \
"${ALT_CERT[@]}" \ "${ALT_CERT[@]}" \
"${ALT_KEY[@]}" \ "${ALT_KEY[@]}" \
--env TLS_LEVEL="${TLS_LEVEL}" \ --env TLS_LEVEL="${TLS_LEVEL}" \
--network "${NETWORK}" \ --network "${NETWORK}" \
--network-alias "${DOMAIN}" \ --network-alias "${DOMAIN}" \
--hostname "mail.${DOMAIN}" \ --hostname "mail.${DOMAIN}" \
--tty \ --tty \
"${NAME}" # Image name "${NAME}" # Image name
assert_success
wait_for_tcp_port_in_container 25 tls_test_cipherlists assert_success
# NOTE: An rDNS query for the container IP will resolve to `<container name>.<network name>.`
# Make directory with test user ownership. Avoids Docker creating with root ownership. wait_for_tcp_port_in_container 25 tls_test_cipherlists
# TODO: Can switch to filename prefix for JSON output when this is resolved: https://github.com/drwetter/testssl.sh/issues/1845 # NOTE: An rDNS query for the container IP will resolve to `<container name>.<network name>.`
mkdir -p "${TLS_RESULTS_DIR}/${RESULTS_PATH}"
# For non-CI test runs, instead of removing prior test files after this test suite completes, # Make directory with test user ownership. Avoids Docker creating with root ownership.
# they're retained and overwritten by future test runs instead. Useful for inspection. # TODO: Can switch to filename prefix for JSON output when this is resolved: https://github.com/drwetter/testssl.sh/issues/1845
# `--preference` reduces the test scope to the cipher suites reported as supported by the server. Completes in ~35% of the time. mkdir -p "${TLS_RESULTS_DIR}/${RESULTS_PATH}"
local TESTSSL_CMD=(--quiet --file "/config/ssl/testssl.txt" --mode parallel --overwrite --preference)
# NOTE: Batch testing ports via `--file` doesn't properly bubble up failure.
# If the failure for a test is misleading consider testing a single port with:
# local TESTSSL_CMD=(--quiet --jsonfile-pretty "${RESULTS_PATH}/port_${PORT}.json" --starttls smtp "${DOMAIN}:${PORT}")
# TODO: Can use `jq` to check for failure when this is resolved: https://github.com/drwetter/testssl.sh/issues/1844
# `--user "<uid>:<gid>"` is a workaround: Avoids `permission denied` write errors for json output, uses `id` to match user uid & gid. # For non-CI test runs, instead of removing prior test files after this test suite completes,
run docker run --rm \ # they're retained and overwritten by future test runs instead. Useful for inspection.
--user "$(id -u):$(id -g)" \ # `--preference` reduces the test scope to the cipher suites reported as supported by the server. Completes in ~35% of the time.
--network "${NETWORK}" \ local TESTSSL_CMD=(--quiet --file "/config/ssl/testssl.txt" --mode parallel --overwrite --preference)
--volume "${TLS_CONFIG_VOLUME}" \ # NOTE: Batch testing ports via `--file` doesn't properly bubble up failure.
--volume "${TLS_RESULTS_DIR}/${RESULTS_PATH}/:/output" \ # If the failure for a test is misleading consider testing a single port with:
--workdir "/output" \ # local TESTSSL_CMD=(--quiet --jsonfile-pretty "${RESULTS_PATH}/port_${PORT}.json" --starttls smtp "${DOMAIN}:${PORT}")
drwetter/testssl.sh:3.1dev "${TESTSSL_CMD[@]}" # TODO: Can use `jq` to check for failure when this is resolved: https://github.com/drwetter/testssl.sh/issues/1844
assert_success
# `--user "<uid>:<gid>"` is a workaround: Avoids `permission denied` write errors for json output, uses `id` to match user uid & gid.
run docker run --rm \
--user "$(id -u):$(id -g)" \
--network "${NETWORK}" \
--volume "${TLS_CONFIG_VOLUME}" \
--volume "${TLS_RESULTS_DIR}/${RESULTS_PATH}/:/output" \
--workdir "/output" \
drwetter/testssl.sh:3.1dev "${TESTSSL_CMD[@]}"
assert_success
} }
# Use `jq` to extract a specific cipher list from the target`testssl.sh` results json output file # Use `jq` to extract a specific cipher list from the target`testssl.sh` results json output file
function compare_cipherlist() { function compare_cipherlist() {
local TARGET_CIPHERLIST=$1 local TARGET_CIPHERLIST=$1
local RESULTS_FILE=$2 local RESULTS_FILE=$2
local EXPECTED_CIPHERLIST=$3 local EXPECTED_CIPHERLIST=$3
run jq '.scanResult[0].serverPreferences[] | select(.id=="'"${TARGET_CIPHERLIST}"'") | .finding' "${TLS_RESULTS_DIR}/${RESULTS_FILE}" run jq '.scanResult[0].serverPreferences[] | select(.id=="'"${TARGET_CIPHERLIST}"'") | .finding' "${TLS_RESULTS_DIR}/${RESULTS_FILE}"
assert_success assert_success
assert_output "${EXPECTED_CIPHERLIST}" assert_output "${EXPECTED_CIPHERLIST}"
} }
# Compares the expected cipher lists against logged test results from `testssl.sh` # Compares the expected cipher lists against logged test results from `testssl.sh`
function check_cipherlists() { function check_cipherlists() {
local RESULTS_FILE=$1 local RESULTS_FILE=$1
local p25=$2 # optional suffix local p25=$2 # optional suffix
# TLS_LEVEL `modern` doesn't have TLS v1.0 or v1.1 cipher suites. Sets TLS v1.2 as minimum. # TLS_LEVEL `modern` doesn't have TLS v1.0 or v1.1 cipher suites. Sets TLS v1.2 as minimum.
if [[ ${TLS_LEVEL} == "intermediate" ]] if [[ ${TLS_LEVEL} == "intermediate" ]]
then then
compare_cipherlist "cipherorder_TLSv1" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1${p25}")" compare_cipherlist "cipherorder_TLSv1" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1${p25}")"
compare_cipherlist "cipherorder_TLSv1_1" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1_1${p25}")" compare_cipherlist "cipherorder_TLSv1_1" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1_1${p25}")"
fi fi
compare_cipherlist "cipherorder_TLSv1_2" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1_2${p25}")"
compare_cipherlist "cipherorder_TLSv1_3" "${RESULTS_FILE}" "$(get_cipherlist 'TLSv1_3')" compare_cipherlist "cipherorder_TLSv1_2" "${RESULTS_FILE}" "$(get_cipherlist "TLSv1_2${p25}")"
compare_cipherlist "cipherorder_TLSv1_3" "${RESULTS_FILE}" "$(get_cipherlist 'TLSv1_3')"
} }
# Expected cipher lists. Should match `TLS_LEVEL` cipher lists set in `start-mailserver.sh`. # Expected cipher lists. Should match `TLS_LEVEL` cipher lists set in `start-mailserver.sh`.
@ -175,64 +181,63 @@ function check_cipherlists() {
# NOTE: If a test fails, look at the `check_ports` params, then update the corresponding associative key's value # NOTE: If a test fails, look at the `check_ports` params, then update the corresponding associative key's value
# with the `actual` error value (assuming an update needs to be made, and not a valid security issue to look into). # with the `actual` error value (assuming an update needs to be made, and not a valid security issue to look into).
function get_cipherlist() { function get_cipherlist() {
local TLS_VERSION=$1 local TLS_VERSION=$1
if [[ ${TLS_VERSION} == "TLSv1_3" ]] if [[ ${TLS_VERSION} == "TLSv1_3" ]]
then then
# TLS v1.3 cipher suites are not user defineable and not unique to the available certificate(s). # TLS v1.3 cipher suites are not user defineable and not unique to the available certificate(s).
# They do not support server enforced order either. # They do not support server enforced order either.
echo '"TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256"' echo '"TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256"'
else else
# Associative array for easy querying of required cipher list
declare -A CIPHER_LIST
# Associative array for easy querying of required cipher list # `intermediate` cipher lists TLS v1.0 and v1.1 cipher suites should be the same:
declare -A CIPHER_LIST CIPHER_LIST["rsa_intermediate_TLSv1"]='"ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"'
CIPHER_LIST["rsa_intermediate_TLSv1_1"]=${CIPHER_LIST["rsa_intermediate_TLSv1"]}
CIPHER_LIST["rsa_intermediate_TLSv1_2"]='"ECDHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA"'
# `modern` cipher lists shouldn't have TLS v1.0 or v1.1 cipher suites:
CIPHER_LIST["rsa_modern_TLSv1_2"]='"ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384"'
# `intermediate` cipher lists TLS v1.0 and v1.1 cipher suites should be the same: # ECDSA:
CIPHER_LIST["rsa_intermediate_TLSv1"]='"ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"' CIPHER_LIST["ecdsa_intermediate_TLSv1"]='"ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA"'
CIPHER_LIST["rsa_intermediate_TLSv1_1"]=${CIPHER_LIST["rsa_intermediate_TLSv1"]} CIPHER_LIST["ecdsa_intermediate_TLSv1_1"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1"]}
CIPHER_LIST["rsa_intermediate_TLSv1_2"]='"ECDHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA"' CIPHER_LIST["ecdsa_intermediate_TLSv1_2"]='"ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA"'
# `modern` cipher lists shouldn't have TLS v1.0 or v1.1 cipher suites: CIPHER_LIST["ecdsa_modern_TLSv1_2"]='"ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305"'
CIPHER_LIST["rsa_modern_TLSv1_2"]='"ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384"'
# ECDSA: # ECDSA + RSA fallback, dual cert support:
CIPHER_LIST["ecdsa_intermediate_TLSv1"]='"ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA"' CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1"]='"ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"'
CIPHER_LIST["ecdsa_intermediate_TLSv1_1"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1"]} CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_1"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1"]}
CIPHER_LIST["ecdsa_intermediate_TLSv1_2"]='"ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA"' CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2"]='"ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA"'
CIPHER_LIST["ecdsa_modern_TLSv1_2"]='"ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305"' CIPHER_LIST["ecdsa_rsa_modern_TLSv1_2"]='"ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384"'
# ECDSA + RSA fallback, dual cert support:
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1"]='"ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"'
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_1"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1"]}
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2"]='"ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA"'
CIPHER_LIST["ecdsa_rsa_modern_TLSv1_2"]='"ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384"'
# Port 25 # Port 25
# TLSv1 and TLSv1_1 share the same cipher suites as other ports have. But the server order differs: # TLSv1 and TLSv1_1 share the same cipher suites as other ports have. But the server order differs:
CIPHER_LIST["rsa_intermediate_TLSv1_p25"]='"ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA"' CIPHER_LIST["rsa_intermediate_TLSv1_p25"]='"ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA"'
CIPHER_LIST["rsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["rsa_intermediate_TLSv1_p25"]} CIPHER_LIST["rsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["rsa_intermediate_TLSv1_p25"]}
# TLSv1_2 has different server order and also includes ARIA, CCM, DHE+CHACHA20-POLY1305 cipher suites: # TLSv1_2 has different server order and also includes ARIA, CCM, DHE+CHACHA20-POLY1305 cipher suites:
CIPHER_LIST["rsa_intermediate_TLSv1_2_p25"]='"ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES256-CCM8 DHE-RSA-AES256-CCM ECDHE-ARIA256-GCM-SHA384 DHE-RSA-ARIA256-GCM-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256 ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ARIA256-GCM-SHA384 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-CCM8 DHE-RSA-AES128-CCM ECDHE-ARIA128-GCM-SHA256 DHE-RSA-ARIA128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA ARIA128-GCM-SHA256"' CIPHER_LIST["rsa_intermediate_TLSv1_2_p25"]='"ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES256-CCM8 DHE-RSA-AES256-CCM ECDHE-ARIA256-GCM-SHA384 DHE-RSA-ARIA256-GCM-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256 ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ARIA256-GCM-SHA384 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-CCM8 DHE-RSA-AES128-CCM ECDHE-ARIA128-GCM-SHA256 DHE-RSA-ARIA128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA ARIA128-GCM-SHA256"'
# Port 25 is unaffected by `TLS_LEVEL` profiles (other than min TLS version), it has the same TLS v1.2 cipher list under both: # Port 25 is unaffected by `TLS_LEVEL` profiles (other than min TLS version), it has the same TLS v1.2 cipher list under both:
CIPHER_LIST["rsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["rsa_intermediate_TLSv1_2_p25"]} CIPHER_LIST["rsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["rsa_intermediate_TLSv1_2_p25"]}
# ECDSA (Port 25): # ECDSA (Port 25):
CIPHER_LIST["ecdsa_intermediate_TLSv1_p25"]='"ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA"' CIPHER_LIST["ecdsa_intermediate_TLSv1_p25"]='"ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA"'
CIPHER_LIST["ecdsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1_p25"]} CIPHER_LIST["ecdsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1_p25"]}
CIPHER_LIST["ecdsa_intermediate_TLSv1_2_p25"]='"ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA"' CIPHER_LIST["ecdsa_intermediate_TLSv1_2_p25"]='"ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA"'
CIPHER_LIST["ecdsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1_2_p25"]} CIPHER_LIST["ecdsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["ecdsa_intermediate_TLSv1_2_p25"]}
# ECDSA + RSA fallback, dual cert support (Port 25): # ECDSA + RSA fallback, dual cert support (Port 25):
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_p25"]='"ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA"' CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_p25"]='"ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA"'
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_p25"]} CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_1_p25"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_p25"]}
CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2_p25"]='"ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM DHE-RSA-AES256-CCM8 DHE-RSA-AES256-CCM ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE-ARIA256-GCM-SHA384 DHE-RSA-ARIA256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ARIA256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM DHE-RSA-AES128-CCM8 DHE-RSA-AES128-CCM ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE-ARIA128-GCM-SHA256 DHE-RSA-ARIA128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA ARIA128-GCM-SHA256"' CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2_p25"]='"ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-CCM8 ECDHE-ECDSA-AES256-CCM DHE-RSA-AES256-CCM8 DHE-RSA-AES256-CCM ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE-ARIA256-GCM-SHA384 DHE-RSA-ARIA256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES256-SHA256 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES256-SHA ARIA256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES128-CCM8 ECDHE-ECDSA-AES128-CCM DHE-RSA-AES128-CCM8 DHE-RSA-AES128-CCM ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE-ARIA128-GCM-SHA256 DHE-RSA-ARIA128-GCM-SHA256 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 DHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA DHE-RSA-AES128-SHA ARIA128-GCM-SHA256"'
CIPHER_LIST["ecdsa_rsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2_p25"]} CIPHER_LIST["ecdsa_rsa_modern_TLSv1_2_p25"]=${CIPHER_LIST["ecdsa_rsa_intermediate_TLSv1_2_p25"]}
local TARGET_QUERY="${KEY_TYPE_LABEL}_${TLS_LEVEL}_${TLS_VERSION}" local TARGET_QUERY="${KEY_TYPE_LABEL}_${TLS_LEVEL}_${TLS_VERSION}"
echo "${CIPHER_LIST[${TARGET_QUERY}]}" echo "${CIPHER_LIST[${TARGET_QUERY}]}"
fi fi
} }

View File

@ -9,8 +9,8 @@ function setup_file() {
PRIVATE_CONFIG="$(duplicate_config_for_container . )" PRIVATE_CONFIG="$(duplicate_config_for_container . )"
docker run -d --name "${CONTAINER}" \ docker run -d --name "${CONTAINER}" \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com "${NAME}" -h mail.my-domain.com "${NAME}"
wait_for_finished_setup_in_container "${CONTAINER}" wait_for_finished_setup_in_container "${CONTAINER}"
} }

View File

@ -3,255 +3,267 @@ load 'test_helper/bats-assert/load'
load 'test_helper/common' load 'test_helper/common'
@test "repeat_until_success_or_timeout returns instantly on success" { @test "repeat_until_success_or_timeout returns instantly on success" {
SECONDS=0 SECONDS=0
repeat_until_success_or_timeout 1 true repeat_until_success_or_timeout 1 true
[[ ${SECONDS} -le 1 ]] [[ ${SECONDS} -le 1 ]]
} }
@test "repeat_until_success_or_timeout waits for timeout on persistent failure" { @test "repeat_until_success_or_timeout waits for timeout on persistent failure" {
SECONDS=0 SECONDS=0
run repeat_until_success_or_timeout 2 false run repeat_until_success_or_timeout 2 false
[[ ${SECONDS} -ge 2 ]] [[ ${SECONDS} -ge 2 ]]
assert_failure assert_failure
assert_output --partial "Timed out on command" assert_output --partial "Timed out on command"
} }
@test "repeat_until_success_or_timeout aborts immediately on fatal failure" { @test "repeat_until_success_or_timeout aborts immediately on fatal failure" {
SECONDS=0 SECONDS=0
run repeat_until_success_or_timeout --fatal-test false 2 false run repeat_until_success_or_timeout --fatal-test false 2 false
[[ ${SECONDS} -le 1 ]] [[ ${SECONDS} -le 1 ]]
assert_failure assert_failure
assert_output --partial "early aborting" assert_output --partial "early aborting"
} }
@test "repeat_until_success_or_timeout expects integer timeout" { @test "repeat_until_success_or_timeout expects integer timeout" {
run repeat_until_success_or_timeout 1 true run repeat_until_success_or_timeout 1 true
assert_success assert_success
run repeat_until_success_or_timeout timeout true run repeat_until_success_or_timeout timeout true
assert_failure assert_failure
run repeat_until_success_or_timeout --fatal-test true timeout true run repeat_until_success_or_timeout --fatal-test true timeout true
assert_failure assert_failure
} }
@test "run_until_success_or_timeout returns instantly on success" { @test "run_until_success_or_timeout returns instantly on success" {
SECONDS=0 SECONDS=0
run_until_success_or_timeout 2 true run_until_success_or_timeout 2 true
[[ ${SECONDS} -le 1 ]] [[ ${SECONDS} -le 1 ]]
assert_success assert_success
} }
@test "run_until_success_or_timeout waits for timeout on persistent failure" { @test "run_until_success_or_timeout waits for timeout on persistent failure" {
SECONDS=0 SECONDS=0
! run_until_success_or_timeout 2 false ! run_until_success_or_timeout 2 false
[[ ${SECONDS} -ge 2 ]] [[ ${SECONDS} -ge 2 ]]
assert_failure assert_failure
} }
@test "repeat_in_container_until_success_or_timeout fails immediately for non-running container" { @test "repeat_in_container_until_success_or_timeout fails immediately for non-running container" {
SECONDS=0 SECONDS=0
! repeat_in_container_until_success_or_timeout 10 name-of-non-existing-container true ! repeat_in_container_until_success_or_timeout 10 name-of-non-existing-container true
[[ ${SECONDS} -le 1 ]] [[ ${SECONDS} -le 1 ]]
} }
@test "repeat_in_container_until_success_or_timeout run command in container" { @test "repeat_in_container_until_success_or_timeout run command in container" {
local CONTAINER_NAME local CONTAINER_NAME
CONTAINER_NAME=$(docker run --rm -d alpine sleep 100) CONTAINER_NAME=$(docker run --rm -d alpine sleep 100)
SECONDS=0 SECONDS=0
! repeat_in_container_until_success_or_timeout 10 "${CONTAINER_NAME}" sh -c "echo '${CONTAINER_NAME}' > /tmp/marker" ! repeat_in_container_until_success_or_timeout 10 "${CONTAINER_NAME}" sh -c "echo '${CONTAINER_NAME}' > /tmp/marker"
[[ ${SECONDS} -le 1 ]] [[ ${SECONDS} -le 1 ]]
run docker exec "${CONTAINER_NAME}" cat /tmp/marker run docker exec "${CONTAINER_NAME}" cat /tmp/marker
assert_output "${CONTAINER_NAME}" assert_output "${CONTAINER_NAME}"
} }
@test "container_is_running" { @test "container_is_running" {
local CONTAINER_NAME local CONTAINER_NAME
CONTAINER_NAME=$(docker run --rm -d alpine sleep 100) CONTAINER_NAME=$(docker run --rm -d alpine sleep 100)
container_is_running "${CONTAINER_NAME}" container_is_running "${CONTAINER_NAME}"
docker rm -f "${CONTAINER_NAME}" docker rm -f "${CONTAINER_NAME}"
! container_is_running "${CONTAINER_NAME}" ! container_is_running "${CONTAINER_NAME}"
} }
@test "wait_for_smtp_port_in_container aborts wait after timeout" { @test "wait_for_smtp_port_in_container aborts wait after timeout" {
local CONTAINER_NAME local CONTAINER_NAME
CONTAINER_NAME=$(docker run --rm -d alpine sleep 100) CONTAINER_NAME=$(docker run --rm -d alpine sleep 100)
SECONDS=0 SECONDS=0
TEST_TIMEOUT_IN_SECONDS=2 run wait_for_smtp_port_in_container "${CONTAINER_NAME}" TEST_TIMEOUT_IN_SECONDS=2 run wait_for_smtp_port_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -ge 2 ]] [[ ${SECONDS} -ge 2 ]]
assert_failure assert_failure
assert_output --partial "Timed out on command" assert_output --partial "Timed out on command"
} }
# NOTE: Test requires external network access available
@test "wait_for_smtp_port_in_container returns immediately when port found" { @test "wait_for_smtp_port_in_container returns immediately when port found" {
local CONTAINER_NAME local CONTAINER_NAME
CONTAINER_NAME=$(docker run --rm -d alpine sh -c "sleep 10") CONTAINER_NAME=$(docker run --rm -d alpine sh -c "sleep 10")
docker exec "${CONTAINER_NAME}" apk add netcat-openbsd docker exec "${CONTAINER_NAME}" apk add netcat-openbsd
docker exec "${CONTAINER_NAME}" nc -l 25 & docker exec "${CONTAINER_NAME}" nc -l 25 &
SECONDS=0 SECONDS=0
TEST_TIMEOUT_IN_SECONDS=5 run wait_for_smtp_port_in_container "${CONTAINER_NAME}" TEST_TIMEOUT_IN_SECONDS=5 run wait_for_smtp_port_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -lt 5 ]] [[ ${SECONDS} -lt 5 ]]
assert_success assert_success
} }
@test "wait_for_finished_setup_in_container" { @test "wait_for_finished_setup_in_container" {
# variable not local to make visible to teardown # variable not local to make visible to teardown
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com \
-t "${NAME}")
teardown() { docker rm -f "${CONTAINER_NAME}"; }
# the setup should not be finished immediately after starting CONTAINER_NAME=$(docker run -d --rm \
! TEST_TIMEOUT_IN_SECONDS=0 wait_for_finished_setup_in_container "${CONTAINER_NAME}" -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com \
-t "${NAME}")
# but it will finish eventually teardown() { docker rm -f "${CONTAINER_NAME}"; }
SECONDS=1
wait_for_finished_setup_in_container "${CONTAINER_NAME}" # the setup should not be finished immediately after starting
[[ ${SECONDS} -gt 0 ]] ! TEST_TIMEOUT_IN_SECONDS=0 wait_for_finished_setup_in_container "${CONTAINER_NAME}"
# but it will finish eventually
SECONDS=1
wait_for_finished_setup_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -gt 0 ]]
} }
@test "duplicate_config_for_container" { @test "duplicate_config_for_container" {
local path local path
path=$(duplicate_config_for_container duplicate_config_test) path=$(duplicate_config_for_container duplicate_config_test)
run cat "${path}/marker" run cat "${path}/marker"
assert_line "This marker file is there to identify the correct config being copied" assert_line "This marker file is there to identify the correct config being copied"
run duplicate_config_for_container non-existant-source-folder "${BATS_TEST_NAME}2" run duplicate_config_for_container non-existant-source-folder "${BATS_TEST_NAME}2"
assert_failure assert_failure
} }
@test "container_has_service_running/wait_for_service" { @test "container_has_service_running/wait_for_service" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
# variable not local to make visible to teardown
CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com \
-t "${NAME}")
teardown() { docker rm -f "${CONTAINER_NAME}"; }
# pick a service that was not started # variable not local to make visible to teardown
! container_has_service_running "${CONTAINER_NAME}" clamav CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com \
-t "${NAME}")
# wait for a service that should be started teardown() { docker rm -f "${CONTAINER_NAME}"; }
wait_for_service "${CONTAINER_NAME}" postfix
# shut down the service # pick a service that was not started
docker exec "${CONTAINER_NAME}" supervisorctl stop postfix ! container_has_service_running "${CONTAINER_NAME}" clamav
# now it should be off # wait for a service that should be started
SECONDS=0 wait_for_service "${CONTAINER_NAME}" postfix
TEST_TIMEOUT_IN_SECONDS=5 run wait_for_service "${CONTAINER_NAME}" postfix
[[ ${SECONDS} -ge 5 ]] # shut down the service
assert_failure docker exec "${CONTAINER_NAME}" supervisorctl stop postfix
# now it should be off
SECONDS=0
TEST_TIMEOUT_IN_SECONDS=5 run wait_for_service "${CONTAINER_NAME}" postfix
[[ ${SECONDS} -ge 5 ]]
assert_failure
} }
@test "wait_for_changes_to_be_detected_in_container fails when timeout is reached" { @test "wait_for_changes_to_be_detected_in_container fails when timeout is reached" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
# variable not local to make visible to teardown
CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com \
-t "${NAME}")
teardown() { docker rm -f "${CONTAINER_NAME}"; }
# wait for the initial checksum detection to complete # variable not local to make visible to teardown
repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" test -e /tmp/docker-mailserver-config-chksum CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com \
-t "${NAME}")
# there should be no changes in the beginning teardown() { docker rm -f "${CONTAINER_NAME}"; }
TEST_TIMEOUT_IN_SECONDS=0 wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}"
# trigger some change # wait for the initial checksum detection to complete
docker exec "${CONTAINER_NAME}" /bin/sh -c "addmailuser auser3@mail.my-domain.com mypassword" repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" test -e /tmp/docker-mailserver-config-chksum
# that should be picked up as not yet detected # there should be no changes in the beginning
! TEST_TIMEOUT_IN_SECONDS=0 wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}" TEST_TIMEOUT_IN_SECONDS=0 wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}"
# trigger some change
docker exec "${CONTAINER_NAME}" /bin/sh -c "addmailuser auser3@mail.my-domain.com mypassword"
# that should be picked up as not yet detected
! TEST_TIMEOUT_IN_SECONDS=0 wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}"
} }
@test "wait_for_changes_to_be_detected_in_container succeeds within timeout" { @test "wait_for_changes_to_be_detected_in_container succeeds within timeout" {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
# variable not local to make visible to teardown
CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com \
-t "${NAME}")
teardown() { docker rm -f "${CONTAINER_NAME}"; }
# wait for the initial checksum detection to complete # variable not local to make visible to teardown
repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" test -e /tmp/docker-mailserver-config-chksum CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-h mail.my-domain.com \
-t "${NAME}")
# trigger some change teardown() { docker rm -f "${CONTAINER_NAME}"; }
docker exec "${CONTAINER_NAME}" /bin/sh -c "addmailuser auser3@mail.my-domain.com mypassword"
# that should eventually be detected # wait for the initial checksum detection to complete
SECONDS=0 repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" test -e /tmp/docker-mailserver-config-chksum
wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -gt 0 ]] # trigger some change
docker exec "${CONTAINER_NAME}" /bin/sh -c "addmailuser auser3@mail.my-domain.com mypassword"
# that should eventually be detected
SECONDS=0
wait_for_changes_to_be_detected_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -gt 0 ]]
} }
# TODO investigate why this test fails # TODO investigate why this test fails
@test "wait_for_empty_mail_queue_in_container fails when timeout reached" { @test "wait_for_empty_mail_queue_in_container fails when timeout reached" {
skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2177' skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2177'
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
# variable not local to make visible to teardown
# enable ClamAV to make message delivery slower, so we can detect it
CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_CLAMAV=1 \
-h mail.my-domain.com \
-t "${NAME}")
teardown() { docker rm -f "${CONTAINER_NAME}"; } # variable not local to make visible to teardown
# enable ClamAV to make message delivery slower, so we can detect it
CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_CLAMAV=1 \
-h mail.my-domain.com \
-t "${NAME}")
wait_for_smtp_port_in_container "${CONTAINER_NAME}" || docker logs "${CONTAINER_NAME}" teardown() { docker rm -f "${CONTAINER_NAME}"; }
SECONDS=0 wait_for_smtp_port_in_container "${CONTAINER_NAME}" || docker logs "${CONTAINER_NAME}"
# no mails -> should return immediately
TEST_TIMEOUT_IN_SECONDS=5 wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -lt 5 ]]
# fill the queue with a message SECONDS=0
docker exec "${CONTAINER_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt" # no mails -> should return immediately
TEST_TIMEOUT_IN_SECONDS=5 wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -lt 5 ]]
# that should still be stuck in the queue # fill the queue with a message
! TEST_TIMEOUT_IN_SECONDS=0 wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}" docker exec "${CONTAINER_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt"
# that should still be stuck in the queue
! TEST_TIMEOUT_IN_SECONDS=0 wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
} }
# TODO investigate why this test fails # TODO investigate why this test fails
@test "wait_for_empty_mail_queue_in_container succeeds within timeout" { @test "wait_for_empty_mail_queue_in_container succeeds within timeout" {
skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2177' skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2177'
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container .) PRIVATE_CONFIG=$(duplicate_config_for_container .)
# variable not local to make visible to teardown
# enable ClamAV to make message delivery slower, so we can detect it
CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_CLAMAV=1 \
-h mail.my-domain.com \
-t "${NAME}")
teardown() { docker rm -f "${CONTAINER_NAME}"; } # variable not local to make visible to teardown
# enable ClamAV to make message delivery slower, so we can detect it
CONTAINER_NAME=$(docker run -d --rm \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e ENABLE_CLAMAV=1 \
-h mail.my-domain.com \
-t "${NAME}")
wait_for_smtp_port_in_container "${CONTAINER_NAME}" || docker logs "${CONTAINER_NAME}" teardown() { docker rm -f "${CONTAINER_NAME}"; }
# fill the queue with a message wait_for_smtp_port_in_container "${CONTAINER_NAME}" || docker logs "${CONTAINER_NAME}"
docker exec "${CONTAINER_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt"
# give it some time to clear the queue # fill the queue with a message
SECONDS=0 docker exec "${CONTAINER_NAME}" /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/amavis-virus.txt"
wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -gt 0 ]] # give it some time to clear the queue
SECONDS=0
wait_for_empty_mail_queue_in_container "${CONTAINER_NAME}"
[[ ${SECONDS} -gt 0 ]]
} }

View File

@ -13,76 +13,86 @@ NUMBER_OF_LOG_LINES=${NUMBER_OF_LOG_LINES-10}
# @param --fatal-test <command eval string> additional test whose failure aborts immediately # @param --fatal-test <command eval string> additional test whose failure aborts immediately
# @param ... test to run # @param ... test to run
function repeat_until_success_or_timeout { function repeat_until_success_or_timeout {
local FATAL_FAILURE_TEST_COMMAND local FATAL_FAILURE_TEST_COMMAND
if [[ "${1}" == "--fatal-test" ]]; then
FATAL_FAILURE_TEST_COMMAND="${2}" if [[ "${1}" == "--fatal-test" ]]; then
shift 2 FATAL_FAILURE_TEST_COMMAND="${2}"
shift 2
fi
if ! [[ "${1}" =~ ^[0-9]+$ ]]; then
echo "First parameter for timeout must be an integer, recieved \"${1}\""
return 1
fi
local TIMEOUT=${1}
local STARTTIME=${SECONDS}
shift 1
until "${@}"
do
if [[ -n ${FATAL_FAILURE_TEST_COMMAND} ]] && ! eval "${FATAL_FAILURE_TEST_COMMAND}"; then
echo "\`${FATAL_FAILURE_TEST_COMMAND}\` failed, early aborting repeat_until_success of \`${*}\`" >&2
return 1
fi fi
if ! [[ "${1}" =~ ^[0-9]+$ ]]; then
echo "First parameter for timeout must be an integer, recieved \"${1}\"" sleep 1
return 1
if [[ $(( SECONDS - STARTTIME )) -gt ${TIMEOUT} ]]; then
echo "Timed out on command: ${*}" >&2
return 1
fi fi
local TIMEOUT=${1} done
local STARTTIME=${SECONDS}
shift 1
until "${@}"
do
if [[ -n ${FATAL_FAILURE_TEST_COMMAND} ]] && ! eval "${FATAL_FAILURE_TEST_COMMAND}"; then
echo "\`${FATAL_FAILURE_TEST_COMMAND}\` failed, early aborting repeat_until_success of \`${*}\`" >&2
return 1
fi
sleep 1
if [[ $(( SECONDS - STARTTIME )) -gt ${TIMEOUT} ]]; then
echo "Timed out on command: ${*}" >&2
return 1
fi
done
} }
# like repeat_until_success_or_timeout but with wrapping the command to run into `run` for later bats consumption # like repeat_until_success_or_timeout but with wrapping the command to run into `run` for later bats consumption
# @param ${1} timeout # @param ${1} timeout
# @param ... test command to run # @param ... test command to run
function run_until_success_or_timeout { function run_until_success_or_timeout {
if ! [[ ${1} =~ ^[0-9]+$ ]]; then if ! [[ ${1} =~ ^[0-9]+$ ]]; then
echo "First parameter for timeout must be an integer, recieved \"${1}\"" echo "First parameter for timeout must be an integer, recieved \"${1}\""
return 1 return 1
fi
local TIMEOUT=${1}
local STARTTIME=${SECONDS}
shift 1
until run "${@}" && [[ $status -eq 0 ]]
do
sleep 1
if (( SECONDS - STARTTIME > TIMEOUT )); then
echo "Timed out on command: ${*}" >&2
return 1
fi fi
local TIMEOUT=${1} done
local STARTTIME=${SECONDS}
shift 1
until run "${@}" && [[ $status -eq 0 ]]
do
sleep 1
if (( SECONDS - STARTTIME > TIMEOUT )); then
echo "Timed out on command: ${*}" >&2
return 1
fi
done
} }
# @param ${1} timeout # @param ${1} timeout
# @param ${2} container name # @param ${2} container name
# @param ... test command for container # @param ... test command for container
function repeat_in_container_until_success_or_timeout() { function repeat_in_container_until_success_or_timeout() {
local TIMEOUT="${1}" local TIMEOUT="${1}"
local CONTAINER_NAME="${2}" local CONTAINER_NAME="${2}"
shift 2 shift 2
repeat_until_success_or_timeout --fatal-test "container_is_running ${CONTAINER_NAME}" "${TIMEOUT}" docker exec "${CONTAINER_NAME}" "${@}"
repeat_until_success_or_timeout --fatal-test "container_is_running ${CONTAINER_NAME}" "${TIMEOUT}" docker exec "${CONTAINER_NAME}" "${@}"
} }
function container_is_running() { function container_is_running() {
[[ "$(docker inspect -f '{{.State.Running}}' "${1}")" == "true" ]] [[ "$(docker inspect -f '{{.State.Running}}' "${1}")" == "true" ]]
} }
# @param ${1} port # @param ${1} port
# @param ${2} container name # @param ${2} container name
function wait_for_tcp_port_in_container() { function wait_for_tcp_port_in_container() {
repeat_until_success_or_timeout --fatal-test "container_is_running ${2}" "${TEST_TIMEOUT_IN_SECONDS}" docker exec "${2}" /bin/sh -c "nc -z 0.0.0.0 ${1}" repeat_until_success_or_timeout --fatal-test "container_is_running ${2}" "${TEST_TIMEOUT_IN_SECONDS}" docker exec "${2}" /bin/sh -c "nc -z 0.0.0.0 ${1}"
} }
# @param ${1} name of the postfix container # @param ${1} name of the postfix container
function wait_for_smtp_port_in_container() { function wait_for_smtp_port_in_container() {
wait_for_tcp_port_in_container 25 "${1}" wait_for_tcp_port_in_container 25 "${1}"
} }
# @param ${1} name of the postfix container # @param ${1} name of the postfix container
@ -94,6 +104,7 @@ function wait_for_smtp_port_in_container_to_respond() {
echo "Unable to receive a valid response from 'nc localhost 25' within 20 seconds" echo "Unable to receive a valid response from 'nc localhost 25' within 20 seconds"
return 1 return 1
fi fi
sleep 1 sleep 1
((COUNT+=1)) ((COUNT+=1))
done done
@ -101,67 +112,73 @@ function wait_for_smtp_port_in_container_to_respond() {
# @param ${1} name of the postfix container # @param ${1} name of the postfix container
function wait_for_amavis_port_in_container() { function wait_for_amavis_port_in_container() {
wait_for_tcp_port_in_container 10024 "${1}" wait_for_tcp_port_in_container 10024 "${1}"
} }
# TODO: Should also fail early on "docker logs ${1} | egrep '^[ FATAL ]'"? # TODO: Should also fail early on "docker logs ${1} | egrep '^[ FATAL ]'"?
# @param ${1} name of the postfix container # @param ${1} name of the postfix container
function wait_for_finished_setup_in_container() { function wait_for_finished_setup_in_container() {
local STATUS=0 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 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" if [[ ${STATUS} -eq 1 ]]; then
docker logs "${1}" | tail -n "${NUMBER_OF_LOG_LINES}" echo "Last ${NUMBER_OF_LOG_LINES} lines of container \`${1}\`'s log"
fi docker logs "${1}" | tail -n "${NUMBER_OF_LOG_LINES}"
return ${STATUS} fi
return ${STATUS}
} }
SETUP_FILE_MARKER="${BATS_TMPDIR}/$(basename "${BATS_TEST_FILENAME}").setup_file" SETUP_FILE_MARKER="${BATS_TMPDIR}/$(basename "${BATS_TEST_FILENAME}").setup_file"
# get the private config path for the given container or test file, if no container name was given # get the private config path for the given container or test file, if no container name was given
function private_config_path() { function private_config_path() {
echo "${PWD}/test/duplicate_configs/${1:-$(basename "${BATS_TEST_FILENAME}")}" echo "${PWD}/test/duplicate_configs/${1:-$(basename "${BATS_TEST_FILENAME}")}"
} }
# @param ${1} relative source in test/config folder # @param ${1} relative source in test/config folder
# @param ${2} (optional) container name, defaults to ${BATS_TEST_FILENAME} # @param ${2} (optional) container name, defaults to ${BATS_TEST_FILENAME}
# @return path to the folder where the config is duplicated # @return path to the folder where the config is duplicated
function duplicate_config_for_container() { function duplicate_config_for_container() {
local OUTPUT_FOLDER local OUTPUT_FOLDER
OUTPUT_FOLDER=$(private_config_path "${2}") || return $? OUTPUT_FOLDER=$(private_config_path "${2}") || return $?
rm -rf "${OUTPUT_FOLDER:?}/" || return $? # cleanup
mkdir -p "${OUTPUT_FOLDER}" || return $? rm -rf "${OUTPUT_FOLDER:?}/" || return $? # cleanup
cp -r "${PWD}/test/config/${1:?}/." "${OUTPUT_FOLDER}" || return $? mkdir -p "${OUTPUT_FOLDER}" || return $?
echo "${OUTPUT_FOLDER}" cp -r "${PWD}/test/config/${1:?}/." "${OUTPUT_FOLDER}" || return $?
echo "${OUTPUT_FOLDER}"
} }
function container_has_service_running() { function container_has_service_running() {
local CONTAINER_NAME="${1}" local CONTAINER_NAME="${1}"
local SERVICE_NAME="${2}" local SERVICE_NAME="${2}"
docker exec "${CONTAINER_NAME}" /usr/bin/supervisorctl status "${SERVICE_NAME}" | grep RUNNING >/dev/null
docker exec "${CONTAINER_NAME}" /usr/bin/supervisorctl status "${SERVICE_NAME}" | grep RUNNING >/dev/null
} }
function wait_for_service() { function wait_for_service() {
local CONTAINER_NAME="${1}" local CONTAINER_NAME="${1}"
local SERVICE_NAME="${2}" local SERVICE_NAME="${2}"
repeat_until_success_or_timeout --fatal-test "container_is_running ${CONTAINER_NAME}" "${TEST_TIMEOUT_IN_SECONDS}" \
container_has_service_running "${CONTAINER_NAME}" "${SERVICE_NAME}" repeat_until_success_or_timeout --fatal-test "container_is_running ${CONTAINER_NAME}" "${TEST_TIMEOUT_IN_SECONDS}" \
container_has_service_running "${CONTAINER_NAME}" "${SERVICE_NAME}"
} }
function wait_for_changes_to_be_detected_in_container() { function wait_for_changes_to_be_detected_in_container() {
local CONTAINER_NAME="${1}" local CONTAINER_NAME="${1}"
local TIMEOUT=${TEST_TIMEOUT_IN_SECONDS} local TIMEOUT=${TEST_TIMEOUT_IN_SECONDS}
# shellcheck disable=SC2016 # shellcheck disable=SC2016
repeat_in_container_until_success_or_timeout "${TIMEOUT}" "${CONTAINER_NAME}" bash -c 'source /usr/local/bin/helpers/index.sh; cmp --silent -- <(_monitored_files_checksums) "${CHKSUM_FILE}" >/dev/null' repeat_in_container_until_success_or_timeout "${TIMEOUT}" "${CONTAINER_NAME}" bash -c 'source /usr/local/bin/helpers/index.sh; cmp --silent -- <(_monitored_files_checksums) "${CHKSUM_FILE}" >/dev/null'
} }
function wait_for_empty_mail_queue_in_container() { function wait_for_empty_mail_queue_in_container() {
local CONTAINER_NAME="${1}" local CONTAINER_NAME="${1}"
local TIMEOUT=${TEST_TIMEOUT_IN_SECONDS} local TIMEOUT=${TEST_TIMEOUT_IN_SECONDS}
# shellcheck disable=SC2016 # shellcheck disable=SC2016
repeat_in_container_until_success_or_timeout "${TIMEOUT}" "${CONTAINER_NAME}" bash -c '[[ $(mailq) == *"Mail queue is empty"* ]]' repeat_in_container_until_success_or_timeout "${TIMEOUT}" "${CONTAINER_NAME}" bash -c '[[ $(mailq) == *"Mail queue is empty"* ]]'
} }
# Common defaults appropriate for most tests, override vars in each test when necessary. # Common defaults appropriate for most tests, override vars in each test when necessary.

View File

@ -9,6 +9,7 @@ setup_file() {
local PRIVATE_CONFIG local PRIVATE_CONFIG
PRIVATE_CONFIG=$(duplicate_config_for_container . mail) PRIVATE_CONFIG=$(duplicate_config_for_container . mail)
mv "${PRIVATE_CONFIG}/user-patches/user-patches.sh" "${PRIVATE_CONFIG}/user-patches.sh" mv "${PRIVATE_CONFIG}/user-patches/user-patches.sh" "${PRIVATE_CONFIG}/user-patches.sh"
docker run --rm -d --name mail \ docker run --rm -d --name mail \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
@ -1033,60 +1034,60 @@ EOF
# alias # alias
@test "checking setup.sh: setup.sh alias list" { @test "checking setup.sh: setup.sh alias list" {
run ./setup.sh alias list run ./setup.sh -c mail alias list
assert_success assert_success
assert_output --partial "alias1@localhost.localdomain user1@localhost.localdomain" assert_output --partial "alias1@localhost.localdomain user1@localhost.localdomain"
assert_output --partial "@localdomain2.com user1@localhost.localdomain" assert_output --partial "@localdomain2.com user1@localhost.localdomain"
} }
@test "checking setup.sh: setup.sh alias add" { @test "checking setup.sh: setup.sh alias add" {
./setup.sh alias add alias@example.com target1@forward.com ./setup.sh -c mail alias add alias@example.com target1@forward.com
./setup.sh alias add alias@example.com target2@forward.com ./setup.sh -c mail alias add alias@example.com target2@forward.com
./setup.sh alias add alias2@example.org target3@forward.com ./setup.sh -c mail alias add alias2@example.org target3@forward.com
sleep 5 sleep 5
run grep "alias@example.com target1@forward.com,target2@forward.com" "$(private_config_path mail)/postfix-virtual.cf" run grep "alias@example.com target1@forward.com,target2@forward.com" "$(private_config_path mail)/postfix-virtual.cf"
assert_success assert_success
} }
@test "checking setup.sh: setup.sh alias del" { @test "checking setup.sh: setup.sh alias del" {
./setup.sh alias del alias@example.com target1@forward.com ./setup.sh -c mail alias del alias@example.com target1@forward.com
run grep "target1@forward.com" "$(private_config_path mail)/postfix-virtual.cf" run grep "target1@forward.com" "$(private_config_path mail)/postfix-virtual.cf"
assert_failure assert_failure
run grep "target2@forward.com" "$(private_config_path mail)/postfix-virtual.cf" run grep "target2@forward.com" "$(private_config_path mail)/postfix-virtual.cf"
assert_output "alias@example.com target2@forward.com" assert_output "alias@example.com target2@forward.com"
./setup.sh alias del alias@example.org target2@forward.com ./setup.sh -c mail alias del alias@example.org target2@forward.com
run grep "alias@example.org" "$(private_config_path mail)/postfix-virtual.cf" run grep "alias@example.org" "$(private_config_path mail)/postfix-virtual.cf"
assert_failure assert_failure
run grep "alias2@example.org" "$(private_config_path mail)/postfix-virtual.cf" run grep "alias2@example.org" "$(private_config_path mail)/postfix-virtual.cf"
assert_success assert_success
./setup.sh alias del alias2@example.org target3@forward.com ./setup.sh -c mail alias del alias2@example.org target3@forward.com
run grep "alias2@example.org" "$(private_config_path mail)/postfix-virtual.cf" run grep "alias2@example.org" "$(private_config_path mail)/postfix-virtual.cf"
assert_failure assert_failure
} }
# quota # quota
@test "checking setup.sh: setup.sh setquota" { @test "checking setup.sh: setup.sh setquota" {
run ./setup.sh email add quota_user@example.com test_password run ./setup.sh -c mail email add quota_user@example.com test_password
run ./setup.sh email add quota_user2@example.com test_password run ./setup.sh -c mail email add quota_user2@example.com test_password
run ./setup.sh quota set quota_user@example.com 12M run ./setup.sh -c mail quota set quota_user@example.com 12M
assert_success assert_success
run ./setup.sh quota set 51M quota_user@example.com run ./setup.sh -c mail quota set 51M quota_user@example.com
assert_failure assert_failure
run ./setup.sh quota set unknown@domain.com 150M run ./setup.sh -c mail quota set unknown@domain.com 150M
assert_failure assert_failure
run ./setup.sh quota set quota_user2 51M run ./setup.sh -c mail quota set quota_user2 51M
assert_failure assert_failure
run /bin/sh -c 'cat ./test/duplicate_configs/mail/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1' run /bin/sh -c 'cat ./test/duplicate_configs/mail/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1'
assert_success assert_success
run ./setup.sh quota set quota_user@example.com 26M run ./setup.sh -c mail quota set quota_user@example.com 26M
assert_success assert_success
run /bin/sh -c 'cat ./test/duplicate_configs/mail/dovecot-quotas.cf | grep -E "^quota_user@example.com\:26M\$" | wc -l | grep 1' run /bin/sh -c 'cat ./test/duplicate_configs/mail/dovecot-quotas.cf | grep -E "^quota_user@example.com\:26M\$" | wc -l | grep 1'
assert_success assert_success
@ -1096,20 +1097,20 @@ EOF
} }
@test "checking setup.sh: setup.sh delquota" { @test "checking setup.sh: setup.sh delquota" {
run ./setup.sh email add quota_user@example.com test_password run ./setup.sh -c mail email add quota_user@example.com test_password
run ./setup.sh email add quota_user2@example.com test_password run ./setup.sh -c mail email add quota_user2@example.com test_password
run ./setup.sh quota set quota_user@example.com 12M run ./setup.sh -c mail quota set quota_user@example.com 12M
assert_success assert_success
run /bin/sh -c 'cat ./test/duplicate_configs/mail/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1' run /bin/sh -c 'cat ./test/duplicate_configs/mail/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1'
assert_success assert_success
run ./setup.sh quota del unknown@domain.com run ./setup.sh -c mail quota del unknown@domain.com
assert_failure assert_failure
run /bin/sh -c 'cat ./test/duplicate_configs/mail/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1' run /bin/sh -c 'cat ./test/duplicate_configs/mail/dovecot-quotas.cf | grep -E "^quota_user@example.com\:12M\$" | wc -l | grep 1'
assert_success assert_success
run ./setup.sh quota del quota_user@example.com run ./setup.sh -c mail quota del quota_user@example.com
assert_success assert_success
run grep "quota_user@example.com" ./test/duplicate_configs/mail/dovecot-quotas.cf run grep "quota_user@example.com" ./test/duplicate_configs/mail/dovecot-quotas.cf
assert_failure assert_failure
@ -1135,10 +1136,10 @@ EOF
} }
@test "checking setup.sh: setup.sh relay add-domain" { @test "checking setup.sh: setup.sh relay add-domain" {
./setup.sh relay add-domain example1.org smtp.relay1.com 2525 ./setup.sh -c mail relay add-domain example1.org smtp.relay1.com 2525
./setup.sh relay add-domain example2.org smtp.relay2.com ./setup.sh -c mail relay add-domain example2.org smtp.relay2.com
./setup.sh relay add-domain example3.org smtp.relay3.com 2525 ./setup.sh -c mail relay add-domain example3.org smtp.relay3.com 2525
./setup.sh relay add-domain example3.org smtp.relay.com 587 ./setup.sh -c mail relay add-domain example3.org smtp.relay.com 587
# check adding # check adding
run /bin/sh -c "cat $(private_config_path mail)/postfix-relaymap.cf | grep -e \"^@example1.org\s\+\[smtp.relay1.com\]:2525\" | wc -l | grep 1" run /bin/sh -c "cat $(private_config_path mail)/postfix-relaymap.cf | grep -e \"^@example1.org\s\+\[smtp.relay1.com\]:2525\" | wc -l | grep 1"
@ -1152,9 +1153,9 @@ EOF
} }
@test "checking setup.sh: setup.sh relay add-auth" { @test "checking setup.sh: setup.sh relay add-auth" {
./setup.sh relay add-auth example.org smtp_user smtp_pass ./setup.sh -c mail relay add-auth example.org smtp_user smtp_pass
./setup.sh relay add-auth example2.org smtp_user2 smtp_pass2 ./setup.sh -c mail relay add-auth example2.org smtp_user2 smtp_pass2
./setup.sh relay add-auth example2.org smtp_user2 smtp_pass_new ./setup.sh -c mail relay add-auth example2.org smtp_user2 smtp_pass_new
# test adding # test adding
run /bin/sh -c "cat $(private_config_path mail)/postfix-sasl-password.cf | grep -e \"^@example.org\s\+smtp_user:smtp_pass\" | wc -l | grep 1" run /bin/sh -c "cat $(private_config_path mail)/postfix-sasl-password.cf | grep -e \"^@example.org\s\+smtp_user:smtp_pass\" | wc -l | grep 1"
@ -1165,7 +1166,7 @@ EOF
} }
@test "checking setup.sh: setup.sh relay exclude-domain" { @test "checking setup.sh: setup.sh relay exclude-domain" {
./setup.sh relay exclude-domain example.org ./setup.sh -c mail relay exclude-domain example.org
run /bin/sh -c "cat $(private_config_path mail)/postfix-relaymap.cf | grep -e \"^@example.org\s*$\" | wc -l | grep 1" run /bin/sh -c "cat $(private_config_path mail)/postfix-relaymap.cf | grep -e \"^@example.org\s*$\" | wc -l | grep 1"
assert_success assert_success