Files
kumomta/crates/integration-tests/source.lua
T
Wez Furlong 42d811d045 add integration test for nxdomain retry schedule
The reported behavior was that messages seemd to be retried much faster
than the retry schedule, and at a quick glance it looked like the
nxdomain code path didn't respest the backoff, but from hooking
up this test and making the durations longer, it really doesn't seem
like the issue was that simple:

refs: https://github.com/KumoCorp/kumomta/issues/271
2024-09-18 17:09:29 -07:00

271 lines
7.0 KiB
Lua

local kumo = require 'kumo'
package.path = '../../assets/?.lua;' .. package.path
log_hooks = require 'policy-extras.log_hooks'
local TEST_DIR = os.getenv 'KUMOD_TEST_DIR'
local SINK_PORT = tonumber(os.getenv 'KUMOD_SMTP_SINK_PORT')
local WEBHOOK_PORT = os.getenv 'KUMOD_WEBHOOK_PORT'
local AMQPHOOK_URL = os.getenv 'KUMOD_AMQPHOOK_URL'
local AMQP_HOST_PORT = os.getenv 'KUMOD_AMQP_HOST_PORT'
local LISTENER_MAP = os.getenv 'KUMOD_LISTENER_DOMAIN_MAP'
kumo.on('init', function()
kumo.configure_accounting_db_path(TEST_DIR .. '/accounting.db')
local relay_hosts = { '0.0.0.0/0' }
local RELAY_HOSTS = os.getenv 'KUMOD_RELAY_HOSTS'
if RELAY_HOSTS then
relay_hosts = kumo.json_parse(RELAY_HOSTS)
end
kumo.start_esmtp_listener {
listen = '127.0.0.1:0',
relay_hosts = relay_hosts,
}
kumo.start_http_listener {
listen = '127.0.0.1:0',
}
kumo.configure_local_logs {
log_dir = TEST_DIR .. '/logs',
max_segment_duration = '1s',
headers = { 'X-*', 'Y-*', 'Subject' },
}
if WEBHOOK_PORT then
kumo.configure_log_hook {
name = 'webhook',
headers = { 'Subject', 'X-*' },
}
end
kumo.define_spool {
name = 'data',
path = TEST_DIR .. '/data-spool',
}
kumo.define_spool {
name = 'meta',
path = TEST_DIR .. '/meta-spool',
}
end)
if AMQPHOOK_URL then
log_hooks:new {
name = 'amqp',
constructor = function(domain, tenant, campaign)
local sender = {}
local client = kumo.amqp.build_client(AMQPHOOK_URL)
function sender:send(msg)
local result = client:publish_with_timeout({
routing_key = 'woot',
payload = msg:get_data(),
}, 20000)
if result.status == 'Ack' or result.status == 'NotRequested' then
return string.format('250 %s', kumo.json_encode(result))
end
-- result.status must be `Nack`; log the full result
kumo.reject(500, kumo.json_encode(result))
end
function sender:close()
client:close()
end
return sender
end,
}
elseif AMQP_HOST_PORT then
log_hooks:new {
name = 'amqp',
constructor = function(domain, tenant, campaign)
local sender = {}
local host, port = table.unpack(kumo.string.split(AMQP_HOST_PORT, ':'))
function sender:send(msg)
kumo.amqp.basic_publish {
routing_key = 'woot',
payload = msg:get_data(),
connection = {
host = host,
port = tonumber(port),
},
}
return '250 ok'
end
return sender
end,
}
end
if WEBHOOK_PORT then
local batch_size = tonumber(os.getenv 'KUMOD_WEBHOOK_BATCH_SIZE')
if batch_size > 1 then
log_hooks:new {
name = 'webhookbatch',
batch_size = batch_size,
constructor = function(domain, tenant, campaign)
local sender = {}
local client = kumo.http.build_client {}
function sender:send_batch(messages)
local payload = {}
for _, msg in ipairs(messages) do
table.insert(payload, msg:get_meta 'log_record')
end
print(string.format('batch size is %d ***************', #payload))
local response = client
:post(
string.format('http://127.0.0.1:%d/log-batch', WEBHOOK_PORT)
)
:header('Content-Type', 'application/json')
:body(kumo.serde.json_encode(payload))
:send()
local disposition = string.format(
'%d %s: %s',
response:status_code(),
response:status_reason(),
response:text()
)
if response:status_is_success() then
return disposition
end
kumo.reject(500, disposition)
end
return sender
end,
}
else
kumo.on('should_enqueue_log_record', function(msg)
local log_record = msg:get_meta 'log_record'
-- avoid an infinite loop caused by logging that we logged
if log_record.queue ~= 'webhook' then
msg:set_meta('queue', 'webhook')
return true
end
return false
end)
kumo.on('make.webhook', function(_domain, _tenant, _campaign)
local sender = {}
local client = kumo.http.build_client {}
function sender:send(message)
local response = client
:post(string.format('http://127.0.0.1:%d/log', WEBHOOK_PORT))
:header('Content-Type', 'application/json')
:body(message:get_data())
:send()
local disposition = string.format(
'%d %s: %s',
response:status_code(),
response:status_reason(),
response:text()
)
if response:status_is_success() then
return disposition
end
kumo.reject(500, disposition)
end
return sender
end)
end
end
kumo.on('get_listener_domain', function(domain, listener, conn_meta)
if LISTENER_MAP then
local map = kumo.json_parse(LISTENER_MAP)
local params = map[domain]
if params then
return kumo.make_listener_domain(params)
end
end
return kumo.make_listener_domain {
relay_to = true,
log_oob = true,
log_arf = true,
}
end)
kumo.on('smtp_server_message_received', function(msg) end)
kumo.on('get_queue_config', function(domain, _tenant, _campaign)
if domain == 'webhook' then
return kumo.make_queue_config {
protocol = {
custom_lua = {
constructor = 'make.webhook',
},
},
}
end
local protocol = {
-- Redirect traffic to the sink
smtp = {
mx_list = { 'localhost' },
},
}
if domain == 'nxdomain' then
-- this nxdomain domain is a special domain that is assumed not
-- to resolve. It is generated by the retry_schedule integration
-- test. for this domain, we don't want to short-circuit dns
-- and go to the sink, because we DO want the dns resolution
-- to successfully return nxdomain in order for the test to
-- exercise the appropriate logic.
protocol = nil
end
return kumo.make_queue_config {
protocol = protocol,
retry_interval = os.getenv 'KUMOD_RETRY_INTERVAL',
strategy = os.getenv 'KUMOD_QUEUE_STRATEGY',
}
end)
kumo.on('get_egress_path_config', function(domain, _source_name, _site_name)
-- Allow sending to a sink
local params = {
enable_tls = os.getenv 'KUMOD_ENABLE_TLS' or 'OpportunisticInsecure',
smtp_port = SINK_PORT,
prohibited_hosts = {},
}
local username = os.getenv 'KUMOD_SMTP_AUTH_USERNAME'
local password = os.getenv 'KUMOD_SMTP_AUTH_PASSWORD'
if username and password then
params.smtp_auth_plain_username = username
params.smtp_auth_plain_password = {
key_data = password,
}
end
if domain == 'webhookbatch.log_hook' then
-- we use a slow throttle here to encourage batches
-- to be used
params.max_message_rate = '3/s'
end
print('get_egress_path_config *******************', domain)
return kumo.make_egress_path(params)
end)
if os.getenv 'KUMOD_WANT_REBIND' then
kumo.on('rebind_message', function(message, data)
message:set_meta('queue', data.queue)
end)
end