Compare commits

...

12 Commits

Author SHA1 Message Date
holger krekel
cbbcf3cbca add marker dynamically to allow "pytest" to execute nicely at repo root without warnings 2023-10-20 22:45:11 +02:00
holger krekel
d2af9df8f9 rename test files to be unambigously numbered 2023-10-20 22:39:23 +02:00
holger krekel
83e6a42252 slight refinement for benchmark formatting, not worth a PR 2023-10-20 18:43:06 +02:00
link2xt
eb69dd58f7 Setup CI 2023-10-20 15:18:17 +02:00
link2xt
31c45f951d dictproxy: use crypt instead of doveadm pw 2023-10-20 14:05:25 +02:00
holger krekel
3012bfb79d some reformatting and striking overall 2023-10-20 11:05:58 +02:00
holger krekel
03442bc115 some improvements, adding a bnech 2023-10-20 11:05:58 +02:00
holger krekel
1ae6291d06 add ping-pong bench and formatting 2023-10-20 11:05:58 +02:00
holger krekel
1b347f97a0 better benchmarking and reporting 2023-10-20 11:05:58 +02:00
link2xt
902f98c9ba Set syslog name for reinject proxy 2023-10-19 03:22:27 +00:00
link2xt
89311063f8 Turn filtermail into a beforequeue handler and implement rate limit 2023-10-19 03:04:00 +00:00
link2xt
329b845c79 Configure journald to retain logs for 3 days 2023-10-18 22:54:50 +02:00
12 changed files with 146 additions and 42 deletions

18
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: CI
on:
pull_request:
push:
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Lint chatmaild
working-directory: chatmaild
run: pipx run tox
- name: Lint deploy-chatmail
working-directory: deploy-chatmail
run: pipx run tox

View File

