Compare commits

...
Author SHA1 Message Date
holger krekel 2dbf31ea16 test: integrate lua testing into regular pytest run for push notifications
turns out Python has the nice https://pypi.org/project/lupa/
that allows us to quite easily test dovecot LUA parts
without figuring out errors on deploy.
2026-08-25 11:12:58 +02:00
holger krekel e489a1ea29 ci: try to fix lack of RFC822 item support in madmail and make CI pass
some local debugging revealed madmail v2 does not support fetching RFC822 items
(gives an empty body) so try BODY.PEEK[] instead.
2026-08-24 18:27:14 +02:00
adbenitezandholger krekel 455da45d36 update gplay to 2.59.1 2026-08-24 17:51:05 +02:00
KamyarATandholger krekel 48ad92bf24 docs: describe Madmail v2 as a Rust chatmail relay
The previous blurb still called Madmail an experimental Maddy fork.
That applied to v1. v2 is a Rust rewrite that ships SMTP, IMAP,
encryption enforcement, and real-time services in a single binary.
2026-08-20 15:36:27 +02:00
6 changed files with 120 additions and 8 deletions
@@ -5,9 +5,9 @@
"sources": [
{
"sourceId": "gplay",
"versionInteger": 754,
"versionString": "2.57.0",
"downloadUrl": "https://github.com/deltachat/deltachat-android/releases/download/v2.57.0/deltachat-gplay-release-2.57.0.apk"
"versionInteger": 757,
"versionString": "2.59.1",
"downloadUrl": "https://github.com/deltachat/deltachat-android/releases/download/v2.59.1/deltachat-gplay-release-2.59.1.apk"
}
]
}
+1
View File
@@ -19,6 +19,7 @@ dependencies = [
"pytest-xdist",
"execnet",
"imap_tools",
"lupa",
"deltachat-rpc-client",
"deltachat-rpc-server",
]
+25
View File
@@ -0,0 +1,25 @@
"""Run the lua scripts we ship under lupa, which bundles Lua 5.4 like dovecot."""
import pytest
from lupa import lua54
from cmdeploy.basedeploy import get_resource
class Lua:
"""A Lua runtime to load shipped scripts and mocks into."""
def __init__(self):
self.rt = lua54.LuaRuntime(unpack_returned_tuples=True)
self.g = self.rt.globals()
def load(self, path):
self.rt.execute(get_resource(path).read_text())
def table(self, **kwargs):
return self.rt.table(**kwargs)
@pytest.fixture
def lua():
return Lua()
+1 -1
View File
@@ -211,7 +211,7 @@ class ImapConn:
status, res = self.conn.select()
if int(res[0]) == 0:
raise ValueError("no messages in imap folder")
status, results = self.conn.fetch("1:*", "(RFC822)")
status, results = self.conn.fetch("1:*", "(BODY.PEEK[])")
assert status == "OK"
return results
@@ -0,0 +1,85 @@
"""Test the push_notification.lua we ship, against a mocked dovecot mail API."""
import textwrap
import pytest
USER1 = "user12345@chat.example.org"
USER2 = "user67890@chat.example.org"
DOVECOT_MOCKS = textwrap.dedent("""
function make_user(username)
local function mailbox(_, name)
record("mailbox " .. name)
return {
sync = function() record("sync") end,
metadata_set = function(_, k, v)
record("metadata_set " .. k .. "=" .. v)
end,
free = function() record("free") end,
}
end
return {username = username, mailbox = mailbox}
end
""")
@pytest.fixture
def script(lua):
lua.rt.execute(DOVECOT_MOCKS)
lua.load("dovecot/push_notification.lua")
return lua
@pytest.fixture
def deliver(script):
def deliver(recipient, sender):
calls = []
script.g.record = calls.append
user = script.g.make_user(recipient)
ctx = script.g.dovecot_lua_notify_begin_txn(user)
event = script.table(mailbox="INBOX", from_address=sender)
script.g.dovecot_lua_notify_event_message_new(ctx, event)
script.g.dovecot_lua_notify_end_txn(ctx, True)
return calls
return deliver
def test_entry_points_have_the_names_dovecot_calls(script):
assert script.g.dovecot_lua_notify_begin_txn is not None
assert script.g.dovecot_lua_notify_event_message_new is not None
assert script.g.dovecot_lua_notify_end_txn is not None
def test_begin_txn_returns_the_user_as_event_context(script):
user = script.g.make_user(USER1)
ctx = script.g.dovecot_lua_notify_begin_txn(user)
ctx.marker = "seen"
assert user.marker == "seen"
def test_incoming_message_notifies_metadata_server(deliver):
assert deliver(USER1, sender=USER2) == [
"mailbox INBOX",
"sync",
"metadata_set /private/messagenew=",
"free",
]
def test_own_message_does_not_wake_the_sending_device(deliver):
assert deliver(USER1, sender=USER1) == [
"mailbox INBOX",
"sync",
"free",
]
def test_message_without_from_address_is_notified(deliver):
assert deliver(USER1, sender=None) == [
"mailbox INBOX",
"sync",
"metadata_set /private/messagenew=",
"free",
]
+5 -4
View File
@@ -14,10 +14,11 @@ We know of three work-in-progress alternative implementation efforts:
it to support all of the features and configuration settings required
to operate as a chatmail relay.
- `Madmail <https://github.com/themadorg/madmail>`_: an
experimental fork of `Maddy Mail Server <https://maddy.email/>`_, modified
for chatmail deployments. It provides a single binary solution
for running a chatmail relay.
- `Madmail <https://github.com/themadorg/madmail>`_: a Rust-based
single-binary chatmail relay. Madmail v2 is a rewrite of an earlier
experimental fork of `Maddy Mail Server <https://maddy.email/>`_.
It includes SMTP, IMAP, encryption enforcement, and real-time
services (TURN/Iroh), and runs on Linux and Windows.
- `Chatmail Cookbook <https://github.com/feld/chatmail-cookbook>`_:
A Chef Cookbook implementing a relay server. The project follows the