diff --git a/target/bin/setquota b/target/bin/setquota index cfb1dc42..53af7d99 100755 --- a/target/bin/setquota +++ b/target/bin/setquota @@ -64,12 +64,15 @@ function _quota_request_if_missing fi } +# Dovecot docs incorrectly refer to these units with names for SI types (base 10), +# But then mentions they're actually treated as IEC type (base 2): +# https://doc.dovecot.org/settings/types/#size function _quota_unit_is_valid { if ! grep -qE "^([0-9]+(B|k|M|G|T)|0)\$" <<< "${QUOTA}" then __usage - _exit_with_error 'Invalid quota format. e.g. 302M (B (byte), k (kilobyte), M (megabyte), G (gigabyte) or T (terabyte))' + _exit_with_error 'Invalid quota format. e.g. 302M (B (byte), k (kibibyte), M (mebibyte), G (gibibyte) or T (tebibyte))' fi } diff --git a/test/tests/parallel/set1/dovecot/dovecot_quotas.bats b/test/tests/parallel/set1/dovecot/dovecot_quotas.bats index a9a1d32a..86b66bfc 100644 --- a/test/tests/parallel/set1/dovecot/dovecot_quotas.bats +++ b/test/tests/parallel/set1/dovecot/dovecot_quotas.bats @@ -1,6 +1,25 @@ load "${REPOSITORY_ROOT}/test/helper/common" load "${REPOSITORY_ROOT}/test/helper/setup" +# upstream default: 10 240 000 +# https://www.postfix.org/postconf.5.html#message_size_limit +# > The maximal size in bytes of a message, including envelope information. +# > The value cannot exceed LONG_MAX (typically, a 32-bit or 64-bit signed integer). +# > Note: Be careful when making changes. Excessively small values will result in the loss of non-delivery notifications, when a bounce message size exceeds the local or remote MTA's message size limit. + +# upstream default: 51 200 000 +# https://www.postfix.org/postconf.5.html#mailbox_size_limit +# > The maximal size of any local(8) individual mailbox or maildir file, or zero (no limit). +# > In fact, this limits the size of any file that is written to upon local delivery, including files written by external commands that are executed by the local(8) delivery agent. +# > The value cannot exceed LONG_MAX (typically, a 32-bit or 64-bit signed integer). +# > This limit must not be smaller than the message size limit. + +# upstream default: 51 200 000 +# https://www.postfix.org/postconf.5.html#virtual_mailbox_limit +# > The maximal size in bytes of an individual virtual(8) mailbox or maildir file, or zero (no limit). +# > This parameter is specific to the virtual(8) delivery agent. +# > It does not apply when mail is delivered with a different mail delivery program. + BATS_TEST_NAME_PREFIX='[Dovecot Quotas] ' CONTAINER_NAME='dms-test_dovecot-quotas' @@ -9,6 +28,8 @@ function setup_file() { local CONTAINER_ARGS_ENV_CUSTOM=( --env ENABLE_QUOTAS=1 + --env POSTFIX_MAILBOX_SIZE_LIMIT=4096000 + --env POSTFIX_MESSAGE_SIZE_LIMIT=2048000 --env PERMIT_DOCKER=container ) _common_container_setup 'CONTAINER_ARGS_ENV_CUSTOM' @@ -115,39 +136,33 @@ function teardown_file() { _default_teardown ; } } @test '(ENV POSTFIX_MAILBOX_SIZE_LIMIT) should be configured for both Postfix and Dovecot' { - local MAILBOX_SIZE_POSTFIX MAILBOX_SIZE_DOVECOT MAILBOX_SIZE_POSTFIX_MB MAILBOX_SIZE_DOVECOT_MB - - MAILBOX_SIZE_POSTFIX=$(_exec_in_container postconf -h mailbox_size_limit) - run echo "${MAILBOX_SIZE_POSTFIX}" - refute_output "" + _run_in_container postconf -h mailbox_size_limit + assert_output 4096000 # Dovecot mailbox is sized by `virtual_mailbox_size` from Postfix: - MAILBOX_SIZE_DOVECOT=$(_exec_in_container postconf -h virtual_mailbox_limit) - assert_equal "${MAILBOX_SIZE_DOVECOT}" "${MAILBOX_SIZE_POSTFIX}" + _run_in_container postconf -h virtual_mailbox_limit + assert_output 4096000 # Quota support: - MAILBOX_SIZE_POSTFIX_MB=$(( MAILBOX_SIZE_POSTFIX / 1000000)) - MAILBOX_SIZE_DOVECOT_MB=$(_exec_in_container_bash 'doveconf -h plugin/quota_rule | grep -oE "[0-9]+"') - run echo "${MAILBOX_SIZE_DOVECOT_MB}" - refute_output "" + _run_in_container doveconf -h plugin/quota_rule + # Global default storage limit quota for each mailbox 4 MiB: + assert_output '*:storage=4M' - assert_equal "${MAILBOX_SIZE_POSTFIX_MB}" "${MAILBOX_SIZE_DOVECOT_MB}" + # Sizes are equivalent - Bytes to MiB (rounded): + run numfmt --to=iec --format '%.0f' 4096000 + assert_output '4M' } @test '(ENV POSTFIX_MESSAGE_SIZE_LIMIT) should be configured for both Postfix and Dovecot' { - local MESSAGE_SIZE_POSTFIX MESSAGE_SIZE_POSTFIX_MB MESSAGE_SIZE_DOVECOT_MB + _run_in_container postconf -h message_size_limit + assert_output 2048000 - MESSAGE_SIZE_POSTFIX=$(_exec_in_container postconf -h message_size_limit) - run echo "${MESSAGE_SIZE_POSTFIX}" - refute_output "" + _run_in_container doveconf -h plugin/quota_max_mail_size + assert_output '2M' - # Quota support: - MESSAGE_SIZE_POSTFIX_MB=$(( MESSAGE_SIZE_POSTFIX / 1000000)) - MESSAGE_SIZE_DOVECOT_MB=$(_exec_in_container_bash 'doveconf -h plugin/quota_max_mail_size | grep -oE "[0-9]+"') - run echo "${MESSAGE_SIZE_DOVECOT_MB}" - refute_output "" - - assert_equal "${MESSAGE_SIZE_POSTFIX_MB}" "${MESSAGE_SIZE_DOVECOT_MB}" + # Sizes are equivalent - Bytes to MiB (rounded): + run numfmt --to=iec --format '%.0f' 2048000 + assert_output '2M' } @test 'Deleting an mailbox account should also remove that account from dovecot-quotas.cf' { @@ -169,26 +184,29 @@ function teardown_file() { _default_teardown ; } } @test 'Dovecot should acknowledge quota configured for accounts' { - _run_in_container_bash "doveadm quota get -u 'user1@localhost.localdomain' | grep 'User quota STORAGE'" - assert_output --partial "- 0" + # sed -nE 's/.*STORAGE.*Limit=([0-9]+).*/\1/p' | numfmt --from-unit=1024 --to=iec --format '%.0f' + local CMD_GET_QUOTA="doveadm -f flow quota get -u 'user1@localhost.localdomain'" - _run_in_container setup quota set user1@localhost.localdomain 50M + # 4M == 4096 kiB (numfmt --to-unit=1024 --from=iec 4M) + _run_in_container_bash "${CMD_GET_QUOTA}" + assert_line --partial 'Type=STORAGE Value=0 Limit=4096' + + # Setting a new limit for the user: + _run_in_container setup quota set 'user1@localhost.localdomain' 50M + assert_success + # 50M (50 * 1024^2) == 51200 kiB (numfmt --to-unit=1024 --from=iec 52428800) + run _repeat_until_success_or_timeout 20 _exec_in_container_bash "${CMD_GET_QUOTA} | grep -o 'Type=STORAGE Value=0 Limit=51200'" assert_success - # wait until quota has been updated - run _repeat_until_success_or_timeout 20 _exec_in_container_bash 'doveadm quota get -u user1@localhost.localdomain | grep -oP "(User quota STORAGE\s+[0-9]+\s+)51200(.*)"' + # Deleting quota resets it to default global quota limit (`plugin/quota_rule`): + _run_in_container setup quota del 'user1@localhost.localdomain' assert_success - - _run_in_container setup quota del user1@localhost.localdomain - assert_success - - # wait until quota has been updated - run _repeat_until_success_or_timeout 20 _exec_in_container_bash 'doveadm quota get -u user1@localhost.localdomain | grep -oP "(User quota STORAGE\s+[0-9]+\s+)-(.*)"' + run _repeat_until_success_or_timeout 20 _exec_in_container_bash "${CMD_GET_QUOTA} | grep -o 'Type=STORAGE Value=0 Limit=4096'" assert_success } @test 'should receive a warning mail from Dovecot when quota is exceeded' { - skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2511' + # skip 'disabled as it fails randomly: https://github.com/docker-mailserver/docker-mailserver/pull/2511' # Prepare _add_mail_account_then_wait_until_ready 'quotauser@otherdomain.tld' @@ -198,7 +216,7 @@ function teardown_file() { _default_teardown ; } assert_success # wait until quota has been updated - run _repeat_until_success_or_timeout 20 _exec_in_container_bash 'doveadm quota get -u quotauser@otherdomain.tld | grep -oP "(User quota STORAGE\s+[0-9]+\s+)10(.*)"' + run _repeat_until_success_or_timeout 20 _exec_in_container_bash "doveadm -f flow quota get -u 'quotauser@otherdomain.tld' | grep -o 'Type=STORAGE Value=0 Limit=10'" assert_success # dovecot and postfix has been restarted