@@ -2,13 +2,13 @@ import logging
import os import os
import sys import sys
import json import json
import crypt
from socketserver import ( from socketserver import (
UnixStreamServer, UnixStreamServer,
StreamRequestHandler, StreamRequestHandler,
ThreadingMixIn, ThreadingMixIn,
) )
import pwd import pwd
import subprocess
from .database import Database from .database import Database
@@ -16,17 +16,9 @@ NOCREATE_FILE = "/etc/chatmail-nocreate"
def encrypt_password(password: str): def encrypt_password(password: str):
password = password.encode("ascii")
# https://doc.dovecot.org/configuration_manual/authentication/password_schemes/ # https://doc.dovecot.org/configuration_manual/authentication/password_schemes/
process = subprocess.Popen( passhash = crypt.crypt(password, crypt.METHOD_SHA512)
["doveadm", "pw", "-s", "SHA512-CRYPT"], return "{SHA512-CRYPT}" + passhash
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
stdout_data, _stderr_data = process.communicate(
input=password + b"\n" + password + b"\n"
)
return stdout_data.decode("ascii").strip()
def create_user(db, user, password): def create_user(db, user, password):

View File

@@ -277,6 +277,22 @@ def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> N
commands=[f"echo {mail_domain} >/etc/mailname; chmod 644 /etc/mailname"], commands=[f"echo {mail_domain} >/etc/mailname; chmod 644 /etc/mailname"],
) )
journald_conf = files.put(
name="Configure journald",
src=importlib.resources.files(__package__).joinpath("journald.conf"),
dest="/etc/systemd/journald.conf",
user="root",
group="root",
mode="644",
)
systemd.service(
name="Start and enable journald",
service="systemd-journald.service",
running=True,
enabled=True,
restarted=journald_conf,
)
def callback(): def callback():
result = server.shell( result = server.shell(
commands=[ commands=[

View File

@@ -1,6 +1,6 @@
import importlib.resources import importlib.resources
from pyinfra.operations import apt, files, systemd, server from pyinfra.operations import apt, files, server
def deploy_acmetool(nginx_hook=False, email="", domains=[]): def deploy_acmetool(nginx_hook=False, email="", domains=[]):

View File

@@ -0,0 +1,2 @@
[Journal]
MaxRetentionSec=3d

View File

@@ -77,4 +77,4 @@ postlog unix-dgram n - n - 1 postlogd
filter unix - n n - - lmtp filter unix - n n - - lmtp
# Local SMTP server for reinjecting filered mail. # Local SMTP server for reinjecting filered mail.
localhost:10025 inet n - n - 10 smtpd localhost:10025 inet n - n - 10 smtpd
-o content_filter= -o syslog_name=postfix/reinject

View File

@@ -1,34 +1,60 @@
def test_tls_serialized_connect(benchmark, imap_or_smtp): def test_tls_imap(benchmark, imap):
def connect(): def imap_connect():
imap_or_smtp.connect() imap.connect()
benchmark(connect) benchmark(imap_connect, 10)
def test_login(benchmark, imap_or_smtp, gencreds): def test_login_imap(benchmark, imap, gencreds):
cls = imap_or_smtp.__class__ def imap_connect_and_login():
conns = [] imap.connect()
for i in range(20): imap.login(*gencreds())
conn = cls(imap_or_smtp.host)
conn.connect()
conns.append(conn)
def login(): benchmark(imap_connect_and_login, 10)
conn = conns.pop()
conn.login(*gencreds())
benchmark(login)
def test_send_and_receive_10(benchmark, cmfactory, lp): def test_tls_smtp(benchmark, smtp):
"""send many messages between two accounts""" def smtp_connect():
ac1, ac2 = cmfactory.get_online_accounts(2) smtp.connect()
chat = cmfactory.get_accepted_chat(ac1, ac2)
def send_10_receive_all(): benchmark(smtp_connect, 10)
for i in range(10):
chat.send_text(f"hello {i}")
for i in range(10):
ac2.wait_next_incoming_message()
benchmark(send_10_receive_all)
def test_login_smtp(benchmark, smtp, gencreds):
def smtp_connect_and_login():
smtp.connect()
smtp.login(*gencreds())
benchmark(smtp_connect_and_login, 10)
class TestDC:
def test_autoconfigure(self, benchmark, cmfactory):
def autoconfig_and_idle_ready():
cmfactory.get_online_accounts(1)
benchmark(autoconfig_and_idle_ready, 5)
def test_ping_pong(self, benchmark, cmfactory):
ac1, ac2 = cmfactory.get_online_accounts(2)
chat = cmfactory.get_accepted_chat(ac1, ac2)
def ping_pong():
chat.send_text("ping")
msg = ac2.wait_next_incoming_message()
msg.chat.send_text("pong")
ac1.wait_next_incoming_message()
benchmark(ping_pong, 5)
def test_send_10_receive_10(self, benchmark, cmfactory, lp):
ac1, ac2 = cmfactory.get_online_accounts(2)
chat = cmfactory.get_accepted_chat(ac1, ac2)
def send_10_receive_10():
for i in range(10):
chat.send_text(f"hello {i}")
for i in range(10):
ac2.wait_next_incoming_message()
benchmark(send_10_receive_10, 5)

View File

@@ -1,10 +1,12 @@
import os import os
import io import io
import time
import random import random
import subprocess import subprocess
import imaplib import imaplib
import smtplib import smtplib
import itertools import itertools
from math import ceil
import pytest import pytest
@@ -14,6 +16,13 @@ def pytest_addoption(parser):
) )
def pytest_configure(config):
config._benchresults = {}
config.addinivalue_line(
"markers", "slow: mark test to require --slow option to run"
)
def pytest_runtest_setup(item): def pytest_runtest_setup(item):
markers = list(item.iter_markers(name="slow")) markers = list(item.iter_markers(name="slow"))
if markers: if markers:
@@ -54,6 +63,49 @@ def pytest_report_header():
return ["-" * len(text), text, "-" * len(text)] return ["-" * len(text), text, "-" * len(text)]
@pytest.fixture
def benchmark(request):
def bench(func, num, name=None):
if name is None:
name = func.__name__
durations = []
for i in range(num):
now = time.time()
func()
durations.append(time.time() - now)
durations.sort()
request.config._benchresults[name] = durations
return bench
def pytest_terminal_summary(terminalreporter):
tr = terminalreporter
results = tr.config._benchresults
if not results:
return
tr.section("benchmark results")
float_names = 'median min max'.split()
width = max(map(len, float_names))
def fcol(parts):
return " ".join(part.rjust(width) for part in parts)
headers = f"{'benchmark name': <30} " + fcol(float_names)
tr.write_line(headers)
tr.write_line("-" * len(headers))
for name, durations in results.items():
measures = [
sorted(durations)[len(durations) // 2],
min(durations),
max(durations),
]
line = f"{name: <30} "
line += fcol(f"{float: 2.2f}" for float in measures)
tr.write_line(line)
@pytest.fixture @pytest.fixture
def imap(maildomain): def imap(maildomain):
return ImapConn(maildomain) return ImapConn(maildomain)

View File

@@ -1,3 +1,2 @@
[pytest] [pytest]
addopts = -vrsx --strict-markers addopts = -vrsx --strict-markers
markers = slow: mark test as slow (requires --slow option to run)

View File

@@ -6,9 +6,8 @@ deploy-chatmail/venv/bin/pip install -e deploy-chatmail
deploy-chatmail/venv/bin/pip install -e chatmaild deploy-chatmail/venv/bin/pip install -e chatmaild
python3 -m venv chatmaild/venv python3 -m venv chatmaild/venv
sudo apt install -y dovecot-core && sudo systemctl disable --now dovecot
chatmaild/venv/bin/pip install --upgrade pytest build 'setuptools>=68' chatmaild/venv/bin/pip install --upgrade pytest build 'setuptools>=68'
chatmaild/venv/bin/pip install -e chatmaild chatmaild/venv/bin/pip install -e chatmaild
python3 -m venv online-tests/venv python3 -m venv online-tests/venv
online-tests/venv/bin/pip install pytest pytest-timeout pdbpp deltachat pytest-benchmark online-tests/venv/bin/pip install pytest pytest-timeout pdbpp deltachat