diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06e188d..3543547 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,6 +80,11 @@ jobs: path: | ci-results/ /tmp/muc-sm-load.json + /tmp/xmpp-message-latency.json + /tmp/personal-message-latency.json + /tmp/push-latency.json + /tmp/push-offline-latency.json + /tmp/bind2-archive-latency.json if-no-files-found: warn retention-days: 14 diff --git a/AGENTS.md b/AGENTS.md index cb87cf1..46eb91a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,8 +28,8 @@ В нём сейчас нет `.git`. Если следующая среда содержит Git checkout, используйте его состояние и инструкции, не создавайте второй расходящийся источник истины. -Версия Rust source — **0.8.0**. Последующие изменения добавили GitHub Actions, -Docker target для проверенного бинарника и этот handoff без изменения Rust source. +Версия Rust source — **0.8.2**. В0.8.0 добавлены durable MUC/SM, затем CI +и этот handoff;0.8.1 исправляет задержку сообщений. См. docs/MESSAGE-LATENCY.md. Перед передачей исходники упаковываются в ZIP; актуальный архив должен содержать этот файл и `.github/workflows/ci.yml`. В среде ChatGPT сохраняйте новый архив через доступный Library workflow, обновляя существующий проект, если его identity @@ -38,7 +38,8 @@ Docker target для проверенного бинарника и этот han ## С чего начать 1. Прочитайте README.md, docs/COMPATIBILITY.md, docs/VALIDATION.md. -2. Для MUC/SM: docs/MUC-RECOVERY.md и CHANGELOG-0.8.0.md. +2. Для MUC/SM: docs/MUC-RECOVERY.md, CHANGELOG-0.8.0.md/0.8.1.md + и docs/MESSAGE-LATENCY.md/PERSONAL-MESSAGE-LATENCY.md. Не возвращайте expiry scan архива на каждый append. 3. Для upload: docs/HTTP-UPLOAD.md, исторические VALIDATION-0.7.8.md/0.7.9.md. 4. Для CI: docs/GITHUB-ACTIONS.md, docs/CI-VALIDATION.md, `.github/workflows/ci.yml`, scripts/ci/verify-all.sh. @@ -189,6 +190,32 @@ GitHub workflow проверен actionlint1.7.7, shell/Python syntax и слу Реального GitHub run, Docker build/run и Gitea push пока НЕ было: Docker daemon здесь отсутствует, доступ к пользовательскому GitHub/Gitea не предоставлен. +## Исправление задержки0.8.1 + +Полный MUC archive expiry на каждом сообщении был причиной seconds-level latency: +100000records, median2518мс до →4.680мс после в realTLS loopback. Убраны no-op +CSI checkpoints и перезаписи неизменённых native exports; private account traffic +не ждёт MUC mutex. Обязательные durable commits сохранены. Четыре новые +структурные регрессии прошли; измерения содержат raw samples и binary hashes. +Результаты нового итогового прогона смотрите в docs/VALIDATION-0.8.1.md. +Старые293tests и10GiB цифры выше относятся к прошлым выпускам. + +## Личная доставка0.8.2 + +Не await push gateway в обработчике личного сообщения: очередь1024/max8worker, +RAII cancellation при stop/error. Сначала durable offline/SM data, потомpush. +Runtime CSI defaults теперь включают OMEMO encrypted/receipts/markers; explicit +список заменяет defaults. Raw native importance function не менялась. Refresh +policy при resume нужен для старых persisted slots. Логmessage-processing-slow +не включает payload. Hub.for_owners выбирает account resources до session locks; +не возвращайте сканирование всех чужих session locks при deliver/carbons. +Archive.edges_store читает только endpoints для Bind2 и metadata IQ; сохранены +bounded Lua/recovery/locks, middle не проверяется этим metadata operation. +Новые тесты: personal_message_latency_network.py, push_latency_network.py, +bind2_archive_latency_network.py, archive_edges.rs, session_routing_isolation.rs. +Результаты текущей версии: docs/VALIDATION-0.8.2.md. Полный MAM query/maintenance +и глобальный mutex SM Store остаются возможными отдельными IO bottlenecks. + ## Ближайшие задачи и границы - Проверить первый настоящий CI run после загрузки репозитория и настройки diff --git a/CHANGELOG-0.8.1.md b/CHANGELOG-0.8.1.md new file mode 100644 index 0000000..2de1f9e --- /dev/null +++ b/CHANGELOG-0.8.1.md @@ -0,0 +1,16 @@ +# 0.8.1 + +- Исправлена задержка доставки MUC с растущим архивом: после каждого сообщения + больше не выполняется полный scan/rewrite архива для expiry. Очистка остаётся + в maintenance и перед MAM-запросами; append и crash checkpoint до fanout сохранены. +- Неизменённые native config/persistent index не перезаписываются при каждом + сообщении. Удалённые файлы восстанавливаются, ошибки экспорта повторяются. +- CSI больше не сохраняет SM snapshot при отсутствии изменения durable очереди. + Изменённая очередь сохраняется до отправки; при ошибке записи очередь откатывается. +- Личные сообщения, IQ и входящая федерация к аккаунтам больше не захватывают + общий MUC mutex, ожидая несвязанную работу с комнатными архивами. +- Добавлены регрессии native exports/archive scanning/CSI rollback и реальный + TLS latency check в verify-local.sh, автоматически включённый и в CI. + +Измерения и границы подтверждения: [docs/MESSAGE-LATENCY.md](docs/MESSAGE-LATENCY.md). +Результаты итогового прогона: [docs/VALIDATION-0.8.1.md](docs/VALIDATION-0.8.1.md). diff --git a/CHANGELOG-0.8.2.md b/CHANGELOG-0.8.2.md new file mode 100644 index 0000000..f8414aa --- /dev/null +++ b/CHANGELOG-0.8.2.md @@ -0,0 +1,21 @@ +# 0.8.2 — задержки личных сообщений + +- Личные сообщения и SM ACK больше не ждут сетевую отправку push. Уведомления + отправляются через очередь1024 с максимум8параллельных маршрутов; worker + и его задачи отменяются при завершении serve. Ошибки очереди/маршрута логируются. +- Offline сообщение сохраняется до публикации push, чтобы проснувшийся клиент + мог сразу получить его. Подтверждена очередь при первом TLS stream push gateway. +- По умолчанию CSI считает важными bodyless OMEMO legacy/2, delivery receipts + и chat markers. Явный список `csi_important_payloads` заменяет расширенные defaults. + Низкоприоритетный headline по-прежнему буферизуется. Policy обновляется и при SM resume. +- Выбор адресатов и carbons фильтрует владельцев до захвата session mutex; + зависшая сессия чужого аккаунта не задерживает этот путь. Duplicate SM ACK + без изменения durable counters/queue не переписывает snapshot. +- Bind2 и MAM metadata IQ читают только первый/последний native record вместо + сканирования всей истории. Индекс не требуется; recovery/лимиты записи сохранены. +- Добавлен `message-processing-slow`: обработка message дольше250мс, поля + duration_ms/route, без payload/токенов. Это время обработки сервером, не peer receipt. +- Новые сетевые регрессии включены в verify-local.sh/GitHub CI. + +Причины, изменение CSI policy, измерения и ограничения: +[docs/PERSONAL-MESSAGE-LATENCY.md](docs/PERSONAL-MESSAGE-LATENCY.md). diff --git a/Cargo.lock b/Cargo.lock index 08d6ee3..428cdfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1111,7 +1111,7 @@ dependencies = [ [[package]] name = "rust-xmpp" -version = "0.8.0" +version = "0.8.2" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml index fa6e75c..2a6db3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-xmpp" -version = "0.8.0" +version = "0.8.2" edition = "2024" description = "Experimental Rust XMPP server with Prosody-compatible storage" license = "MIT" diff --git a/README.md b/README.md index d88a3be..48cd1d1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Rust XMPP 0.8.0 +# Rust XMPP 0.8.2 Сервер на Rust, разрабатываемый для замены **Prosody 13.0 nightly 100, cafd74b9c5ea** с предоставленными модулями. Читает существующий Lua-конфиг, @@ -238,3 +238,16 @@ recovery Rust служит собственный журнал. Перед от Полные тесты, Linux binary artifact и Docker push после проверок: [настройка workflow](docs/GITHUB-ACTIONS.md). Registry и credentials задаются через GitHub Actions variables/secrets. + +## Задержка сообщений в0.8.1 + +Устранены полный проход по MUC-архиву на каждом сообщении, повторные записи +неизменённых native-файлов и no-op CSI checkpoints. Проверенный сценарий +с100000 MAM-записей: median MUC delivery2.5с→4.7мс на loopback. +[Причины, измерения и границы](docs/MESSAGE-LATENCY.md). + +## Личные сообщения в0.8.2 + +Push routing больше не блокирует отправителя/SM ACK; CSI defaults немедленно +передают bodyless OMEMO и receipts. Bind2/MAM metadata не сканируют всю историю. +[Причины, тесты и конфигурация](docs/PERSONAL-MESSAGE-LATENCY.md). diff --git a/docs/COMPATIBILITY.md b/docs/COMPATIBILITY.md index e652864..e52b113 100644 --- a/docs/COMPATIBILITY.md +++ b/docs/COMPATIBILITY.md @@ -11,14 +11,14 @@ |---|---|---| | Конфигурация | Lua/JSON/YAML/YML/TOML, Include, глобальные и локальные области, наследование модулей | Lua VM ограничена; не все функции окружения конфигуратора Prosody доступны. Runtime обслуживает один VirtualHost и его компоненты | | Хранилище | internal `.dat`, `.list`, бинарные строки, смешанные ключи Lua, атомарные записи, потоковые архивы, инвалидирование `.lidx` | SQL, external storage остальных модулей и произвольные драйверы не реализованы; S3 uploads поддержаны. Каталог блокируется между процессами Rust; Prosody в блокировке не участвует | -| Аккаунты, saslauth | internal_hashed SHA-1/SHA-256, SASLprep, PLAIN внутри TLS, SCRAM и PLUS с tls-exporter/tls-server-end-point, SSDP, SASL2 | Только internal_hashed; опциональный sasl2_bind2 (alias bind2) поддерживает inline bind/SM/CSI/Carbons. SASL2 inline SM resume и takeover живого транспорта реализованы; MAM metadata при Bind2 читает весь архив синхронно | +| Аккаунты, saslauth | internal_hashed SHA-1/SHA-256, SASLprep, PLAIN внутри TLS, SCRAM и PLUS с tls-exporter/tls-server-end-point, SSDP, SASL2 | Только internal_hashed; опциональный sasl2_bind2 (alias bind2) поддерживает inline bind/SM/CSI/Carbons. SASL2 inline SM resume и takeover живого транспорта реализованы; Bind2/MAM metadata читает endpoints без полного scan; полные MAM queries всё ещё могут сканировать историю | | Сообщения и presence | локальная маршрутизация, приоритеты ресурсов, контакты/подписки/probes, offline, carbons, блокировки | Полная совместимость всех пограничных сценариев маршрутизации ещё не подтверждена | | MAM | личный и комнатный MAM2, prefs, формы, RSM, фильтры времени/контакта/ID, extended queries, metadata, stanza-id, expiry | Нет доказательства совпадения каждой ошибки и порядка результатов при всех комбинациях запроса | | MUC | комнаты, несколько ресурсов, роли/affiliations, owner/admin, конфигурация, приглашения, история без MAM и MAM, occupant-id/avatar, hats, PM/presence policies, регистрация, административные ad-hoc команды; журнал конфигурации, членства и истории до ответа, crash recovery persistent/temporary комнат | Rust-журнал авторитетен, native config/state — экспорт. Без SM восстановление требует новой аутентификации точного полного JID; grace по умолчанию 300 с, `muc_recovery_grace_period` 1..604800. Действующая приватная SM-запись восстанавливает логическое членство до listeners. Произвольные Lua-модули не запускаются; [MUC-RECOVERY.md](MUC-RECOVERY.md) | | PEP/pubsub | persistent nodes/items, ACL, subscriptions, publish/retract/purge/delete, owner/configuration, caps, OMEMO XML как payload | Не все необязательные политики узлов Prosody реализованы; OMEMO шифруют клиенты, криптография OMEMO не часть сервера | | private/bookmarks/vCard | private XML, старые и новые закладки, vCard/temp-vCard4 и avatar-переходы | Межклиентное поведение нужно дополнительно проверить настоящими клиентами | | SM/push | acknowledgements после обработки, resumable XEP-0198 sessions, replay, ограниченные очереди, приватный durable snapshot, heartbeat и shutdown checkpoint; legacy SASL/SASL2 resume после restart; native регистрации push | Нужны новый TLS/SASL-транспорт и токен того же владельца; TCP/TLS-сокеты не сохраняются. SM-снимок не native Prosody: 256 MiB суммарно, 8 MiB/4096 stanza на сессию. При неопределённой отправке возможен replay. Есть coalescing и watchdog первого push; реальный APNs/FCM цикл не подтверждён | -| CSI | active/inactive, ограниченный буфер, native importance rules, delay, flush при клиентской активности и grace period | Событие socket drain приближено завершением записи; необязательные расширенные XPath-фильтры поддержаны не полностью | +| CSI | active/inactive, ограниченный буфер, native importance function + runtime defaults для OMEMO/receipts/markers, delay, flush при клиентской активности и grace period | Defaults0.8.2 важнее по доставке, чем строгая native policy; явный csi_important_payloads заменяет defaults. Событие socket drain приближено завершением записи; необязательные расширенные XPath-фильтры поддержаны не полностью | | Федерация | входящие/исходящие STARTTLS, CA/DNS-ID, SASL EXTERNAL, DNS SRV, проверка домена каждого stanza, ограниченный пул соединений | Нет dialback/DANE/OtherName-only/SRV-ID/bidi/direct TLS | | HTTP upload | Несколько XEP-0363 components, Host/path isolation, local/S3 gateway, multipart/SigV4, streaming PUT, GET/HEAD/range/conditional, квоты/expiry, native metadata/JWT; offline local↔S3/S3↔S3 migration с SHA-256/resume; intent/exact-key recovery и quarantine; реальный 10 GiB PUT/GET через MinIO проверен | MinIO single-node с описанным netlink adapter тестовой среды; AWS/distributed deployment не проверены. Миграция требует остановки сервера и временного места под один файл; source сохраняется. Потерянные ownership metadata и неопределённый Complete требуют отдельного разбора; HTTP-UPLOAD.md | | WebSocket/BOSH | WS/WSS и HTTP/HTTPS, общая XMPP-сессия, origin rules, BOSH RID/retry/hold/reorder/restart; http_altconnect XRD/JRD discovery; http_paths, HTTP Host/fallback, внешний URL, доверенные IP/CIDR и forwarded headers для TLS reverse proxy | Один VirtualHost с компонентами; нет PROXYv1/v2, произвольных Lua HTTP-приложений и горячей перенастройки. См. HTTP-PROXY.md | diff --git a/docs/GITHUB-ACTIONS.md b/docs/GITHUB-ACTIONS.md index de0b63e..614d3d4 100644 --- a/docs/GITHUB-ACTIONS.md +++ b/docs/GITHUB-ACTIONS.md @@ -53,7 +53,7 @@ Image smoke проходит и на PR. Только после успеха в - `sha-<полный40символьныйcommit>` — каждый публикуемый commit; - `latest` — только основная ветка; -- `v0.8.0` — пример version tag; он должен совпадать с Cargo.toml. +- `v0.8.2` — пример version tag; он должен совпадать с Cargo.toml. Version tag не меняет latest; prerelease также не перезаписывает latest. Собирается Linux amd64, не multiarch. Локальный `docker build .` по-прежнему diff --git a/docs/MESSAGE-LATENCY.md b/docs/MESSAGE-LATENCY.md new file mode 100644 index 0000000..ee43817 --- /dev/null +++ b/docs/MESSAGE-LATENCY.md @@ -0,0 +1,63 @@ +# Задержка доставки: исправление 0.8.1 + +В0.8.0 MUC после каждого groupchat append запускал expire_before. Эта операция +под общим mutex компонента проходила по всему архиву и записывала сохранённые +записи во временный файл даже при отсутствии истёкших записей. Задержка каждого +сообщения росла с размером истории. Дополнительно переписывались неизменённые +native room config/persistent index, а CSI сохранял полную durable SM-сессию +даже при пустой/неизменённой очереди. + +В0.8.1 эти лишние операции исключены из обычного пути доставки. Очистка архива +остаётся в периодическом maintenance (интервал сервера300с) и перед MAM-запросами. +Неизменённые native-файлы не переписываются; недостающие/изменённые экспорты и +повтор после ошибки сохранены. Авторитетный MUC checkpoint и SM state по-прежнему +записываются до подтверждения соответствующих изменений. CSI откатывает изменение +очереди при ошибке checkpoint. Ненаправленный в MUC account traffic обходит mutex +компонента и не ждёт его обслуживания архивов. + +## Измерение + +Настоящий STARTTLS, два клиента, durable SM, MUC MAM с finite retention, +active/inactive CSI. Изолированный loopback; архив native `.list` заполнен до +запуска сервера. Проверяются доставка sender echo/peer, counters, durable CSI +buffer/flush и точное число записей архива. Порог задержки в миллисекундах не +используется как flaky assertion; структурные регрессии запрещают полный scan +архива при append и запись неизменённых native-файлов. + +Active CSI, MUC peer, мс: + +| Записей истории | 0.8.0 median / p95 | 0.8.1 median / p95 | +|---:|---:|---:| +|0|9.425 / 11.221|5.054 / 7.643| +|1000|32.718 / 36.995|4.280 / 6.605| +|10000|259.472 / 269.067|4.895 / 6.307| +|100000|2517.940 / 2520.941|4.680 / 14.532| + +Inactive CSI,100000 записей: median3866.027→4.285мс, +p95 4150.867→5.072мс. Первые три строки —5samples/state, последняя —3. +Это ограниченное сравнение на одном loopback host, а не production SLA и не +доказательство всех возможных причин задержки у реальных клиентов. +Полные сырые samples и SHA-256 обеих сборок — validation-logs-0.8.1/latency-*.json. + +Команды: + +```bash +python3 tests/message_latency_network.py --binary target/release/rust-xmpp \ + --rounds 5 --history-records 0 1000 10000 --output /tmp/message-latency.json +python3 tests/message_latency_network.py --binary target/release/rust-xmpp \ + --rounds 3 --history-records 100000 --output /tmp/message-latency-100k.json +``` + +Быстрая проверка0/10000 records уже включена в verify-local.sh и GitHub Actions. +Для повторной медленной проверки используйте сохранённую0.8.0 release-сборку; +не приписывайте исходному бинарнику результаты пересобранной новой версии. + +## Если задержка остаётся в целевой установке + +Сопоставьте время отправки, получения и отображения delivery/read receipt, +тип чата, transport, состояние CSI и наличие федерации. Доставка сообщения и +receipt — разные события. Native CSI policy для низкоприоритетных payload не +менялась. Длительный MAM query, периодическая очистка большого архива, медленный +диск или внешний XMPP-домен могут иметь отдельную задержку. Текущие изменения +не отключают fsync, не обещают exactly-once и не подменяют проверку реальных +Conversations/Monal/Gajim либо deployment. diff --git a/docs/PERSONAL-MESSAGE-LATENCY.md b/docs/PERSONAL-MESSAGE-LATENCY.md new file mode 100644 index 0000000..96f8528 --- /dev/null +++ b/docs/PERSONAL-MESSAGE-LATENCY.md @@ -0,0 +1,102 @@ +# Личные сообщения: исправления0.8.2 + +Предыдущий0.8.1 устранил per-message MUC archive scan и часть лишних CSI writes. +Отдельная проверка личных чатов обнаружила другие причины. Испытания ниже +проведены на loopback; это не подтверждение поведения конкретной production-сессии. + +## Push не должен останавливать чат + +В прежнем обработчике после локальной доставки выполнялся await внешнего +push IQ route и только потом обновлялся handled и читалось следующее сообщение. +Неполадки DNS/TCP/TLS/SASL внешнего шлюза задерживали отправителя до сетевого +таймаута (30с на route). При полностью offline получателе push даже отправлялся +раньше записи offline archive. + +Регрессия воспроизвела настоящий исходящий STARTTLS к шлюзу, который после TLS +не присылает features. У0.8.1 через2с первое сообщение уже в durable SM pending, +второго нет, SM ACK отсутствует. У0.8.0 с полностью offline получателем в этот +момент ещё нет даже первого offline record. В0.8.2 в обоих сценариях оба сообщения +сохранены и sender ACK h=4 соответствует входящим4 stanza при том же зависшем +шлюзе. Offline records присутствуют уже при первом post-TLS stream gateway. + +Уведомления теперь маршрутизирует ограниченный worker:1024queued,8in-flight. +При переполнении/ошибке notification routing пишет warning; подтверждение +сообщения не означает успешный push. Очередь уведомлений не durable и при +остановке отменяется; сами сообщения сохраняются независимо. Проверен XMPP +push fixture, не APNs/FCM и не промышленный мобильный цикл. + +## CSI и зашифрованные сообщения без body + +Прежняя policy считала unimportant receipt-only и ciphertext-only OMEMO без +body/EME. При `inactive` они могли ждать активности клиента. В тесте намеренный +dwell2с показан отдельно: это время удержания, не вычислительная задержка. +Сервер уже быстро отвечал SM ACK, но пользователь ещё не видел payload/receipt. + +Default `csi_important_payloads` в0.8.2: + +- `{eu.siacs.conversations.axolotl}encrypted` +- `{urn:xmpp:omemo:2}encrypted` +- `{urn:xmpp:receipts}received` +- `{urn:xmpp:chat-markers:0}received` +- `{urn:xmpp:chat-markers:0}displayed` +- `{urn:xmpp:chat-markers:0}acknowledged` + +Они выходят без ожидания active. Body, EME и остальные прежние important payload +сохраняют поведение; headline и прочие unimportant данные продолжают буферизоваться. +Явный список заменяет defaults: если уже настроили свой список, добавьте нужные +пути туда. Для строгой прежней policy в JSON используйте `csi_important_payloads: []`; +эквивалентный явно непустой Lua-list без новых extensions: +`csi_important_payloads = { "{urn:xmpp:eme:0}encryption" }` (EME уже important). +Defaults увеличивают число немедленных доставок и возможных пробуждений клиента. +Старая importance function/native oracle сохранена; изменён именно runtime default. +На bind и resume применяется текущая конфигурация, включая сохранённые старые slots. + +В6TLS fixtures:100000MAM/user, roster0/5000/10000,500durable pending, default/explicit[]: +все проверки прошли. Default inactive OMEMO legacy/2 —2.58–4.06мс, +receipts —7.36–35.56мс; при explicit[] сохраняется hold до active. +Headline buffering, EME delivery и точный счёт100523MAM records/user проверены. +Это XML/wire проверка доставки ciphertext, не проверка OMEMO криптографии клиента. + +## Большой личный архив при входе + +Bind2 и обычный MAM metadata IQ раньше декодировали все записи ради start/end. +На100000records,5samples: + +| Операция | Старая медиана |0.8.2медиана | +|---|---:|---:| +|SASL2 Bind2 authenticate→success|2742.353мс|1.976мс| +|TCP/STARTTLS→Bind2 success|2745.115мс|3.565мс| +|MAM metadata IQ|2437.945мс|0.355мс| + +Baseline0.8.0 содержит тот же прежний scan path; hash сохранён в raw report. +Новый edges_store читает ограниченные endpoint records под существующей блокировкой, +не создаёт/не требует index и восстанавливает partial append. Проверяются exact +IDs/timestamps. Это операция metadata, не проверка integrity всех промежуточных +записей. Полные MAM queries и периодическая очистка всё ещё могут читать архив. + +## Проверка и диагностика + +Новые scripts: + +```bash +python3 tests/push_latency_network.py --binary target/release/rust-xmpp --recipient hibernating +python3 tests/push_latency_network.py --binary target/release/rust-xmpp --recipient offline +python3 tests/personal_message_latency_network.py --binary target/release/rust-xmpp +python3 tests/bind2_archive_latency_network.py --binary target/release/rust-xmpp --records 100000 --samples 5 +``` + +Быстрые варианты включены в verify-local.sh и CI. Push fixture использует +loopback port5269; конфликт порта является ошибкой fixture. Global DNS/resolv.conf +не меняются; fixture использует special-use localhost и другой account domain. + +`message-processing-slow` warning содержит duration_ms, route и correlation connection. +Оно фиксирует завершившуюся серверную обработку>250мс, без текста сообщения. +Если задержка остаётся, сопоставьте его с клиентским временем, типом transport, +CSI state, регистрацией push и внешней федерацией. Отсутствие warning не доказывает +отсутствие сетевого/клиентского ожидания до/после обработки. + +SM Store пока использует общий mutex для durable slot IO; обязательный fsync +не отключён. Полные архивные запросы/maintenance, большие roster, медленный диск +и внешняя федерация имеют собственную стоимость. Производственная квалификация +клиентов и полная замена Prosody остаются за рамками этих fixtures. +Итоговые тесты/сырые отчёты: VALIDATION-0.8.2.md и validation-logs-0.8.2/. diff --git a/docs/SOURCE-SHA256.txt b/docs/SOURCE-SHA256.txt index 30a8e61..1f324b4 100644 --- a/docs/SOURCE-SHA256.txt +++ b/docs/SOURCE-SHA256.txt @@ -1,5 +1,8 @@ -9c4e46e42c549436c503a4cd70f90efd8f7754ce8c2103a6d1352cd34174aac0 .github/workflows/ci.yml -06e1035f41aa02cd4d0fbc14db3160290f9e5384791c1b93f3268bc67aeee3e2 AGENTS.md +79f3f5cd46255826869c9151151d3471dd7139c2ea8fb2da4b2b6fbea113f0cf .github/workflows/ci.yml +d9732ba55b93d2907cd1a2a0fa20bc1f46e0f2970de0e9f2bf730048212cfc31 AGENTS.md +f8e6a12039b067ed5af42320bca42fb0555d9a5f438d1652860a5be4534469d1 Cargo.lock +4e8d7ee328f044be284e0cb436f13a468adcac3058bbb1be381f8bff96603e5a Cargo.toml +6be2fbcd1da8a07dda7daf3ddd727b38f363751ebace9c0b87c282f8961cffed Dockerfile 7136ea911bb6b6d352f703f80efeebde921028ea9dc39cd0d2cd55ea465f8c37 examples/config.json 8a65739eb5c24f10b9f2c509f0bd050fb1115706e6a41fdf804b9e0e44f583fd examples/config.toml ca86274bcf4dc5daebbf69c9f003854afca92954719aff068f810e0a3d615dea examples/config.yaml @@ -22,13 +25,13 @@ b1018e1b279c89f6cf14b4017e4f1b14e9165afef2f668cec6ac8bbe0c710d85 scripts/integr e08ac6136cce27cda2ddbd510da0f25750766ab0150a9f4b8f87c953276d16e9 scripts/prosody_compat/oracle.lua 2c7a2c946885205e9df38b97305073a8ac72f58ac8ff84fc6f9af320c35bbc96 scripts/prosody_compat/verify.sh 1b9ed063daf3e0320819b4fe0135c96dd27e49877044aa2f5093b8ab4fbda41d scripts/smoke.py -caa74bdd83f0b952b875f613cdbd238d7f903408c2176d54178ce18994b53e95 scripts/verify-local.sh +c32bc7ed2d5f954a2b3de06db31fb1580378259edfc8ce574aa5cd5719cc2a59 scripts/verify-local.sh a2e47f547ab9349f84ee6c4f8e51c147b7110b41a82c17cdb938027a84d82ef3 src/account_modules.rs 5637f816586f0613b83e14d0ed478bd539f325b70ccbfc9fdf893adbe494453d src/admin.rs -89d7e29d8f8daab614c9c836864b166fdaa324ca035c2d3d5f95639c24b2a9e1 src/archive.rs +7b844cbe377b057555436378ab8bd784f99b85e7c9992cb3c5a044f40326951f src/archive.rs e15b079a420227ee59e3b7ac305783c51eb59d76a8fb5dd12760547b0f812107 src/auth.rs 83ac35a4c9d20debf006fe80fba8e423c09806fb2526ff384b188ca28d612a5e src/config.rs -55f8e68d0d41a81d2254a0c5aef4146488127f771c5b71ccd2e23d17dd1e8e79 src/csi.rs +175ab07f17ba14c51c76857c4905b0a587d8be68e2be5179456e9c71a523c487 src/csi.rs 834ebe4a1f2d46ab932c14c0a2c7be3375873a71ef56026d372c86e60ef041fc src/data_lock.rs 1c8aa5cb816a32a0f9f24589ac00beba27544a83c3d9aad771523a1d1cbcd4c8 src/extras.rs dca8959effb123b94e1fbd42c561a79c721178c4b612a004db9f9fccb3b8950d src/federation.rs @@ -41,8 +44,8 @@ c604a0a764ffac6bae0c9aa15c9ef7022d35cb1f8c9159eb66257114445621c5 src/http_trans a21e1119ea0271b63935e92eb106ab6076f0035e6d3a06c21a352f152b9b37db src/logging.rs 58ce2a9daa36ac26b39c8f263a16f4fa8cc4e57c91bbbf5b24a6aad3f1a326e0 src/lua.rs a264e2765a31c8c096462551aca229530cad356e39e338370d1a0bdd97860680 src/main.rs -71d5d185900b9cde190e10e2f28371cd5042d98b5900b4385d823f724234fced src/mam.rs -d8b69775bcdb01597bcaffa6123c636a226922f349beaa274fe77ff1e36bc5ef src/muc.rs +68d97d96aa3a370474c144ccfdbf16109c46a6b14123d55d30464237ae29a958 src/mam.rs +f17b06fe5b76381b5cdbfc2b668107f6c2b0b456c05b7a7709bea6a284531ff5 src/muc.rs c7ba46a140b9dce65cc573176265d6f77049ae657a70ffe59611a1c0f3ef89af src/muc_admin.rs ed2f07105ffeb80396aaf91c7a1fe9a8dc88d17235d03a0796372c1797c1506a src/muc_history.rs 636f6ea7ad7cc98390ac775a93b469d2f3e0f9e138be5bd1e256cad5037c7183 src/muc_recovery.rs @@ -53,9 +56,9 @@ f09a6479b76c9c601a169b5f1f9cf1364e82df5ae27e4bab8d1b1428b5cad457 src/preauth.rs 8dbb7a6b43a5f0562a775df42a959ab8badc466135a8b32da86cd79615b5acbf src/pubsub.rs 913cd033f60a68f6c7cf9b3adbaf76db1c5c9bc88a0599196d373b16b64c0a1e src/push.rs bec477f2520af6a9d7ca54e43eb12158b53e3cf09057653e504dfdeab956885e src/sasl.rs -9cfef150f88a08ee0cfb33b63b621e5ecd058daa08f19119379c099f9c7f7e7a src/server.rs +a445dcab6d0275861b08412a4bd622cb72c3f462ebba5eaedad360e740a6513c src/server.rs c7450f9058528e3030df559840f87dae591a2b88be8503872956e9b78435d916 src/session_store.rs -a4e6faac3b5ab9b7e6e2c586387cb32d18a01fbd1ef65302cbc92ccbce934044 src/sessions.rs +1d4e890315886bc4fd0b824e034a5c1833a1f2c1347e8c3ca77254e13a2acab9 src/sessions.rs 71d7ce1036a091d8c27016ea7ce4cffedf904dfca9d1cc4891b7dc66a1e06a4e src/storage.rs 462b00edb2c1e02dd34524bafe4f82b5ef902028b44310ba31b085d31f4dc2aa src/tls_binding.rs a78592aa79d8f01c22af1457d0c3f5922863ccd3e8ebb1aa05e043cc44579b8a src/upload_migration.rs @@ -63,8 +66,10 @@ f9b023565711e0217238b53fb678c5fb14849cdcd2efcd0fce249018274fad69 src/wire.rs b4eb7a230570dfde0fd0d301a6ace36559a5eae3e1402e42c76f014f61739c24 tests/_wire_client.py 45613ad6c53087a50c6c3a7969b30783578c334499bc6baceadb2d18b0b3ea4e tests/admin_socket.rs 0645fda01bede4362d998ef22aefdd2c02578dd2c2aae3878d0cff87b3679835 tests/android_sasl_network.py +ad225ade463f55bfd0734e67f5306e274cd9aab59e10e91469bf7263547cdf79 tests/archive_edges.rs 366b315521bd4f4448c0bac17bf74ddb77a728ff41fc48e29d46377625e0330f tests/archive_mam.rs cb6b7bbcd1bc7ee01a4ccf892d4b6074765685c56c4b8bb46e0381b834577b6a tests/auth.rs +011bbdd00c8ff8b648076d133086c395f6784cdcbb0c9f4e1efcbc15c1e79d9c tests/bind2_archive_latency_network.py b3c3470f0b9b64584abf98c26a4578b0b90089086d00f7b07187aa5f6db6a417 tests/cli.rs cc58adbb0fc867802b09cf7bd0d25397a273e721fbd0d0cb0ce30c19e80c13a2 tests/config.rs ba364e9ea561624b2c649cd0dda559e213c75e6d7080ae85f0c23f1f13d117e1 tests/csi.rs @@ -83,6 +88,7 @@ f1ea3eb78d5c716f4281cf17cb41b9fb22e08dbb4cf08ed9c8477c79b7d2382b tests/http_pro da2fc65e931ec74fbcdcd26d04f2cb073e2dc1e354139135166c79580973a477 tests/iq_errors.rs 05160f17f8098466a67c9b069c165dc9d94a84ab03a49896169f110baf8e869a tests/logging.rs dfc3429e3e755d4c99ec1bd8ee6fb0f1f6aaf86414d5adaca7e9e3b18c7fe3f7 tests/logging_network.py +0141961eadf9246ce287d7ee0dbbbf5243fd6e1332e09ccd2f6a591be419c2c3 tests/message_latency_network.py 329ccbd4faee6cbbfa92d2fa0248844721b7ffc033baae4ec2570e9893f5df9f tests/message_routing.rs 1134fefd5bb75884b096b8542c4f9745e64fd5dfcf87a6bba8d665aad2185a8a tests/muc_access.rs 8120c66b85c0884619e39eea0b8761e11b41f2ed14c5be00146e35ca4714a9a0 tests/muc_crash_network.py @@ -91,6 +97,7 @@ dfc3429e3e755d4c99ec1bd8ee6fb0f1f6aaf86414d5adaca7e9e3b18c7fe3f7 tests/logging_ 1d06b769b59012732ba04497a995f4f54df127f58c5f4f264a5df99589f31a94 tests/muc_extensions.rs a8a01faf51bf82bce6cbb2616cdaabb6337047d1c5f17d5f39975c0528a1d5ae tests/muc_flow.rs b24bd920f096576c2009ff1ccc0366eb8734c5f0b2feb39f04ad7087268a94b9 tests/muc_history.rs +1b34ab721eec69295e1274e44bfd108c0e117dd383624cb6c98d851eb20e7a9a tests/muc_latency_storage.rs 1f3df5f3f39143adc2b2a419fac0cd74b2229337ffa86570261d1f6ac61137a1 tests/muc_native.rs 3df2736ccfd25a6cab290df80ceb7474ea44bb02af6cf768a9216d6b8f7f8630 tests/muc_optional_admin.rs 5dc93407a658b45e504b89e26cfc8f495cd28ad90d0a308b7d228a472435ff9f tests/muc_protocol.rs @@ -106,6 +113,7 @@ dd68c50d7d7cfd7871f69331a2787e0336dcab73762a82c599cee2a39920ae95 tests/pep_diag 42b6c19d14e60b0c93193b4df473a0dd7cfcdb19250245ab94a7e1a237608395 tests/pep_item_order.rs 3e349f9219da20602a239a6c4ce71dc045faf9afb1c36599e2b41e90b2423508 tests/pep_notifications_network.py 83cea7164e5e6aadfc126b6b8349eb242bc113ba638385fa13c51ffda32aa57a tests/pep_order_network.py +08d1a1c5585dba862b78deddab59bd45282610afa58852b29ef56f3023a79de9 tests/personal_message_latency_network.py 6a078c3fbddff07131f3247d01fb1e13bc923888d93ea30175adda471cbece2f tests/preauth.rs b4048d34620bd0726cfb79d4d1cca9635f27ca8e58c8ad61d619af63672a2e09 tests/preauth_native.rs 06a66caa73c179b9d3b239e6f4deac6fc876d8c8dfeafe302f043d85d9f4beb9 tests/preauth_network.py @@ -113,6 +121,7 @@ fa1eae49717ca9fb8b118f40058dff0c068c8f28823ea1b0ac42fd0c3e935bda tests/pubsub_n 359de6dd2d960e63296f1109617f139bed2eac40409e50f72ff745897ba943ac tests/pubsub_persistence.rs 6fb7475ca7359ad870a83d5f143a1994c7bd34e9b56e275f7496ba8da291ee17 tests/push.rs b8dd71798f96931f7ab4489cdb1e258556f41411815ef38d3a03e80e4e8fbdfc tests/push_discovery.py +44c8e642f725be2292dfc5282feac8772ac34824927b63058f03f7c98285e5b6 tests/push_latency_network.py abf5e6a32ab542ccba5861eaaf7aed9a86b8306abfe2c329646d54e43176dc0c tests/reference/COPYING 1ecd0a5c122910cbd066922c95ff0c32e945a07e2c9b0a37a30e5f035b5ecea6 tests/reference/configmanager.lua f407c6565fa73b6653e7e73204daa65ae1d87111e82c6b96154aea76497ad65d tests/reference_prosody.rs @@ -125,6 +134,7 @@ ddd9d5b46dc943138a334c64477fb11970b3d45e4cfbeaafc7348754f1e5e29e tests/sasl_acc a7d1519f4f44cc7bfad3d20bcfdf455e92abdd084feed493ffc9e0267a387740 tests/sasl_network.py 4748fa227743686f78a0fa0364735d2dda5995f8d70a79ad03c1aa1decb42978 tests/sasl_retry_network.py d8882b8aabd6ff603c81fbbc259eefa68772afb2b3eec2e003ac29efd65d146b tests/sasl_web_network.py +7d69c14ced7884450b9a1ff63cd984cdb9dfe948d6c56631c7593b6fabdabf7f tests/session_routing_isolation.rs d9eef5c37fcd99404619d61dbf7a2bf7673087924d93e69b08769e716afe297b tests/sm_durable_slots.rs 0b74b2ff47b8ae681b5613bc87e914fdf8e5033156180df06ff2174df2781a5a tests/sm_restart_network.py 72f2d60e47e5295b82d497289b78925a64a1d986c70c277015ae228d211d32bb tests/storage_accounts.rs diff --git a/docs/VALIDATION-0.8.1.md b/docs/VALIDATION-0.8.1.md new file mode 100644 index 0000000..c69352c --- /dev/null +++ b/docs/VALIDATION-0.8.1.md @@ -0,0 +1,48 @@ +# Проверка 0.8.1 + +2026-10-21, Linux x86_64, Rust1.99.1. Итоговый **единый** прогон: +[verify.txt](validation-logs-0.8.1/verify.txt). Структурированный отчёт: +[validation-results.json](validation-results.json). + +| Проверка | Результат | +|---|---| +| cargo tests |297 passed,0failed,11ignored в обычном наборе| +| fmt / Clippy all-targets -D warnings / release |Успешно| +| Новые структурные регрессии |2CSI mutation/rollback +2MUC archive scan/native export/retry — успешно| +| Сеть |Весь verify-local.sh, включая10MUC crash cases, SM restart/offline fanout, PEP/push, Android SASL, WSS/BOSH/proxy, upload/S3/migration — успешно| +| Native reference |8module/storage +1TLS/SASL EXTERNAL federation — успешно| +| Общая нагрузка |100accounts,500TLS,5000ping,5000messages,10000MAM,failures=[]| +| MUC+SM нагрузка |500resources,10rooms,25000presence,1500deliveries,SIGKILL и10resume — успешно| +| Latency regression |0/10000records в полном прогоне; отдельное сравнение0/1000/10000/100000 до/после — успешно| + +MUC+SM connect 3.149с; join 25.54с; +весь сценарий 39.535с; выборочный peakRSS 41.25MiB. + +100000записей, active CSI MUC peer: median 2517.940→4.680мс, +p95 2520.941→14.532мс. Inactive CSI median +3866.027→4.285мс. По3samples/state для большого архива; +это loopback измерение с проверкой точного количества MAM-записей, не production SLA. +Сырые samples: validation-logs-0.8.1/latency-*.json. +Причины и изменения: [MESSAGE-LATENCY.md](MESSAGE-LATENCY.md). + +Release SHA-256: `c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977`. Baseline0.8.0 SHA-256: +`74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a`. Отчёты автоматически связывают результат с бинарником. + +Повторение: `XMPP_LOAD_CHECK=1 bash scripts/verify-local.sh` с native env +по scripts/prosody_compat/README.md. Использованы CARGO_INCREMENTAL=0, +CARGO_PROFILE_DEV_DEBUG=0 и CARGO_PROFILE_TEST_DEBUG=0; native Lua-зависимости +из Ubuntu packages извлечены в частный /tmp prefix из-за ограничений среды. +Оригинальные compiled Prosody modules предоставленной ревизии сохранены. + +Никакой fsync не отключён. Подтверждённые изменения MUC/SM остаются durable, +CSI queue mutation откатывается при ошибке записи. Старые crash/owner/token/h/ +account deletion/recreation тесты проходят. Периодический maintenance и MAM +queries всё ещё работают с архивом; исправление устраняет scan на каждый append, +а не обещает постоянную стоимость любой архивной операции. + +Ignored native9тестов выполнены отдельно внутри того же verify-local.sh. +Оставшиеся AF_UNIX admin и>128MiB archive tests по-прежнему входят в полный CI +entrypoint, но в этом локальном прогоне не запускались. Передачи10GiB не +повторялись: старые0.7.8/0.7.9отчёты не относятся к новой сборке. +Настоящие production клиенты, DNSSEC, APNs/FCM и полный Prosody parity этим +не подтверждаются. Общие пределы: [COMPATIBILITY.md](COMPATIBILITY.md). diff --git a/docs/VALIDATION-0.8.2.md b/docs/VALIDATION-0.8.2.md new file mode 100644 index 0000000..ec92a09 --- /dev/null +++ b/docs/VALIDATION-0.8.2.md @@ -0,0 +1,51 @@ +# Проверка0.8.2 + +2026-10-21, Linux x86_64, Rust1.99.1. Итоговый единый прогон: +[verify.txt](validation-logs-0.8.2/verify.txt). Machine-readable report: +[validation-results.json](validation-results.json). + +|Проверка|Результат| +|---|---| +|Rust ordinary tests|305passed,0failed,11ignored| +|fmt / Clippy all-targets -D warnings / release|Успешно| +|Новые Rust regressions|6archive endpoints/recovery/limits +2account-lock/duplicateACK — успешно| +|Личная доставка|6fixtures:100000MAM/user, roster0/5000/10000,500SMpending, default/native CSI — успешно| +|Неподвижный push gateway|Настоящий STARTTLS; hibernating+offline: bothmessagesdurable, senderACKh=4 до ответа gateway; offline сохранён до первого postTLSstream| +|Bind2 и MAM metadata|100000records,5reconnects+5IQ, exactIDs/timestamps — успешно| +|Сетевые регрессии|Весь verify-local.sh, включаяprivate WSS/BOSH chat, PEP/push,AndroidSASL,MUCcrash/SMrestart,S3/migration — успешно| +|Native reference|8module/storage +1TLS/SASL EXTERNAL federation — успешно| +|Общая нагрузка|500TLS,100accounts,5000ping,5000messages,10000MAM,failures=[]| +|MUC+SM нагрузка|500resources,10rooms,25000presence,1500messages,SIGKILL+10resume — успешно| + +MUC+SM total 45.54с, peak sampled RSS 40.94MiB. + +Воспроизведение личного push-stall: прежний0.8.1 за2с сохраняет только первое +сообщение и не отвечаетSMACK при зависшем postTLSfeatures gateway. Новый0.8.2 +сохраняет оба и отвечаетh=4 в том же2сокне; тестовое окно не является latency SLA. +Offline ordering baseline проверен на0.8.0; его точный hash указан отдельно. + +Bind2 authenticate→success median2742.353→1.976мс; metadataIQ2437.945→0.355мс. +Baseline0.8.0hash74882319… содержит тот же прежний scan path. Все raw samples, +IDs, timestamps и hashes — validation-logs-0.8.2/bind2-*.json. + +Default inactive OMEMO доставлен за2.58–4.06мс, receipts7.36–35.56мс в checked +fixtures; explicit[] сохраняет удержание доactive. Намеренный CSI dwell2с +отдельно обозначен в отчёте и не выдаётся за время вычисления/доставки. +Каждый personalarchive содержит ровно100523records/user. Детали и настройка: +[PERSONAL-MESSAGE-LATENCY.md](PERSONAL-MESSAGE-LATENCY.md). + +Release SHA-256: `130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5`. Все новые final reports содержат этот hash. +Команда: `XMPP_LOAD_CHECK=1 bash scripts/verify-local.sh` с native env согласно +scripts/prosody_compat/README.md. Использованы CARGO_INCREMENTAL=0, +CARGO_PROFILE_DEV_DEBUG=0, CARGO_PROFILE_TEST_DEBUG=0. Перед итоговым прогоном +устранены stale package linker artifacts очисткой package build outputs; +исходники не менялись после финальной сборки. Воспроизведение прошло одним +последующим полным прогоном; preliminary compiler errors не являются test failures. + +Это loopback, не production клиента/диска/сети. Fsync и durable commit до +подтверждения сохранены; boundedpushqueue не обещает durable notification delivery. +SMglobalIOmutex, полные MAMqueries и maintenance остаются отдельной стоимостью. +9nativeignoredtests выполнены; остальные AF_UNIX/largearchiveignoredtests и +10GiBtransfers в этом локальном прогоне не запускались (полный CI entrypoint +по-прежнему включает их). Старые largeupload результаты не приписываются0.8.2. +Общие границы: [COMPATIBILITY.md](COMPATIBILITY.md). diff --git a/docs/VALIDATION.md b/docs/VALIDATION.md index ca44f44..ec92a09 100644 --- a/docs/VALIDATION.md +++ b/docs/VALIDATION.md @@ -1,50 +1,51 @@ -# Проверка 0.8.0 +# Проверка0.8.2 -Linux x86_64, Rust1.99.1, 2026-10-20. Итоговый полный прогон: -[verify.txt](validation-logs-0.8.0/verify.txt). -Структурированный отчёт: [validation-results.json](validation-results.json). +2026-10-21, Linux x86_64, Rust1.99.1. Итоговый единый прогон: +[verify.txt](validation-logs-0.8.2/verify.txt). Machine-readable report: +[validation-results.json](validation-results.json). -| Проверка | Результат | +|Проверка|Результат| |---|---| -| Rust tests | 293 passed, 0 failed, 11 ignored | -| fmt / Clippy all-targets -D warnings / release | Успешно | -| MUC SIGKILL через настоящий STARTTLS | temporary/persistent комнаты, несколько ресурсов, show/status/roles, порядок истории, подтверждённые leave/kick/demotion/password/config, фиксированный/custom grace — успешно | -| SM между процессами | SIGKILL/SIGTERM, legacy SASL/SASL2, counters, ack/replay, неверные owner/token/h, resource conflict — успешно | -| MUC offline fanout | До аутентификации Bob новое сообщение Alice уже в приватной durable SM-очереди; после resume доставка без history delay — успешно | -| Отзыв SM | Удаление аккаунта подтверждается; после повторного создания старый SM-токен отклоняется | -| MUC+SM нагрузка | 100 аккаунтов, 500 TLS-ресурсов, 10 комнат, 25000 join presence; SIGKILL и resume представителей всех комнат — успешно | -| Native reference | 8 module/storage + 1 TLS/SASL EXTERNAL federation — успешно | -| Остальные сетевые регрессии | Android SASL, WSS/BOSH/proxy/altconnect, PEP/push/preauth, resource policies, upload/S3/migration — успешно | +|Rust ordinary tests|305passed,0failed,11ignored| +|fmt / Clippy all-targets -D warnings / release|Успешно| +|Новые Rust regressions|6archive endpoints/recovery/limits +2account-lock/duplicateACK — успешно| +|Личная доставка|6fixtures:100000MAM/user, roster0/5000/10000,500SMpending, default/native CSI — успешно| +|Неподвижный push gateway|Настоящий STARTTLS; hibernating+offline: bothmessagesdurable, senderACKh=4 до ответа gateway; offline сохранён до первого postTLSstream| +|Bind2 и MAM metadata|100000records,5reconnects+5IQ, exactIDs/timestamps — успешно| +|Сетевые регрессии|Весь verify-local.sh, включаяprivate WSS/BOSH chat, PEP/push,AndroidSASL,MUCcrash/SMrestart,S3/migration — успешно| +|Native reference|8module/storage +1TLS/SASL EXTERNAL federation — успешно| +|Общая нагрузка|500TLS,100accounts,5000ping,5000messages,10000MAM,failures=[]| +|MUC+SM нагрузка|500resources,10rooms,25000presence,1500messages,SIGKILL+10resume — успешно| -Нагрузка MUC+SM: connect 5.193 с; join 46.703 с; -полный сценарий 78.857 с; выборочный peak RSS 41.26 MiB. -Детали fanout, CPU, slots и replay: [muc-sm-load.json](validation-logs-0.8.0/muc-sm-load.json). -Это loopback smoke measurement, а не гарантия production capacity. +MUC+SM total 45.54с, peak sampled RSS 40.94MiB. -SHA-256 итоговой release-сборки: `74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a`. -Основной прогон: `XMPP_LOAD_CHECK=1 bash scripts/verify-local.sh`; native env описан -в scripts/prosody_compat/README.md. В этой среде дополнительно применены -CARGO_INCREMENTAL=0, CARGO_PROFILE_DEV_DEBUG=0, CARGO_PROFILE_TEST_DEBUG=0. +Воспроизведение личного push-stall: прежний0.8.1 за2с сохраняет только первое +сообщение и не отвечаетSMACK при зависшем postTLSfeatures gateway. Новый0.8.2 +сохраняет оба и отвечаетh=4 в том же2сокне; тестовое окно не является latency SLA. +Offline ordering baseline проверен на0.8.0; его точный hash указан отдельно. -Первый основной прогон остановился на пятисекундном readiness timeout нового -нагрузочного теста после успешных обычных и сетевых проверок. В самом тесте -таймаут увеличен до60секунд; нагрузка500 повторена с той же release-сборкой, -а native-проверки выполнены отдельно. verify.txt объединяет успешные части -этих запусков; первоначальный лог сохранён в initial-load-timeout.txt. +Bind2 authenticate→success median2742.353→1.976мс; metadataIQ2437.945→0.355мс. +Baseline0.8.0hash74882319… содержит тот же прежний scan path. Все raw samples, +IDs, timestamps и hashes — validation-logs-0.8.2/bind2-*.json. -В процессе проверки исправлены потеря сохранённых presence/history, защита -истёкших recovery claims, отсутствие успешного ответа при удалении аккаунта, -учёт stanza до SM enable и потеря MUC fanout до подключения другого участника. -Первоначальный тест последнего случая принимал позднюю историю за доставку; -итоговый тест проверяет именно private pending queue до аутентификации. +Default inactive OMEMO доставлен за2.58–4.06мс, receipts7.36–35.56мс в checked +fixtures; explicit[] сохраняет удержание доactive. Намеренный CSI dwell2с +отдельно обозначен в отчёте и не выдаётся за время вычисления/доставки. +Каждый personalarchive содержит ровно100523records/user. Детали и настройка: +[PERSONAL-MESSAGE-LATENCY.md](PERSONAL-MESSAGE-LATENCY.md). -Реальные TCP/TLS-сокеты после завершения процесса отсутствуют: требуется новое -защищённое аутентифицированное соединение. SM допускает повторную доставку при -неопределённом сетевом результате; это не exactly-once транзакция между всеми -хранилищами и сетью. Известные встроенные возможности MUC перенесены, произвольные -community Lua-модули не исполняются. Пределы записей и порядок восстановления: -[MUC-RECOVERY.md](MUC-RECOVERY.md). Полная замена всей установки и проверка -реальными клиентами этим не заявляются: [COMPATIBILITY.md](COMPATIBILITY.md). +Release SHA-256: `130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5`. Все новые final reports содержат этот hash. +Команда: `XMPP_LOAD_CHECK=1 bash scripts/verify-local.sh` с native env согласно +scripts/prosody_compat/README.md. Использованы CARGO_INCREMENTAL=0, +CARGO_PROFILE_DEV_DEBUG=0, CARGO_PROFILE_TEST_DEBUG=0. Перед итоговым прогоном +устранены stale package linker artifacts очисткой package build outputs; +исходники не менялись после финальной сборки. Воспроизведение прошло одним +последующим полным прогоном; preliminary compiler errors не являются test failures. -10GiB upload в0.8.0 не повторялся. Исторические испытания local/MinIO находятся -в VALIDATION-0.7.8.md и VALIDATION-0.7.9.md; их результаты не приписываются новой сборке. +Это loopback, не production клиента/диска/сети. Fsync и durable commit до +подтверждения сохранены; boundedpushqueue не обещает durable notification delivery. +SMglobalIOmutex, полные MAMqueries и maintenance остаются отдельной стоимостью. +9nativeignoredtests выполнены; остальные AF_UNIX/largearchiveignoredtests и +10GiBtransfers в этом локальном прогоне не запускались (полный CI entrypoint +по-прежнему включает их). Старые largeupload результаты не приписываются0.8.2. +Общие границы: [COMPATIBILITY.md](COMPATIBILITY.md). diff --git a/docs/validation-logs-0.8.1/latency-100k-after.json b/docs/validation-logs-0.8.1/latency-100k-after.json new file mode 100644 index 0000000..c56c87e --- /dev/null +++ b/docs/validation-logs-0.8.1/latency-100k-after.json @@ -0,0 +1,232 @@ +{ + "binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "scope": "loopback STARTTLS; isolated fixture; no production latency claim", + "cases": [ + { + "mam_enabled": false, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 2.188561000025402, + "p95_ms": 2.3107499999923675, + "max_ms": 2.3107499999923675, + "samples_ms": [ + 2.0956669999350197, + 2.188561000025402, + 2.3107499999923675 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 4.38233800002763, + "p95_ms": 4.56658600000992, + "max_ms": 4.56658600000992, + "samples_ms": [ + 4.381051999985175, + 4.38233800002763, + 4.56658600000992 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 3.617779000023802, + "p95_ms": 3.788068999938332, + "max_ms": 3.788068999938332, + "samples_ms": [ + 3.264654999952654, + 3.617779000023802, + 3.788068999938332 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 3.8124090000337674, + "p95_ms": 3.8366489999361875, + "max_ms": 3.8366489999361875, + "samples_ms": [ + 3.3308939999869835, + 3.8124090000337674, + 3.8366489999361875 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 2.189512999962062, + "p95_ms": 2.2236539999767047, + "max_ms": 2.2236539999767047, + "samples_ms": [ + 2.1697740000945487, + 2.189512999962062, + 2.2236539999767047 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 4.169533999970554, + "p95_ms": 4.451736999953937, + "max_ms": 4.451736999953937, + "samples_ms": [ + 4.0612270000792705, + 4.169533999970554, + 4.451736999953937 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 3.311576999976751, + "p95_ms": 4.169272000012825, + "max_ms": 4.169272000012825, + "samples_ms": [ + 3.2493040000645124, + 3.311576999976751, + 4.169272000012825 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 3.372077999983958, + "p95_ms": 4.188992999957009, + "max_ms": 4.188992999957009, + "samples_ms": [ + 3.315083000074992, + 3.372077999983958, + 4.188992999957009 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 3.6135210000338702, + "p95_ms": 3.6135210000338702, + "max_ms": 3.6135210000338702, + "samples_ms": [ + 3.6135210000338702 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 0, + "muc_archive_records": 0, + "wire_body_deliveries": 27, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 100000, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 4.533615000013924, + "p95_ms": 4.635108000002219, + "max_ms": 4.635108000002219, + "samples_ms": [ + 3.9327949999687917, + 4.533615000013924, + 4.635108000002219 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 8.584756000004745, + "p95_ms": 9.454648999962956, + "max_ms": 9.454648999962956, + "samples_ms": [ + 8.391761999973824, + 8.584756000004745, + 9.454648999962956 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 4.660852999904819, + "p95_ms": 14.45046399999228, + "max_ms": 14.45046399999228, + "samples_ms": [ + 4.372101999933875, + 4.660852999904819, + 14.45046399999228 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 4.680227999983799, + "p95_ms": 14.532127000052242, + "max_ms": 14.532127000052242, + "samples_ms": [ + 4.40479399992455, + 4.680227999983799, + 14.532127000052242 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 5.005547999985538, + "p95_ms": 5.457555000020875, + "max_ms": 5.457555000020875, + "samples_ms": [ + 4.749896000021181, + 5.005547999985538, + 5.457555000020875 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 9.33329400004368, + "p95_ms": 9.77378499999304, + "max_ms": 9.77378499999304, + "samples_ms": [ + 8.875206999960028, + 9.33329400004368, + 9.77378499999304 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 4.230191000033301, + "p95_ms": 5.015898000010566, + "max_ms": 5.015898000010566, + "samples_ms": [ + 4.2100000000573345, + 4.230191000033301, + 5.015898000010566 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 4.284876000042459, + "p95_ms": 5.071866999969643, + "max_ms": 5.071866999969643, + "samples_ms": [ + 4.257245000076182, + 4.284876000042459, + 5.071866999969643 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 5.098277999991296, + "p95_ms": 5.098277999991296, + "max_ms": 5.098277999991296, + "samples_ms": [ + 5.098277999991296 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 26, + "muc_archive_records": 100006, + "wire_body_deliveries": 27, + "status": "pass" + } + ] +} diff --git a/docs/validation-logs-0.8.1/latency-100k-before.json b/docs/validation-logs-0.8.1/latency-100k-before.json new file mode 100644 index 0000000..297c43b --- /dev/null +++ b/docs/validation-logs-0.8.1/latency-100k-before.json @@ -0,0 +1,232 @@ +{ + "binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "scope": "loopback STARTTLS; isolated fixture; no production latency claim", + "cases": [ + { + "mam_enabled": false, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 4.910238999968897, + "p95_ms": 5.052589999991142, + "max_ms": 5.052589999991142, + "samples_ms": [ + 4.849958000022525, + 4.910238999968897, + 5.052589999991142 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 9.99482099996385, + "p95_ms": 10.185542000044734, + "max_ms": 10.185542000044734, + "samples_ms": [ + 9.438553999984833, + 9.99482099996385, + 10.185542000044734 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 7.185058999993998, + "p95_ms": 7.319806000054996, + "max_ms": 7.319806000054996, + "samples_ms": [ + 5.824679000056676, + 7.185058999993998, + 7.319806000054996 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 7.9024159999789845, + "p95_ms": 8.338388999959534, + "max_ms": 8.338388999959534, + "samples_ms": [ + 6.551824999974087, + 7.9024159999789845, + 8.338388999959534 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 6.445996999900672, + "p95_ms": 7.172110000055909, + "max_ms": 7.172110000055909, + "samples_ms": [ + 4.87915000007888, + 6.445996999900672, + 7.172110000055909 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 10.659646999897632, + "p95_ms": 12.850071000002572, + "max_ms": 12.850071000002572, + "samples_ms": [ + 9.232021000002533, + 10.659646999897632, + 12.850071000002572 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 9.392836000074567, + "p95_ms": 14.882106999948519, + "max_ms": 14.882106999948519, + "samples_ms": [ + 5.741209000007075, + 9.392836000074567, + 14.882106999948519 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 10.40252400002828, + "p95_ms": 16.07552799998757, + "max_ms": 16.07552799998757, + "samples_ms": [ + 6.522893999999724, + 10.40252400002828, + 16.07552799998757 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 6.09094300000379, + "p95_ms": 6.09094300000379, + "max_ms": 6.09094300000379, + "samples_ms": [ + 6.09094300000379 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 0, + "muc_archive_records": 0, + "wire_body_deliveries": 27, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 100000, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 8.917705999920145, + "p95_ms": 10.107052999956068, + "max_ms": 10.107052999956068, + "samples_ms": [ + 8.420038000053864, + 8.917705999920145, + 10.107052999956068 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 16.42384999991009, + "p95_ms": 17.16581000005135, + "max_ms": 17.16581000005135, + "samples_ms": [ + 16.391191000025174, + 16.42384999991009, + 17.16581000005135 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 2517.3544539999284, + "p95_ms": 2520.2535930000067, + "max_ms": 2520.2535930000067, + "samples_ms": [ + 2501.2779300000147, + 2517.3544539999284, + 2520.2535930000067 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 2517.9402029999665, + "p95_ms": 2520.940784000004, + "max_ms": 2520.940784000004, + "samples_ms": [ + 2502.2604349999256, + 2517.9402029999665, + 2520.940784000004 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 24.452612999994017, + "p95_ms": 26.775254999961362, + "max_ms": 26.775254999961362, + "samples_ms": [ + 8.767078000005313, + 24.452612999994017, + 26.775254999961362 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 36.83773900002052, + "p95_ms": 50.86929899994175, + "max_ms": 50.86929899994175, + "samples_ms": [ + 17.80327500000567, + 36.83773900002052, + 50.86929899994175 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 3855.8298680000007, + "p95_ms": 4150.020520999988, + "max_ms": 4150.020520999988, + "samples_ms": [ + 2901.40261199997, + 3855.8298680000007, + 4150.020520999988 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 3866.027479999957, + "p95_ms": 4150.866962999999, + "max_ms": 4150.866962999999, + "samples_ms": [ + 2901.4587140000003, + 3866.027479999957, + 4150.866962999999 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 22.82110700002704, + "p95_ms": 22.82110700002704, + "max_ms": 22.82110700002704, + "samples_ms": [ + 22.82110700002704 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 26, + "muc_archive_records": 100006, + "wire_body_deliveries": 27, + "status": "pass" + } + ] +} diff --git a/docs/validation-logs-0.8.1/latency-after.json b/docs/validation-logs-0.8.1/latency-after.json new file mode 100644 index 0000000..b1dca9b --- /dev/null +++ b/docs/validation-logs-0.8.1/latency-after.json @@ -0,0 +1,522 @@ +{ + "binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "scope": "loopback STARTTLS; isolated fixture; no production latency claim", + "cases": [ + { + "mam_enabled": false, + "sm_enabled": true, + "rounds": 5, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 5, + "median_ms": 2.2083669999801714, + "p95_ms": 2.7524509999921065, + "max_ms": 2.7524509999921065, + "samples_ms": [ + 2.0349779999833117, + 2.1022979999543168, + 2.2083669999801714, + 2.581427999984953, + 2.7524509999921065 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 4.559320999987904, + "p95_ms": 5.448408999995991, + "max_ms": 5.448408999995991, + "samples_ms": [ + 3.9975349999394894, + 4.301345000044421, + 4.559320999987904, + 4.565895999917302, + 5.448408999995991 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 4.29816700000174, + "p95_ms": 11.835469999937231, + "max_ms": 11.835469999937231, + "samples_ms": [ + 3.717826999945828, + 3.95383000000038, + 4.29816700000174, + 11.782627000002321, + 11.835469999937231 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 4.366868000033719, + "p95_ms": 11.859378999929504, + "max_ms": 11.859378999929504, + "samples_ms": [ + 3.7456439999914437, + 4.002205000006143, + 4.366868000033719, + 11.841935000006742, + 11.859378999929504 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 5, + "median_ms": 2.1559959999422063, + "p95_ms": 2.7428159999089985, + "max_ms": 2.7428159999089985, + "samples_ms": [ + 1.889266000034695, + 2.07170299995596, + 2.1559959999422063, + 2.2102450000147655, + 2.7428159999089985 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 4.291513999987728, + "p95_ms": 4.628346999993482, + "max_ms": 4.628346999993482, + "samples_ms": [ + 4.097702999956709, + 4.117672000006678, + 4.291513999987728, + 4.321024999967449, + 4.628346999993482 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 3.607771000019966, + "p95_ms": 4.329054999971049, + "max_ms": 4.329054999971049, + "samples_ms": [ + 3.0511659999774565, + 3.3668879999595447, + 3.607771000019966, + 3.629876999980297, + 4.329054999971049 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 3.669854000008854, + "p95_ms": 4.375101999926301, + "max_ms": 4.375101999926301, + "samples_ms": [ + 3.109387999984392, + 3.436124000018026, + 3.669854000008854, + 3.692369999953371, + 4.375101999926301 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 3.450391999990643, + "p95_ms": 3.450391999990643, + "max_ms": 3.450391999990643, + "samples_ms": [ + 3.450391999990643 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 0, + "muc_archive_records": 0, + "wire_body_deliveries": 43, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 5, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 5, + "median_ms": 5.680922999999893, + "p95_ms": 5.92475899998135, + "max_ms": 5.92475899998135, + "samples_ms": [ + 4.959245000009105, + 5.657132000010279, + 5.680922999999893, + 5.683216000079483, + 5.92475899998135 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 10.62067800000932, + "p95_ms": 11.266418999980488, + "max_ms": 11.266418999980488, + "samples_ms": [ + 9.56820900000821, + 10.354214000017237, + 10.62067800000932, + 11.083625999958713, + 11.266418999980488 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 4.932548000056158, + "p95_ms": 7.615871999973933, + "max_ms": 7.615871999973933, + "samples_ms": [ + 4.048796000006405, + 4.207175000033203, + 4.932548000056158, + 5.545106999989002, + 7.615871999973933 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 5.05425800008652, + "p95_ms": 7.6429759999427915, + "max_ms": 7.6429759999427915, + "samples_ms": [ + 4.07517700000426, + 4.236438000020826, + 5.05425800008652, + 5.570927000007941, + 7.6429759999427915 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 5, + "median_ms": 5.44478100005108, + "p95_ms": 5.556554000008873, + "max_ms": 5.556554000008873, + "samples_ms": [ + 4.727472000013222, + 4.8114250000708125, + 5.44478100005108, + 5.505089000052976, + 5.556554000008873 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 10.183787000073607, + "p95_ms": 10.890477999964787, + "max_ms": 10.890477999964787, + "samples_ms": [ + 9.888724000006732, + 9.945942000058494, + 10.183787000073607, + 10.306656000011571, + 10.890477999964787 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 5.1263200000448705, + "p95_ms": 5.255117000046994, + "max_ms": 5.255117000046994, + "samples_ms": [ + 4.305390000013176, + 5.036372000063238, + 5.1263200000448705, + 5.168275000073663, + 5.255117000046994 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 5.184012999961851, + "p95_ms": 5.310040000040317, + "max_ms": 5.310040000040317, + "samples_ms": [ + 4.368295000062972, + 5.154129000061403, + 5.184012999961851, + 5.191530000047351, + 5.310040000040317 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 5.2187170000479455, + "p95_ms": 5.2187170000479455, + "max_ms": 5.2187170000479455, + "samples_ms": [ + 5.2187170000479455 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 42, + "muc_archive_records": 10, + "wire_body_deliveries": 43, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 5, + "seeded_muc_archive_records": 1000, + "active": { + "direct_peer": { + "samples": 5, + "median_ms": 5.179283999950712, + "p95_ms": 5.702402999986589, + "max_ms": 5.702402999986589, + "samples_ms": [ + 4.691908000040712, + 5.172169999923426, + 5.179283999950712, + 5.635785999970722, + 5.702402999986589 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 9.836759999984679, + "p95_ms": 10.818348000043443, + "max_ms": 10.818348000043443, + "samples_ms": [ + 9.177894999993441, + 9.73506099990118, + 9.836759999984679, + 10.593198000037773, + 10.818348000043443 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 4.2178580000609145, + "p95_ms": 6.532151999977032, + "max_ms": 6.532151999977032, + "samples_ms": [ + 3.8601360000711793, + 4.174319999947329, + 4.2178580000609145, + 4.571829000042271, + 6.532151999977032 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 4.280302000097436, + "p95_ms": 6.605132999993657, + "max_ms": 6.605132999993657, + "samples_ms": [ + 3.8853840000001583, + 4.233521999935874, + 4.280302000097436, + 4.673529000001508, + 6.605132999993657 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 5, + "median_ms": 5.289302999926804, + "p95_ms": 5.9182850000070175, + "max_ms": 5.9182850000070175, + "samples_ms": [ + 4.637428000023647, + 4.646944000000985, + 5.289302999926804, + 5.336470000088411, + 5.9182850000070175 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 9.881779000011193, + "p95_ms": 11.126878000027318, + "max_ms": 11.126878000027318, + "samples_ms": [ + 9.666927000012038, + 9.780869999985953, + 9.881779000011193, + 9.893610999938574, + 11.126878000027318 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 5.337903999929949, + "p95_ms": 6.605088000014803, + "max_ms": 6.605088000014803, + "samples_ms": [ + 4.4430670000110695, + 4.566451999949095, + 5.337903999929949, + 5.398619999937182, + 6.605088000014803 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 5.365761999996721, + "p95_ms": 6.657663000055436, + "max_ms": 6.657663000055436, + "samples_ms": [ + 4.503487999954814, + 4.589735999957156, + 5.365761999996721, + 5.456013999946663, + 6.657663000055436 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 6.4426129999901605, + "p95_ms": 6.4426129999901605, + "max_ms": 6.4426129999901605, + "samples_ms": [ + 6.4426129999901605 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 42, + "muc_archive_records": 1010, + "wire_body_deliveries": 43, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 5, + "seeded_muc_archive_records": 10000, + "active": { + "direct_peer": { + "samples": 5, + "median_ms": 5.5639299999938885, + "p95_ms": 6.427136000070277, + "max_ms": 6.427136000070277, + "samples_ms": [ + 4.3693179999308995, + 5.252241999983198, + 5.5639299999938885, + 6.115242999953807, + 6.427136000070277 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 10.580320000030952, + "p95_ms": 11.34455600004003, + "max_ms": 11.34455600004003, + "samples_ms": [ + 8.862616999977035, + 10.534624999991138, + 10.580320000030952, + 10.863696000001255, + 11.34455600004003 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 4.871052999988024, + "p95_ms": 6.248740000046382, + "max_ms": 6.248740000046382, + "samples_ms": [ + 4.298133000020243, + 4.364993999956823, + 4.871052999988024, + 5.0552000000152475, + 6.248740000046382 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 4.894828000033158, + "p95_ms": 6.306694000045354, + "max_ms": 6.306694000045354, + "samples_ms": [ + 4.328496999960407, + 4.393286999970769, + 4.894828000033158, + 5.0838870000688985, + 6.306694000045354 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 5, + "median_ms": 4.837865000013153, + "p95_ms": 6.154906000006122, + "max_ms": 6.154906000006122, + "samples_ms": [ + 4.644825000013952, + 4.6781300000020565, + 4.837865000013153, + 6.011097999930826, + 6.154906000006122 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 9.839443999908326, + "p95_ms": 11.105878999956076, + "max_ms": 11.105878999956076, + "samples_ms": [ + 9.05296900009489, + 9.732880000001387, + 9.839443999908326, + 10.890076000009685, + 11.105878999956076 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 4.868799000064428, + "p95_ms": 5.506852999928924, + "max_ms": 5.506852999928924, + "samples_ms": [ + 4.652097999951366, + 4.654195000057371, + 4.868799000064428, + 5.197563999900012, + 5.506852999928924 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 4.921641999999338, + "p95_ms": 5.567783999936182, + "max_ms": 5.567783999936182, + "samples_ms": [ + 4.707422999899791, + 4.71425300008832, + 4.921641999999338, + 5.261014999973668, + 5.567783999936182 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 6.844148000027417, + "p95_ms": 6.844148000027417, + "max_ms": 6.844148000027417, + "samples_ms": [ + 6.844148000027417 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 42, + "muc_archive_records": 10010, + "wire_body_deliveries": 43, + "status": "pass" + } + ] +} diff --git a/docs/validation-logs-0.8.1/latency-before.json b/docs/validation-logs-0.8.1/latency-before.json new file mode 100644 index 0000000..928b1b0 --- /dev/null +++ b/docs/validation-logs-0.8.1/latency-before.json @@ -0,0 +1,522 @@ +{ + "binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "scope": "loopback STARTTLS; isolated fixture; no production latency claim", + "cases": [ + { + "mam_enabled": false, + "sm_enabled": true, + "rounds": 5, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 5, + "median_ms": 5.10814599999776, + "p95_ms": 6.436508999968282, + "max_ms": 6.436508999968282, + "samples_ms": [ + 4.687508000017715, + 5.018378999977813, + 5.10814599999776, + 5.499873000019306, + 6.436508999968282 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 10.949089000007461, + "p95_ms": 11.194100000011531, + "max_ms": 11.194100000011531, + "samples_ms": [ + 9.188771000026463, + 9.251739999967867, + 10.949089000007461, + 11.097223999968264, + 11.194100000011531 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 6.3955159999977695, + "p95_ms": 10.028454999996939, + "max_ms": 10.028454999996939, + "samples_ms": [ + 5.6768890000284955, + 6.070047000036993, + 6.3955159999977695, + 6.783154999993712, + 10.028454999996939 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 7.227664999959416, + "p95_ms": 10.73728499994786, + "max_ms": 10.73728499994786, + "samples_ms": [ + 6.249474000014743, + 6.710089000023345, + 7.227664999959416, + 7.554007000010188, + 10.73728499994786 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 5, + "median_ms": 4.543079999962174, + "p95_ms": 5.169351999995797, + "max_ms": 5.169351999995797, + "samples_ms": [ + 3.9885659999754353, + 4.165818999979365, + 4.543079999962174, + 4.987367000012455, + 5.169351999995797 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 9.515092000015102, + "p95_ms": 12.47698700001365, + "max_ms": 12.47698700001365, + "samples_ms": [ + 8.106691999955729, + 8.858637999992425, + 9.515092000015102, + 9.874779000028866, + 12.47698700001365 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 5.794529000013426, + "p95_ms": 7.275404999973034, + "max_ms": 7.275404999973034, + "samples_ms": [ + 5.51126799996382, + 5.724920000034217, + 5.794529000013426, + 6.444504000000961, + 7.275404999973034 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 6.479804000036893, + "p95_ms": 8.207588000004762, + "max_ms": 8.207588000004762, + "samples_ms": [ + 6.077395999966484, + 6.479181999964112, + 6.479804000036893, + 7.2692859999961, + 8.207588000004762 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 4.576559000042835, + "p95_ms": 4.576559000042835, + "max_ms": 4.576559000042835, + "samples_ms": [ + 4.576559000042835 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 0, + "muc_archive_records": 0, + "wire_body_deliveries": 43, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 5, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 5, + "median_ms": 8.454973000027621, + "p95_ms": 9.086850000016966, + "max_ms": 9.086850000016966, + "samples_ms": [ + 7.875873999978467, + 7.919512999990275, + 8.454973000027621, + 8.744820000003983, + 9.086850000016966 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 15.02084100002321, + "p95_ms": 18.49304000000984, + "max_ms": 18.49304000000984, + "samples_ms": [ + 14.658381000003828, + 15.0033279999775, + 15.02084100002321, + 16.241458000024522, + 18.49304000000984 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 8.695557000010012, + "p95_ms": 10.132943000030536, + "max_ms": 10.132943000030536, + "samples_ms": [ + 6.247895000001336, + 8.190369000033115, + 8.695557000010012, + 8.886856000003718, + 10.132943000030536 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 9.425391000036143, + "p95_ms": 11.220557999990888, + "max_ms": 11.220557999990888, + "samples_ms": [ + 6.928168999991158, + 9.00288799999771, + 9.425391000036143, + 9.836486999972749, + 11.220557999990888 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 5, + "median_ms": 8.574552000027325, + "p95_ms": 11.412799000027007, + "max_ms": 11.412799000027007, + "samples_ms": [ + 7.429673999979514, + 8.434421999993447, + 8.574552000027325, + 10.991448000027049, + 11.412799000027007 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 16.801955000005364, + "p95_ms": 20.960896000019602, + "max_ms": 20.960896000019602, + "samples_ms": [ + 15.289625999969303, + 16.07350099999394, + 16.801955000005364, + 19.067943000038667, + 20.960896000019602 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 9.673966000036671, + "p95_ms": 10.545491000016227, + "max_ms": 10.545491000016227, + "samples_ms": [ + 8.954777999974795, + 9.244574000035755, + 9.673966000036671, + 10.407988999986628, + 10.545491000016227 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 10.7329940000227, + "p95_ms": 11.54250500002263, + "max_ms": 11.54250500002263, + "samples_ms": [ + 9.77221699997699, + 10.012581000012233, + 10.7329940000227, + 11.414449999961107, + 11.54250500002263 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 8.784937999962494, + "p95_ms": 8.784937999962494, + "max_ms": 8.784937999962494, + "samples_ms": [ + 8.784937999962494 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 42, + "muc_archive_records": 10, + "wire_body_deliveries": 43, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 5, + "seeded_muc_archive_records": 1000, + "active": { + "direct_peer": { + "samples": 5, + "median_ms": 7.590319999962958, + "p95_ms": 8.892007999975249, + "max_ms": 8.892007999975249, + "samples_ms": [ + 5.31427799995754, + 6.9214119999969625, + 7.590319999962958, + 7.624421999992137, + 8.892007999975249 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 13.376056000026892, + "p95_ms": 15.464272999963669, + "max_ms": 15.464272999963669, + "samples_ms": [ + 12.23329399999784, + 13.25195099997245, + 13.376056000026892, + 14.078856999958589, + 15.464272999963669 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 31.94280399998206, + "p95_ms": 35.83487499997773, + "max_ms": 35.83487499997773, + "samples_ms": [ + 30.683405999980096, + 31.05138800003715, + 31.94280399998206, + 34.427220999987185, + 35.83487499997773 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 32.718170999999074, + "p95_ms": 36.99477299994669, + "max_ms": 36.99477299994669, + "samples_ms": [ + 31.32484000002478, + 31.708390999995117, + 32.718170999999074, + 35.15474099998528, + 36.99477299994669 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 5, + "median_ms": 6.955795000010312, + "p95_ms": 7.9194580000034875, + "max_ms": 7.9194580000034875, + "samples_ms": [ + 6.15931200002251, + 6.666912000014236, + 6.955795000010312, + 7.675652999978411, + 7.9194580000034875 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 13.159411000003729, + "p95_ms": 15.27061000001595, + "max_ms": 15.27061000001595, + "samples_ms": [ + 12.274962999981653, + 13.057566999975734, + 13.159411000003729, + 14.08330199996044, + 15.27061000001595 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 34.13865300001362, + "p95_ms": 36.99340499997561, + "max_ms": 36.99340499997561, + "samples_ms": [ + 30.982952999977442, + 32.71812099995941, + 34.13865300001362, + 35.38880100001052, + 36.99340499997561 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 36.06873300003599, + "p95_ms": 38.31650299997591, + "max_ms": 38.31650299997591, + "samples_ms": [ + 33.48175599995784, + 34.2965520000007, + 36.06873300003599, + 36.353186000042115, + 38.31650299997591 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 12.115028999971855, + "p95_ms": 12.115028999971855, + "max_ms": 12.115028999971855, + "samples_ms": [ + 12.115028999971855 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 42, + "muc_archive_records": 1010, + "wire_body_deliveries": 43, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 5, + "seeded_muc_archive_records": 10000, + "active": { + "direct_peer": { + "samples": 5, + "median_ms": 9.04404400000658, + "p95_ms": 12.927059999981338, + "max_ms": 12.927059999981338, + "samples_ms": [ + 8.594286000004558, + 9.04279899998528, + 9.04404400000658, + 10.732668000002832, + 12.927059999981338 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 18.81452300000319, + "p95_ms": 21.198468999955367, + "max_ms": 21.198468999955367, + "samples_ms": [ + 17.06366100000878, + 17.834419999985585, + 18.81452300000319, + 18.89581300002874, + 21.198468999955367 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 258.5251909999897, + "p95_ms": 269.03445800002146, + "max_ms": 269.03445800002146, + "samples_ms": [ + 243.74590799999396, + 244.56996899999695, + 258.5251909999897, + 260.5109279999738, + 269.03445800002146 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 259.47216499997694, + "p95_ms": 269.0669140000068, + "max_ms": 269.0669140000068, + "samples_ms": [ + 244.58446500000264, + 245.61970199999905, + 259.47216499997694, + 261.3186459999497, + 269.0669140000068 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 5, + "median_ms": 9.321043999989342, + "p95_ms": 11.691385000005994, + "max_ms": 11.691385000005994, + "samples_ms": [ + 9.130955999978596, + 9.257138999998915, + 9.321043999989342, + 9.393109000029654, + 11.691385000005994 + ] + }, + "direct_application_rtt": { + "samples": 5, + "median_ms": 22.537706999969487, + "p95_ms": 22.7979030000256, + "max_ms": 22.7979030000256, + "samples_ms": [ + 18.378415999961817, + 18.92694800000072, + 22.537706999969487, + 22.614556000007724, + 22.7979030000256 + ] + }, + "muc_sender_echo": { + "samples": 5, + "median_ms": 257.6139750000266, + "p95_ms": 278.14462699996056, + "max_ms": 278.14462699996056, + "samples_ms": [ + 248.2455429999959, + 251.84251700000004, + 257.6139750000266, + 262.41991000000553, + 278.14462699996056 + ] + }, + "muc_peer": { + "samples": 5, + "median_ms": 258.46415800003797, + "p95_ms": 278.8930929999651, + "max_ms": 278.8930929999651, + "samples_ms": [ + 250.01428399997394, + 253.1065140000237, + 258.46415800003797, + 263.1856349999566, + 278.8930929999651 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 11.461830000030204, + "p95_ms": 11.461830000030204, + "max_ms": 11.461830000030204, + "samples_ms": [ + 11.461830000030204 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 42, + "muc_archive_records": 10010, + "wire_body_deliveries": 43, + "status": "pass" + } + ] +} diff --git a/docs/validation-logs-0.8.1/muc-sm-load.json b/docs/validation-logs-0.8.1/muc-sm-load.json new file mode 100644 index 0000000..78e2824 --- /dev/null +++ b/docs/validation-logs-0.8.1/muc-sm-load.json @@ -0,0 +1,62 @@ +{ + "clients": 500, + "accounts": 100, + "rooms": 10, + "message_rounds": 3, + "concurrency": 20, + "binary": "/tmp/xmpp-durable-muc-load-p95vsvii/rust-xmpp", + "binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "before": { + "rss_kib": 10076, + "cpu_seconds": 0.0, + "fd_count": 12 + }, + "connect_seconds": 3.149, + "connect_latency": { + "samples": 500, + "median_ms": 121.817, + "p95_ms": 169.081, + "max_ms": 257.299 + }, + "phase": "completed", + "status": "pass", + "elapsed_seconds": 39.535, + "join_seconds": 25.54, + "joined": { + "rss_kib": 42224, + "cpu_seconds": 14.41, + "fd_count": 512 + }, + "join_presence_deliveries": 25000, + "slots_joined": { + "count": 500, + "bytes": 309790 + }, + "message_seconds": 5.504, + "room_messages_sent": 30, + "room_messages_delivered": 1500, + "before_kill": { + "rss_kib": 42224, + "cpu_seconds": 17.88, + "fd_count": 512 + }, + "slots_before_kill": { + "count": 500, + "bytes": 514030 + }, + "restart_seconds": 2.962, + "resumed_resources": 10, + "replayed_pending_room_messages": 10, + "membership_groupchat_deliveries_after_resume": 10, + "after_resume": { + "rss_kib": 20796, + "cpu_seconds": 2.81, + "fd_count": 22 + }, + "slots_after_resume": { + "count": 500, + "bytes": 671070 + }, + "total_seconds": 39.535, + "peak_rss_kib": 42240 +} diff --git a/docs/validation-logs-0.8.1/verify.txt b/docs/validation-logs-0.8.1/verify.txt new file mode 100644 index 0000000..af77d49 --- /dev/null +++ b/docs/validation-logs-0.8.1/verify.txt @@ -0,0 +1,1198 @@ + Finished `test` profile [unoptimized] target(s) in 0.11s + Running unittests src/lib.rs (target/debug/deps/rust_xmpp-1dba4060b94f6305) + +running 48 tests +test csi::checkpoint_tests::only_queue_changes_require_a_checkpoint ... ok +test federation::tests::starttls_must_be_an_immediate_stream_feature ... ok +test federation::tests::federation_domains_are_dns_names_and_case_insensitive ... ok +test federation::tests::external_must_be_in_the_advertised_mechanisms ... ok +test http_config::tests::external_prefix_and_standard_port ... ok +test csi::checkpoint_tests::failed_queue_checkpoints_restore_append_and_drain_without_copying_queue ... ok +test federation::tests::stream_restarts_compare_canonical_domains ... ok +test http_config::tests::literal_pchars_and_percent_encoding_are_supported ... ok +test http_proxy::tests::config_validation_and_network_boundaries ... ok +test http_config::tests::routes_hosts_and_default_without_overriding_known_hosts ... ok +test http_config::tests::invalid_paths_types_urls_and_conflicts_are_errors ... ok +test http_proxy::tests::empty_native_lua_table_disables_proxy_trust ... ok +test http_config::tests::mounts_inherit_per_app_and_expand_virtual_host ... ok +test http_proxy::tests::forwarded_mode_stops_at_first_untrusted_hop ... ok +test http_proxy::tests::forwarded_tls_termination_cannot_upgrade_a_plaintext_chain_hop ... ok +test http_proxy::tests::legacy_chain_uses_rightmost_untrusted_and_tls_is_preserved ... ok +test http_proxy::tests::malformed_forwarded_and_unknown_identifiers_are_ignored ... ok +test http_proxy::tests::untrusted_socket_ignores_spoofed_headers ... ok +test http_transport::tests::bosh_processing_capacity_is_bounded ... ok +test http_transport::tests::independent_framing ... ok +test http_transport::tests::websocket_preserves_inherited_namespaces_and_spaced_declarations ... ok +test http_transport::tests::configured_mount_host_origin_and_secure_dispatch ... ok +test logging::tests::console_aliases_share_one_sink_with_combined_levels ... ok +test sasl::tests::reject_malformed_and_downgrade ... ok +test sasl::tests::rfc5802_sha1_vector ... ok +test server::authorization_tests::http_interfaces_follow_secure_override_wildcards_and_global_fallback ... ok +test server::authorization_tests::pep_diagnostics_count_only_first_item_devices_without_logging_ids ... ok +test server::authorization_tests::pep_diagnostics_exclude_payloads_and_identifiers ... ok +test http_service::tests::upload_claim_refreshes_completion_state_after_an_earlier_snapshot ... ok +test sessions::push_timeout_tests::first_important_push_shortens_extended_hibernation_once ... ok +test sessions::tests::acknowledgement_wraps ... ok +test sessions::tests::graceful_disconnect_is_not_resumable ... ok +test sessions::tests::resume_replays_only_unacked_and_checks_owner ... ok +test sessions::tests::traffic_before_sm_enable_is_not_counted ... ok +test upload_migration::tests::local_spool_checks_size_and_hash_and_preserves_source ... ok +test upload_migration::tests::pending_and_corrupt_journals_block_startup ... ok +test wire::tests::arbitrary_prefix_and_inherited_namespaces ... ok +test wire::tests::cdata_and_comments_frame_without_counting_brackets ... ok +test wire::tests::declarations_rejected ... ok +test wire::tests::fragmented_and_pipelined ... ok +test wire::tests::invalid_namespace_and_declarations_rejected ... ok +test http_service::tests::upload_internal_mount_is_independent_of_advertised_proxy_prefix ... ok +test sasl::tests::sha256_independent_python_vector ... ok +test http_service::tests::abandoned_slots_release_quota_without_pruning_existing_or_active_files ... ok +test sasl::tests::plus_channel_binding_and_ssdp_are_authenticated ... ok +test server::authorization_tests::upload_requires_registered_local_account_or_explicit_remote_access ... ok +test sasl::tests::wrong_proof_nonce_binding_and_duplicates ... ok +test admin::tests::real_admin_xml_protocol_over_duplex ... ok + +test result: ok. 48 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.39s + + Running unittests src/main.rs (target/debug/deps/rust_xmpp-18c1e37579680121) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/admin_socket.rs (target/debug/deps/admin_socket-98ea57263855c936) + +running 1 test +test prosody_wire_commands_password_prompt_and_safe_errors ... ignored, requires AF_UNIX socket permission; run on target host with --ignored + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/archive_mam.rs (target/debug/deps/archive_mam-3fba5ff1bd14ff0e) + +running 14 tests +test archive_larger_than_128mib_streams ... ignored, large-file scalability regression; run explicitly +test mam_preferences_persist ... ok +test corrupt_archive_reports_server_error_and_namespace_stripping_is_precise ... ok +test legacy_records_binary_cache_and_roundtrip ... ok +test append_is_incremental_and_recovers_torn_tail ... ok +test archive_roundtrip_preserves_default_namespace_resets ... ok +test real_archive_sid_and_sender_privacy ... ok +test equal_cursors_and_normalized_query_jids ... ok +test smart_enable_and_message_selection ... ok +test muc_archive_filters_stanza_kind_instead_of_sender_jid ... ok +test zero_page_dates_and_invalid_forms ... ok +test mam_paging_filters_and_forbidden ... ok +test extended_ids_ranges_flip_and_metadata ... ok +test namespaces_expiry_and_concurrent_append ... ok + +test result: ok. 13 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/auth.rs (target/debug/deps/auth-33143b97a74eee33) + +running 3 tests +test traversal_and_malicious_account_records_rejected ... ok +test create_and_read_hashed_accounts ... ok +test authentication_prepares_names_without_relaxing_account_management ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.67s + + Running tests/cli.rs (target/debug/deps/cli-81c768157b2e259b) + +running 2 tests +test server_cannot_be_mistaken_for_running_service ... ok +test conversion_preserves_source_and_refuses_overwrite ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/config.rs (target/debug/deps/config-91d6a6fd8d03deb0) + +running 12 tests +test component_can_explicitly_enable_global_modules ... ok +test include_cycles_rejected ... ok +test declarations_and_overrides ... ok +test include_has_own_global_scope_and_parent_scope_is_restored ... ok +test storage_paths_encode_like_prosody ... ok +test tables_cannot_recurse_forever ... ok +test supplied_configuration_scopes_arithmetic_and_modules ... ok +test runtime_capabilities_are_unavailable ... ok +test malformed_values_rejected ... ok +test all_formats_round_trip_actual_config ... ok +test supplied_config_matches_original_prosody_loader ... ok +test loops_are_bounded ... ok + +test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/csi.rs (target/debug/deps/csi-484464365f1be63b) + +running 2 tests +test bounded_queue_flush_delay_activity_and_grace ... ok +test native_importance_rules ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/csi_native.rs (target/debug/deps/csi_native-22d788125d4db792) + +running 1 test +test native_prosody_csi_importance_matches ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/data_lock.rs (target/debug/deps/data_lock-8d78dbe5153f1bd0) + +running 2 tests +test child_process_probe ... ok +test excludes_another_process_and_releases_on_drop ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/debug_legacy.rs (target/debug/deps/debug_legacy-8eed3e61532fa343) + +running 1 test +test debug_empty_legacy_bind ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s + + Running tests/federation_tls.rs (target/debug/deps/federation_tls-5b930bc0a4897f80) + +running 3 tests +test native_prosody_tls_external_bidirectional ... ignored, requires native Prosody cafd74b9c5ea and Lua TLS dependencies +test mutual_tls_external_delivery_and_certificate_identity_rejection ... ok +test reuses_connections_serializes_writes_and_retires_idle_or_closed_peers ... ok + +test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.11s + + Running tests/gajim_features.rs (target/debug/deps/gajim_features-5ea32b08cb6c3580) + +running 6 tests +test security_catalog_default_is_a_real_label_and_module_can_be_disabled ... ok +test unsupported_security_policy_configuration_returns_explicit_error ... ok +test policy_catalog_selects_default_policy_and_maps_display_and_explicit_label ... ok +test security_catalogs_serve_both_versions_and_preserve_requested_target ... ok +test actual_example_policy_configuration_exposes_classifications_as_catalog_labels ... ok +test malformed_or_unknown_policy_catalog_schemas_are_rejected ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/http_altconnect.rs (target/debug/deps/http_altconnect-075f1b2186b0b689) + +running 3 tests +test native_link_order_schemes_and_loaded_module_gates ... ok +test public_prefix_and_host_paths_inherit_independently ... ok +test bad_advertisement_types_and_route_collisions_are_rejected ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/http_transport.rs (target/debug/deps/http_transport-f94bf41ca6508ce7) + +running 10 tests +test configured_origin_is_enforced ... ok +test bosh_preserves_namespace_inherited_from_body ... ok +test transport_paths_and_cors_preflight_match_prosody ... ok +test bosh_session_retries_restart_termination ... ok +test bosh_termination_waits_for_graceful_cleanup_before_reconnect ... ok +test bosh_reorders_two_requests_without_replaying_stanzas ... ok +test websocket_frames_are_independent_xml ... ok +test websocket_disconnect_delivers_eof_without_graceful_close ... ok +test websocket_close_allows_graceful_engine_cleanup ... ok +test bosh_retry_survives_aborted_http_request_without_replaying_stanzas ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s + + Running tests/http_upload.rs (target/debug/deps/http_upload-985df4a30ade1594) + +running 5 tests +test https_endpoint_uses_real_tls ... ok +test percent_escape_case_and_equivalent_url_spelling ... ok +test persisted_prosody_archive_and_hs256_slot_survive_without_sidecar ... ok +test expired_upload_releases_quota ... ok +test upload_authorization_streaming_ranges_and_restart ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s + + Running tests/iq_errors.rs (target/debug/deps/iq_errors-57e28d145c2197b1) + +running 2 tests +test pep_errors_identify_the_account_and_echo_the_request ... ok +test server_errors_without_target_remain_unaddressed_and_escape_attributes ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/logging.rs (target/debug/deps/logging-6cd0153609754520) + +running 10 tests +test native_console_shorthands_are_accepted ... ok +test json_records_and_bounded_ranges ... ok +test filters_appends_escapes_and_redacts ... ok +test rejects_malformed_configuration ... ok +test overlapping_shorthand_destinations_receive_each_record_once ... ok +test explicit_sink_levels_select_exactly_and_deduplicate ... ok +test failed_reopen_keeps_all_original_handles ... ok +test reopen_rotated_files_updates_clones ... ok +test shared_sink_unions_levels_and_preserves_distinct_destinations ... ok +test cloned_loggers_serialize_records ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/message_routing.rs (target/debug/deps/message_routing-efbb4699b234977b) + +running 2 tests +test unknown_resource_falls_back_to_available_bare_jid ... ok +test headline_uses_all_nonnegative_available_resources_and_errors_never_fallback ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/muc_access.rs (target/debug/deps/muc_access-602820b6fe312a25) + +running 3 tests +test binary_occupant_id_salt_survives_saves_and_restarts ... ok +test moderators_cannot_kick_or_demote_other_moderators ... ok +test nested_affiliations_do_not_fall_back_to_obsolete_flat_entries ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/muc_crash_state.rs (target/debug/deps/muc_crash_state-9359f59aa4d6add4) + +running 7 tests +test safe_presence_checkpoint_sanitization_is_idempotent ... ok +test foreign_stanzas_do_not_initialize_or_rewrite_muc_checkpoint ... ok +test durable_disconnect_removes_last_temporary_room_without_shutdown_export ... ok +test journal_failure_returns_no_routing_and_rolls_back_role_mutation ... ok +test acknowledged_kick_and_room_destruction_cannot_resurrect_membership ... ok +test dormant_deadline_stays_fixed_when_another_occupant_recovers_and_sends ... ok +test temporary_membership_and_full_bounded_history_survive_ungraceful_loss ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/muc_domain_bans.rs (target/debug/deps/muc_domain_bans-87bb89a13f7d66ac) + +running 2 tests +test native_domain_bans_block_remote_users_but_allow_explicit_members ... ok +test applying_domain_ban_removes_remote_occupants_and_blocks_rejoin ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/muc_extensions.rs (target/debug/deps/muc_extensions-d892b608e50c5d11) + +running 10 tests +test broadcast_roles_hide_visitors_and_configuration_announces_transition ... ok +test disabled_optional_vcard_and_occupant_ids_are_not_advertised_or_emitted ... ok +test messages_cannot_spoof_room_identity_hats_or_occupant_identifiers ... ok +test large_optional_history_does_not_prevent_checkpointing_membership ... ok +test mam_all_rooms_presence_logging_public_queries_and_optional_totals ... ok +test restricted_private_messages_allow_self_and_optional_moderators ... ok +test offline_reserved_affiliates_follow_anonymity_and_roominfo_counts_nicknames ... ok +test language_config_sections_discovery_and_native_affiliation_hats ... ok +test recovery_claim_is_durable_and_unrelated_disconnect_keeps_temporary_claims ... ok +test explicit_new_nickname_consumes_old_proof_and_pending_nicks_are_reserved ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/muc_flow.rs (target/debug/deps/muc_flow-23834b608bde0e71) + +running 18 tests +test configured_lock_timeout_expires_without_owner_submission ... ok +test iq_response_requires_expected_sender ... ok +test join_lock_chat_leave ... ok +test authorization_and_conflict ... ok +test multiple_resources_share_nick_and_private_delivery ... ok +test occupant_id_is_stable_and_spoofed_ids_removed ... ok +test nick_invite_destroy_and_local_creation ... ok +test persistence_roundtrip ... ok +test preserves_unknown_binary_mixed_room_fields ... ok +test native_muc_archive_type_and_anonymity_are_preserved ... ok +test restored_temporary_room_is_deleted_after_last_disconnect ... ok +test maintenance_expires_idle_archives_and_tombstones ... ok +test archive_history_and_permissions ... ok +test persistent_destroy_creates_prosody_tombstone ... ok +test switching_to_members_only_removes_unaffiliated_users ... ok +test reserved_nickname_blocks_other_users ... ok +test visitor_voice_request_cannot_spoof_identity_or_grant_itself_voice ... ok +test room_vcard_owner_only_and_avatar_presence ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s + + Running tests/muc_history.rs (target/debug/deps/muc_history-39f64fc14afaae94) + +running 10 tests +test only_direct_history_children_are_parsed ... ok +test maxchars_counts_transmitted_utf8_bytes_including_address_and_delay ... ok +test capacity_changes_trim_and_zero_disables_history ... ok +test explicit_count_and_zero_limit ... ok +test replay_carries_room_delay_and_recipient ... ok +test snapshot_restores_last_message_without_adding_another_delay ... ok +test subjects_and_hints_follow_native_history_eligibility ... ok +test since_and_seconds_use_stricter_cutoff_inclusive ... ok +test ordinary_history_is_bounded_and_returns_oldest_first ... ok +test default_count_applies_only_without_valid_explicit_constraints ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/muc_latency_storage.rs (target/debug/deps/muc_latency_storage-24b24d815895d8ab) + +running 2 tests +test groupchat_skips_native_rewrites_and_archive_retention_scan ... ok +test native_exports_repair_missing_files_and_export_changed_config ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/muc_native.rs (target/debug/deps/muc_native-1deb258080c3107b) + +running 1 test +test actual_prosody_muc_mam_reads_rust_and_writes_native_archive ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/muc_optional_admin.rs (target/debug/deps/muc_optional_admin-09092f76957af1ff) + +running 4 tests +test default_registration_denies_unaffiliated_users ... ok +test configured_tombstone_expiry_allows_immediate_recreation ... ok +test optional_registration_grants_membership_and_enforces_reserved_nickname ... ok +test administration_commands_recheck_authority_bind_sessions_and_update_live_rooms ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/muc_protocol.rs (target/debug/deps/muc_protocol-ff2c35e16474b6f1) + +running 5 tests +test ordinary_presence_extensions_survive_but_client_identity_is_filtered ... ok +test subject_with_body_remains_an_ordinary_groupchat_message ... ok +test probes_and_invalid_presence_cannot_join_or_rename ... ok +test room_creation_policies_apply_only_to_new_rooms ... ok +test error_messages_kick_only_on_delivery_failure_and_presence_errors_kick ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/muc_recovery.rs (target/debug/deps/muc_recovery-56ecc83fbb4b8e27) + +running 7 tests +test claim_is_one_time_and_does_not_change_untrusted_role ... ok +test pending_snapshot_keeps_original_checkpoint_time ... ok +test recovery_claim_requires_exact_authenticated_resource_and_expires ... ok +test native_checkpoint_roundtrip_filters_sensitive_extensions ... ok +test native_last_message_roundtrip_preserves_namespaces_and_rejects_other_rooms ... ok +test oversized_status_never_prevents_membership_checkpoint ... ok +test configuration_fingerprint_is_independent_of_lua_table_iteration_order ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/muc_restart_state.rs (target/debug/deps/muc_restart_state-20cc7fc55f4f661b) + +running 3 tests +test unrelated_disconnect_does_not_delete_dormant_temporary_room ... ok +test changed_configuration_invalidates_auto_recovery_without_disclosing_password ... ok +test repeated_restart_keeps_dormant_claim_and_deadline_without_ghost_routing ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/muc_state_native.rs (target/debug/deps/muc_state_native-f35f6eeee693220a) + +running 1 test +test actual_prosody_restores_rust_checkpoint_and_rust_reads_native_freeze ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/pep_client_interop.rs (target/debug/deps/pep_client_interop-116d3f27d1887fec) + +running 7 tests +test native_component_notification_type_applies_to_events_and_subscription_replay ... ok +test missing_own_omemo_bundle_returns_recoverable_item_not_found ... ok +test publish_options_match_implicit_notification_defaults_on_old_nodes ... ok +test migrated_native_configuration_can_roundtrip_access_model_edit ... ok +test native_itemreply_controls_publisher_visibility_in_reads_and_replays ... ok +test avatar_and_omemo_publish_options_support_readback_and_caps_notifications ... ok +test native_open_and_subscriber_publish_models_preserve_outcast_and_blocking_checks ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.19s + + Running tests/pep_diagnostics.rs (target/debug/deps/pep_diagnostics-7741e2c6c32d43e3) + +running 6 tests +test nonempty_xml_can_be_an_empty_android_device_list ... ok +test only_first_direct_item_is_parsed_and_protocols_are_distinct ... ok +test avatar_classification_does_not_inspect_or_expose_avatar_data ... ok +test payloadless_notification_is_visible_without_identifiers ... ok +test arbitrary_node_payload_and_wrong_namespace_do_not_leak ... ok +test signed_integer_limits_and_duplicates_match_java_parser ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/pep_discovery.rs (target/debug/deps/pep_discovery-8d14ca1d74370630) + +running 4 tests +test standalone_component_does_not_claim_pep_automatic_subscriptions ... ok +test account_discovery_does_not_intercept_server_or_resource_caps ... ok +test account_disco_advertises_pep_without_requiring_a_node ... ok +test node_discovery_keeps_node_identity_errors_and_access_checks ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s + + Running tests/pep_item_order.rs (target/debug/deps/pep_item_order-b2fa0224be6531ab) + +running 2 tests +test native_prosody_orders_retained_pep_items_newest_first ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA +test first_pep_item_is_current_device_list_even_with_retained_old_items ... ok + +test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.07s + + Running tests/preauth.rs (target/debug/deps/preauth-bcb62603a77510a9) + +running 10 tests +test duplicate_or_wrong_namespace_tokens_do_not_qualify ... ok +test standard_adhoc_command_returns_contact_uri ... ok +test unknown_tokens_do_not_create_invite_stores_and_disabled_accounts_cannot_issue ... ok +test prosody_numeric_expiry_is_consumed_and_other_entries_preserved ... ok +test unknown_client_token_is_preserved_on_remote_and_pending_delivery ... ok +test concurrent_redemption_has_exactly_one_winner ... ok +test identity_scope_does_not_burn_on_wrong_sender_or_leak_to_prosody ... ok +test invitations_expire_are_single_use_and_owner_scoped ... ok +test valid_token_autoapproves_and_sends_reciprocal_request ... ok +test local_invitation_updates_both_rosters_without_granting_reverse_subscription ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/preauth_native.rs (target/debug/deps/preauth_native-aa108ad5d4963eb6) + +running 1 test +test native_prosody_invitation_tokens_roundtrip ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/pubsub_native.rs (target/debug/deps/pubsub_native-53c63bfbbc6345ac) + +running 1 test +test native_prosody_pep_reads_rust_and_rust_reads_native ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/pubsub_persistence.rs (target/debug/deps/pubsub_persistence-70493c941948c65c) + +running 18 tests +test modern_bookmarks_notify_legacy_capability ... ok +test native_string_max_items_satisfies_numeric_publish_precondition ... ok +test configurable_limits_component_creation_and_publisher ... ok +test capability_discovery_replays_and_filters_notifications ... ok +test configure_requires_owner ... ok +test open_model_and_notifications ... ok +test nonpersistent_items_stay_in_memory_and_can_be_made_persistent ... ok +test reads_prosody_legacy_fixture ... ok +test full_jid_block_applies_to_reads_subscription_replays_and_events ... ok +test publish_options_conflict_is_recoverable_and_preserves_item ... ok +test pep_persists_namespaces_and_enforces_owner ... ok +test remote_unavailable_is_scoped_to_addressed_owner_and_cancels_pending ... ok +test roster_presence_access_and_foreign_subscription_denied ... ok +test remote_caps_replay_and_open_node_privacy_revoke ... ok +test subscription_options_disable_events_and_require_subscriber ... ok +test payload_policy_applies_to_subscription_and_caps_replays ... ok +test native_notification_fields_and_retract_policy_are_independent ... ok +test component_default_retention_matches_prosody_twenty_items ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.24s + + Running tests/push.rs (target/debug/deps/push-f7822aa8c48ee6ec) + +running 7 tests +test native_push_body_lookup_excludes_extensions ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA +test foreign_account_cannot_register ... ok +test queue_coalesces_and_importance_matches_native ... ok +test push_summary_never_copies_foreign_namespace_body ... ok +test stable_client_registration_and_targeted_notification ... ok +test reenable_cancels_old_errors_and_failure_counts_are_per_account ... ok +test registrations_notifications_and_authenticated_errors ... ok + +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.07s + + Running tests/reference_prosody.rs (target/debug/deps/reference_prosody-2be357bf8c803be8) + +running 1 test +test real_prosody_storage_and_auth_roundtrip ... ignored, requires native supplied Prosody source; run scripts/prosody_compat/verify.sh + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/resource_sessions.rs (target/debug/deps/resource_sessions-c5aabe5ec7bb9c57) + +running 7 tests +test invalid_resume_owner_or_ack_does_not_evict_active_session ... ok +test kick_new_leaves_existing_session_unchanged ... ok +test random_conflicts_get_distinct_resources_for_same_owner ... ok +test replacement_revokes_hibernating_resume_and_survives_old_cleanup ... ok +test increment_skips_occupied_suffixes_and_preserves_sessions ... ok +test concurrent_default_binds_replace_atomically ... ok +test active_resume_preserves_state_and_replaces_transport_notifier ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/sasl_accounts.rs (target/debug/deps/sasl_accounts-86c86459dcf107f9) + +running 1 test +test disabled_legacy_and_unicode_accounts ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.43s + + Running tests/sm_durable_slots.rs (target/debug/deps/sm_durable_slots-76db8932b2edbb64) + +running 11 tests +test corrupt_committed_slot_fails_recovery_closed ... ok +test durable_tokens_and_private_pending_output_have_owner_only_permissions ... ok +test session_reference_does_not_keep_store_locked_or_allow_unpersisted_writes ... ok +test recovery_discards_owned_crash_temps_and_keeps_last_committed_slot ... ok +test durable_counters_wrap_without_accepting_stale_acknowledgements ... ok +test disconnected_deadline_is_fixed_across_recovery ... ok +test independent_hubs_with_identical_connection_names_keep_their_own_slots ... ok +test shutdown_freeze_retires_old_transport_before_cleanup ... ok +test restart_restores_owner_presence_and_only_unacknowledged_output ... ok +test graceful_close_conflict_account_purge_and_expiration_remove_tokens ... ok +test store_has_one_process_owner_and_enforces_output_byte_bound ... ok + +test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s + + Running tests/storage_accounts.rs (target/debug/deps/storage_accounts-834822f717e90132) + +running 20 tests +test broken_roster_is_not_overwritten ... ok +test inbound_subscription_requires_pending_to_grant_to ... ok +test account_purge_refuses_symlink_store_without_touching_other_files ... ok +test blocklist_enforcement_api ... ok +test malformed_legacy_vcard_and_private_bookmarks_rejected ... ok +test domain_roster_and_block_jid_normalization ... ok +test private_and_vcard_authorization ... ok +test malformed_roster_iq_never_mutates ... ok +test privacy_migration_only_default_deny_jids ... ok +test reads_timestamp_blocklist_and_keeps_metadata ... ok +test roster_empty_name_and_foreign_group_ignored ... ok +test purge_account_exact_files_preserves_others_and_extras ... ok +test roster_preserves_subscription_and_metadata ... ok +test subscription_handshake_and_cancel ... ok +test legacy_bookmarks_respect_host_limit_and_read_over_256 ... ok +test bookmarks_private_pep_bidirectional_and_private ... ok +test password_change_after_purge_never_recreates_account ... ok +test legacy_migration_clears_source_after_success ... ok +test vcard_pep_conversion_and_avatar ... ok +test creation_and_purge_are_serialized ... ok + +test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.92s + + Running tests/storage_compat.rs (target/debug/deps/storage_compat-42a6d5716b16b9e1) + +running 6 tests +test empty_namespace_preserved ... ok +test stanza_roundtrip ... ok +test mixed_binary_roundtrip ... ok +test path_and_atomic_update ... ok +test rejects_cycles_code_and_bad_files ... ok +test concurrent_updates_do_not_lose_entries ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/tls_binding.rs (target/debug/deps/tls_binding-25db34289830aad8) + +running 4 tests +test malformed_der_and_pss_parameters_fail_closed ... ok +test unknown_and_eddsa_algorithms_fail_closed ... ok +test ecdsa_uses_certificate_signature_hash ... ok +test rsa_signature_digest_and_weak_hash_upgrade ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.45s + + Running tests/tls_plus_network.rs (target/debug/deps/tls_plus_network-1a0fc780c64bdfe1) + +running 2 tests +test disabling_plus_hides_bindings_and_accepts_scram_y_with_mechanisms_only_ssdp ... ok +test starttls_scram_plus_binds_real_tls_and_authenticates_ssdp_sasl1_and_sasl2 ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.91s + + Doc-tests rust_xmpp + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Finished `dev` profile [unoptimized] target(s) in 0.11s + Finished `release` profile [optimized] target(s) in 0.09s +PASS: integrated TCP roster/subscriptions, client IQ routing, CSI buffering/keepalive flush, MAM, blocking, OMEMO PEP, MUC, offline replay and SM resumption +PASS: graceful SIGTERM shutdown +PASS: independent SCRAM-SHA-1 over TLS, SASL1/SASL2, SSDP verification, server signatures and wrong-password rejection +PASS: independent SCRAM-SHA-256 over TLS, SASL1/SASL2, SSDP verification, server signatures and wrong-password rejection +PASS: Android TLS1.2 selector, TLS1.2/1.3 SCRAM SHA1/256 PLUS, SASL1/2, SSDP on/off and invalid binding rejection +PASS: JSON file logging, TLS/auth/bind correlation, rejection reasons, secret redaction and SIGHUP rotation +PASS: 20 TLS1.2/1.3 SASL1/2 cases: prepared PLAIN identities and canonical binds, invalid authz rejection, SCRAM abort/retry and active exchange restart +PASS: WSS SCRAM-SHA-256 SASL1/SASL2 with GS2 y, absent CB/PLUS, SSDP without CB separator, server signatures, bind and ping +PASS: HTTPS-only configured interfaces (127.0.0.1,::1), verified TLS, reproduced original Origin 403 then allowed Converse Origin 101, xmpp subprotocol, both WS paths, RFC 7395 open/features/close and private HTTP diagnostics +PASS: custom WS/BOSH routes, default-route 404, exact Origin policy, verified TLS proxy rewrite, trusted HTTPS metadata, untrusted/spoofed metadata denial, IPv6 when available, authenticated WS/BOSH bind/ping in legacy and RFC7239 modes and cached BOSH RID retry +PASS: XEP-0156 XRD/JRD parity, CORS, safe methods, ignored JSONP, host checks, secure URL preference, custom mounts/public prefixes, module and advertisement gates, HTTP fallback and verified WSS framing +PASS: SASL2 Bind2 TLS flow, inline SM/CSI/Carbons, private random resource, malformed requests, authentication failure and fallback +PASS: bind2-disabled, SSDP=False, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: bind2-disabled, SSDP=True, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: bind2-enabled, SSDP=False, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: bind2-enabled, SSDP=True, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: sm-disabled, SSDP=False, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: sm-disabled, SSDP=True, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: enabled-False-registration-False +PASS: enabled-False-registration-True +PASS: enabled-True-registration-False +PASS: enabled-True-registration-True +PASS: Gajim domain/account discovery, both label catalogs, authenticated password changes, IBR registration gates and fresh logins +PASS: SASL2 inline SM active/EOF resume, authenticated owner/id/h checks, replay ordering, full JID, Bind2 fallback and malformed requests +PASS: TLS account/domain discovery with PEP and push enabled/disabled; real push enable, publish options, per-node and service-wide disable +PASS: TLS Monocles/Conversations PEP first-run, no-to publishing, owner config recovery, migrated metadata, device item selectors and restart persistence +PASS: Android first-item device-list parsing sees latest publish and replacement before and after restart +PASS: STARTTLS PEP replay/live diagnostics, legacy/OMEMO2, payloadless notifications with intact IQ payloads, and private values excluded +PASS: TLS invitation command discovery, preapproval, single-use mutual roster, replay denial, unknown preauth forwarding/offline pending, account isolation +PASS: STARTTLS MUC SIGTERM restart restores live temporary/persistent rooms, exact full-JID membership, roles, presence and groupchat routing; rejects automatic cross-resource/account claims and nickname theft +PASS: recovery-history +PASS: leave +PASS: kick +PASS: demotion +PASS: password +PASS: configuration +PASS: restart-grace +PASS: custom-grace +PASS: unknown-module +PASS: destroy-tombstone +PASS: actual STARTTLS SIGKILL MUC recovery, history, acknowledged barriers and fixed grace +PASS: TLS legacy/SASL2 durable SM after SIGKILL/SIGTERM, counters, ack pruning, at-least-once pending replay, owner/token/h rejection, transport/resource conflict, MUC activation/offline fanout, grace expiry and account deletion/recreation revocation +{ + "binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "scope": "loopback STARTTLS; isolated fixture; no production latency claim", + "cases": [ + { + "mam_enabled": false, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 1.8904600000269056, + "p95_ms": 1.9304429999920103, + "max_ms": 1.9304429999920103, + "samples_ms": [ + 1.8756470000198533, + 1.8904600000269056, + 1.9304429999920103 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 4.25472400002036, + "p95_ms": 4.37473499994212, + "max_ms": 4.37473499994212, + "samples_ms": [ + 3.8919710000300256, + 4.25472400002036, + 4.37473499994212 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 3.5698000000365937, + "p95_ms": 3.893650999998499, + "max_ms": 3.893650999998499, + "samples_ms": [ + 3.1098660000452583, + 3.5698000000365937, + 3.893650999998499 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 3.6192310000160433, + "p95_ms": 3.9405589999432777, + "max_ms": 3.9405589999432777, + "samples_ms": [ + 3.154005000055804, + 3.6192310000160433, + 3.9405589999432777 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 2.1467320000283507, + "p95_ms": 2.613242999927934, + "max_ms": 2.613242999927934, + "samples_ms": [ + 2.124384000012469, + 2.1467320000283507, + 2.613242999927934 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 4.911349999929371, + "p95_ms": 5.607715999985885, + "max_ms": 5.607715999985885, + "samples_ms": [ + 4.401708000045801, + 4.911349999929371, + 5.607715999985885 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 4.0735349999749815, + "p95_ms": 4.238021000105618, + "max_ms": 4.238021000105618, + "samples_ms": [ + 3.089648000013767, + 4.0735349999749815, + 4.238021000105618 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 4.11955900005978, + "p95_ms": 4.2870900000480106, + "max_ms": 4.2870900000480106, + "samples_ms": [ + 3.1140530001039224, + 4.11955900005978, + 4.2870900000480106 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 3.5513789999868095, + "p95_ms": 3.5513789999868095, + "max_ms": 3.5513789999868095, + "samples_ms": [ + 3.5513789999868095 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 0, + "muc_archive_records": 0, + "wire_body_deliveries": 27, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 5.57562999995298, + "p95_ms": 6.627433999938148, + "max_ms": 6.627433999938148, + "samples_ms": [ + 5.414346000065962, + 5.57562999995298, + 6.627433999938148 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 11.672713999928419, + "p95_ms": 12.136518000033902, + "max_ms": 12.136518000033902, + "samples_ms": [ + 9.967780000010862, + 11.672713999928419, + 12.136518000033902 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 5.446227999982511, + "p95_ms": 6.189593000044624, + "max_ms": 6.189593000044624, + "samples_ms": [ + 5.022585999995499, + 5.446227999982511, + 6.189593000044624 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 5.501564000041981, + "p95_ms": 6.313648000059402, + "max_ms": 6.313648000059402, + "samples_ms": [ + 5.076121999991301, + 5.501564000041981, + 6.313648000059402 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 5.386627000007138, + "p95_ms": 5.490081000061764, + "max_ms": 5.490081000061764, + "samples_ms": [ + 5.2206389999582825, + 5.386627000007138, + 5.490081000061764 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 10.997781000014584, + "p95_ms": 11.280016000000614, + "max_ms": 11.280016000000614, + "samples_ms": [ + 10.779805999959535, + 10.997781000014584, + 11.280016000000614 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 5.9416880000071615, + "p95_ms": 6.300728000042, + "max_ms": 6.300728000042, + "samples_ms": [ + 5.658265000079155, + 5.9416880000071615, + 6.300728000042 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 5.995042000108697, + "p95_ms": 6.3529389999530395, + "max_ms": 6.3529389999530395, + "samples_ms": [ + 5.773301000090214, + 5.995042000108697, + 6.3529389999530395 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 6.166175999965162, + "p95_ms": 6.166175999965162, + "max_ms": 6.166175999965162, + "samples_ms": [ + 6.166175999965162 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 26, + "muc_archive_records": 6, + "wire_body_deliveries": 27, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 10000, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 5.892937999988135, + "p95_ms": 6.487584999945284, + "max_ms": 6.487584999945284, + "samples_ms": [ + 5.324401000052603, + 5.892937999988135, + 6.487584999945284 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 10.666736999951354, + "p95_ms": 12.053192999928797, + "max_ms": 12.053192999928797, + "samples_ms": [ + 9.926160000077289, + 10.666736999951354, + 12.053192999928797 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 5.197909000003165, + "p95_ms": 5.9229750000895365, + "max_ms": 5.9229750000895365, + "samples_ms": [ + 4.911608000043088, + 5.197909000003165, + 5.9229750000895365 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 5.222090000074786, + "p95_ms": 5.947224999999889, + "max_ms": 5.947224999999889, + "samples_ms": [ + 4.934721000040554, + 5.222090000074786, + 5.947224999999889 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 5.153808000045501, + "p95_ms": 5.780468000011751, + "max_ms": 5.780468000011751, + "samples_ms": [ + 5.086673999926461, + 5.153808000045501, + 5.780468000011751 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 9.816193999995448, + "p95_ms": 10.903567000013936, + "max_ms": 10.903567000013936, + "samples_ms": [ + 9.812457999942126, + 9.816193999995448, + 10.903567000013936 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 5.199423000021852, + "p95_ms": 5.341851000025599, + "max_ms": 5.341851000025599, + "samples_ms": [ + 4.466079999929207, + 5.199423000021852, + 5.341851000025599 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 5.223214000011467, + "p95_ms": 5.400911000037922, + "max_ms": 5.400911000037922, + "samples_ms": [ + 4.519688999948812, + 5.223214000011467, + 5.400911000037922 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 6.889136999916445, + "p95_ms": 6.889136999916445, + "max_ms": 6.889136999916445, + "samples_ms": [ + 6.889136999916445 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 26, + "muc_archive_records": 10006, + "wire_body_deliveries": 27, + "status": "pass" + } + ] +} +PASS: TLS conflict_resolve=default, live and hibernating SM resources +PASS: TLS conflict_resolve=kick_old, live and hibernating SM resources +PASS: TLS conflict_resolve=kick_new, live and hibernating SM resources +PASS: TLS conflict_resolve=increment, live and hibernating SM resources +PASS: TLS conflict_resolve=random, live and hibernating SM resources +PASS: integrated WSS + HTTPS BOSH SASL/bind, CSI, inherited BOSH namespaces, roster, bidirectional chat, upload IQ/PUT/GET/reuse, graceful SM close and same-resource relogin under kick_new +PASS: integrated WSS + HTTPS BOSH SASL/bind, CSI, inherited BOSH namespaces, roster, bidirectional chat, upload IQ/PUT/GET/reuse, graceful SM close and same-resource relogin under kick_new +PASS: configured upload HTTP path with $host through integrated listener +PASS: multiple upload hosts/shared-host paths, discovery, quotas, JWT isolation, persistence, transport composition and conflict validation +PASS upload S3 protocol fixture: SigV4, multipart, abort, range, restart, expiry and backend isolation +PASS upload migration: local -> S3 -> S3 -> local, hashes, original URLs/JWT/HEAD, lock, dry-run, fail-closed resume +{ + "total_load_wall_seconds": 8.892, + "requested_resources": 500, + "authenticated_bound_resources": 500, + "connection_setup_concurrency": 50, + "setup_wall_seconds": 0.646, + "setup_latency": { + "samples": 500, + "median_ms": 60.166, + "p95_ms": 81.981, + "max_ms": 105.233 + }, + "ping_rounds": 10, + "ping_round_trip": { + "samples": 5000, + "median_ms": 10.879, + "p95_ms": 21.103, + "max_ms": 23.338 + }, + "accounts": 100, + "message_rounds": 10, + "messages_sent": 5000, + "messages_received": 5000, + "message_batch_seconds": 6.009, + "metrics_before": { + "rss_kib": 8412, + "cpu_seconds": 0.0, + "fd_count": 11 + }, + "metrics_connected": { + "rss_kib": 27472, + "cpu_seconds": 1.09, + "fd_count": 511 + }, + "metrics_after_workload": { + "rss_kib": 28176, + "cpu_seconds": 11.23, + "fd_count": 511 + }, + "metrics_two_seconds_after_disconnect": { + "rss_kib": 28240, + "cpu_seconds": 11.27, + "fd_count": 11 + }, + "sampled_peak_rss_kib": 28240, + "fd_delta_after_disconnect": 0, + "failures": [], + "scope": "One loopback host, 100 accounts with distinct resources, TLS+PLAIN, ping and directed messages; not a production benchmark or proof of no memory leaks.", + "mam": { + "archive_files": 100, + "records": 10000, + "expected_records": 10000 + } +} +MUC+SM load: connected (3.149s) +MUC+SM load: joined (28.693s) +MUC+SM load: fanout_verified (34.197s) +MUC+SM load: before_sigkill (36.066s) +{ + "clients": 500, + "accounts": 100, + "rooms": 10, + "message_rounds": 3, + "concurrency": 20, + "binary": "/tmp/xmpp-durable-muc-load-p95vsvii/rust-xmpp", + "binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "before": { + "rss_kib": 10076, + "cpu_seconds": 0.0, + "fd_count": 12 + }, + "connect_seconds": 3.149, + "connect_latency": { + "samples": 500, + "median_ms": 121.817, + "p95_ms": 169.081, + "max_ms": 257.299 + }, + "phase": "completed", + "status": "pass", + "elapsed_seconds": 39.535, + "join_seconds": 25.54, + "joined": { + "rss_kib": 42224, + "cpu_seconds": 14.41, + "fd_count": 512 + }, + "join_presence_deliveries": 25000, + "slots_joined": { + "count": 500, + "bytes": 309790 + }, + "message_seconds": 5.504, + "room_messages_sent": 30, + "room_messages_delivered": 1500, + "before_kill": { + "rss_kib": 42224, + "cpu_seconds": 17.88, + "fd_count": 512 + }, + "slots_before_kill": { + "count": 500, + "bytes": 514030 + }, + "restart_seconds": 2.962, + "resumed_resources": 10, + "replayed_pending_room_messages": 10, + "membership_groupchat_deliveries_after_resume": 10, + "after_resume": { + "rss_kib": 20796, + "cpu_seconds": 2.81, + "fd_count": 22 + }, + "slots_after_resume": { + "count": 500, + "bytes": 671070 + }, + "total_seconds": 39.535, + "peak_rss_kib": 42240 +} + Finished `test` profile [unoptimized] target(s) in 0.09s + Running tests/csi_native.rs (target/debug/deps/csi_native-22d788125d4db792) + +running 1 test +test native_prosody_csi_importance_matches ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/muc_native.rs (target/debug/deps/muc_native-1deb258080c3107b) + +running 1 test +test actual_prosody_muc_mam_reads_rust_and_writes_native_archive ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s + + Running tests/muc_state_native.rs (target/debug/deps/muc_state_native-f35f6eeee693220a) + +running 1 test +test actual_prosody_restores_rust_checkpoint_and_rust_reads_native_freeze ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/pep_item_order.rs (target/debug/deps/pep_item_order-b2fa0224be6531ab) + +running 1 test +test native_prosody_orders_retained_pep_items_newest_first ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.09s + + Running tests/preauth_native.rs (target/debug/deps/preauth_native-aa108ad5d4963eb6) + +running 1 test +test native_prosody_invitation_tokens_roundtrip ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.11s + + Running tests/pubsub_native.rs (target/debug/deps/pubsub_native-53c63bfbbc6345ac) + +running 1 test +test native_prosody_pep_reads_rust_and_rust_reads_native ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.11s + + Running tests/push.rs (target/debug/deps/push-f7822aa8c48ee6ec) + +running 1 test +test native_push_body_lookup_excludes_extensions ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.00s + + Running tests/reference_prosody.rs (target/debug/deps/reference_prosody-2be357bf8c803be8) + +running 1 test +PROSODY_NATIVE_ROUNDTRIP_OK SHA-1 +PROSODY_NATIVE_FINAL_OK SHA-1 +PROSODY_NATIVE_ROUNDTRIP_OK SHA-256 +PROSODY_NATIVE_FINAL_OK SHA-256 +test real_prosody_storage_and_auth_roundtrip ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.70s + + Finished `test` profile [unoptimized] target(s) in 0.08s + Running tests/federation_tls.rs (target/debug/deps/federation_tls-5b930bc0a4897f80) + +running 1 test +test native_prosody_tls_external_bidirectional ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.90s + diff --git a/docs/validation-logs-0.8.2/bind2-after.json b/docs/validation-logs-0.8.2/bind2-after.json new file mode 100644 index 0000000..fd289dd --- /dev/null +++ b/docs/validation-logs-0.8.2/bind2-after.json @@ -0,0 +1,164 @@ +{ + "binary_source": "/tmp/rust-xmpp-0.8.2-final", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "real loopback TCP/STARTTLS/SASL2 Bind2; isolated personal MAM fixture; no production latency claim", + "timing": "raw ordered samples; auth timer starts before authenticate and ends at parsed success; full timer includes TCP/STARTTLS/features; metadata IQ timer runs from send to parsed result", + "result": { + "status": "pass", + "seeded_personal_archive_records": 100000, + "archive_bytes": 21488890, + "archive_expires_after": "never", + "index_present_before_start": false, + "reconnect_samples": 5, + "expected_metadata": { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + "observed_metadata": [ + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + } + ], + "mam_metadata_iq": { + "samples_ms": [ + 0.4802089999884629, + 0.35487300010572653, + 0.3393980000510055, + 0.49224100007450033, + 0.3266720000283385 + ], + "median_ms": 0.35487300010572653, + "p95_ms": 0.49224100007450033, + "max_ms": 0.49224100007450033 + }, + "observed_iq_metadata": [ + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + } + ], + "sasl2_bind2_success": { + "samples_ms": [ + 1.9306740000502032, + 2.103263999970295, + 2.0025989999794547, + 1.9764060000397876, + 1.8955069999719854 + ], + "median_ms": 1.9764060000397876, + "p95_ms": 2.103263999970295, + "max_ms": 2.103263999970295 + }, + "tcp_starttls_to_bind2_success": { + "samples_ms": [ + 6.099597000002177, + 3.735450000021956, + 3.564695000022766, + 3.3520640001825086, + 3.3587010000246664 + ], + "median_ms": 3.564695000022766, + "p95_ms": 6.099597000002177, + "max_ms": 6.099597000002177 + } + } +} diff --git a/docs/validation-logs-0.8.2/bind2-before-0.8.0.json b/docs/validation-logs-0.8.2/bind2-before-0.8.0.json new file mode 100644 index 0000000..1b36f88 --- /dev/null +++ b/docs/validation-logs-0.8.2/bind2-before-0.8.0.json @@ -0,0 +1,164 @@ +{ + "binary_source": "/tmp/xmpp-message-latency-original-binary", + "binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "scope": "real loopback TCP/STARTTLS/SASL2 Bind2; isolated personal MAM fixture; no production latency claim", + "timing": "raw ordered samples; auth timer starts before authenticate and ends at parsed success; full timer includes TCP/STARTTLS/features; metadata IQ timer runs from send to parsed result", + "result": { + "status": "pass", + "seeded_personal_archive_records": 100000, + "archive_bytes": 21488890, + "archive_expires_after": "never", + "index_present_before_start": false, + "reconnect_samples": 5, + "expected_metadata": { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + "observed_metadata": [ + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + } + ], + "mam_metadata_iq": { + "samples_ms": [ + 2809.4374219999736, + 2219.536220000009, + 1944.7504689999278, + 2437.94546800018, + 3715.6457869998576 + ], + "median_ms": 2437.94546800018, + "p95_ms": 3715.6457869998576, + "max_ms": 3715.6457869998576 + }, + "observed_iq_metadata": [ + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + } + ], + "sasl2_bind2_success": { + "samples_ms": [ + 2973.741726999833, + 1934.8616100000982, + 2034.18535600008, + 3162.465005000058, + 2742.352718999882 + ], + "median_ms": 2742.352718999882, + "p95_ms": 3162.465005000058, + "max_ms": 3162.465005000058 + }, + "tcp_starttls_to_bind2_success": { + "samples_ms": [ + 2977.800272999957, + 1937.2807600000215, + 2036.7481539999517, + 3165.2697970000645, + 2745.1149930000156 + ], + "median_ms": 2745.1149930000156, + "p95_ms": 3165.2697970000645, + "max_ms": 3165.2697970000645 + } + } +} diff --git a/docs/validation-logs-0.8.2/muc-sm-load.json b/docs/validation-logs-0.8.2/muc-sm-load.json new file mode 100644 index 0000000..b8a0c44 --- /dev/null +++ b/docs/validation-logs-0.8.2/muc-sm-load.json @@ -0,0 +1,62 @@ +{ + "clients": 500, + "accounts": 100, + "rooms": 10, + "message_rounds": 3, + "concurrency": 20, + "binary": "/tmp/xmpp-durable-muc-load-qywt10tu/rust-xmpp", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "before": { + "rss_kib": 9548, + "cpu_seconds": 0.0, + "fd_count": 12 + }, + "connect_seconds": 2.918, + "connect_latency": { + "samples": 500, + "median_ms": 114.756, + "p95_ms": 154.077, + "max_ms": 206.971 + }, + "phase": "completed", + "status": "pass", + "elapsed_seconds": 45.54, + "join_seconds": 30.37, + "joined": { + "rss_kib": 41856, + "cpu_seconds": 16.64, + "fd_count": 514 + }, + "join_presence_deliveries": 25000, + "slots_joined": { + "count": 500, + "bytes": 309790 + }, + "message_seconds": 6.696, + "room_messages_sent": 30, + "room_messages_delivered": 1500, + "before_kill": { + "rss_kib": 41884, + "cpu_seconds": 20.77, + "fd_count": 512 + }, + "slots_before_kill": { + "count": 500, + "bytes": 514030 + }, + "restart_seconds": 2.763, + "resumed_resources": 10, + "replayed_pending_room_messages": 10, + "membership_groupchat_deliveries_after_resume": 10, + "after_resume": { + "rss_kib": 20984, + "cpu_seconds": 2.66, + "fd_count": 22 + }, + "slots_after_resume": { + "count": 500, + "bytes": 671070 + }, + "total_seconds": 45.54, + "peak_rss_kib": 41920 +} diff --git a/docs/validation-logs-0.8.2/personal-after.json b/docs/validation-logs-0.8.2/personal-after.json new file mode 100644 index 0000000..e37e3c9 --- /dev/null +++ b/docs/validation-logs-0.8.2/personal-after.json @@ -0,0 +1,1338 @@ +{ + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback STARTTLS; fixture only; forced CSI dwell explicitly separated", + "cases": [ + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 9.934385999940787, + "p95_ms": 26.116932000149973, + "max_ms": 26.116932000149973, + "samples_ms": [ + 7.292991999975129, + 9.934385999940787, + 26.116932000149973 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 9.88499300001422, + "p95_ms": 26.069592000112607, + "max_ms": 26.069592000112607, + "samples_ms": [ + 7.199500000069747, + 9.88499300001422, + 26.069592000112607 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 18.881290000081208, + "p95_ms": 32.769330000064656, + "max_ms": 32.769330000064656, + "samples_ms": [ + 14.889820999997028, + 18.881290000081208, + 32.769330000064656 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 7.525431999965804, + "p95_ms": 8.887985999990633, + "max_ms": 8.887985999990633, + "samples_ms": [ + 6.574537000005876, + 7.525431999965804, + 8.887985999990633 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 7.353217999934714, + "p95_ms": 7.73648599988519, + "max_ms": 7.73648599988519, + "samples_ms": [ + 7.3501320000559645, + 7.353217999934714, + 7.73648599988519 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 7.314217999919492, + "p95_ms": 7.696787999975641, + "max_ms": 7.696787999975641, + "samples_ms": [ + 7.308291999834182, + 7.314217999919492, + 7.696787999975641 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 16.435919999821635, + "p95_ms": 16.575810999938767, + "max_ms": 16.575810999938767, + "samples_ms": [ + 13.911000999996759, + 16.435919999821635, + 16.575810999938767 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 8.640340999818363, + "p95_ms": 9.163700000044628, + "max_ms": 9.163700000044628, + "samples_ms": [ + 6.498096000086662, + 8.640340999818363, + 9.163700000044628 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 7.020568999905663, + "sender_sm_handled_ms": 6.979878000038298, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 7.3571890000039275, + "sender_sm_handled_ms": 7.423431999995955, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-active": { + "delivery_ms": 5.90487999988909, + "sender_sm_handled_ms": 5.856321000010212, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 4.060041999991881, + "sender_sm_handled_ms": 3.603028000043196, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-active": { + "delivery_ms": 4.710215000159224, + "sender_sm_handled_ms": 4.808065000133865, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 3.6635650001244358, + "sender_sm_handled_ms": 3.289268000116863, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-active": { + "delivery_ms": 12.312145000123564, + "sender_sm_handled_ms": 12.042657999927542, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 11.414976999958526, + "sender_sm_handled_ms": 11.446671000157949, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 4.6950840001045435, + "sender_sm_handled_ms": 4.662712000026659, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 5.844635999892489, + "sender_sm_handled_ms": 5.903024999952322, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-active": { + "delivery_ms": 6.98627899987514, + "sender_sm_handled_ms": 6.9448439999177936, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 7.439451999971425, + "sender_sm_handled_ms": 7.503360000100656, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-active": { + "delivery_ms": 16.166666000117402, + "sender_sm_handled_ms": 16.096403000119608, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 8.581391999996413, + "sender_sm_handled_ms": 8.542475000012928, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-active": { + "delivery_ms": 3.829828000107227, + "sender_sm_handled_ms": 3.327058999957444, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2017.080266999983, + "sender_sm_handled_ms": 3.2593890000498504, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 9.675382000068566 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 6.670822999922166, + "sender_sm_handled_ms": 6.573753000111537 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "default", + "baseline_expect_held": false, + "roster_contacts_per_user": 0, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "always" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 7.09640600007333, + "p95_ms": 19.445947999884083, + "max_ms": 19.445947999884083, + "samples_ms": [ + 5.935086999897976, + 7.09640600007333, + 19.445947999884083 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 7.064623999895048, + "p95_ms": 19.50181399979556, + "max_ms": 19.50181399979556, + "samples_ms": [ + 5.811342000015429, + 7.064623999895048, + 19.50181399979556 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 13.734022999869921, + "p95_ms": 24.49354800000947, + "max_ms": 24.49354800000947, + "samples_ms": [ + 12.908389999893188, + 13.734022999869921, + 24.49354800000947 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 6.591360999891549, + "p95_ms": 6.944055999838383, + "max_ms": 6.944055999838383, + "samples_ms": [ + 4.945848000033948, + 6.591360999891549, + 6.944055999838383 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 7.593367999788825, + "p95_ms": 11.505353000075047, + "max_ms": 11.505353000075047, + "samples_ms": [ + 6.660383000053116, + 7.593367999788825, + 11.505353000075047 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 7.272773999829951, + "p95_ms": 11.469916000123703, + "max_ms": 11.469916000123703, + "samples_ms": [ + 6.7844489999515645, + 7.272773999829951, + 11.469916000123703 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 14.649553999788623, + "p95_ms": 23.104979999970965, + "max_ms": 23.104979999970965, + "samples_ms": [ + 13.741463999849657, + 14.649553999788623, + 23.104979999970965 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 7.024535999789805, + "p95_ms": 11.512823999964894, + "max_ms": 11.512823999964894, + "samples_ms": [ + 6.917227999792885, + 7.024535999789805, + 11.512823999964894 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 11.159964999933436, + "sender_sm_handled_ms": 10.724457999913284, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2027.1901230000822, + "sender_sm_handled_ms": 16.822652999962884, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 4.099048000171024 + }, + "omemo_legacy_only-active": { + "delivery_ms": 3.2380130001001817, + "sender_sm_handled_ms": 3.3119140000508196, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2007.7756410000802, + "sender_sm_handled_ms": 2.5553959999342624, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.355625000087457 + }, + "omemo_2_only-active": { + "delivery_ms": 2.5906000000759377, + "sender_sm_handled_ms": 2.6901890000772255, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2007.8129270000318, + "sender_sm_handled_ms": 2.521771000147055, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.5775889999076753 + }, + "omemo_with_eme-active": { + "delivery_ms": 4.35501399988425, + "sender_sm_handled_ms": 4.417945999875883, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 4.823192000003473, + "sender_sm_handled_ms": 4.498243000170987, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 4.931894000037573, + "sender_sm_handled_ms": 5.009728000004543, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 2010.9646770001746, + "sender_sm_handled_ms": 5.511606000027314, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.7539110001507652 + }, + "marker_displayed-active": { + "delivery_ms": 4.515692000040872, + "sender_sm_handled_ms": 4.570190000094954, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 2010.8637490000092, + "sender_sm_handled_ms": 4.831804000104967, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.418779999970866 + }, + "marker_acknowledged-active": { + "delivery_ms": 5.429266999954052, + "sender_sm_handled_ms": 5.485873999987234, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 2010.9519340001043, + "sender_sm_handled_ms": 5.667000000130429, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.6569639999488572 + }, + "low_priority_headline-active": { + "delivery_ms": 2.6243269999213226, + "sender_sm_handled_ms": 2.6806579999174573, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2013.0899620000946, + "sender_sm_handled_ms": 3.175567999960549, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 5.7868270000653865 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 4.632757999843307, + "sender_sm_handled_ms": 4.711322999810363 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "native", + "baseline_expect_held": false, + "roster_contacts_per_user": 0, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "always" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 20.33114999994723, + "p95_ms": 31.98645999987093, + "max_ms": 31.98645999987093, + "samples_ms": [ + 20.288011000047845, + 20.33114999994723, + 31.98645999987093 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 20.34745700007079, + "p95_ms": 32.04224299997804, + "max_ms": 32.04224299997804, + "samples_ms": [ + 20.195752000063294, + 20.34745700007079, + 32.04224299997804 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 40.47510100008367, + "p95_ms": 51.530768999782595, + "max_ms": 51.530768999782595, + "samples_ms": [ + 39.586511999914364, + 40.47510100008367, + 51.530768999782595 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 19.449356999984957, + "p95_ms": 20.07229100013319, + "max_ms": 20.07229100013319, + "samples_ms": [ + 19.222442999989653, + 19.449356999984957, + 20.07229100013319 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 19.866232999902422, + "p95_ms": 19.99418900004457, + "max_ms": 19.99418900004457, + "samples_ms": [ + 18.697023999948215, + 19.866232999902422, + 19.99418900004457 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 19.92523299986715, + "p95_ms": 20.051580000199465, + "max_ms": 20.051580000199465, + "samples_ms": [ + 18.734036999831005, + 19.92523299986715, + 20.051580000199465 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 39.72956699999486, + "p95_ms": 39.851432999967074, + "max_ms": 39.851432999967074, + "samples_ms": [ + 37.525556999980836, + 39.72956699999486, + 39.851432999967074 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 19.628184999874065, + "p95_ms": 19.861294000065755, + "max_ms": 19.861294000065755, + "samples_ms": [ + 18.7452420000227, + 19.628184999874065, + 19.861294000065755 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 19.35876399988956, + "sender_sm_handled_ms": 19.39277399992534, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 20.21448599998621, + "sender_sm_handled_ms": 20.265132000076846, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.3836280001887644, + "sender_sm_handled_ms": 2.4238510000031965, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2.801203999979407, + "sender_sm_handled_ms": 2.362454000149228, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-active": { + "delivery_ms": 2.5594769999770506, + "sender_sm_handled_ms": 2.297387999988132, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2.6781149999806075, + "sender_sm_handled_ms": 2.738028000067061, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-active": { + "delivery_ms": 22.61464299999716, + "sender_sm_handled_ms": 22.67238699982954, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 18.439037000007374, + "sender_sm_handled_ms": 18.469434000053297, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 19.863233999785734, + "sender_sm_handled_ms": 19.831823999993503, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 20.1924399998461, + "sender_sm_handled_ms": 20.24753899991083, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-active": { + "delivery_ms": 18.414425999935702, + "sender_sm_handled_ms": 18.46614800001589, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 19.89041999991059, + "sender_sm_handled_ms": 20.036751999896296, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-active": { + "delivery_ms": 21.71829600001729, + "sender_sm_handled_ms": 21.777248000034888, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 22.17192300008719, + "sender_sm_handled_ms": 22.221732000161865, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-active": { + "delivery_ms": 2.7961150001374335, + "sender_sm_handled_ms": 2.8303950000463374, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2007.8849290000562, + "sender_sm_handled_ms": 2.1910489999754645, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.9039710000470222 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 49.80743399983112, + "sender_sm_handled_ms": 50.571967999985645 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "default", + "baseline_expect_held": false, + "roster_contacts_per_user": 5000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 19.69621900002494, + "p95_ms": 42.19270699991284, + "max_ms": 42.19270699991284, + "samples_ms": [ + 19.40504599997439, + 19.69621900002494, + 42.19270699991284 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 19.74441700008356, + "p95_ms": 42.227931000070384, + "max_ms": 42.227931000070384, + "samples_ms": [ + 19.43559999995159, + 19.74441700008356, + 42.227931000070384 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 44.52753300006407, + "p95_ms": 75.65286299995932, + "max_ms": 75.65286299995932, + "samples_ms": [ + 42.811708000044746, + 44.52753300006407, + 75.65286299995932 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 25.051753000070676, + "p95_ms": 33.38162399995781, + "max_ms": 33.38162399995781, + "samples_ms": [ + 23.028330999977698, + 25.051753000070676, + 33.38162399995781 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 42.020123999918724, + "p95_ms": 47.60321899993869, + "max_ms": 47.60321899993869, + "samples_ms": [ + 27.62041099981616, + 42.020123999918724, + 47.60321899993869 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 41.989471999841044, + "p95_ms": 47.52414699987639, + "max_ms": 47.52414699987639, + "samples_ms": [ + 27.66665999979523, + 41.989471999841044, + 47.52414699987639 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 65.51842899989424, + "p95_ms": 68.45925399989028, + "max_ms": 68.45925399989028, + "samples_ms": [ + 57.403068999974494, + 65.51842899989424, + 68.45925399989028 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 23.450656000022718, + "p95_ms": 29.673266000145304, + "max_ms": 29.673266000145304, + "samples_ms": [ + 20.829446999869106, + 23.450656000022718, + 29.673266000145304 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 34.73295300000245, + "sender_sm_handled_ms": 34.78218899999774, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2059.095004000028, + "sender_sm_handled_ms": 52.21434100008082, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.3442760000307317 + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.289026999960697, + "sender_sm_handled_ms": 2.3513429998729407, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2009.0180530000907, + "sender_sm_handled_ms": 3.837167000028785, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4215010000953043 + }, + "omemo_2_only-active": { + "delivery_ms": 4.889154000011331, + "sender_sm_handled_ms": 4.845507000027283, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2008.3065920000536, + "sender_sm_handled_ms": 3.9267600000130187, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4437199999974837 + }, + "omemo_with_eme-active": { + "delivery_ms": 21.84222599998975, + "sender_sm_handled_ms": 21.90294799993353, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 19.991322999885597, + "sender_sm_handled_ms": 20.052289999966888, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 18.39728599998125, + "sender_sm_handled_ms": 18.452361000072415, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 2023.2745979999436, + "sender_sm_handled_ms": 18.036617000007027, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.5344959999765706 + }, + "marker_displayed-active": { + "delivery_ms": 26.334099999985483, + "sender_sm_handled_ms": 26.397696000003634, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 2026.6623259999506, + "sender_sm_handled_ms": 21.236640999859446, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.6908580000745133 + }, + "marker_acknowledged-active": { + "delivery_ms": 25.270920999901136, + "sender_sm_handled_ms": 25.33230399990316, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 2024.7716760000003, + "sender_sm_handled_ms": 19.67220400001679, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4173909999044554 + }, + "low_priority_headline-active": { + "delivery_ms": 2.4848110001585155, + "sender_sm_handled_ms": 2.5410260000171547, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2009.189195999852, + "sender_sm_handled_ms": 3.168506000065463, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.8620499999997264 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 18.413032999887946, + "sender_sm_handled_ms": 18.463912000015625 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "native", + "baseline_expect_held": false, + "roster_contacts_per_user": 5000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 44.51364500005184, + "p95_ms": 45.964571000013166, + "max_ms": 45.964571000013166, + "samples_ms": [ + 34.22456300017984, + 44.51364500005184, + 45.964571000013166 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 44.59098000006634, + "p95_ms": 46.02178000004642, + "max_ms": 46.02178000004642, + "samples_ms": [ + 34.27662300009615, + 44.59098000006634, + 46.02178000004642 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 78.4022109999114, + "p95_ms": 84.20188900004177, + "max_ms": 84.20188900004177, + "samples_ms": [ + 69.01028000015685, + 78.4022109999114, + 84.20188900004177 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 34.68925800007128, + "p95_ms": 38.13306400002148, + "max_ms": 38.13306400002148, + "samples_ms": [ + 33.770842999956585, + 34.68925800007128, + 38.13306400002148 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 34.21878900007869, + "p95_ms": 43.838538000045446, + "max_ms": 43.838538000045446, + "samples_ms": [ + 33.93446700010827, + 34.21878900007869, + 43.838538000045446 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 34.27054200005841, + "p95_ms": 43.7583899999936, + "max_ms": 43.7583899999936, + "samples_ms": [ + 33.985251000103744, + 34.27054200005841, + 43.7583899999936 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 76.79010300012123, + "p95_ms": 82.84399400008624, + "max_ms": 82.84399400008624, + "samples_ms": [ + 69.896123000035, + 76.79010300012123, + 82.84399400008624 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 38.97644600010608, + "p95_ms": 42.48225700007424, + "max_ms": 42.48225700007424, + "samples_ms": [ + 35.87241099990024, + 38.97644600010608, + 42.48225700007424 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 34.985323999990214, + "sender_sm_handled_ms": 35.049269999944954, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 35.55981799991059, + "sender_sm_handled_ms": 35.26781599998685, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-active": { + "delivery_ms": 3.1153810000432713, + "sender_sm_handled_ms": 2.836314999967726, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 3.5253139999440464, + "sender_sm_handled_ms": 3.246257999990121, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-active": { + "delivery_ms": 2.6683359999424283, + "sender_sm_handled_ms": 2.73817299989787, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2.579258999958256, + "sender_sm_handled_ms": 2.6347149998855457, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-active": { + "delivery_ms": 35.76059600004555, + "sender_sm_handled_ms": 35.81379399997786, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 34.746401000120386, + "sender_sm_handled_ms": 34.470927000029405, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 35.26329699980124, + "sender_sm_handled_ms": 35.22362599983353, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 40.00390000010157, + "sender_sm_handled_ms": 40.05440700007057, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-active": { + "delivery_ms": 34.927564000099665, + "sender_sm_handled_ms": 35.009467000008954, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 34.24647799988634, + "sender_sm_handled_ms": 34.29243499999757, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-active": { + "delivery_ms": 41.09236700014662, + "sender_sm_handled_ms": 40.82514500009893, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 36.06466299993372, + "sender_sm_handled_ms": 36.11676799982888, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-active": { + "delivery_ms": 2.648137999813116, + "sender_sm_handled_ms": 2.3808849998658843, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2007.5651479999124, + "sender_sm_handled_ms": 2.4262659999294556, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4597710000998632 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 36.61754500012648, + "sender_sm_handled_ms": 36.68361800009734 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "default", + "baseline_expect_held": false, + "roster_contacts_per_user": 10000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 46.439240999916365, + "p95_ms": 47.083156000098825, + "max_ms": 47.083156000098825, + "samples_ms": [ + 33.328300999983185, + 46.439240999916365, + 47.083156000098825 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 46.541515999933836, + "p95_ms": 47.150886000054015, + "max_ms": 47.150886000054015, + "samples_ms": [ + 33.39255400010188, + 46.541515999933836, + 47.150886000054015 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 86.8808379998427, + "p95_ms": 122.29052700013199, + "max_ms": 122.29052700013199, + "samples_ms": [ + 70.00579500004278, + 86.8808379998427, + 122.29052700013199 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 40.29070799992951, + "p95_ms": 75.055433000216, + "max_ms": 75.055433000216, + "samples_ms": [ + 36.56819799994082, + 40.29070799992951, + 75.055433000216 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 72.27235899995321, + "p95_ms": 93.65072800005692, + "max_ms": 93.65072800005692, + "samples_ms": [ + 48.87795400009054, + 72.27235899995321, + 93.65072800005692 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 72.12816399987787, + "p95_ms": 93.74595000008412, + "max_ms": 93.74595000008412, + "samples_ms": [ + 48.939044000007925, + 72.12816399987787, + 93.74595000008412 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 139.73325400002068, + "p95_ms": 172.07185899997057, + "max_ms": 172.07185899997057, + "samples_ms": [ + 105.53995500004021, + 139.73325400002068, + 172.07185899997057 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 67.41313900010937, + "p95_ms": 78.24904599988258, + "max_ms": 78.24904599988258, + "samples_ms": [ + 56.54710499993598, + 67.41313900010937, + 78.24904599988258 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 56.88246400018215, + "sender_sm_handled_ms": 56.438711000055264, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2072.487570000021, + "sender_sm_handled_ms": 62.108405999879324, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 6.061285999976462 + }, + "omemo_legacy_only-active": { + "delivery_ms": 12.879445999942618, + "sender_sm_handled_ms": 12.823433999983536, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2015.3352209999866, + "sender_sm_handled_ms": 10.757178999938333, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.0457470000110334 + }, + "omemo_2_only-active": { + "delivery_ms": 3.401804000077391, + "sender_sm_handled_ms": 3.4893090000878146, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2006.9976510001197, + "sender_sm_handled_ms": 2.974240999947142, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.460532000010062 + }, + "omemo_with_eme-active": { + "delivery_ms": 38.3093650000319, + "sender_sm_handled_ms": 38.26694500003214, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 45.05769899992629, + "sender_sm_handled_ms": 45.11449300002823, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 35.31643999986045, + "sender_sm_handled_ms": 35.363737999887235, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 2039.1413359998296, + "sender_sm_handled_ms": 34.155746999886105, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.2997989999803394 + }, + "marker_displayed-active": { + "delivery_ms": 38.61728900005801, + "sender_sm_handled_ms": 38.655942000104915, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 2041.3829850001548, + "sender_sm_handled_ms": 36.01217200002793, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.7297940000844392 + }, + "marker_acknowledged-active": { + "delivery_ms": 36.434277999887854, + "sender_sm_handled_ms": 36.49695899980543, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 2039.6239120000246, + "sender_sm_handled_ms": 34.225130000095305, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.6989709999961633 + }, + "low_priority_headline-active": { + "delivery_ms": 3.2863559999896097, + "sender_sm_handled_ms": 3.340819000186457, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2008.6065660000259, + "sender_sm_handled_ms": 2.7695109999967826, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.135354000074585 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 36.98667300000125, + "sender_sm_handled_ms": 37.06163999981982 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "native", + "baseline_expect_held": false, + "roster_contacts_per_user": 10000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + } + ] +} diff --git a/docs/validation-logs-0.8.2/personal-before-0.8.1.json b/docs/validation-logs-0.8.2/personal-before-0.8.1.json new file mode 100644 index 0000000..feeee89 --- /dev/null +++ b/docs/validation-logs-0.8.2/personal-before-0.8.1.json @@ -0,0 +1,498 @@ +{ + "binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "scope": "loopback STARTTLS; fixture only; forced CSI dwell explicitly separated", + "cases": [ + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 4.817936999870653, + "p95_ms": 16.517306000196186, + "max_ms": 16.517306000196186, + "samples_ms": [ + 4.748034999920492, + 4.817936999870653, + 16.517306000196186 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 4.7456789998250315, + "p95_ms": 16.426100000217048, + "max_ms": 16.426100000217048, + "samples_ms": [ + 4.626912000048833, + 4.7456789998250315, + 16.426100000217048 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 10.344463999899745, + "p95_ms": 21.304692000057912, + "max_ms": 21.304692000057912, + "samples_ms": [ + 9.215212999833966, + 10.344463999899745, + 21.304692000057912 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 4.755211999963649, + "p95_ms": 5.568677999917782, + "max_ms": 5.568677999917782, + "samples_ms": [ + 4.3716870000025665, + 4.755211999963649, + 5.568677999917782 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 4.89018300004318, + "p95_ms": 5.018079000137732, + "max_ms": 5.018079000137732, + "samples_ms": [ + 4.7031279998464015, + 4.89018300004318, + 5.018079000137732 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 4.817049000166662, + "p95_ms": 5.079797999997027, + "max_ms": 5.079797999997027, + "samples_ms": [ + 4.60740799985615, + 4.817049000166662, + 5.079797999997027 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 9.543050000047515, + "p95_ms": 10.455423000166775, + "max_ms": 10.455423000166775, + "samples_ms": [ + 9.271581000120932, + 9.543050000047515, + 10.455423000166775 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 4.79821100020672, + "p95_ms": 5.540141000210497, + "max_ms": 5.540141000210497, + "samples_ms": [ + 4.134176999968986, + 4.79821100020672, + 5.540141000210497 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 5.081753000013123, + "sender_sm_handled_ms": 4.81151700000737, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2010.5149120001897, + "sender_sm_handled_ms": 4.923649000147634, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.6535839999960444 + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.6542460000200663, + "sender_sm_handled_ms": 2.3668179999276617, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2012.9395249998652, + "sender_sm_handled_ms": 2.5684999998247804, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 3.8570599999729893 + }, + "omemo_2_only-active": { + "delivery_ms": 2.803322000090702, + "sender_sm_handled_ms": 2.5052290000076027, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2006.170849, + "sender_sm_handled_ms": 2.1322459999737475, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.5037350001421146 + }, + "omemo_with_eme-active": { + "delivery_ms": 5.247026000006372, + "sender_sm_handled_ms": 4.908949999844481, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 6.537689000197133, + "sender_sm_handled_ms": 6.264521000048262, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 4.346552000015436, + "sender_sm_handled_ms": 4.268297999942661 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100517, + 100517 + ], + "roster_contacts_per_user": 0, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "always" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 19.816834000039307, + "p95_ms": 34.282772000096884, + "max_ms": 34.282772000096884, + "samples_ms": [ + 19.449956000016755, + 19.816834000039307, + 34.282772000096884 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 19.71937500002241, + "p95_ms": 34.19807699992816, + "max_ms": 34.19807699992816, + "samples_ms": [ + 19.322317000160183, + 19.71937500002241, + 34.19807699992816 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 39.9533730001167, + "p95_ms": 54.972926000118605, + "max_ms": 54.972926000118605, + "samples_ms": [ + 39.557586999990235, + 39.9533730001167, + 54.972926000118605 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 20.108162000042284, + "p95_ms": 20.66232500010301, + "max_ms": 20.66232500010301, + "samples_ms": [ + 20.07690499999626, + 20.108162000042284, + 20.66232500010301 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 21.33975200013083, + "p95_ms": 22.656845000028625, + "max_ms": 22.656845000028625, + "samples_ms": [ + 19.565955999951257, + 21.33975200013083, + 22.656845000028625 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 21.24135799999749, + "p95_ms": 22.574971000040023, + "max_ms": 22.574971000040023, + "samples_ms": [ + 19.466118999844184, + 21.24135799999749, + 22.574971000040023 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 42.33967000004668, + "p95_ms": 42.759643999943364, + "max_ms": 42.759643999943364, + "samples_ms": [ + 39.931753000018944, + 42.33967000004668, + 42.759643999943364 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 20.32766500019534, + "p95_ms": 21.3887639999939, + "max_ms": 21.3887639999939, + "samples_ms": [ + 19.65616699999373, + 20.32766500019534, + 21.3887639999939 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 20.706908999954976, + "sender_sm_handled_ms": 20.764115000019956, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2024.603683000123, + "sender_sm_handled_ms": 19.517362000215144, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.5455170000441285 + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.6721889998952975, + "sender_sm_handled_ms": 2.4056919999111415, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2008.3468199998151, + "sender_sm_handled_ms": 2.188200999853507, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.0773089997874195 + }, + "omemo_2_only-active": { + "delivery_ms": 3.2299929998771404, + "sender_sm_handled_ms": 2.707185999952344, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2008.4954139999809, + "sender_sm_handled_ms": 2.423592000013741, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.214231000152722 + }, + "omemo_with_eme-active": { + "delivery_ms": 22.333799999842086, + "sender_sm_handled_ms": 22.02385900000081, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 36.01745500009201, + "sender_sm_handled_ms": 35.61825799988583, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 18.815608000068096, + "sender_sm_handled_ms": 18.779131000201232 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100517, + 100517 + ], + "roster_contacts_per_user": 5000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 36.994213000070886, + "p95_ms": 46.157045999962065, + "max_ms": 46.157045999962065, + "samples_ms": [ + 32.354088000147385, + 36.994213000070886, + 46.157045999962065 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 37.03395700017609, + "p95_ms": 46.22371799996472, + "max_ms": 46.22371799996472, + "samples_ms": [ + 32.41653200007022, + 37.03395700017609, + 46.22371799996472 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 70.08860200016898, + "p95_ms": 79.21533199987607, + "max_ms": 79.21533199987607, + "samples_ms": [ + 64.34645700005603, + 70.08860200016898, + 79.21533199987607 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 32.9383449998204, + "p95_ms": 33.00209500002893, + "max_ms": 33.00209500002893, + "samples_ms": [ + 31.880290000117384, + 32.9383449998204, + 33.00209500002893 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 36.834342000020115, + "p95_ms": 39.296434999869234, + "max_ms": 39.296434999869234, + "samples_ms": [ + 32.84419600004185, + 36.834342000020115, + 39.296434999869234 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 36.63234700002249, + "p95_ms": 39.167316999964896, + "max_ms": 39.167316999964896, + "samples_ms": [ + 32.901452000032805, + 36.63234700002249, + 39.167316999964896 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 74.8365649999414, + "p95_ms": 82.56400300001587, + "max_ms": 82.56400300001587, + "samples_ms": [ + 65.61269799999536, + 74.8365649999414, + 82.56400300001587 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 35.5047470000045, + "p95_ms": 45.70364199980759, + "max_ms": 45.70364199980759, + "samples_ms": [ + 32.67074199993658, + 35.5047470000045, + 45.70364199980759 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 35.88422400002855, + "sender_sm_handled_ms": 35.596954999846275, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2042.8565239999443, + "sender_sm_handled_ms": 37.33574900002168, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.5680029998748068 + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.439558000105535, + "sender_sm_handled_ms": 2.5105040001562884, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2008.4427409999535, + "sender_sm_handled_ms": 2.87832799995158, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.7736980000790936 + }, + "omemo_2_only-active": { + "delivery_ms": 2.8043899999374844, + "sender_sm_handled_ms": 2.46161499990194, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2006.2423169999875, + "sender_sm_handled_ms": 2.324273000112953, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4116319998720428 + }, + "omemo_with_eme-active": { + "delivery_ms": 37.31560400001399, + "sender_sm_handled_ms": 37.00228699995023, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 34.92131200005133, + "sender_sm_handled_ms": 34.618570000020554, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 37.54468600004657, + "sender_sm_handled_ms": 37.61967200011895 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100517, + 100517 + ], + "roster_contacts_per_user": 10000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + } + ] +} diff --git a/docs/validation-logs-0.8.2/push-hibernating-after.json b/docs/validation-logs-0.8.2/push-hibernating-after.json new file mode 100644 index 0000000..1f6461a --- /dev/null +++ b/docs/validation-logs-0.8.2/push-hibernating-after.json @@ -0,0 +1,25 @@ +{ + "status": "pass", + "recipient_state": "hibernating", + "durable_pending_at_gateway_stream": { + "push-first": true, + "push-second": true + }, + "observation_seconds": 2, + "elapsed_seconds": 2.0038609230000475, + "gateway_post_tls_stream_observed": true, + "gateway_post_tls_stream_at_bound": true, + "blocked_stage": "post-tls-features", + "durable_pending": { + "push-first": true, + "push-second": true + }, + "sender_sm_ack_h": [ + 4 + ], + "sender_inputs": 4, + "sender_handled_before": 2, + "binary_version": "rust-xmpp 0.8.2 \u2014 experimental XMPP runtime", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback TLS fixture; stalled external XMPP push service; no APNs/FCM" +} diff --git a/docs/validation-logs-0.8.2/push-hibernating-before-0.8.1.json b/docs/validation-logs-0.8.2/push-hibernating-before-0.8.1.json new file mode 100644 index 0000000..e9bf78b --- /dev/null +++ b/docs/validation-logs-0.8.2/push-hibernating-before-0.8.1.json @@ -0,0 +1,17 @@ +{ + "status": "reproduced-blocking", + "observation_seconds": 2, + "elapsed_seconds": 2.005253799000002, + "gateway_post_tls_stream_observed": true, + "gateway_post_tls_stream_at_bound": true, + "blocked_stage": "post-tls-features", + "durable_pending": { + "push-first": true, + "push-second": false + }, + "sender_sm_ack_h": [], + "sender_inputs": 4, + "sender_handled_before": 2, + "binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "scope": "loopback TLS fixture; stalled external XMPP push service; no APNs/FCM" +} diff --git a/docs/validation-logs-0.8.2/push-offline-after.json b/docs/validation-logs-0.8.2/push-offline-after.json new file mode 100644 index 0000000..c5c1f8e --- /dev/null +++ b/docs/validation-logs-0.8.2/push-offline-after.json @@ -0,0 +1,25 @@ +{ + "status": "pass", + "recipient_state": "offline", + "durable_pending_at_gateway_stream": { + "push-first": true, + "push-second": true + }, + "observation_seconds": 2, + "elapsed_seconds": 2.00361997899995, + "gateway_post_tls_stream_observed": true, + "gateway_post_tls_stream_at_bound": true, + "blocked_stage": "post-tls-features", + "durable_pending": { + "push-first": true, + "push-second": true + }, + "sender_sm_ack_h": [ + 4 + ], + "sender_inputs": 4, + "sender_handled_before": 2, + "binary_version": "rust-xmpp 0.8.2 \u2014 experimental XMPP runtime", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback TLS fixture; stalled external XMPP push service; no APNs/FCM" +} diff --git a/docs/validation-logs-0.8.2/push-offline-before-0.8.0.json b/docs/validation-logs-0.8.2/push-offline-before-0.8.0.json new file mode 100644 index 0000000..dc24ef2 --- /dev/null +++ b/docs/validation-logs-0.8.2/push-offline-before-0.8.0.json @@ -0,0 +1,23 @@ +{ + "status": "reproduced-blocking", + "recipient_state": "offline", + "durable_pending_at_gateway_stream": { + "push-first": false, + "push-second": false + }, + "observation_seconds": 2, + "elapsed_seconds": 2.007238984000196, + "gateway_post_tls_stream_observed": true, + "gateway_post_tls_stream_at_bound": true, + "blocked_stage": "post-tls-features", + "durable_pending": { + "push-first": false, + "push-second": false + }, + "sender_sm_ack_h": [], + "sender_inputs": 4, + "sender_handled_before": 2, + "binary_version": "rust-xmpp 0.8.0 \u2014 experimental XMPP runtime", + "binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "scope": "loopback TLS fixture; stalled external XMPP push service; no APNs/FCM" +} diff --git a/docs/validation-logs-0.8.2/verify.txt b/docs/validation-logs-0.8.2/verify.txt new file mode 100644 index 0000000..d20fecc --- /dev/null +++ b/docs/validation-logs-0.8.2/verify.txt @@ -0,0 +1,1785 @@ + Finished `test` profile [unoptimized] target(s) in 0.09s + Running unittests src/lib.rs (target/debug/deps/rust_xmpp-38e1427c800466b2) + +running 48 tests +test federation::tests::external_must_be_in_the_advertised_mechanisms ... ok +test csi::checkpoint_tests::only_queue_changes_require_a_checkpoint ... ok +test federation::tests::starttls_must_be_an_immediate_stream_feature ... ok +test federation::tests::federation_domains_are_dns_names_and_case_insensitive ... ok +test csi::checkpoint_tests::failed_queue_checkpoints_restore_append_and_drain_without_copying_queue ... ok +test http_config::tests::external_prefix_and_standard_port ... ok +test http_config::tests::literal_pchars_and_percent_encoding_are_supported ... ok +test federation::tests::stream_restarts_compare_canonical_domains ... ok +test http_config::tests::mounts_inherit_per_app_and_expand_virtual_host ... ok +test http_proxy::tests::config_validation_and_network_boundaries ... ok +test http_proxy::tests::empty_native_lua_table_disables_proxy_trust ... ok +test http_config::tests::routes_hosts_and_default_without_overriding_known_hosts ... ok +test http_config::tests::invalid_paths_types_urls_and_conflicts_are_errors ... ok +test http_proxy::tests::forwarded_mode_stops_at_first_untrusted_hop ... ok +test http_proxy::tests::forwarded_tls_termination_cannot_upgrade_a_plaintext_chain_hop ... ok +test http_proxy::tests::legacy_chain_uses_rightmost_untrusted_and_tls_is_preserved ... ok +test http_proxy::tests::malformed_forwarded_and_unknown_identifiers_are_ignored ... ok +test http_proxy::tests::untrusted_socket_ignores_spoofed_headers ... ok +test http_transport::tests::bosh_processing_capacity_is_bounded ... ok +test logging::tests::console_aliases_share_one_sink_with_combined_levels ... ok +test http_transport::tests::independent_framing ... ok +test http_transport::tests::websocket_preserves_inherited_namespaces_and_spaced_declarations ... ok +test http_transport::tests::configured_mount_host_origin_and_secure_dispatch ... ok +test sasl::tests::reject_malformed_and_downgrade ... ok +test sasl::tests::rfc5802_sha1_vector ... ok +test server::authorization_tests::http_interfaces_follow_secure_override_wildcards_and_global_fallback ... ok +test server::authorization_tests::pep_diagnostics_count_only_first_item_devices_without_logging_ids ... ok +test server::authorization_tests::pep_diagnostics_exclude_payloads_and_identifiers ... ok +test http_service::tests::upload_claim_refreshes_completion_state_after_an_earlier_snapshot ... ok +test sessions::push_timeout_tests::first_important_push_shortens_extended_hibernation_once ... ok +test sessions::tests::acknowledgement_wraps ... ok +test sessions::tests::graceful_disconnect_is_not_resumable ... ok +test sessions::tests::resume_replays_only_unacked_and_checks_owner ... ok +test sessions::tests::traffic_before_sm_enable_is_not_counted ... ok +test upload_migration::tests::local_spool_checks_size_and_hash_and_preserves_source ... ok +test sasl::tests::sha256_independent_python_vector ... ok +test upload_migration::tests::pending_and_corrupt_journals_block_startup ... ok +test wire::tests::cdata_and_comments_frame_without_counting_brackets ... ok +test wire::tests::declarations_rejected ... ok +test wire::tests::arbitrary_prefix_and_inherited_namespaces ... ok +test wire::tests::fragmented_and_pipelined ... ok +test wire::tests::invalid_namespace_and_declarations_rejected ... ok +test http_service::tests::upload_internal_mount_is_independent_of_advertised_proxy_prefix ... ok +test http_service::tests::abandoned_slots_release_quota_without_pruning_existing_or_active_files ... ok +test sasl::tests::plus_channel_binding_and_ssdp_are_authenticated ... ok +test sasl::tests::wrong_proof_nonce_binding_and_duplicates ... ok +test server::authorization_tests::upload_requires_registered_local_account_or_explicit_remote_access ... ok +test admin::tests::real_admin_xml_protocol_over_duplex ... ok + +test result: ok. 48 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s + + Running unittests src/main.rs (target/debug/deps/rust_xmpp-a8bdc6924635990d) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/admin_socket.rs (target/debug/deps/admin_socket-1f007583c281465f) + +running 1 test +test prosody_wire_commands_password_prompt_and_safe_errors ... ignored, requires AF_UNIX socket permission; run on target host with --ignored + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/archive_edges.rs (target/debug/deps/archive_edges-529570ff6b63852e) + +running 6 tests +test missing_empty_whitespace_and_single_record ... ok +test endpoint_read_recovers_partial_append_before_seeking ... ok +test multiline_endpoints_match_native_scanner_with_blank_lines ... ok +test metadata_skips_large_malformed_middle_without_creating_cache ... ok +test oversized_prefix_and_malformed_endpoints_fail ... ok +test tail_padding_respects_record_bound ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.29s + + Running tests/archive_mam.rs (target/debug/deps/archive_mam-572ffd7f852ac936) + +running 14 tests +test archive_larger_than_128mib_streams ... ignored, large-file scalability regression; run explicitly +test mam_preferences_persist ... ok +test corrupt_archive_reports_server_error_and_namespace_stripping_is_precise ... ok +test legacy_records_binary_cache_and_roundtrip ... ok +test append_is_incremental_and_recovers_torn_tail ... ok +test real_archive_sid_and_sender_privacy ... ok +test smart_enable_and_message_selection ... ok +test archive_roundtrip_preserves_default_namespace_resets ... ok +test zero_page_dates_and_invalid_forms ... ok +test muc_archive_filters_stanza_kind_instead_of_sender_jid ... ok +test equal_cursors_and_normalized_query_jids ... ok +test mam_paging_filters_and_forbidden ... ok +test extended_ids_ranges_flip_and_metadata ... ok +test namespaces_expiry_and_concurrent_append ... ok + +test result: ok. 13 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.05s + + Running tests/auth.rs (target/debug/deps/auth-b1e74cc670008567) + +running 3 tests +test traversal_and_malicious_account_records_rejected ... ok +test create_and_read_hashed_accounts ... ok +test authentication_prepares_names_without_relaxing_account_management ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.83s + + Running tests/cli.rs (target/debug/deps/cli-5795d35b672f9a5e) + +running 2 tests +test server_cannot_be_mistaken_for_running_service ... ok +test conversion_preserves_source_and_refuses_overwrite ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/config.rs (target/debug/deps/config-a1e97258229e64ec) + +running 12 tests +test include_cycles_rejected ... ok +test include_has_own_global_scope_and_parent_scope_is_restored ... ok +test malformed_values_rejected ... ok +test storage_paths_encode_like_prosody ... ok +test declarations_and_overrides ... ok +test component_can_explicitly_enable_global_modules ... ok +test tables_cannot_recurse_forever ... ok +test runtime_capabilities_are_unavailable ... ok +test all_formats_round_trip_actual_config ... ok +test supplied_configuration_scopes_arithmetic_and_modules ... ok +test supplied_config_matches_original_prosody_loader ... ok +test loops_are_bounded ... ok + +test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/csi.rs (target/debug/deps/csi-462ff6a05a98698b) + +running 2 tests +test native_importance_rules ... ok +test bounded_queue_flush_delay_activity_and_grace ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/csi_native.rs (target/debug/deps/csi_native-5df50c44655375cc) + +running 1 test +test native_prosody_csi_importance_matches ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/data_lock.rs (target/debug/deps/data_lock-ff51b3b8bf36f127) + +running 2 tests +test child_process_probe ... ok +test excludes_another_process_and_releases_on_drop ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/debug_legacy.rs (target/debug/deps/debug_legacy-5790ccc96c542463) + +running 1 test +test debug_empty_legacy_bind ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s + + Running tests/federation_tls.rs (target/debug/deps/federation_tls-915bcd4fb11fa78e) + +running 3 tests +test native_prosody_tls_external_bidirectional ... ignored, requires native Prosody cafd74b9c5ea and Lua TLS dependencies +test mutual_tls_external_delivery_and_certificate_identity_rejection ... ok +test reuses_connections_serializes_writes_and_retires_idle_or_closed_peers ... ok + +test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 1.35s + + Running tests/gajim_features.rs (target/debug/deps/gajim_features-307217cac6d799f7) + +running 6 tests +test unsupported_security_policy_configuration_returns_explicit_error ... ok +test security_catalog_default_is_a_real_label_and_module_can_be_disabled ... ok +test policy_catalog_selects_default_policy_and_maps_display_and_explicit_label ... ok +test actual_example_policy_configuration_exposes_classifications_as_catalog_labels ... ok +test security_catalogs_serve_both_versions_and_preserve_requested_target ... ok +test malformed_or_unknown_policy_catalog_schemas_are_rejected ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/http_altconnect.rs (target/debug/deps/http_altconnect-1edbacb0b673eb04) + +running 3 tests +test public_prefix_and_host_paths_inherit_independently ... ok +test native_link_order_schemes_and_loaded_module_gates ... ok +test bad_advertisement_types_and_route_collisions_are_rejected ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/http_transport.rs (target/debug/deps/http_transport-56a3c9a60085223b) + +running 10 tests +test configured_origin_is_enforced ... ok +test bosh_preserves_namespace_inherited_from_body ... ok +test transport_paths_and_cors_preflight_match_prosody ... ok +test bosh_session_retries_restart_termination ... ok +test bosh_termination_waits_for_graceful_cleanup_before_reconnect ... ok +test bosh_reorders_two_requests_without_replaying_stanzas ... ok +test websocket_frames_are_independent_xml ... ok +test websocket_disconnect_delivers_eof_without_graceful_close ... ok +test websocket_close_allows_graceful_engine_cleanup ... ok +test bosh_retry_survives_aborted_http_request_without_replaying_stanzas ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s + + Running tests/http_upload.rs (target/debug/deps/http_upload-edc08d20e242dc2c) + +running 5 tests +test https_endpoint_uses_real_tls ... ok +test percent_escape_case_and_equivalent_url_spelling ... ok +test expired_upload_releases_quota ... ok +test persisted_prosody_archive_and_hs256_slot_survive_without_sidecar ... ok +test upload_authorization_streaming_ranges_and_restart ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s + + Running tests/iq_errors.rs (target/debug/deps/iq_errors-5273fb4dd23efc00) + +running 2 tests +test pep_errors_identify_the_account_and_echo_the_request ... ok +test server_errors_without_target_remain_unaddressed_and_escape_attributes ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/logging.rs (target/debug/deps/logging-7964ebc3b48c5b5a) + +running 10 tests +test rejects_malformed_configuration ... ok +test filters_appends_escapes_and_redacts ... ok +test explicit_sink_levels_select_exactly_and_deduplicate ... ok +test json_records_and_bounded_ranges ... ok +test overlapping_shorthand_destinations_receive_each_record_once ... ok +test native_console_shorthands_are_accepted ... ok +test failed_reopen_keeps_all_original_handles ... ok +test reopen_rotated_files_updates_clones ... ok +test shared_sink_unions_levels_and_preserves_distinct_destinations ... ok +test cloned_loggers_serialize_records ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/message_routing.rs (target/debug/deps/message_routing-9ff761a80bd9ea4c) + +running 2 tests +test unknown_resource_falls_back_to_available_bare_jid ... ok +test headline_uses_all_nonnegative_available_resources_and_errors_never_fallback ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/muc_access.rs (target/debug/deps/muc_access-ca10e0a3b6b4c573) + +running 3 tests +test binary_occupant_id_salt_survives_saves_and_restarts ... ok +test nested_affiliations_do_not_fall_back_to_obsolete_flat_entries ... ok +test moderators_cannot_kick_or_demote_other_moderators ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/muc_crash_state.rs (target/debug/deps/muc_crash_state-fcff6398b26afea6) + +running 7 tests +test safe_presence_checkpoint_sanitization_is_idempotent ... ok +test foreign_stanzas_do_not_initialize_or_rewrite_muc_checkpoint ... ok +test durable_disconnect_removes_last_temporary_room_without_shutdown_export ... ok +test journal_failure_returns_no_routing_and_rolls_back_role_mutation ... ok +test dormant_deadline_stays_fixed_when_another_occupant_recovers_and_sends ... ok +test acknowledged_kick_and_room_destruction_cannot_resurrect_membership ... ok +test temporary_membership_and_full_bounded_history_survive_ungraceful_loss ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/muc_domain_bans.rs (target/debug/deps/muc_domain_bans-c92cfb46ff3e627b) + +running 2 tests +test native_domain_bans_block_remote_users_but_allow_explicit_members ... ok +test applying_domain_ban_removes_remote_occupants_and_blocks_rejoin ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/muc_extensions.rs (target/debug/deps/muc_extensions-e03d9b143497aa1f) + +running 10 tests +test disabled_optional_vcard_and_occupant_ids_are_not_advertised_or_emitted ... ok +test broadcast_roles_hide_visitors_and_configuration_announces_transition ... ok +test messages_cannot_spoof_room_identity_hats_or_occupant_identifiers ... ok +test large_optional_history_does_not_prevent_checkpointing_membership ... ok +test mam_all_rooms_presence_logging_public_queries_and_optional_totals ... ok +test restricted_private_messages_allow_self_and_optional_moderators ... ok +test offline_reserved_affiliates_follow_anonymity_and_roominfo_counts_nicknames ... ok +test language_config_sections_discovery_and_native_affiliation_hats ... ok +test recovery_claim_is_durable_and_unrelated_disconnect_keeps_temporary_claims ... ok +test explicit_new_nickname_consumes_old_proof_and_pending_nicks_are_reserved ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/muc_flow.rs (target/debug/deps/muc_flow-355b906e416aa97d) + +running 18 tests +test configured_lock_timeout_expires_without_owner_submission ... ok +test join_lock_chat_leave ... ok +test iq_response_requires_expected_sender ... ok +test multiple_resources_share_nick_and_private_delivery ... ok +test authorization_and_conflict ... ok +test occupant_id_is_stable_and_spoofed_ids_removed ... ok +test nick_invite_destroy_and_local_creation ... ok +test native_muc_archive_type_and_anonymity_are_preserved ... ok +test persistence_roundtrip ... ok +test preserves_unknown_binary_mixed_room_fields ... ok +test archive_history_and_permissions ... ok +test restored_temporary_room_is_deleted_after_last_disconnect ... ok +test maintenance_expires_idle_archives_and_tombstones ... ok +test switching_to_members_only_removes_unaffiliated_users ... ok +test persistent_destroy_creates_prosody_tombstone ... ok +test reserved_nickname_blocks_other_users ... ok +test room_vcard_owner_only_and_avatar_presence ... ok +test visitor_voice_request_cannot_spoof_identity_or_grant_itself_voice ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s + + Running tests/muc_history.rs (target/debug/deps/muc_history-9b21ff3e8450378e) + +running 10 tests +test only_direct_history_children_are_parsed ... ok +test replay_carries_room_delay_and_recipient ... ok +test capacity_changes_trim_and_zero_disables_history ... ok +test maxchars_counts_transmitted_utf8_bytes_including_address_and_delay ... ok +test ordinary_history_is_bounded_and_returns_oldest_first ... ok +test since_and_seconds_use_stricter_cutoff_inclusive ... ok +test subjects_and_hints_follow_native_history_eligibility ... ok +test default_count_applies_only_without_valid_explicit_constraints ... ok +test explicit_count_and_zero_limit ... ok +test snapshot_restores_last_message_without_adding_another_delay ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/muc_latency_storage.rs (target/debug/deps/muc_latency_storage-f8eee07f03a446d4) + +running 2 tests +test groupchat_skips_native_rewrites_and_archive_retention_scan ... ok +test native_exports_repair_missing_files_and_export_changed_config ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/muc_native.rs (target/debug/deps/muc_native-3166df0798e2ca45) + +running 1 test +test actual_prosody_muc_mam_reads_rust_and_writes_native_archive ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/muc_optional_admin.rs (target/debug/deps/muc_optional_admin-9746314ec5520f32) + +running 4 tests +test default_registration_denies_unaffiliated_users ... ok +test configured_tombstone_expiry_allows_immediate_recreation ... ok +test optional_registration_grants_membership_and_enforces_reserved_nickname ... ok +test administration_commands_recheck_authority_bind_sessions_and_update_live_rooms ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/muc_protocol.rs (target/debug/deps/muc_protocol-3cfa9e446d24df6b) + +running 5 tests +test ordinary_presence_extensions_survive_but_client_identity_is_filtered ... ok +test subject_with_body_remains_an_ordinary_groupchat_message ... ok +test probes_and_invalid_presence_cannot_join_or_rename ... ok +test room_creation_policies_apply_only_to_new_rooms ... ok +test error_messages_kick_only_on_delivery_failure_and_presence_errors_kick ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/muc_recovery.rs (target/debug/deps/muc_recovery-6442766a992abf47) + +running 7 tests +test claim_is_one_time_and_does_not_change_untrusted_role ... ok +test pending_snapshot_keeps_original_checkpoint_time ... ok +test recovery_claim_requires_exact_authenticated_resource_and_expires ... ok +test native_checkpoint_roundtrip_filters_sensitive_extensions ... ok +test native_last_message_roundtrip_preserves_namespaces_and_rejects_other_rooms ... ok +test oversized_status_never_prevents_membership_checkpoint ... ok +test configuration_fingerprint_is_independent_of_lua_table_iteration_order ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/muc_restart_state.rs (target/debug/deps/muc_restart_state-76d3a3c721692e77) + +running 3 tests +test unrelated_disconnect_does_not_delete_dormant_temporary_room ... ok +test changed_configuration_invalidates_auto_recovery_without_disclosing_password ... ok +test repeated_restart_keeps_dormant_claim_and_deadline_without_ghost_routing ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/muc_state_native.rs (target/debug/deps/muc_state_native-7ba549656d076f8e) + +running 1 test +test actual_prosody_restores_rust_checkpoint_and_rust_reads_native_freeze ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/pep_client_interop.rs (target/debug/deps/pep_client_interop-7ee84bf880521b84) + +running 7 tests +test native_component_notification_type_applies_to_events_and_subscription_replay ... ok +test missing_own_omemo_bundle_returns_recoverable_item_not_found ... ok +test migrated_native_configuration_can_roundtrip_access_model_edit ... ok +test publish_options_match_implicit_notification_defaults_on_old_nodes ... ok +test avatar_and_omemo_publish_options_support_readback_and_caps_notifications ... ok +test native_itemreply_controls_publisher_visibility_in_reads_and_replays ... ok +test native_open_and_subscriber_publish_models_preserve_outcast_and_blocking_checks ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s + + Running tests/pep_diagnostics.rs (target/debug/deps/pep_diagnostics-4c38fd2757d1f173) + +running 6 tests +test nonempty_xml_can_be_an_empty_android_device_list ... ok +test only_first_direct_item_is_parsed_and_protocols_are_distinct ... ok +test payloadless_notification_is_visible_without_identifiers ... ok +test avatar_classification_does_not_inspect_or_expose_avatar_data ... ok +test arbitrary_node_payload_and_wrong_namespace_do_not_leak ... ok +test signed_integer_limits_and_duplicates_match_java_parser ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/pep_discovery.rs (target/debug/deps/pep_discovery-a7b6920ee431059a) + +running 4 tests +test standalone_component_does_not_claim_pep_automatic_subscriptions ... ok +test account_disco_advertises_pep_without_requiring_a_node ... ok +test account_discovery_does_not_intercept_server_or_resource_caps ... ok +test node_discovery_keeps_node_identity_errors_and_access_checks ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s + + Running tests/pep_item_order.rs (target/debug/deps/pep_item_order-348ec81a9dff89ce) + +running 2 tests +test native_prosody_orders_retained_pep_items_newest_first ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA +test first_pep_item_is_current_device_list_even_with_retained_old_items ... ok + +test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.07s + + Running tests/preauth.rs (target/debug/deps/preauth-93a7965d860c3bfd) + +running 10 tests +test duplicate_or_wrong_namespace_tokens_do_not_qualify ... ok +test unknown_tokens_do_not_create_invite_stores_and_disabled_accounts_cannot_issue ... ok +test standard_adhoc_command_returns_contact_uri ... ok +test prosody_numeric_expiry_is_consumed_and_other_entries_preserved ... ok +test concurrent_redemption_has_exactly_one_winner ... ok +test identity_scope_does_not_burn_on_wrong_sender_or_leak_to_prosody ... ok +test unknown_client_token_is_preserved_on_remote_and_pending_delivery ... ok +test valid_token_autoapproves_and_sends_reciprocal_request ... ok +test invitations_expire_are_single_use_and_owner_scoped ... ok +test local_invitation_updates_both_rosters_without_granting_reverse_subscription ... ok + +test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/preauth_native.rs (target/debug/deps/preauth_native-d3108a41866410e8) + +running 1 test +test native_prosody_invitation_tokens_roundtrip ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/pubsub_native.rs (target/debug/deps/pubsub_native-cf7f3ce57932fb20) + +running 1 test +test native_prosody_pep_reads_rust_and_rust_reads_native ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/pubsub_persistence.rs (target/debug/deps/pubsub_persistence-43f88f67ec488bf6) + +running 18 tests +test native_string_max_items_satisfies_numeric_publish_precondition ... ok +test modern_bookmarks_notify_legacy_capability ... ok +test configurable_limits_component_creation_and_publisher ... ok +test configure_requires_owner ... ok +test capability_discovery_replays_and_filters_notifications ... ok +test open_model_and_notifications ... ok +test nonpersistent_items_stay_in_memory_and_can_be_made_persistent ... ok +test reads_prosody_legacy_fixture ... ok +test full_jid_block_applies_to_reads_subscription_replays_and_events ... ok +test publish_options_conflict_is_recoverable_and_preserves_item ... ok +test pep_persists_namespaces_and_enforces_owner ... ok +test remote_unavailable_is_scoped_to_addressed_owner_and_cancels_pending ... ok +test roster_presence_access_and_foreign_subscription_denied ... ok +test remote_caps_replay_and_open_node_privacy_revoke ... ok +test subscription_options_disable_events_and_require_subscriber ... ok +test native_notification_fields_and_retract_policy_are_independent ... ok +test payload_policy_applies_to_subscription_and_caps_replays ... ok +test component_default_retention_matches_prosody_twenty_items ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s + + Running tests/push.rs (target/debug/deps/push-ccfa1624e569224a) + +running 7 tests +test native_push_body_lookup_excludes_extensions ... ignored, requires PROSODY_REFERENCE_SOURCE and PROSODY_REFERENCE_LUA +test foreign_account_cannot_register ... ok +test queue_coalesces_and_importance_matches_native ... ok +test push_summary_never_copies_foreign_namespace_body ... ok +test stable_client_registration_and_targeted_notification ... ok +test reenable_cancels_old_errors_and_failure_counts_are_per_account ... ok +test registrations_notifications_and_authenticated_errors ... ok + +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.07s + + Running tests/reference_prosody.rs (target/debug/deps/reference_prosody-5f71195b880160bb) + +running 1 test +test real_prosody_storage_and_auth_roundtrip ... ignored, requires native supplied Prosody source; run scripts/prosody_compat/verify.sh + +test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/resource_sessions.rs (target/debug/deps/resource_sessions-59c420101878c0f2) + +running 7 tests +test increment_skips_occupied_suffixes_and_preserves_sessions ... ok +test invalid_resume_owner_or_ack_does_not_evict_active_session ... ok +test kick_new_leaves_existing_session_unchanged ... ok +test random_conflicts_get_distinct_resources_for_same_owner ... ok +test replacement_revokes_hibernating_resume_and_survives_old_cleanup ... ok +test concurrent_default_binds_replace_atomically ... ok +test active_resume_preserves_state_and_replaces_transport_notifier ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/sasl_accounts.rs (target/debug/deps/sasl_accounts-5cc5681e1456081e) + +running 1 test +test disabled_legacy_and_unicode_accounts ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s + + Running tests/session_routing_isolation.rs (target/debug/deps/session_routing_isolation-d75e1e139b68f3ee) + +running 2 tests +test unrelated_busy_session_does_not_block_account_routing_or_carbons_selection ... ok +test duplicate_acknowledgement_does_not_rewrite_durable_slot ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/sm_durable_slots.rs (target/debug/deps/sm_durable_slots-800c006bb74cbd7b) + +running 11 tests +test corrupt_committed_slot_fails_recovery_closed ... ok +test durable_tokens_and_private_pending_output_have_owner_only_permissions ... ok +test session_reference_does_not_keep_store_locked_or_allow_unpersisted_writes ... ok +test recovery_discards_owned_crash_temps_and_keeps_last_committed_slot ... ok +test disconnected_deadline_is_fixed_across_recovery ... ok +test durable_counters_wrap_without_accepting_stale_acknowledgements ... ok +test independent_hubs_with_identical_connection_names_keep_their_own_slots ... ok +test shutdown_freeze_retires_old_transport_before_cleanup ... ok +test restart_restores_owner_presence_and_only_unacknowledged_output ... ok +test graceful_close_conflict_account_purge_and_expiration_remove_tokens ... ok +test store_has_one_process_owner_and_enforces_output_byte_bound ... ok + +test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s + + Running tests/storage_accounts.rs (target/debug/deps/storage_accounts-3218c0ab42cc0ef1) + +running 20 tests +test broken_roster_is_not_overwritten ... ok +test account_purge_refuses_symlink_store_without_touching_other_files ... ok +test inbound_subscription_requires_pending_to_grant_to ... ok +test blocklist_enforcement_api ... ok +test malformed_legacy_vcard_and_private_bookmarks_rejected ... ok +test malformed_roster_iq_never_mutates ... ok +test domain_roster_and_block_jid_normalization ... ok +test private_and_vcard_authorization ... ok +test privacy_migration_only_default_deny_jids ... ok +test roster_empty_name_and_foreign_group_ignored ... ok +test purge_account_exact_files_preserves_others_and_extras ... ok +test reads_timestamp_blocklist_and_keeps_metadata ... ok +test roster_preserves_subscription_and_metadata ... ok +test subscription_handshake_and_cancel ... ok +test legacy_bookmarks_respect_host_limit_and_read_over_256 ... ok +test bookmarks_private_pep_bidirectional_and_private ... ok +test password_change_after_purge_never_recreates_account ... ok +test legacy_migration_clears_source_after_success ... ok +test vcard_pep_conversion_and_avatar ... ok +test creation_and_purge_are_serialized ... ok + +test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.96s + + Running tests/storage_compat.rs (target/debug/deps/storage_compat-1e6be452f95faf27) + +running 6 tests +test empty_namespace_preserved ... ok +test stanza_roundtrip ... ok +test mixed_binary_roundtrip ... ok +test path_and_atomic_update ... ok +test rejects_cycles_code_and_bad_files ... ok +test concurrent_updates_do_not_lose_entries ... ok + +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s + + Running tests/tls_binding.rs (target/debug/deps/tls_binding-3336b59f016514bd) + +running 4 tests +test malformed_der_and_pss_parameters_fail_closed ... ok +test unknown_and_eddsa_algorithms_fail_closed ... ok +test ecdsa_uses_certificate_signature_hash ... ok +test rsa_signature_digest_and_weak_hash_upgrade ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.26s + + Running tests/tls_plus_network.rs (target/debug/deps/tls_plus_network-bd294afb1dab1079) + +running 2 tests +test disabling_plus_hides_bindings_and_accepts_scram_y_with_mechanisms_only_ssdp ... ok +test starttls_scram_plus_binds_real_tls_and_authenticates_ssdp_sasl1_and_sasl2 ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.99s + + Doc-tests rust_xmpp + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Checking rust-xmpp v0.8.2 (/workspace/scratch/362577cdf2e0/recovered/rust-xmpp) + Finished `dev` profile [unoptimized] target(s) in 6.00s + Compiling rust-xmpp v0.8.2 (/workspace/scratch/362577cdf2e0/recovered/rust-xmpp) + Finished `release` profile [optimized] target(s) in 17.65s +PASS: integrated TCP roster/subscriptions, client IQ routing, CSI buffering/keepalive flush, MAM, blocking, OMEMO PEP, MUC, offline replay and SM resumption +PASS: graceful SIGTERM shutdown +PASS: independent SCRAM-SHA-1 over TLS, SASL1/SASL2, SSDP verification, server signatures and wrong-password rejection +PASS: independent SCRAM-SHA-256 over TLS, SASL1/SASL2, SSDP verification, server signatures and wrong-password rejection +PASS: Android TLS1.2 selector, TLS1.2/1.3 SCRAM SHA1/256 PLUS, SASL1/2, SSDP on/off and invalid binding rejection +PASS: JSON file logging, TLS/auth/bind correlation, rejection reasons, secret redaction and SIGHUP rotation +PASS: 20 TLS1.2/1.3 SASL1/2 cases: prepared PLAIN identities and canonical binds, invalid authz rejection, SCRAM abort/retry and active exchange restart +PASS: WSS SCRAM-SHA-256 SASL1/SASL2 with GS2 y, absent CB/PLUS, SSDP without CB separator, server signatures, bind and ping +PASS: HTTPS-only configured interfaces (127.0.0.1,::1), verified TLS, reproduced original Origin 403 then allowed Converse Origin 101, xmpp subprotocol, both WS paths, RFC 7395 open/features/close and private HTTP diagnostics +PASS: custom WS/BOSH routes, default-route 404, exact Origin policy, verified TLS proxy rewrite, trusted HTTPS metadata, untrusted/spoofed metadata denial, IPv6 when available, authenticated WS/BOSH bind/ping in legacy and RFC7239 modes and cached BOSH RID retry +PASS: XEP-0156 XRD/JRD parity, CORS, safe methods, ignored JSONP, host checks, secure URL preference, custom mounts/public prefixes, module and advertisement gates, HTTP fallback and verified WSS framing +PASS: SASL2 Bind2 TLS flow, inline SM/CSI/Carbons, private random resource, malformed requests, authentication failure and fallback +{ + "binary_source": "/workspace/scratch/362577cdf2e0/recovered/rust-xmpp/target/release/rust-xmpp", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "real loopback TCP/STARTTLS/SASL2 Bind2; isolated personal MAM fixture; no production latency claim", + "timing": "raw ordered samples; auth timer starts before authenticate and ends at parsed success; full timer includes TCP/STARTTLS/features; metadata IQ timer runs from send to parsed result", + "result": { + "status": "pass", + "seeded_personal_archive_records": 10000, + "archive_bytes": 2138890, + "archive_expires_after": "never", + "index_present_before_start": false, + "reconnect_samples": 2, + "expected_metadata": { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-9999", + "timestamp": "2026-01-01T02:46:39Z" + } + }, + "observed_metadata": [ + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-9999", + "timestamp": "2026-01-01T02:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-9999", + "timestamp": "2026-01-01T02:46:39Z" + } + } + ], + "mam_metadata_iq": { + "samples_ms": [ + 0.48561099993094103, + 0.3918390000308136 + ], + "median_ms": 0.43872499998087733, + "p95_ms": 0.48561099993094103, + "max_ms": 0.48561099993094103 + }, + "observed_iq_metadata": [ + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-9999", + "timestamp": "2026-01-01T02:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-9999", + "timestamp": "2026-01-01T02:46:39Z" + } + } + ], + "sasl2_bind2_success": { + "samples_ms": [ + 2.1194830001149967, + 2.040264000015668 + ], + "median_ms": 2.0798735000653323, + "p95_ms": 2.1194830001149967, + "max_ms": 2.1194830001149967 + }, + "tcp_starttls_to_bind2_success": { + "samples_ms": [ + 5.600974000117276, + 4.001876000074844 + ], + "median_ms": 4.80142500009606, + "p95_ms": 5.600974000117276, + "max_ms": 5.600974000117276 + } + } +} +PASS: bind2-disabled, SSDP=False, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: bind2-disabled, SSDP=True, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: bind2-enabled, SSDP=False, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: bind2-enabled, SSDP=True, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: sm-disabled, SSDP=False, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: sm-disabled, SSDP=True, SCRAM-SHA-1/PLAIN success and wrong-password rejection +PASS: enabled-False-registration-False +PASS: enabled-False-registration-True +PASS: enabled-True-registration-False +PASS: enabled-True-registration-True +PASS: Gajim domain/account discovery, both label catalogs, authenticated password changes, IBR registration gates and fresh logins +PASS: SASL2 inline SM active/EOF resume, authenticated owner/id/h checks, replay ordering, full JID, Bind2 fallback and malformed requests +PASS: TLS account/domain discovery with PEP and push enabled/disabled; real push enable, publish options, per-node and service-wide disable +PASS: TLS Monocles/Conversations PEP first-run, no-to publishing, owner config recovery, migrated metadata, device item selectors and restart persistence +PASS: Android first-item device-list parsing sees latest publish and replacement before and after restart +PASS: STARTTLS PEP replay/live diagnostics, legacy/OMEMO2, payloadless notifications with intact IQ payloads, and private values excluded +PASS: TLS invitation command discovery, preapproval, single-use mutual roster, replay denial, unknown preauth forwarding/offline pending, account isolation +PASS: STARTTLS MUC SIGTERM restart restores live temporary/persistent rooms, exact full-JID membership, roles, presence and groupchat routing; rejects automatic cross-resource/account claims and nickname theft +PASS: recovery-history +PASS: leave +PASS: kick +PASS: demotion +PASS: password +PASS: configuration +PASS: restart-grace +PASS: custom-grace +PASS: unknown-module +PASS: destroy-tombstone +PASS: actual STARTTLS SIGKILL MUC recovery, history, acknowledged barriers and fixed grace +PASS: TLS legacy/SASL2 durable SM after SIGKILL/SIGTERM, counters, ack pruning, at-least-once pending replay, owner/token/h rejection, transport/resource conflict, MUC activation/offline fanout, grace expiry and account deletion/recreation revocation +{ + "status": "pass", + "recipient_state": "hibernating", + "durable_pending_at_gateway_stream": { + "push-first": true, + "push-second": true + }, + "observation_seconds": 2, + "elapsed_seconds": 2.003336481999895, + "gateway_post_tls_stream_observed": true, + "gateway_post_tls_stream_at_bound": true, + "blocked_stage": "post-tls-features", + "durable_pending": { + "push-first": true, + "push-second": true + }, + "sender_sm_ack_h": [ + 4 + ], + "sender_inputs": 4, + "sender_handled_before": 2, + "binary_version": "rust-xmpp 0.8.2 \u2014 experimental XMPP runtime", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback TLS fixture; stalled external XMPP push service; no APNs/FCM" +} +{ + "status": "pass", + "recipient_state": "offline", + "durable_pending_at_gateway_stream": { + "push-first": true, + "push-second": true + }, + "observation_seconds": 2, + "elapsed_seconds": 2.003422064999995, + "gateway_post_tls_stream_observed": true, + "gateway_post_tls_stream_at_bound": true, + "blocked_stage": "post-tls-features", + "durable_pending": { + "push-first": true, + "push-second": true + }, + "sender_sm_ack_h": [ + 4 + ], + "sender_inputs": 4, + "sender_handled_before": 2, + "binary_version": "rust-xmpp 0.8.2 \u2014 experimental XMPP runtime", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback TLS fixture; stalled external XMPP push service; no APNs/FCM" +} +personal latency: roster=0 csi=default pass +personal latency: roster=0 csi=native pass +{ + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback STARTTLS; fixture only; forced CSI dwell explicitly separated", + "cases": [ + { + "active": { + "delivery": { + "samples": 1, + "median_ms": 5.898467999941204, + "p95_ms": 5.898467999941204, + "max_ms": 5.898467999941204, + "samples_ms": [ + 5.898467999941204 + ] + }, + "sender_sm_handled": { + "samples": 1, + "median_ms": 5.955301000085456, + "p95_ms": 5.955301000085456, + "max_ms": 5.955301000085456, + "samples_ms": [ + 5.955301000085456 + ] + }, + "client_receipt_end_to_end": { + "samples": 1, + "median_ms": 11.52267599991319, + "p95_ms": 11.52267599991319, + "max_ms": 11.52267599991319, + "samples_ms": [ + 11.52267599991319 + ] + }, + "receipt_return_leg": { + "samples": 1, + "median_ms": 5.5240560000129335, + "p95_ms": 5.5240560000129335, + "max_ms": 5.5240560000129335, + "samples_ms": [ + 5.5240560000129335 + ] + } + }, + "inactive": { + "delivery": { + "samples": 1, + "median_ms": 4.9996000000192, + "p95_ms": 4.9996000000192, + "max_ms": 4.9996000000192, + "samples_ms": [ + 4.9996000000192 + ] + }, + "sender_sm_handled": { + "samples": 1, + "median_ms": 5.049544000030437, + "p95_ms": 5.049544000030437, + "max_ms": 5.049544000030437, + "samples_ms": [ + 5.049544000030437 + ] + }, + "client_receipt_end_to_end": { + "samples": 1, + "median_ms": 10.256448000063756, + "p95_ms": 10.256448000063756, + "max_ms": 10.256448000063756, + "samples_ms": [ + 10.256448000063756 + ] + }, + "receipt_return_leg": { + "samples": 1, + "median_ms": 5.164884999885544, + "p95_ms": 5.164884999885544, + "max_ms": 5.164884999885544, + "samples_ms": [ + 5.164884999885544 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 5.4200179999952525, + "sender_sm_handled_ms": 5.149896999910197, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 6.477969000115991, + "sender_sm_handled_ms": 6.528719000016281, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.6012589999027114, + "sender_sm_handled_ms": 2.25184500004616, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2.677618000006987, + "sender_sm_handled_ms": 2.388846000030753, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-active": { + "delivery_ms": 2.8155520001291734, + "sender_sm_handled_ms": 2.5596980001409975, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2.3918289998619002, + "sender_sm_handled_ms": 2.5288639999416773, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-active": { + "delivery_ms": 6.469658000014533, + "sender_sm_handled_ms": 6.071715999951266, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 5.763843999829987, + "sender_sm_handled_ms": 5.498118999867074, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 5.723702000068442, + "sender_sm_handled_ms": 5.800507999992988, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 5.224138999892602, + "sender_sm_handled_ms": 5.269049999924391, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-active": { + "delivery_ms": 4.882467000015822, + "sender_sm_handled_ms": 4.619819000026837, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 5.130316000077073, + "sender_sm_handled_ms": 5.17818499997702, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-active": { + "delivery_ms": 5.376310999963607, + "sender_sm_handled_ms": 5.419898999889483, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 4.4944280000436265, + "sender_sm_handled_ms": 4.538808000006611, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-active": { + "delivery_ms": 2.5788319999264786, + "sender_sm_handled_ms": 2.6217439999527414, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 105.4084539998712, + "sender_sm_handled_ms": 2.466636999997718, + "durably_csi_buffered": true, + "forced_dwell_seconds": 0.1, + "after_activation_ms": 1.2791879998985678 + }, + "sm_backlog": { + "seeded_messages": 30, + "durable_pending_before_sample": 30, + "delivery_ms": 5.419491999873571, + "sender_sm_handled_ms": 5.45745999988867 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 1045, + 1045 + ], + "csi_policy": "default", + "baseline_expect_held": false, + "roster_contacts_per_user": 0, + "seeded_personal_mam_records_per_user": 1000, + "archive_policy": "always" + }, + { + "active": { + "delivery": { + "samples": 1, + "median_ms": 4.6241080001436785, + "p95_ms": 4.6241080001436785, + "max_ms": 4.6241080001436785, + "samples_ms": [ + 4.6241080001436785 + ] + }, + "sender_sm_handled": { + "samples": 1, + "median_ms": 4.675272999975277, + "p95_ms": 4.675272999975277, + "max_ms": 4.675272999975277, + "samples_ms": [ + 4.675272999975277 + ] + }, + "client_receipt_end_to_end": { + "samples": 1, + "median_ms": 11.19549800000641, + "p95_ms": 11.19549800000641, + "max_ms": 11.19549800000641, + "samples_ms": [ + 11.19549800000641 + ] + }, + "receipt_return_leg": { + "samples": 1, + "median_ms": 6.481966999899669, + "p95_ms": 6.481966999899669, + "max_ms": 6.481966999899669, + "samples_ms": [ + 6.481966999899669 + ] + } + }, + "inactive": { + "delivery": { + "samples": 1, + "median_ms": 4.219304999878659, + "p95_ms": 4.219304999878659, + "max_ms": 4.219304999878659, + "samples_ms": [ + 4.219304999878659 + ] + }, + "sender_sm_handled": { + "samples": 1, + "median_ms": 4.188289000012446, + "p95_ms": 4.188289000012446, + "max_ms": 4.188289000012446, + "samples_ms": [ + 4.188289000012446 + ] + }, + "client_receipt_end_to_end": { + "samples": 1, + "median_ms": 8.215965999852415, + "p95_ms": 8.215965999852415, + "max_ms": 8.215965999852415, + "samples_ms": [ + 8.215965999852415 + ] + }, + "receipt_return_leg": { + "samples": 1, + "median_ms": 3.949046999878192, + "p95_ms": 3.949046999878192, + "max_ms": 3.949046999878192, + "samples_ms": [ + 3.949046999878192 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 5.282910000005359, + "sender_sm_handled_ms": 5.250210000212974, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 107.79111700003341, + "sender_sm_handled_ms": 4.669279000154347, + "durably_csi_buffered": true, + "forced_dwell_seconds": 0.1, + "after_activation_ms": 1.295297000069695 + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.3090270001375757, + "sender_sm_handled_ms": 2.27164900002208, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 105.63563399978193, + "sender_sm_handled_ms": 2.5065989998438454, + "durably_csi_buffered": true, + "forced_dwell_seconds": 0.1, + "after_activation_ms": 1.4283949999480683 + }, + "omemo_2_only-active": { + "delivery_ms": 3.0785230001129094, + "sender_sm_handled_ms": 2.815693000002284, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 105.92662799990649, + "sender_sm_handled_ms": 2.6854249999814783, + "durably_csi_buffered": true, + "forced_dwell_seconds": 0.1, + "after_activation_ms": 1.4315339999484422 + }, + "omemo_with_eme-active": { + "delivery_ms": 5.072951000101966, + "sender_sm_handled_ms": 5.133502000035151, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 4.533319999836749, + "sender_sm_handled_ms": 4.182857999921907, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 4.940346000012141, + "sender_sm_handled_ms": 4.9051930000132415, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 107.6849860000948, + "sender_sm_handled_ms": 4.809152999996513, + "durably_csi_buffered": true, + "forced_dwell_seconds": 0.1, + "after_activation_ms": 1.2185890000182553 + }, + "marker_displayed-active": { + "delivery_ms": 6.003739000107089, + "sender_sm_handled_ms": 5.970016999981453, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 108.04682499997398, + "sender_sm_handled_ms": 5.041579999897294, + "durably_csi_buffered": true, + "forced_dwell_seconds": 0.1, + "after_activation_ms": 1.3216969998666173 + }, + "marker_acknowledged-active": { + "delivery_ms": 5.391338000208634, + "sender_sm_handled_ms": 5.359653000141407, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 108.52011399992989, + "sender_sm_handled_ms": 5.426697999837415, + "durably_csi_buffered": true, + "forced_dwell_seconds": 0.1, + "after_activation_ms": 1.4085519999298413 + }, + "low_priority_headline-active": { + "delivery_ms": 2.107198999965476, + "sender_sm_handled_ms": 2.1354900000005728, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 105.84732500001337, + "sender_sm_handled_ms": 2.947453000160749, + "durably_csi_buffered": true, + "forced_dwell_seconds": 0.1, + "after_activation_ms": 1.3171460000194202 + }, + "sm_backlog": { + "seeded_messages": 30, + "durable_pending_before_sample": 30, + "delivery_ms": 4.9609029999828635, + "sender_sm_handled_ms": 4.8794330000418995 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 1045, + 1045 + ], + "csi_policy": "native", + "baseline_expect_held": false, + "roster_contacts_per_user": 0, + "seeded_personal_mam_records_per_user": 1000, + "archive_policy": "always" + } + ] +} +{ + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback STARTTLS; isolated fixture; no production latency claim", + "cases": [ + { + "mam_enabled": false, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 2.207064000003811, + "p95_ms": 2.31560400015951, + "max_ms": 2.31560400015951, + "samples_ms": [ + 2.1327009999367874, + 2.207064000003811, + 2.31560400015951 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 4.342912000083743, + "p95_ms": 4.343500999993921, + "max_ms": 4.343500999993921, + "samples_ms": [ + 4.340781000109928, + 4.342912000083743, + 4.343500999993921 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 3.751291000071433, + "p95_ms": 3.98709000000963, + "max_ms": 3.98709000000963, + "samples_ms": [ + 3.167029999985971, + 3.751291000071433, + 3.98709000000963 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 3.800929000135511, + "p95_ms": 4.058147000023382, + "max_ms": 4.058147000023382, + "samples_ms": [ + 3.213999000081458, + 3.800929000135511, + 4.058147000023382 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 2.1468990000812482, + "p95_ms": 2.2382999998171726, + "max_ms": 2.2382999998171726, + "samples_ms": [ + 2.0623069999601285, + 2.1468990000812482, + 2.2382999998171726 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 4.326573999833272, + "p95_ms": 4.731506000098307, + "max_ms": 4.731506000098307, + "samples_ms": [ + 4.256434000126319, + 4.326573999833272, + 4.731506000098307 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 4.095932000154789, + "p95_ms": 4.202324000061708, + "max_ms": 4.202324000061708, + "samples_ms": [ + 3.922682999927929, + 4.095932000154789, + 4.202324000061708 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 4.158353000093484, + "p95_ms": 4.24932800001443, + "max_ms": 4.24932800001443, + "samples_ms": [ + 3.987202999951478, + 4.158353000093484, + 4.24932800001443 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 3.577008000092974, + "p95_ms": 3.577008000092974, + "max_ms": 3.577008000092974, + "samples_ms": [ + 3.577008000092974 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 0, + "muc_archive_records": 0, + "wire_body_deliveries": 27, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 0, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 4.883541000026526, + "p95_ms": 4.969659000153115, + "max_ms": 4.969659000153115, + "samples_ms": [ + 4.867412000066906, + 4.883541000026526, + 4.969659000153115 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 9.389586999986932, + "p95_ms": 10.380178000104934, + "max_ms": 10.380178000104934, + "samples_ms": [ + 9.35220099995604, + 9.389586999986932, + 10.380178000104934 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 5.294828999922174, + "p95_ms": 5.965621000086685, + "max_ms": 5.965621000086685, + "samples_ms": [ + 5.169418999912523, + 5.294828999922174, + 5.965621000086685 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 5.337166999879628, + "p95_ms": 6.0567010000340815, + "max_ms": 6.0567010000340815, + "samples_ms": [ + 5.2173299998230505, + 5.337166999879628, + 6.0567010000340815 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 5.3765260001910065, + "p95_ms": 5.566310999938651, + "max_ms": 5.566310999938651, + "samples_ms": [ + 4.528385999947204, + 5.3765260001910065, + 5.566310999938651 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 9.84278600003563, + "p95_ms": 10.273650000044654, + "max_ms": 10.273650000044654, + "samples_ms": [ + 8.965130999968096, + 9.84278600003563, + 10.273650000044654 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 4.887700999915978, + "p95_ms": 5.089487999839548, + "max_ms": 5.089487999839548, + "samples_ms": [ + 4.66315499988923, + 4.887700999915978, + 5.089487999839548 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 4.914501000030214, + "p95_ms": 5.114395999953558, + "max_ms": 5.114395999953558, + "samples_ms": [ + 4.6877269999185955, + 4.914501000030214, + 5.114395999953558 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 6.5506310002092505, + "p95_ms": 6.5506310002092505, + "max_ms": 6.5506310002092505, + "samples_ms": [ + 6.5506310002092505 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 26, + "muc_archive_records": 6, + "wire_body_deliveries": 27, + "status": "pass" + }, + { + "mam_enabled": true, + "sm_enabled": true, + "rounds": 3, + "seeded_muc_archive_records": 10000, + "active": { + "direct_peer": { + "samples": 3, + "median_ms": 5.358960999956253, + "p95_ms": 6.358858999874428, + "max_ms": 6.358858999874428, + "samples_ms": [ + 5.166170999927999, + 5.358960999956253, + 6.358858999874428 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 10.897862999854624, + "p95_ms": 12.18967599993448, + "max_ms": 12.18967599993448, + "samples_ms": [ + 10.845436999943558, + 10.897862999854624, + 12.18967599993448 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 4.747507000047335, + "p95_ms": 6.196442999907958, + "max_ms": 6.196442999907958, + "samples_ms": [ + 4.668570000148975, + 4.747507000047335, + 6.196442999907958 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 4.796950000127254, + "p95_ms": 6.22125099994264, + "max_ms": 6.22125099994264, + "samples_ms": [ + 4.721154999970167, + 4.796950000127254, + 6.22125099994264 + ] + } + }, + "inactive": { + "direct_peer": { + "samples": 3, + "median_ms": 5.4617969999526395, + "p95_ms": 5.527729000050385, + "max_ms": 5.527729000050385, + "samples_ms": [ + 5.247237000048699, + 5.4617969999526395, + 5.527729000050385 + ] + }, + "direct_application_rtt": { + "samples": 3, + "median_ms": 10.389861000021483, + "p95_ms": 10.755525999911697, + "max_ms": 10.755525999911697, + "samples_ms": [ + 10.168332000148439, + 10.389861000021483, + 10.755525999911697 + ] + }, + "muc_sender_echo": { + "samples": 3, + "median_ms": 4.754735000005894, + "p95_ms": 4.782060000025012, + "max_ms": 4.782060000025012, + "samples_ms": [ + 4.514305999919088, + 4.754735000005894, + 4.782060000025012 + ] + }, + "muc_peer": { + "samples": 3, + "median_ms": 4.8038820000329, + "p95_ms": 4.83561600003668, + "max_ms": 4.83561600003668, + "samples_ms": [ + 4.5686299999943, + 4.8038820000329, + 4.83561600003668 + ] + } + }, + "urgent_flush": { + "samples": 1, + "median_ms": 6.587177000028532, + "p95_ms": 6.587177000028532, + "max_ms": 6.587177000028532, + "samples_ms": [ + 6.587177000028532 + ] + }, + "headline_durably_buffered": true, + "activation_drained_queue": true, + "personal_archive_records": 26, + "muc_archive_records": 10006, + "wire_body_deliveries": 27, + "status": "pass" + } + ] +} +PASS: TLS conflict_resolve=default, live and hibernating SM resources +PASS: TLS conflict_resolve=kick_old, live and hibernating SM resources +PASS: TLS conflict_resolve=kick_new, live and hibernating SM resources +PASS: TLS conflict_resolve=increment, live and hibernating SM resources +PASS: TLS conflict_resolve=random, live and hibernating SM resources +PASS: integrated WSS + HTTPS BOSH SASL/bind, CSI, inherited BOSH namespaces, roster, bidirectional chat, upload IQ/PUT/GET/reuse, graceful SM close and same-resource relogin under kick_new +PASS: integrated WSS + HTTPS BOSH SASL/bind, CSI, inherited BOSH namespaces, roster, bidirectional chat, upload IQ/PUT/GET/reuse, graceful SM close and same-resource relogin under kick_new +PASS: configured upload HTTP path with $host through integrated listener +PASS: multiple upload hosts/shared-host paths, discovery, quotas, JWT isolation, persistence, transport composition and conflict validation +PASS upload S3 protocol fixture: SigV4, multipart, abort, range, restart, expiry and backend isolation +PASS upload migration: local -> S3 -> S3 -> local, hashes, original URLs/JWT/HEAD, lock, dry-run, fail-closed resume +{ + "total_load_wall_seconds": 11.197, + "requested_resources": 500, + "authenticated_bound_resources": 500, + "connection_setup_concurrency": 50, + "setup_wall_seconds": 0.769, + "setup_latency": { + "samples": 500, + "median_ms": 72.064, + "p95_ms": 102.309, + "max_ms": 112.205 + }, + "ping_rounds": 10, + "ping_round_trip": { + "samples": 5000, + "median_ms": 12.125, + "p95_ms": 32.772, + "max_ms": 37.617 + }, + "accounts": 100, + "message_rounds": 10, + "messages_sent": 5000, + "messages_received": 5000, + "message_batch_seconds": 8.136, + "metrics_before": { + "rss_kib": 8448, + "cpu_seconds": 0.0, + "fd_count": 11 + }, + "metrics_connected": { + "rss_kib": 27268, + "cpu_seconds": 1.43, + "fd_count": 511 + }, + "metrics_after_workload": { + "rss_kib": 27876, + "cpu_seconds": 15.05, + "fd_count": 511 + }, + "metrics_two_seconds_after_disconnect": { + "rss_kib": 27636, + "cpu_seconds": 15.11, + "fd_count": 11 + }, + "sampled_peak_rss_kib": 28004, + "fd_delta_after_disconnect": 0, + "failures": [], + "scope": "One loopback host, 100 accounts with distinct resources, TLS+PLAIN, ping and directed messages; not a production benchmark or proof of no memory leaks.", + "mam": { + "archive_files": 100, + "records": 10000, + "expected_records": 10000 + } +} +MUC+SM load: connected (2.918s) +MUC+SM load: joined (33.295s) +MUC+SM load: fanout_verified (39.991s) +MUC+SM load: before_sigkill (42.259s) +{ + "clients": 500, + "accounts": 100, + "rooms": 10, + "message_rounds": 3, + "concurrency": 20, + "binary": "/tmp/xmpp-durable-muc-load-qywt10tu/rust-xmpp", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "before": { + "rss_kib": 9548, + "cpu_seconds": 0.0, + "fd_count": 12 + }, + "connect_seconds": 2.918, + "connect_latency": { + "samples": 500, + "median_ms": 114.756, + "p95_ms": 154.077, + "max_ms": 206.971 + }, + "phase": "completed", + "status": "pass", + "elapsed_seconds": 45.54, + "join_seconds": 30.37, + "joined": { + "rss_kib": 41856, + "cpu_seconds": 16.64, + "fd_count": 514 + }, + "join_presence_deliveries": 25000, + "slots_joined": { + "count": 500, + "bytes": 309790 + }, + "message_seconds": 6.696, + "room_messages_sent": 30, + "room_messages_delivered": 1500, + "before_kill": { + "rss_kib": 41884, + "cpu_seconds": 20.77, + "fd_count": 512 + }, + "slots_before_kill": { + "count": 500, + "bytes": 514030 + }, + "restart_seconds": 2.763, + "resumed_resources": 10, + "replayed_pending_room_messages": 10, + "membership_groupchat_deliveries_after_resume": 10, + "after_resume": { + "rss_kib": 20984, + "cpu_seconds": 2.66, + "fd_count": 22 + }, + "slots_after_resume": { + "count": 500, + "bytes": 671070 + }, + "total_seconds": 45.54, + "peak_rss_kib": 41920 +} + Finished `test` profile [unoptimized] target(s) in 0.08s + Running tests/csi_native.rs (target/debug/deps/csi_native-5df50c44655375cc) + +running 1 test +test native_prosody_csi_importance_matches ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s + + Running tests/muc_native.rs (target/debug/deps/muc_native-3166df0798e2ca45) + +running 1 test +test actual_prosody_muc_mam_reads_rust_and_writes_native_archive ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s + + Running tests/muc_state_native.rs (target/debug/deps/muc_state_native-7ba549656d076f8e) + +running 1 test +test actual_prosody_restores_rust_checkpoint_and_rust_reads_native_freeze ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s + + Running tests/pep_item_order.rs (target/debug/deps/pep_item_order-348ec81a9dff89ce) + +running 1 test +test native_prosody_orders_retained_pep_items_newest_first ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.10s + + Running tests/preauth_native.rs (target/debug/deps/preauth_native-d3108a41866410e8) + +running 1 test +test native_prosody_invitation_tokens_roundtrip ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.11s + + Running tests/pubsub_native.rs (target/debug/deps/pubsub_native-cf7f3ce57932fb20) + +running 1 test +test native_prosody_pep_reads_rust_and_rust_reads_native ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s + + Running tests/push.rs (target/debug/deps/push-ccfa1624e569224a) + +running 1 test +test native_push_body_lookup_excludes_extensions ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.01s + + Running tests/reference_prosody.rs (target/debug/deps/reference_prosody-5f71195b880160bb) + +running 1 test +PROSODY_NATIVE_ROUNDTRIP_OK SHA-1 +PROSODY_NATIVE_FINAL_OK SHA-1 +PROSODY_NATIVE_ROUNDTRIP_OK SHA-256 +PROSODY_NATIVE_FINAL_OK SHA-256 +test real_prosody_storage_and_auth_roundtrip ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.76s + + Finished `test` profile [unoptimized] target(s) in 0.08s + Running tests/federation_tls.rs (target/debug/deps/federation_tls-915bcd4fb11fa78e) + +running 1 test +test native_prosody_tls_external_bidirectional ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.98s + diff --git a/docs/validation-results-0.8.0.json b/docs/validation-results-0.8.0.json new file mode 100644 index 0000000..76873a5 --- /dev/null +++ b/docs/validation-results-0.8.0.json @@ -0,0 +1,88 @@ +{ + "version": "0.8.0", + "date_utc": "2026-10-20", + "ordinary_tests": { + "passed": 293, + "failed": 0, + "ignored": 11 + }, + "fmt": "passed", + "clippy": "passed", + "release": "passed", + "release_binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "native_module_tests": 8, + "native_federation_tests": 1, + "muc_crash_network": "passed: real TLS, SIGKILL, temporary/persistent rooms, multiple resources, saved presence/roles, ordered history, acknowledged leave/kick/demotion/password/config, fixed grace, unsupported module rejection; destroy/tombstone separate log", + "sm_restart_network": "passed: SIGKILL/SIGTERM, legacy/SASL2, counter/replay/ack pruning, owner/token/h isolation, resource conflict, account deletion/recreation revocation, MUC offline fanout durable before recipient authentication", + "muc_sm_load": { + "clients": 500, + "accounts": 100, + "rooms": 10, + "message_rounds": 3, + "concurrency": 20, + "binary": "/tmp/xmpp-durable-muc-load-g0crm4ik/rust-xmpp", + "binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "before": { + "rss_kib": 9696, + "cpu_seconds": 0.0, + "fd_count": 12 + }, + "connect_seconds": 5.193, + "connect_latency": { + "samples": 500, + "median_ms": 204.391, + "p95_ms": 270.035, + "max_ms": 332.503 + }, + "phase": "completed", + "status": "pass", + "elapsed_seconds": 78.857, + "join_seconds": 46.703, + "joined": { + "rss_kib": 42248, + "cpu_seconds": 17.77, + "fd_count": 513 + }, + "join_presence_deliveries": 25000, + "slots_joined": { + "count": 500, + "bytes": 309790 + }, + "message_seconds": 10.861, + "room_messages_sent": 30, + "room_messages_delivered": 1500, + "before_kill": { + "rss_kib": 42128, + "cpu_seconds": 23.12, + "fd_count": 514 + }, + "slots_before_kill": { + "count": 500, + "bytes": 514030 + }, + "restart_seconds": 10.559, + "resumed_resources": 10, + "replayed_pending_room_messages": 10, + "membership_groupchat_deliveries_after_resume": 10, + "after_resume": { + "rss_kib": 21168, + "cpu_seconds": 5.03, + "fd_count": 23 + }, + "slots_after_resume": { + "count": 500, + "bytes": 671070 + }, + "total_seconds": 78.857, + "peak_rss_kib": 42252 + }, + "upload": "S3 fixture/migration/network regression passed; large 10GiB transfer retained as historical0.7.9 validation, not repeated0.8.0", + "limitations": [ + "New TLS/SASL connection required; TCP/TLS sockets cannot survive process exit", + "At-least-once SM replay, not cross-store/network exactly-once transaction", + "Known builtin MUC features ported; arbitrary community Lua modules not executed", + "Private durable SM format is Rust-specific, bounded queues and component checkpoint; see MUC-RECOVERY.md", + "Loopback smoke tests, not production capacity or real client qualification", + "Full Prosody parity remains subject to COMPATIBILITY.md" + ] +} diff --git a/docs/validation-results-0.8.1.json b/docs/validation-results-0.8.1.json new file mode 100644 index 0000000..7af8591 --- /dev/null +++ b/docs/validation-results-0.8.1.json @@ -0,0 +1,190 @@ +{ + "version": "0.8.1", + "date_utc": "2026-10-21", + "ordinary_tests": { + "passed": 297, + "failed": 0, + "ignored": 11 + }, + "fmt": "passed", + "clippy": "passed", + "release": "passed", + "release_binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "native_module_tests": 8, + "native_federation_tests": 1, + "full_verify": "passed in single final run with native and both500-client loads", + "message_latency": { + "scope": "loopback STARTTLS; isolated fixture; no production latency claim", + "before_binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "after_binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "muc_history_records": 100000, + "rounds_per_state": 3, + "active_before": { + "samples": 3, + "median_ms": 2517.9402029999665, + "p95_ms": 2520.940784000004, + "max_ms": 2520.940784000004, + "samples_ms": [ + 2502.2604349999256, + 2517.9402029999665, + 2520.940784000004 + ] + }, + "active_after": { + "samples": 3, + "median_ms": 4.680227999983799, + "p95_ms": 14.532127000052242, + "max_ms": 14.532127000052242, + "samples_ms": [ + 4.40479399992455, + 4.680227999983799, + 14.532127000052242 + ] + }, + "inactive_before": { + "samples": 3, + "median_ms": 3866.027479999957, + "p95_ms": 4150.866962999999, + "max_ms": 4150.866962999999, + "samples_ms": [ + 2901.4587140000003, + 3866.027479999957, + 4150.866962999999 + ] + }, + "inactive_after": { + "samples": 3, + "median_ms": 4.284876000042459, + "p95_ms": 5.071866999969643, + "max_ms": 5.071866999969643, + "samples_ms": [ + 4.257245000076182, + 4.284876000042459, + 5.071866999969643 + ] + } + }, + "general_load": { + "total_load_wall_seconds": 8.892, + "requested_resources": 500, + "authenticated_bound_resources": 500, + "connection_setup_concurrency": 50, + "setup_wall_seconds": 0.646, + "setup_latency": { + "samples": 500, + "median_ms": 60.166, + "p95_ms": 81.981, + "max_ms": 105.233 + }, + "ping_rounds": 10, + "ping_round_trip": { + "samples": 5000, + "median_ms": 10.879, + "p95_ms": 21.103, + "max_ms": 23.338 + }, + "accounts": 100, + "message_rounds": 10, + "messages_sent": 5000, + "messages_received": 5000, + "message_batch_seconds": 6.009, + "metrics_before": { + "rss_kib": 8412, + "cpu_seconds": 0.0, + "fd_count": 11 + }, + "metrics_connected": { + "rss_kib": 27472, + "cpu_seconds": 1.09, + "fd_count": 511 + }, + "metrics_after_workload": { + "rss_kib": 28176, + "cpu_seconds": 11.23, + "fd_count": 511 + }, + "metrics_two_seconds_after_disconnect": { + "rss_kib": 28240, + "cpu_seconds": 11.27, + "fd_count": 11 + }, + "sampled_peak_rss_kib": 28240, + "fd_delta_after_disconnect": 0, + "failures": [], + "scope": "One loopback host, 100 accounts with distinct resources, TLS+PLAIN, ping and directed messages; not a production benchmark or proof of no memory leaks.", + "mam": { + "archive_files": 100, + "records": 10000, + "expected_records": 10000 + } + }, + "muc_sm_load": { + "clients": 500, + "accounts": 100, + "rooms": 10, + "message_rounds": 3, + "concurrency": 20, + "binary": "/tmp/xmpp-durable-muc-load-p95vsvii/rust-xmpp", + "binary_sha256": "c57757476f2019c60ac877e4a66364b17283218e3cc244ae3f29cde1d3be2977", + "before": { + "rss_kib": 10076, + "cpu_seconds": 0.0, + "fd_count": 12 + }, + "connect_seconds": 3.149, + "connect_latency": { + "samples": 500, + "median_ms": 121.817, + "p95_ms": 169.081, + "max_ms": 257.299 + }, + "phase": "completed", + "status": "pass", + "elapsed_seconds": 39.535, + "join_seconds": 25.54, + "joined": { + "rss_kib": 42224, + "cpu_seconds": 14.41, + "fd_count": 512 + }, + "join_presence_deliveries": 25000, + "slots_joined": { + "count": 500, + "bytes": 309790 + }, + "message_seconds": 5.504, + "room_messages_sent": 30, + "room_messages_delivered": 1500, + "before_kill": { + "rss_kib": 42224, + "cpu_seconds": 17.88, + "fd_count": 512 + }, + "slots_before_kill": { + "count": 500, + "bytes": 514030 + }, + "restart_seconds": 2.962, + "resumed_resources": 10, + "replayed_pending_room_messages": 10, + "membership_groupchat_deliveries_after_resume": 10, + "after_resume": { + "rss_kib": 20796, + "cpu_seconds": 2.81, + "fd_count": 22 + }, + "slots_after_resume": { + "count": 500, + "bytes": 671070 + }, + "total_seconds": 39.535, + "peak_rss_kib": 42240 + }, + "large_upload": "10GiB not repeated in0.8.1; S3 fixture/migration/network regression passed; historical0.7.8/0.7.9 reports retained", + "limitations": [ + "Loopback timing, not production SLA or real client qualification", + "Required disk synchronization remains, at-least-once SM replay", + "Periodic archive maintenance and large MAM queries still perform archive IO", + "Full Prosody compatibility and production deployment not asserted; see COMPATIBILITY.md" + ] +} diff --git a/docs/validation-results.json b/docs/validation-results.json index 76873a5..715eb62 100644 --- a/docs/validation-results.json +++ b/docs/validation-results.json @@ -1,88 +1,1694 @@ { - "version": "0.8.0", - "date_utc": "2026-10-20", + "version": "0.8.2", + "date_utc": "2026-10-21", "ordinary_tests": { - "passed": 293, + "passed": 305, "failed": 0, "ignored": 11 }, "fmt": "passed", "clippy": "passed", "release": "passed", - "release_binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "release_binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", "native_module_tests": 8, "native_federation_tests": 1, - "muc_crash_network": "passed: real TLS, SIGKILL, temporary/persistent rooms, multiple resources, saved presence/roles, ordered history, acknowledged leave/kick/demotion/password/config, fixed grace, unsupported module rejection; destroy/tombstone separate log", - "sm_restart_network": "passed: SIGKILL/SIGTERM, legacy/SASL2, counter/replay/ack pruning, owner/token/h isolation, resource conflict, account deletion/recreation revocation, MUC offline fanout durable before recipient authentication", + "full_verify": "passed in one final run including both500-client loads and allnewquicknetworkregressions", + "personal_message_latency": { + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback STARTTLS; fixture only; forced CSI dwell explicitly separated", + "cases": [ + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 9.934385999940787, + "p95_ms": 26.116932000149973, + "max_ms": 26.116932000149973, + "samples_ms": [ + 7.292991999975129, + 9.934385999940787, + 26.116932000149973 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 9.88499300001422, + "p95_ms": 26.069592000112607, + "max_ms": 26.069592000112607, + "samples_ms": [ + 7.199500000069747, + 9.88499300001422, + 26.069592000112607 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 18.881290000081208, + "p95_ms": 32.769330000064656, + "max_ms": 32.769330000064656, + "samples_ms": [ + 14.889820999997028, + 18.881290000081208, + 32.769330000064656 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 7.525431999965804, + "p95_ms": 8.887985999990633, + "max_ms": 8.887985999990633, + "samples_ms": [ + 6.574537000005876, + 7.525431999965804, + 8.887985999990633 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 7.353217999934714, + "p95_ms": 7.73648599988519, + "max_ms": 7.73648599988519, + "samples_ms": [ + 7.3501320000559645, + 7.353217999934714, + 7.73648599988519 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 7.314217999919492, + "p95_ms": 7.696787999975641, + "max_ms": 7.696787999975641, + "samples_ms": [ + 7.308291999834182, + 7.314217999919492, + 7.696787999975641 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 16.435919999821635, + "p95_ms": 16.575810999938767, + "max_ms": 16.575810999938767, + "samples_ms": [ + 13.911000999996759, + 16.435919999821635, + 16.575810999938767 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 8.640340999818363, + "p95_ms": 9.163700000044628, + "max_ms": 9.163700000044628, + "samples_ms": [ + 6.498096000086662, + 8.640340999818363, + 9.163700000044628 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 7.020568999905663, + "sender_sm_handled_ms": 6.979878000038298, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 7.3571890000039275, + "sender_sm_handled_ms": 7.423431999995955, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-active": { + "delivery_ms": 5.90487999988909, + "sender_sm_handled_ms": 5.856321000010212, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 4.060041999991881, + "sender_sm_handled_ms": 3.603028000043196, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-active": { + "delivery_ms": 4.710215000159224, + "sender_sm_handled_ms": 4.808065000133865, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 3.6635650001244358, + "sender_sm_handled_ms": 3.289268000116863, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-active": { + "delivery_ms": 12.312145000123564, + "sender_sm_handled_ms": 12.042657999927542, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 11.414976999958526, + "sender_sm_handled_ms": 11.446671000157949, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 4.6950840001045435, + "sender_sm_handled_ms": 4.662712000026659, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 5.844635999892489, + "sender_sm_handled_ms": 5.903024999952322, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-active": { + "delivery_ms": 6.98627899987514, + "sender_sm_handled_ms": 6.9448439999177936, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 7.439451999971425, + "sender_sm_handled_ms": 7.503360000100656, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-active": { + "delivery_ms": 16.166666000117402, + "sender_sm_handled_ms": 16.096403000119608, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 8.581391999996413, + "sender_sm_handled_ms": 8.542475000012928, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-active": { + "delivery_ms": 3.829828000107227, + "sender_sm_handled_ms": 3.327058999957444, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2017.080266999983, + "sender_sm_handled_ms": 3.2593890000498504, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 9.675382000068566 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 6.670822999922166, + "sender_sm_handled_ms": 6.573753000111537 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "default", + "baseline_expect_held": false, + "roster_contacts_per_user": 0, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "always" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 7.09640600007333, + "p95_ms": 19.445947999884083, + "max_ms": 19.445947999884083, + "samples_ms": [ + 5.935086999897976, + 7.09640600007333, + 19.445947999884083 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 7.064623999895048, + "p95_ms": 19.50181399979556, + "max_ms": 19.50181399979556, + "samples_ms": [ + 5.811342000015429, + 7.064623999895048, + 19.50181399979556 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 13.734022999869921, + "p95_ms": 24.49354800000947, + "max_ms": 24.49354800000947, + "samples_ms": [ + 12.908389999893188, + 13.734022999869921, + 24.49354800000947 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 6.591360999891549, + "p95_ms": 6.944055999838383, + "max_ms": 6.944055999838383, + "samples_ms": [ + 4.945848000033948, + 6.591360999891549, + 6.944055999838383 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 7.593367999788825, + "p95_ms": 11.505353000075047, + "max_ms": 11.505353000075047, + "samples_ms": [ + 6.660383000053116, + 7.593367999788825, + 11.505353000075047 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 7.272773999829951, + "p95_ms": 11.469916000123703, + "max_ms": 11.469916000123703, + "samples_ms": [ + 6.7844489999515645, + 7.272773999829951, + 11.469916000123703 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 14.649553999788623, + "p95_ms": 23.104979999970965, + "max_ms": 23.104979999970965, + "samples_ms": [ + 13.741463999849657, + 14.649553999788623, + 23.104979999970965 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 7.024535999789805, + "p95_ms": 11.512823999964894, + "max_ms": 11.512823999964894, + "samples_ms": [ + 6.917227999792885, + 7.024535999789805, + 11.512823999964894 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 11.159964999933436, + "sender_sm_handled_ms": 10.724457999913284, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2027.1901230000822, + "sender_sm_handled_ms": 16.822652999962884, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 4.099048000171024 + }, + "omemo_legacy_only-active": { + "delivery_ms": 3.2380130001001817, + "sender_sm_handled_ms": 3.3119140000508196, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2007.7756410000802, + "sender_sm_handled_ms": 2.5553959999342624, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.355625000087457 + }, + "omemo_2_only-active": { + "delivery_ms": 2.5906000000759377, + "sender_sm_handled_ms": 2.6901890000772255, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2007.8129270000318, + "sender_sm_handled_ms": 2.521771000147055, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.5775889999076753 + }, + "omemo_with_eme-active": { + "delivery_ms": 4.35501399988425, + "sender_sm_handled_ms": 4.417945999875883, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 4.823192000003473, + "sender_sm_handled_ms": 4.498243000170987, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 4.931894000037573, + "sender_sm_handled_ms": 5.009728000004543, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 2010.9646770001746, + "sender_sm_handled_ms": 5.511606000027314, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.7539110001507652 + }, + "marker_displayed-active": { + "delivery_ms": 4.515692000040872, + "sender_sm_handled_ms": 4.570190000094954, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 2010.8637490000092, + "sender_sm_handled_ms": 4.831804000104967, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.418779999970866 + }, + "marker_acknowledged-active": { + "delivery_ms": 5.429266999954052, + "sender_sm_handled_ms": 5.485873999987234, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 2010.9519340001043, + "sender_sm_handled_ms": 5.667000000130429, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.6569639999488572 + }, + "low_priority_headline-active": { + "delivery_ms": 2.6243269999213226, + "sender_sm_handled_ms": 2.6806579999174573, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2013.0899620000946, + "sender_sm_handled_ms": 3.175567999960549, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 5.7868270000653865 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 4.632757999843307, + "sender_sm_handled_ms": 4.711322999810363 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "native", + "baseline_expect_held": false, + "roster_contacts_per_user": 0, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "always" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 20.33114999994723, + "p95_ms": 31.98645999987093, + "max_ms": 31.98645999987093, + "samples_ms": [ + 20.288011000047845, + 20.33114999994723, + 31.98645999987093 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 20.34745700007079, + "p95_ms": 32.04224299997804, + "max_ms": 32.04224299997804, + "samples_ms": [ + 20.195752000063294, + 20.34745700007079, + 32.04224299997804 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 40.47510100008367, + "p95_ms": 51.530768999782595, + "max_ms": 51.530768999782595, + "samples_ms": [ + 39.586511999914364, + 40.47510100008367, + 51.530768999782595 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 19.449356999984957, + "p95_ms": 20.07229100013319, + "max_ms": 20.07229100013319, + "samples_ms": [ + 19.222442999989653, + 19.449356999984957, + 20.07229100013319 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 19.866232999902422, + "p95_ms": 19.99418900004457, + "max_ms": 19.99418900004457, + "samples_ms": [ + 18.697023999948215, + 19.866232999902422, + 19.99418900004457 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 19.92523299986715, + "p95_ms": 20.051580000199465, + "max_ms": 20.051580000199465, + "samples_ms": [ + 18.734036999831005, + 19.92523299986715, + 20.051580000199465 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 39.72956699999486, + "p95_ms": 39.851432999967074, + "max_ms": 39.851432999967074, + "samples_ms": [ + 37.525556999980836, + 39.72956699999486, + 39.851432999967074 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 19.628184999874065, + "p95_ms": 19.861294000065755, + "max_ms": 19.861294000065755, + "samples_ms": [ + 18.7452420000227, + 19.628184999874065, + 19.861294000065755 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 19.35876399988956, + "sender_sm_handled_ms": 19.39277399992534, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 20.21448599998621, + "sender_sm_handled_ms": 20.265132000076846, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.3836280001887644, + "sender_sm_handled_ms": 2.4238510000031965, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2.801203999979407, + "sender_sm_handled_ms": 2.362454000149228, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-active": { + "delivery_ms": 2.5594769999770506, + "sender_sm_handled_ms": 2.297387999988132, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2.6781149999806075, + "sender_sm_handled_ms": 2.738028000067061, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-active": { + "delivery_ms": 22.61464299999716, + "sender_sm_handled_ms": 22.67238699982954, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 18.439037000007374, + "sender_sm_handled_ms": 18.469434000053297, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 19.863233999785734, + "sender_sm_handled_ms": 19.831823999993503, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 20.1924399998461, + "sender_sm_handled_ms": 20.24753899991083, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-active": { + "delivery_ms": 18.414425999935702, + "sender_sm_handled_ms": 18.46614800001589, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 19.89041999991059, + "sender_sm_handled_ms": 20.036751999896296, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-active": { + "delivery_ms": 21.71829600001729, + "sender_sm_handled_ms": 21.777248000034888, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 22.17192300008719, + "sender_sm_handled_ms": 22.221732000161865, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-active": { + "delivery_ms": 2.7961150001374335, + "sender_sm_handled_ms": 2.8303950000463374, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2007.8849290000562, + "sender_sm_handled_ms": 2.1910489999754645, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.9039710000470222 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 49.80743399983112, + "sender_sm_handled_ms": 50.571967999985645 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "default", + "baseline_expect_held": false, + "roster_contacts_per_user": 5000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 19.69621900002494, + "p95_ms": 42.19270699991284, + "max_ms": 42.19270699991284, + "samples_ms": [ + 19.40504599997439, + 19.69621900002494, + 42.19270699991284 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 19.74441700008356, + "p95_ms": 42.227931000070384, + "max_ms": 42.227931000070384, + "samples_ms": [ + 19.43559999995159, + 19.74441700008356, + 42.227931000070384 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 44.52753300006407, + "p95_ms": 75.65286299995932, + "max_ms": 75.65286299995932, + "samples_ms": [ + 42.811708000044746, + 44.52753300006407, + 75.65286299995932 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 25.051753000070676, + "p95_ms": 33.38162399995781, + "max_ms": 33.38162399995781, + "samples_ms": [ + 23.028330999977698, + 25.051753000070676, + 33.38162399995781 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 42.020123999918724, + "p95_ms": 47.60321899993869, + "max_ms": 47.60321899993869, + "samples_ms": [ + 27.62041099981616, + 42.020123999918724, + 47.60321899993869 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 41.989471999841044, + "p95_ms": 47.52414699987639, + "max_ms": 47.52414699987639, + "samples_ms": [ + 27.66665999979523, + 41.989471999841044, + 47.52414699987639 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 65.51842899989424, + "p95_ms": 68.45925399989028, + "max_ms": 68.45925399989028, + "samples_ms": [ + 57.403068999974494, + 65.51842899989424, + 68.45925399989028 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 23.450656000022718, + "p95_ms": 29.673266000145304, + "max_ms": 29.673266000145304, + "samples_ms": [ + 20.829446999869106, + 23.450656000022718, + 29.673266000145304 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 34.73295300000245, + "sender_sm_handled_ms": 34.78218899999774, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2059.095004000028, + "sender_sm_handled_ms": 52.21434100008082, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.3442760000307317 + }, + "omemo_legacy_only-active": { + "delivery_ms": 2.289026999960697, + "sender_sm_handled_ms": 2.3513429998729407, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2009.0180530000907, + "sender_sm_handled_ms": 3.837167000028785, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4215010000953043 + }, + "omemo_2_only-active": { + "delivery_ms": 4.889154000011331, + "sender_sm_handled_ms": 4.845507000027283, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2008.3065920000536, + "sender_sm_handled_ms": 3.9267600000130187, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4437199999974837 + }, + "omemo_with_eme-active": { + "delivery_ms": 21.84222599998975, + "sender_sm_handled_ms": 21.90294799993353, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 19.991322999885597, + "sender_sm_handled_ms": 20.052289999966888, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 18.39728599998125, + "sender_sm_handled_ms": 18.452361000072415, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 2023.2745979999436, + "sender_sm_handled_ms": 18.036617000007027, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.5344959999765706 + }, + "marker_displayed-active": { + "delivery_ms": 26.334099999985483, + "sender_sm_handled_ms": 26.397696000003634, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 2026.6623259999506, + "sender_sm_handled_ms": 21.236640999859446, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.6908580000745133 + }, + "marker_acknowledged-active": { + "delivery_ms": 25.270920999901136, + "sender_sm_handled_ms": 25.33230399990316, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 2024.7716760000003, + "sender_sm_handled_ms": 19.67220400001679, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4173909999044554 + }, + "low_priority_headline-active": { + "delivery_ms": 2.4848110001585155, + "sender_sm_handled_ms": 2.5410260000171547, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2009.189195999852, + "sender_sm_handled_ms": 3.168506000065463, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.8620499999997264 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 18.413032999887946, + "sender_sm_handled_ms": 18.463912000015625 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "native", + "baseline_expect_held": false, + "roster_contacts_per_user": 5000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 44.51364500005184, + "p95_ms": 45.964571000013166, + "max_ms": 45.964571000013166, + "samples_ms": [ + 34.22456300017984, + 44.51364500005184, + 45.964571000013166 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 44.59098000006634, + "p95_ms": 46.02178000004642, + "max_ms": 46.02178000004642, + "samples_ms": [ + 34.27662300009615, + 44.59098000006634, + 46.02178000004642 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 78.4022109999114, + "p95_ms": 84.20188900004177, + "max_ms": 84.20188900004177, + "samples_ms": [ + 69.01028000015685, + 78.4022109999114, + 84.20188900004177 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 34.68925800007128, + "p95_ms": 38.13306400002148, + "max_ms": 38.13306400002148, + "samples_ms": [ + 33.770842999956585, + 34.68925800007128, + 38.13306400002148 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 34.21878900007869, + "p95_ms": 43.838538000045446, + "max_ms": 43.838538000045446, + "samples_ms": [ + 33.93446700010827, + 34.21878900007869, + 43.838538000045446 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 34.27054200005841, + "p95_ms": 43.7583899999936, + "max_ms": 43.7583899999936, + "samples_ms": [ + 33.985251000103744, + 34.27054200005841, + 43.7583899999936 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 76.79010300012123, + "p95_ms": 82.84399400008624, + "max_ms": 82.84399400008624, + "samples_ms": [ + 69.896123000035, + 76.79010300012123, + 82.84399400008624 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 38.97644600010608, + "p95_ms": 42.48225700007424, + "max_ms": 42.48225700007424, + "samples_ms": [ + 35.87241099990024, + 38.97644600010608, + 42.48225700007424 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 34.985323999990214, + "sender_sm_handled_ms": 35.049269999944954, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 35.55981799991059, + "sender_sm_handled_ms": 35.26781599998685, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-active": { + "delivery_ms": 3.1153810000432713, + "sender_sm_handled_ms": 2.836314999967726, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 3.5253139999440464, + "sender_sm_handled_ms": 3.246257999990121, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-active": { + "delivery_ms": 2.6683359999424283, + "sender_sm_handled_ms": 2.73817299989787, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2.579258999958256, + "sender_sm_handled_ms": 2.6347149998855457, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-active": { + "delivery_ms": 35.76059600004555, + "sender_sm_handled_ms": 35.81379399997786, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 34.746401000120386, + "sender_sm_handled_ms": 34.470927000029405, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 35.26329699980124, + "sender_sm_handled_ms": 35.22362599983353, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 40.00390000010157, + "sender_sm_handled_ms": 40.05440700007057, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-active": { + "delivery_ms": 34.927564000099665, + "sender_sm_handled_ms": 35.009467000008954, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 34.24647799988634, + "sender_sm_handled_ms": 34.29243499999757, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-active": { + "delivery_ms": 41.09236700014662, + "sender_sm_handled_ms": 40.82514500009893, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 36.06466299993372, + "sender_sm_handled_ms": 36.11676799982888, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-active": { + "delivery_ms": 2.648137999813116, + "sender_sm_handled_ms": 2.3808849998658843, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2007.5651479999124, + "sender_sm_handled_ms": 2.4262659999294556, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.4597710000998632 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 36.61754500012648, + "sender_sm_handled_ms": 36.68361800009734 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "default", + "baseline_expect_held": false, + "roster_contacts_per_user": 10000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + }, + { + "active": { + "delivery": { + "samples": 3, + "median_ms": 46.439240999916365, + "p95_ms": 47.083156000098825, + "max_ms": 47.083156000098825, + "samples_ms": [ + 33.328300999983185, + 46.439240999916365, + 47.083156000098825 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 46.541515999933836, + "p95_ms": 47.150886000054015, + "max_ms": 47.150886000054015, + "samples_ms": [ + 33.39255400010188, + 46.541515999933836, + 47.150886000054015 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 86.8808379998427, + "p95_ms": 122.29052700013199, + "max_ms": 122.29052700013199, + "samples_ms": [ + 70.00579500004278, + 86.8808379998427, + 122.29052700013199 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 40.29070799992951, + "p95_ms": 75.055433000216, + "max_ms": 75.055433000216, + "samples_ms": [ + 36.56819799994082, + 40.29070799992951, + 75.055433000216 + ] + } + }, + "inactive": { + "delivery": { + "samples": 3, + "median_ms": 72.27235899995321, + "p95_ms": 93.65072800005692, + "max_ms": 93.65072800005692, + "samples_ms": [ + 48.87795400009054, + 72.27235899995321, + 93.65072800005692 + ] + }, + "sender_sm_handled": { + "samples": 3, + "median_ms": 72.12816399987787, + "p95_ms": 93.74595000008412, + "max_ms": 93.74595000008412, + "samples_ms": [ + 48.939044000007925, + 72.12816399987787, + 93.74595000008412 + ] + }, + "client_receipt_end_to_end": { + "samples": 3, + "median_ms": 139.73325400002068, + "p95_ms": 172.07185899997057, + "max_ms": 172.07185899997057, + "samples_ms": [ + 105.53995500004021, + 139.73325400002068, + 172.07185899997057 + ] + }, + "receipt_return_leg": { + "samples": 3, + "median_ms": 67.41313900010937, + "p95_ms": 78.24904599988258, + "max_ms": 78.24904599988258, + "samples_ms": [ + 56.54710499993598, + 67.41313900010937, + 78.24904599988258 + ] + } + }, + "receipt_only-active": { + "delivery_ms": 56.88246400018215, + "sender_sm_handled_ms": 56.438711000055264, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "receipt_only-inactive": { + "delivery_ms": 2072.487570000021, + "sender_sm_handled_ms": 62.108405999879324, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 6.061285999976462 + }, + "omemo_legacy_only-active": { + "delivery_ms": 12.879445999942618, + "sender_sm_handled_ms": 12.823433999983536, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_legacy_only-inactive": { + "delivery_ms": 2015.3352209999866, + "sender_sm_handled_ms": 10.757178999938333, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.0457470000110334 + }, + "omemo_2_only-active": { + "delivery_ms": 3.401804000077391, + "sender_sm_handled_ms": 3.4893090000878146, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_2_only-inactive": { + "delivery_ms": 2006.9976510001197, + "sender_sm_handled_ms": 2.974240999947142, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.460532000010062 + }, + "omemo_with_eme-active": { + "delivery_ms": 38.3093650000319, + "sender_sm_handled_ms": 38.26694500003214, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "omemo_with_eme-inactive": { + "delivery_ms": 45.05769899992629, + "sender_sm_handled_ms": 45.11449300002823, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-active": { + "delivery_ms": 35.31643999986045, + "sender_sm_handled_ms": 35.363737999887235, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_received-inactive": { + "delivery_ms": 2039.1413359998296, + "sender_sm_handled_ms": 34.155746999886105, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.2997989999803394 + }, + "marker_displayed-active": { + "delivery_ms": 38.61728900005801, + "sender_sm_handled_ms": 38.655942000104915, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_displayed-inactive": { + "delivery_ms": 2041.3829850001548, + "sender_sm_handled_ms": 36.01217200002793, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.7297940000844392 + }, + "marker_acknowledged-active": { + "delivery_ms": 36.434277999887854, + "sender_sm_handled_ms": 36.49695899980543, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "marker_acknowledged-inactive": { + "delivery_ms": 2039.6239120000246, + "sender_sm_handled_ms": 34.225130000095305, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 1.6989709999961633 + }, + "low_priority_headline-active": { + "delivery_ms": 3.2863559999896097, + "sender_sm_handled_ms": 3.340819000186457, + "durably_csi_buffered": false, + "forced_dwell_seconds": 0, + "after_activation_ms": null + }, + "low_priority_headline-inactive": { + "delivery_ms": 2008.6065660000259, + "sender_sm_handled_ms": 2.7695109999967826, + "durably_csi_buffered": true, + "forced_dwell_seconds": 2.0, + "after_activation_ms": 2.135354000074585 + }, + "sm_backlog": { + "seeded_messages": 500, + "durable_pending_before_sample": 500, + "delivery_ms": 36.98667300000125, + "sender_sm_handled_ms": 37.06163999981982 + }, + "status": "pass", + "final_personal_mam_records_per_user": [ + 100523, + 100523 + ], + "csi_policy": "native", + "baseline_expect_held": false, + "roster_contacts_per_user": 10000, + "seeded_personal_mam_records_per_user": 100000, + "archive_policy": "roster" + } + ] + }, + "push_latency": [ + { + "status": "pass", + "recipient_state": "hibernating", + "durable_pending_at_gateway_stream": { + "push-first": true, + "push-second": true + }, + "observation_seconds": 2, + "elapsed_seconds": 2.0038609230000475, + "gateway_post_tls_stream_observed": true, + "gateway_post_tls_stream_at_bound": true, + "blocked_stage": "post-tls-features", + "durable_pending": { + "push-first": true, + "push-second": true + }, + "sender_sm_ack_h": [ + 4 + ], + "sender_inputs": 4, + "sender_handled_before": 2, + "binary_version": "rust-xmpp 0.8.2 — experimental XMPP runtime", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback TLS fixture; stalled external XMPP push service; no APNs/FCM" + }, + { + "status": "pass", + "recipient_state": "offline", + "durable_pending_at_gateway_stream": { + "push-first": true, + "push-second": true + }, + "observation_seconds": 2, + "elapsed_seconds": 2.00361997899995, + "gateway_post_tls_stream_observed": true, + "gateway_post_tls_stream_at_bound": true, + "blocked_stage": "post-tls-features", + "durable_pending": { + "push-first": true, + "push-second": true + }, + "sender_sm_ack_h": [ + 4 + ], + "sender_inputs": 4, + "sender_handled_before": 2, + "binary_version": "rust-xmpp 0.8.2 — experimental XMPP runtime", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "loopback TLS fixture; stalled external XMPP push service; no APNs/FCM" + } + ], + "bind2_metadata_latency": { + "binary_source": "/tmp/rust-xmpp-0.8.2-final", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", + "scope": "real loopback TCP/STARTTLS/SASL2 Bind2; isolated personal MAM fixture; no production latency claim", + "timing": "raw ordered samples; auth timer starts before authenticate and ends at parsed success; full timer includes TCP/STARTTLS/features; metadata IQ timer runs from send to parsed result", + "result": { + "status": "pass", + "seeded_personal_archive_records": 100000, + "archive_bytes": 21488890, + "archive_expires_after": "never", + "index_present_before_start": false, + "reconnect_samples": 5, + "expected_metadata": { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + "observed_metadata": [ + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + } + ], + "mam_metadata_iq": { + "samples_ms": [ + 0.4802089999884629, + 0.35487300010572653, + 0.3393980000510055, + 0.49224100007450033, + 0.3266720000283385 + ], + "median_ms": 0.35487300010572653, + "p95_ms": 0.49224100007450033, + "max_ms": 0.49224100007450033 + }, + "observed_iq_metadata": [ + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + }, + { + "start": { + "id": "seed-0", + "timestamp": "2026-01-01T00:00:00Z" + }, + "end": { + "id": "seed-99999", + "timestamp": "2026-01-02T03:46:39Z" + } + } + ], + "sasl2_bind2_success": { + "samples_ms": [ + 1.9306740000502032, + 2.103263999970295, + 2.0025989999794547, + 1.9764060000397876, + 1.8955069999719854 + ], + "median_ms": 1.9764060000397876, + "p95_ms": 2.103263999970295, + "max_ms": 2.103263999970295 + }, + "tcp_starttls_to_bind2_success": { + "samples_ms": [ + 6.099597000002177, + 3.735450000021956, + 3.564695000022766, + 3.3520640001825086, + 3.3587010000246664 + ], + "median_ms": 3.564695000022766, + "p95_ms": 6.099597000002177, + "max_ms": 6.099597000002177 + } + } + }, + "general_load": { + "total_load_wall_seconds": 11.197, + "requested_resources": 500, + "authenticated_bound_resources": 500, + "connection_setup_concurrency": 50, + "setup_wall_seconds": 0.769, + "setup_latency": { + "samples": 500, + "median_ms": 72.064, + "p95_ms": 102.309, + "max_ms": 112.205 + }, + "ping_rounds": 10, + "ping_round_trip": { + "samples": 5000, + "median_ms": 12.125, + "p95_ms": 32.772, + "max_ms": 37.617 + }, + "accounts": 100, + "message_rounds": 10, + "messages_sent": 5000, + "messages_received": 5000, + "message_batch_seconds": 8.136, + "metrics_before": { + "rss_kib": 8448, + "cpu_seconds": 0.0, + "fd_count": 11 + }, + "metrics_connected": { + "rss_kib": 27268, + "cpu_seconds": 1.43, + "fd_count": 511 + }, + "metrics_after_workload": { + "rss_kib": 27876, + "cpu_seconds": 15.05, + "fd_count": 511 + }, + "metrics_two_seconds_after_disconnect": { + "rss_kib": 27636, + "cpu_seconds": 15.11, + "fd_count": 11 + }, + "sampled_peak_rss_kib": 28004, + "fd_delta_after_disconnect": 0, + "failures": [], + "scope": "One loopback host, 100 accounts with distinct resources, TLS+PLAIN, ping and directed messages; not a production benchmark or proof of no memory leaks.", + "mam": { + "archive_files": 100, + "records": 10000, + "expected_records": 10000 + } + }, "muc_sm_load": { "clients": 500, "accounts": 100, "rooms": 10, "message_rounds": 3, "concurrency": 20, - "binary": "/tmp/xmpp-durable-muc-load-g0crm4ik/rust-xmpp", - "binary_sha256": "74882319fcb467dd1e1813ab61e85441ffd3dae2f9f7961b28fd98ec5da7c89a", + "binary": "/tmp/xmpp-durable-muc-load-qywt10tu/rust-xmpp", + "binary_sha256": "130431025c4c7c2f72e28b77a31c83867f857ef8bb56d1f71b10e4b19d7caaf5", "before": { - "rss_kib": 9696, + "rss_kib": 9548, "cpu_seconds": 0.0, "fd_count": 12 }, - "connect_seconds": 5.193, + "connect_seconds": 2.918, "connect_latency": { "samples": 500, - "median_ms": 204.391, - "p95_ms": 270.035, - "max_ms": 332.503 + "median_ms": 114.756, + "p95_ms": 154.077, + "max_ms": 206.971 }, "phase": "completed", "status": "pass", - "elapsed_seconds": 78.857, - "join_seconds": 46.703, + "elapsed_seconds": 45.54, + "join_seconds": 30.37, "joined": { - "rss_kib": 42248, - "cpu_seconds": 17.77, - "fd_count": 513 + "rss_kib": 41856, + "cpu_seconds": 16.64, + "fd_count": 514 }, "join_presence_deliveries": 25000, "slots_joined": { "count": 500, "bytes": 309790 }, - "message_seconds": 10.861, + "message_seconds": 6.696, "room_messages_sent": 30, "room_messages_delivered": 1500, "before_kill": { - "rss_kib": 42128, - "cpu_seconds": 23.12, - "fd_count": 514 + "rss_kib": 41884, + "cpu_seconds": 20.77, + "fd_count": 512 }, "slots_before_kill": { "count": 500, "bytes": 514030 }, - "restart_seconds": 10.559, + "restart_seconds": 2.763, "resumed_resources": 10, "replayed_pending_room_messages": 10, "membership_groupchat_deliveries_after_resume": 10, "after_resume": { - "rss_kib": 21168, - "cpu_seconds": 5.03, - "fd_count": 23 + "rss_kib": 20984, + "cpu_seconds": 2.66, + "fd_count": 22 }, "slots_after_resume": { "count": 500, "bytes": 671070 }, - "total_seconds": 78.857, - "peak_rss_kib": 42252 + "total_seconds": 45.54, + "peak_rss_kib": 41920 }, - "upload": "S3 fixture/migration/network regression passed; large 10GiB transfer retained as historical0.7.9 validation, not repeated0.8.0", "limitations": [ - "New TLS/SASL connection required; TCP/TLS sockets cannot survive process exit", - "At-least-once SM replay, not cross-store/network exactly-once transaction", - "Known builtin MUC features ported; arbitrary community Lua modules not executed", - "Private durable SM format is Rust-specific, bounded queues and component checkpoint; see MUC-RECOVERY.md", - "Loopback smoke tests, not production capacity or real client qualification", - "Full Prosody parity remains subject to COMPATIBILITY.md" + "Loopback fixtures; no actual production client/push/DNS qualification", + "CSI runtime default extends native importance policy; explicit list overrides", + "Push routing ephemeral bounded1024/max8; message durability independent", + "SM Store global IO mutex remains; archive queries/maintenance may still scan", + "10GiB transfers not repeated0.8.2; see historical0.7.8/0.7.9reports", + "AF_UNIX and largearchiveignoredtests remain CIentrypoint only; native9ignored tests explicitlyexecuted" ] } diff --git a/scripts/verify-local.sh b/scripts/verify-local.sh index d618361..0805930 100755 --- a/scripts/verify-local.sh +++ b/scripts/verify-local.sh @@ -18,6 +18,7 @@ python3 tests/wss_interop.py --binary target/release/rust-xmpp python3 tests/http_proxy_paths_network.py --binary target/release/rust-xmpp python3 tests/http_altconnect_network.py --binary target/release/rust-xmpp python3 tests/sasl2_bind.py target/release/rust-xmpp +python3 tests/bind2_archive_latency_network.py --binary target/release/rust-xmpp --records 10000 --samples 2 --output /tmp/bind2-archive-latency.json python3 tests/sasl2_cached_inline.py target/release/rust-xmpp python3 tests/gajim_discovery_network.py target/release/rust-xmpp python3 tests/sasl2_resume.py target/release/rust-xmpp @@ -29,6 +30,10 @@ python3 tests/preauth_network.py target/release/rust-xmpp python3 tests/muc_restart_network.py target/release/rust-xmpp python3 tests/muc_crash_network.py target/release/rust-xmpp python3 tests/sm_restart_network.py target/release/rust-xmpp +python3 tests/push_latency_network.py --binary target/release/rust-xmpp --recipient hibernating --output /tmp/push-latency.json +python3 tests/push_latency_network.py --binary target/release/rust-xmpp --recipient offline --output /tmp/push-offline-latency.json +python3 tests/personal_message_latency_network.py --binary target/release/rust-xmpp --rounds 1 --history-records 1000 --roster-sizes 0 --backlog 30 --csi-dwell 0.1 --output /tmp/personal-message-latency.json +python3 tests/message_latency_network.py --binary target/release/rust-xmpp --rounds 3 --history-records 0 10000 --output /tmp/xmpp-message-latency.json python3 tests/resource_rebind.py target/release/rust-xmpp python3 scripts/integration_http.py python3 scripts/integration_http.py --custom-upload-path diff --git a/src/archive.rs b/src/archive.rs index e1dbbcd..3c93af8 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -5,7 +5,7 @@ use crate::{ }; use anyhow::{Result, anyhow, bail}; use std::{ - io::{BufRead, BufReader, Read, Write}, + io::{BufRead, BufReader, Read, Seek, SeekFrom, Write}, path::Path, sync::{Arc, Mutex, OnceLock, Weak}, }; @@ -212,46 +212,23 @@ fn scan_unlocked Result<()>>( let mut reader = BufReader::new(file); let mut line = Vec::new(); let mut record = Vec::new(); - let lua = crate::lua::bounded_vm().map_err(|e| anyhow!(e.to_string()))?; - let env = lua.create_table().map_err(|e| anyhow!(e.to_string()))?; + let decoder = RecordDecoder::new()?; let mut decode = |data: &[u8]| -> Result<()> { - if data.iter().all(u8::is_ascii_whitespace) { - return Ok(()); + if let Some(entry) = decoder.decode(data)? { + visit(entry)?; } - let count = std::rc::Rc::new(std::cell::Cell::new(0)); - lua.set_hook( - mlua::HookTriggers::new().every_nth_instruction(1000), - move |_, _| { - count.set(count.get() + 1); - if count.get() > 2000 { - return Err(mlua::Error::runtime("archive record instruction limit")); - } - Ok(mlua::VmState::Continue) - }, - ) - .map_err(|e| anyhow!(e.to_string()))?; - let mut chunk = b"local function item(v) return v end; return ".to_vec(); - chunk.extend(data); - let value = lua - .load(&chunk) - .set_mode(mlua::chunk::ChunkMode::Text) - .set_environment(env.clone()) - .eval::() - .map_err(|e| anyhow!(e.to_string()))?; - visit(decode_entry(&storage::from_lua(value)?)?)?; - lua.gc_collect().map_err(|e| anyhow!(e.to_string()))?; Ok(()) }; loop { line.clear(); let n = (&mut reader) - .take(16 * 1024 * 1024 + 1) + .take(MAX_RECORD_BYTES as u64 + 1) .read_until(b'\n', &mut line)?; if n == 0 { break; } anyhow::ensure!( - line.len() <= 16 * 1024 * 1024, + line.len() <= MAX_RECORD_BYTES, "archive record line exceeds 16 MiB" ); if line.starts_with(b"item") && !record.is_empty() { @@ -260,12 +237,148 @@ fn scan_unlocked Result<()>>( } record.extend_from_slice(&line); anyhow::ensure!( - record.len() <= 16 * 1024 * 1024, + record.len() <= MAX_RECORD_BYTES, "archive record exceeds 16 MiB" ); } decode(&record) } +const MAX_RECORD_BYTES: usize = 16 * 1024 * 1024; + +/// One bounded Lua sandbox shared by the scan and endpoint readers. +struct RecordDecoder { + lua: mlua::Lua, + env: mlua::Table, +} +impl RecordDecoder { + fn new() -> Result { + let lua = crate::lua::bounded_vm().map_err(|e| anyhow!(e.to_string()))?; + let env = lua.create_table().map_err(|e| anyhow!(e.to_string()))?; + Ok(Self { lua, env }) + } + fn decode(&self, data: &[u8]) -> Result> { + anyhow::ensure!( + data.len() <= MAX_RECORD_BYTES, + "archive record exceeds 16 MiB" + ); + if data.iter().all(u8::is_ascii_whitespace) { + return Ok(None); + } + let count = std::rc::Rc::new(std::cell::Cell::new(0)); + self.lua + .set_hook( + mlua::HookTriggers::new().every_nth_instruction(1000), + move |_, _| { + count.set(count.get() + 1); + if count.get() > 2000 { + return Err(mlua::Error::runtime("archive record instruction limit")); + } + Ok(mlua::VmState::Continue) + }, + ) + .map_err(|e| anyhow!(e.to_string()))?; + let mut chunk = b"local function item(v) return v end; return ".to_vec(); + chunk.extend(data); + let value = self + .lua + .load(&chunk) + .set_mode(mlua::chunk::ChunkMode::Text) + .set_environment(self.env.clone()) + .eval::() + .map_err(|e| anyhow!(e.to_string()))?; + let entry = decode_entry(&storage::from_lua(value)?)?; + self.lua.gc_collect().map_err(|e| anyhow!(e.to_string()))?; + Ok(Some(entry)) + } +} + +/// Read just the first and last native records of a consistent archive snapshot. +/// This metadata operation deliberately does not validate intervening records. +/// Neither a missing nor a stale native binary index causes a history scan. +pub fn edges_store( + root: &Path, + host: &str, + user: Option<&str>, + store: &str, +) -> Result> { + let _life = LIFECYCLE + .read() + .map_err(|_| anyhow!("archive lifecycle lock poisoned"))?; + let lock = archive_lock(root, host, user, store)?; + let _guard = lock.lock().map_err(|_| anyhow!("archive lock poisoned"))?; + let path = storage::path(root, host, user, store).with_extension("list"); + recover_append(&path)?; + let mut file = match std::fs::File::open(&path) { + Ok(file) => file, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(e) => return Err(e.into()), + }; + let decoder = RecordDecoder::new()?; + let first = match first_record(&mut BufReader::new(&mut file), &decoder)? { + Some(entry) => entry, + None => return Ok(None), + }; + let length = file.metadata()?.len(); + let mut window = 8192u64.min(length); + loop { + let start = length - window; + // Include one preceding byte to distinguish a real line boundary from + // an `item` prefix coincidentally at the beginning of the seek window. + let read_start = start.saturating_sub(1); + file.seek(SeekFrom::Start(read_start))?; + let mut tail = vec![0; (length - read_start) as usize]; + file.read_exact(&mut tail)?; + let boundary = (0..tail.len()).rev().find(|&i| { + (i > 0 && tail[i - 1] == b'\n' || i == 0 && read_start == 0) + && tail[i..].starts_with(b"item") + }); + if let Some(boundary) = boundary { + let last = decoder + .decode(&tail[boundary..])? + .ok_or_else(|| anyhow!("empty archive endpoint"))?; + return Ok(Some((first, last))); + } + anyhow::ensure!( + start > 0 && window < MAX_RECORD_BYTES as u64, + "archive last record exceeds 16 MiB or has no native item boundary" + ); + window = (window * 2).min(MAX_RECORD_BYTES as u64).min(length); + } +} + +fn first_record(reader: &mut R, decoder: &RecordDecoder) -> Result> { + let mut record = Vec::new(); + loop { + // Inspect only the next line's marker before reading its contents: the + // second record may be enormous or malformed and is irrelevant here. + let mut prefix = Vec::new(); + let n = (&mut *reader).take(4).read_until(b'\n', &mut prefix)?; + if n == 0 { + return decoder.decode(&record); + } + if prefix.starts_with(b"item") && !record.is_empty() { + if let Some(entry) = decoder.decode(&record)? { + return Ok(Some(entry)); + } + record.clear(); + } + record.extend_from_slice(&prefix); + anyhow::ensure!( + record.len() <= MAX_RECORD_BYTES, + "archive record exceeds 16 MiB" + ); + if !prefix.ends_with(b"\n") { + let remaining = (MAX_RECORD_BYTES - record.len() + 1) as u64; + (&mut *reader) + .take(remaining) + .read_until(b'\n', &mut record)?; + anyhow::ensure!( + record.len() <= MAX_RECORD_BYTES, + "archive record exceeds 16 MiB" + ); + } + } +} fn load_unlocked(root: &Path, host: &str, user: Option<&str>, store: &str) -> Result> { let mut out = vec![]; scan_unlocked(root, host, user, store, |e| { diff --git a/src/csi.rs b/src/csi.rs index 8afa477..334dd25 100644 --- a/src/csi.rs +++ b/src/csi.rs @@ -1,6 +1,17 @@ //! Write buffering matching the supplied Prosody mod_csi_simple importance policy. use crate::{protocol, wire::escape}; use std::time::{Duration, Instant}; +/// Runtime defaults: visible encrypted chat and delivery/read confirmation must +/// not remain asleep merely because a client omitted a fallback body or EME. +/// An explicit csi_important_payloads list replaces these defaults. +pub const DEFAULT_IMPORTANT_PAYLOADS: &[&str] = &[ + "{eu.siacs.conversations.axolotl}encrypted", + "{urn:xmpp:omemo:2}encrypted", + "{urn:xmpp:receipts}received", + "{urn:xmpp:chat-markers:0}received", + "{urn:xmpp:chat-markers:0}displayed", + "{urn:xmpp:chat-markers:0}acknowledged", +]; #[derive(Clone, Debug, Default)] pub struct Buffer { inactive: bool, @@ -19,6 +30,37 @@ pub(crate) struct DurableBuffer { resume_delay_ms: u64, important_payloads: Vec, } +/// Output awaiting persistence. Rollback reuses the drained queue without cloning it. +pub(crate) struct PendingOutput { + output: Vec, + previous: Option, +} +struct QueueChange { + queued: usize, + bytes: usize, + flushing_until: Option, + appended: bool, +} +impl PendingOutput { + pub(crate) fn durable_changed(&self) -> bool { + self.previous.is_some() + } + pub(crate) fn commit(self) -> Vec { + self.output + } + pub(crate) fn rollback(mut self, buffer: &mut Buffer) { + if let Some(previous) = self.previous { + if previous.appended { + buffer.queue.pop(); + } else { + self.output.truncate(previous.queued); + buffer.queue = self.output; + } + buffer.bytes = previous.bytes; + buffer.flushing_until = previous.flushing_until; + } + } +} impl Buffer { pub(crate) fn durable(&self) -> DurableBuffer { DurableBuffer { @@ -63,17 +105,47 @@ impl Buffer { } /// Client input flushes held output without declaring the client active. pub fn activity(&mut self, now: Instant) -> Vec { + self.pending_activity(now).commit() + } + pub(crate) fn pending_activity(&mut self, now: Instant) -> PendingOutput { if self.inactive && !self.queue.is_empty() { + let previous = self.queue_change(false); self.flushing_until = Some(now + self.resume_delay); - self.drain() + PendingOutput { + output: self.drain(), + previous: Some(previous), + } } else { - Vec::new() + PendingOutput { + output: Vec::new(), + previous: None, + } } } pub fn output(&mut self, xml: String, owner: &str, now: Instant) -> Vec { - if !self.inactive || self.flushing_until.is_some_and(|until| now < until) { - return vec![xml]; + self.pending_output(xml, owner, now).commit() + } + fn queue_change(&self, appended: bool) -> QueueChange { + QueueChange { + queued: self.queue.len(), + bytes: self.bytes, + flushing_until: self.flushing_until, + appended, } + } + pub(crate) fn pending_output( + &mut self, + xml: String, + owner: &str, + now: Instant, + ) -> PendingOutput { + if !self.inactive || self.flushing_until.is_some_and(|until| now < until) { + return PendingOutput { + output: vec![xml], + previous: None, + }; + } + let mut previous = self.queue_change(false); self.flushing_until = None; if self.queue.len() >= self.limit.max(1) || self.bytes.saturating_add(xml.len()) > 4 * 1024 * 1024 @@ -82,12 +154,19 @@ impl Buffer { self.flushing_until = Some(now + self.resume_delay); let mut output = self.drain(); output.push(xml); - output + PendingOutput { + output, + previous: (previous.queued > 0).then_some(previous), + } } else { + previous.appended = true; let xml = delayed(&xml, owner); self.bytes += xml.len(); self.queue.push(xml); - Vec::new() + PendingOutput { + output: Vec::new(), + previous: Some(previous), + } } } } @@ -199,3 +278,82 @@ fn delayed(xml: &str, owner: &str) -> String { } output } + +#[cfg(test)] +mod checkpoint_tests { + use super::*; + + #[test] + fn only_queue_changes_require_a_checkpoint() { + let now = Instant::now(); + let mut buffer = Buffer::default(); + buffer.configure(2, Duration::from_secs(5), vec![]); + assert!(!buffer.pending_activity(now).durable_changed()); + assert!( + !buffer + .pending_output("".into(), "a@example", now) + .durable_changed() + ); + buffer.set_inactive(true); + // An important stanza starts the transient grace period but changes no durable queue. + let output = buffer.pending_output( + "hi".into(), + "a@example", + now, + ); + assert!(!output.durable_changed()); + assert_eq!(output.commit().len(), 1); + assert!( + !buffer + .pending_output("".into(), "a@example", now) + .durable_changed() + ); + let later = now + Duration::from_secs(6); + let output = buffer.pending_output("".into(), "a@example", later); + assert!(output.durable_changed()); + assert!(output.commit().is_empty()); + let output = buffer.pending_activity(later); + assert!(output.durable_changed()); + assert_eq!(output.commit().len(), 1); + assert!(!buffer.pending_activity(later).durable_changed()); + } + + #[test] + fn failed_queue_checkpoints_restore_append_and_drain_without_copying_queue() { + let now = Instant::now(); + let mut buffer = Buffer::default(); + buffer.configure(2, Duration::from_secs(5), vec![]); + buffer.set_inactive(true); + buffer.output("".into(), "a@example", now); + let before = serde_json::to_value(buffer.durable()).unwrap(); + let bytes = buffer.bytes; + let until = buffer.flushing_until; + for operation in 0..3 { + let output = match operation { + 0 => buffer.pending_output("".into(), "a@example", now), + 1 => buffer.pending_output( + "hi".into(), + "a@example", + now, + ), + _ => buffer.pending_activity(now), + }; + assert!(output.durable_changed()); + output.rollback(&mut buffer); + assert_eq!(serde_json::to_value(buffer.durable()).unwrap(), before); + assert_eq!(buffer.bytes, bytes); + assert_eq!(buffer.flushing_until, until); + } + // A successful retry still sends the held stanza before the new message. + let output = buffer + .pending_output( + "hi".into(), + "a@example", + now, + ) + .commit(); + assert_eq!(output.len(), 2); + assert!(output[0].contains("id='held'")); + assert!(output[1].contains("hi")); + } +} diff --git a/src/mam.rs b/src/mam.rs index f8358e0..efb4b72 100644 --- a/src/mam.rs +++ b/src/mam.rs @@ -274,16 +274,12 @@ pub fn handle_archive_query_with_options( let (iq, q) = request; let typ = iq.attribute("type").unwrap_or(""); if q.tag_name().name() == "metadata" && typ == "get" { - let mut first = None; - let mut last = None; - archive::scan_store(root, host, user, store, |e| { - if first.is_none() { - first = Some((e.id.clone(), e.when)); - } - last = Some((e.id, e.when)); - Ok(()) - }) - .context("MAM archive read failed")?; + let edges = + archive::edges_store(root, host, user, store).context("MAM archive read failed")?; + let (first, last) = match edges { + Some((first, last)) => (Some((first.id, first.when)), Some((last.id, last.when))), + None => (None, None), + }; let mut payload = format!(""); if let Some((id, when)) = first { payload.push_str(&format!( diff --git a/src/muc.rs b/src/muc.rs index bb48c59..98b5e96 100644 --- a/src/muc.rs +++ b/src/muc.rs @@ -990,10 +990,18 @@ impl Muc { if r.data("persistent").as_bool() == Some(true) || self.pending_occupants.has_room(room) { let mut merged = r.original.clone(); merge_value(&mut merged, &r.frozen); - crate::storage::atomic_write( - &self.path(room), - crate::storage::serialize(&merged)?.as_bytes(), - )?; + let path = self.path(room); + let encoded = crate::storage::serialize(&merged)?; + // Native files are compatibility exports. Keep retrying missing or + // changed exports, but avoid an atomic write/fsync for unchanged rooms. + let unchanged = match std::fs::read(&path) { + Ok(bytes) => bytes == encoded.as_bytes(), + Err(error) if error.kind() == std::io::ErrorKind::NotFound => false, + Err(error) => return Err(error.into()), + }; + if !unchanged { + crate::storage::atomic_write(&path, encoded.as_bytes())?; + } let path = self .root .join(crate::storage::encode_name(&self.domain)) @@ -1003,8 +1011,10 @@ impl Muc { } else { json!({}) }; - index[room] = json!(true); - write_value(&path, &index)?; + if index.get(room) != Some(&json!(true)) { + index[room] = json!(true); + write_value(&path, &index)?; + } } else if self.path(room).exists() { std::fs::remove_file(self.path(room))?; crate::storage::update(&self.root, &self.domain, None, "persistent", |v| { @@ -2059,18 +2069,8 @@ impl Muc { xml: archived, }, )?; - if let Some(seconds) = self.retention_seconds { - crate::archive::expire_before( - &self.root, - &self.domain, - Some(room.split('@').next().unwrap()), - "muc_log", - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH)? - .as_secs_f64() - - seconds, - )?; - } + // Retention runs during maintenance and before MAM queries. + // A normal append must not scan/rewrite the entire archive. payload } else { payload diff --git a/src/server.rs b/src/server.rs index 42c7d08..0a8254c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -46,6 +46,7 @@ pub struct Runtime { uploads: Arc>, started: Instant, push: Arc>, + push_routes: mpsc::Sender<(String, String)>, federation: Option, stopping: Arc, } @@ -318,33 +319,24 @@ impl Drop for Cleanup { )); } } - if !queued.is_empty() - && let Ok(handle) = tokio::runtime::Handle::try_current() - { - let rt = self.runtime.clone(); - handle.spawn(async move { - for (user, identifier, messages) in queued { - let result = rt.push.lock().unwrap().notify_queue( - &rt.data, - &rt.domain, - &user, - &messages, - &rt.config, - &identifier, - ); - let notifications = if let Ok(result) = result { - if result.reset_watchdog { - reset_push_watchdog(&rt, &user, &identifier); - } - result.deliveries - } else { - Vec::new() - }; - for (to, payload) in notifications { - let _ = route_delivery(&rt, &to, &payload).await; - } + let rt = &self.runtime; + for (user, identifier, messages) in queued { + let result = rt.push.lock().unwrap().notify_queue( + &rt.data, + &rt.domain, + &user, + &messages, + &rt.config, + &identifier, + ); + if let Ok(result) = result { + if result.reset_watchdog { + reset_push_watchdog(rt, &user, &identifier); } - }); + for (to, payload) in result.deliveries { + enqueue_push_route(rt, to, payload); + } + } } } } @@ -565,7 +557,7 @@ fn reset_push_watchdog(rt: &Runtime, user: &str, identifier: &str) { "smacks_hibernation_time", 300, )); - for session in rt.hub.all() { + for session in rt.hub.for_owners(&[&owner]) { let mut s = session.lock().unwrap(); if s.owner == owner && s.push_identifier.as_deref() == Some(identifier) { s.first_important_push(timeout); @@ -932,6 +924,7 @@ pub async fn serve(path: &Path) -> Result<()> { "durable-sessions-loaded", &[("count", &hub.all().len().to_string())], ); + let (push_routes, push_route_rx) = mpsc::channel(1024); let runtime = Runtime { _data_guard: data_guard, domain: domain.clone(), @@ -963,9 +956,14 @@ pub async fn serve(path: &Path) -> Result<()> { uploads: Arc::new(uploads), started: Instant::now(), push: Default::default(), + push_routes, stopping: Default::default(), federation, }; + let push_worker = PushRouteWorker(tokio::spawn(run_push_routes( + runtime.clone(), + push_route_rx, + ))); let interfaces = c .option(&domain, "interfaces") .and_then(|v| v.as_array()) @@ -1317,6 +1315,7 @@ pub async fn serve(path: &Path) -> Result<()> { ); } tasks.abort_all(); + push_worker.0.abort(); Ok(()) } fn bind_listener(addr: std::net::SocketAddr) -> Result { @@ -1350,9 +1349,14 @@ async fn csi_send( let output = if let Some(session) = session { let mut s = session.lock().unwrap(); let owner = s.owner.clone(); - let output = s.csi.output(xml.into(), &owner, Instant::now()); - s.checkpoint()?; - output + let output = s.csi.pending_output(xml.into(), &owner, Instant::now()); + if output.durable_changed() + && let Err(error) = s.checkpoint() + { + output.rollback(&mut s.csi); + return Err(error); + } + output.commit() } else { vec![xml.into()] }; @@ -1367,9 +1371,14 @@ async fn csi_activity( ) -> Result<()> { let output = if let Some(s) = session { let mut s = s.lock().unwrap(); - let output = s.csi.activity(Instant::now()); - s.checkpoint()?; - output + let output = s.csi.pending_activity(Instant::now()); + if output.durable_changed() + && let Err(error) = s.checkpoint() + { + output.rollback(&mut s.csi); + return Err(error); + } + output.commit() } else { Vec::new() }; @@ -2433,6 +2442,17 @@ fn pep_iq_metadata( Some(fields) } +// Ordinary account traffic must not wait for MUC archive maintenance or room +// checkpoints. Component identity comes from immutable, validated configuration. +fn is_muc_destination(config: &Config, target: &str) -> bool { + let target = protocol::bare(target); + let domain = target.rsplit_once('@').map_or(target, |(_, domain)| domain); + config + .hosts + .get(domain) + .is_some_and(|host| host.component.as_deref() == Some("muc")) +} + fn dispatch_iq( rt: &Runtime, jid: &str, @@ -2446,7 +2466,7 @@ fn dispatch_iq( let typ = iq.attribute("type").unwrap_or(""); let target = iq.attribute("to").unwrap_or(&rt.domain); let target_bare = protocol::bare(target); - { + if is_muc_destination(&rt.config, target) { let mut rooms = rt.mucs.lock().unwrap(); for muc in rooms.values_mut() { if let Some(result) = muc.handle(jid, iq)? { @@ -2875,15 +2895,7 @@ impl AsyncRead for ActivityReader<'_, S> { result } } -fn configure_bound_session( - rt: &Runtime, - s: &SharedSession, - client_id: Option, - csi_inactive: bool, -) -> Result<()> { - s.lock().unwrap().ack_limit = - number(&rt.config, &rt.domain, "smacks_max_unacked", 100) as usize; - s.lock().unwrap().client_id = client_id.clone(); +fn configure_csi_buffer(rt: &Runtime, buffer: &mut crate::csi::Buffer) { if rt.enabled("csi_simple") { let limit = number(&rt.config, &rt.domain, "csi_queue_size", 256) as usize; let delay = period( @@ -2901,13 +2913,25 @@ fn configure_bound_session( .filter_map(|v| v.as_str().map(str::to_owned)) .collect() }) - .unwrap_or_default(); - s.lock() - .unwrap() - .csi - .configure(limit, Duration::from_secs_f64(delay), payloads); + .unwrap_or_else(|| { + crate::csi::DEFAULT_IMPORTANT_PAYLOADS + .iter() + .map(|value| (*value).to_owned()) + .collect() + }); + buffer.configure(limit, Duration::from_secs_f64(delay), payloads); } +} +fn configure_bound_session( + rt: &Runtime, + s: &SharedSession, + client_id: Option, + csi_inactive: bool, +) -> Result<()> { let mut session = s.lock().unwrap(); + session.ack_limit = number(&rt.config, &rt.domain, "smacks_max_unacked", 100) as usize; + session.client_id = client_id; + configure_csi_buffer(rt, &mut session.csi); session.csi.set_inactive(csi_inactive); session.checkpoint()?; Ok(()) @@ -2978,7 +3002,14 @@ async fn restore_muc_after_resume( rt: &Runtime, ctx: &ConnectionLog, ) -> Result<()> { - let full = session.lock().unwrap().jid.clone(); + let full = { + let mut state = session.lock().unwrap(); + // Restored slots may contain the previous release's policy; current + // explicit configuration/defaults apply equally to bind and resume. + configure_csi_buffer(rt, &mut state.csi); + state.checkpoint()?; + state.jid.clone() + }; let results = { let mut rooms = rt.mucs.lock().unwrap(); rooms @@ -3084,15 +3115,11 @@ async fn authenticated_transport( } } if rt.enabled("mam") { - let mut first = None; - let mut last = None; - crate::archive::scan_store(&rt.data, &rt.domain, Some(&user), "archive", |entry| { - if first.is_none() { - first = Some((entry.id.clone(), entry.when)); - } - last = Some((entry.id, entry.when)); - Ok(()) - })?; + let edges = crate::archive::edges_store(&rt.data, &rt.domain, Some(&user), "archive")?; + let (first, last) = match edges { + Some((first, last)) => (Some((first.id, first.when)), Some((last.id, last.when))), + None => (None, None), + }; bound.push_str(""); for (element, edge) in [("start", first), ("end", last)] { if let Some((id, when)) = edge { @@ -3275,6 +3302,7 @@ async fn authenticated_transport( ); ctx.event(Level::Debug, "stanza-received", &[("kind", kind)]); let handled_session = session.clone(); + let processing_started = Instant::now(); async { if kind == "iq" { let typ = n.attribute("type").unwrap_or(""); @@ -3434,7 +3462,7 @@ async fn authenticated_transport( apply(stream, session.as_ref(), &rt, result).await?; } else { let full = jid.as_deref().context("binding required")?; - let muc_result = { + let muc_result = if n.attribute("to").is_some_and(|to| is_muc_destination(&rt.config, to)) { let mut rooms = rt.mucs.lock().unwrap(); let mut found = None; for muc in rooms.values_mut() { @@ -3444,6 +3472,8 @@ async fn authenticated_transport( } } found + } else { + None }; if let Some(result) = muc_result { apply(stream, session.as_ref(), &rt, result).await?; @@ -3652,7 +3682,7 @@ async fn authenticated_transport( && n.tag_name().name() == "private" }) { - for s in rt.hub.all() { + for s in rt.hub.for_owners(&[&owner, protocol::bare(to)]) { let mut s = s.lock().unwrap(); if !s.carbons || s.jid == full || target_jids.contains(&s.jid) { continue; @@ -3675,20 +3705,11 @@ async fn authenticated_transport( } } } - if rt.enabled("cloud_notify") - && typ != "error" - && let Some(u) = &local - { - let doc = roxmltree::Document::parse(&xml)?; - let pushes = message_pushes(&rt, u, to, delivered, doc.root_element())?; - for (to, payload) in pushes { - let _ = route_delivery(&rt, &to, &payload).await; - } - } - + // A push can wake the client immediately. Commit offline delivery + // before publishing its notification, just as for durable SM output. if delivered == 0 && !matches!(typ, "error" | "headline") { - let queued = if let Some(u) = local { - crate::account_modules::offline_enqueue(&rt.data, &rt.domain, &u, &xml)? + let queued = if let Some(u) = &local { + crate::account_modules::offline_enqueue(&rt.data, &rt.domain, u, &xml)? } else { false }; @@ -3696,6 +3717,17 @@ async fn authenticated_transport( emit(stream,session.as_ref(),&format!("",escape(n.attribute("id").unwrap_or("")),escape(to),escape(full))).await?; } } + if rt.enabled("cloud_notify") + && typ != "error" + && let Some(u) = &local + { + let doc = roxmltree::Document::parse(&xml)?; + let pushes = message_pushes(&rt, u, to, delivered, doc.root_element())?; + for (to, payload) in pushes { + enqueue_push_route(&rt, to, payload); + } + } + } Ok::<(), anyhow::Error>(()) }.await?; @@ -3705,6 +3737,28 @@ async fn authenticated_transport( state.mark_handled()?; } } + if kind == "message" && processing_started.elapsed() >= Duration::from_millis(250) { + let route = n.attribute("to").map_or("implicit", |to| { + if is_muc_destination(&rt.config, to) { + "muc" + } else if rt.owner(to).is_some() { + "local" + } else { + "remote-or-component" + } + }); + ctx.event( + Level::Warn, + "message-processing-slow", + &[ + ( + "duration_ms", + &processing_started.elapsed().as_millis().to_string(), + ), + ("route", route), + ], + ); + } } Ok(()) } @@ -3734,6 +3788,53 @@ fn period(value: Option<&serde_json::Value>, default: Option) -> Option default, } } +// The guard lives in serve rather than Runtime: Runtime clones inside queued +// routes must not keep their own worker (and the data-directory lock) alive. +struct PushRouteWorker(tokio::task::JoinHandle<()>); +impl Drop for PushRouteWorker { + fn drop(&mut self) { + self.0.abort(); + } +} +fn enqueue_push_route(rt: &Runtime, to: String, xml: String) { + if let Err(error) = rt.push_routes.try_send((to, xml)) { + let reason = match error { + mpsc::error::TrySendError::Full(_) => "queue-full", + mpsc::error::TrySendError::Closed(_) => "worker-closed", + }; + rt.logger.event( + Level::Warn, + "push", + None, + "notification-routing-failed", + &[("reason", reason)], + ); + } +} +async fn run_push_routes(rt: Runtime, mut receiver: mpsc::Receiver<(String, String)>) { + let mut routes = tokio::task::JoinSet::new(); + loop { + tokio::select! { + result = routes.join_next(), if !routes.is_empty() => { + if result.is_some_and(|result| result.is_err()) { + rt.logger.event(Level::Warn, "push", None, + "notification-routing-failed", &[("reason", "routing-task-failed")]); + } + } + next = receiver.recv(), if routes.len() < 8 => { + let Some((to, xml)) = next else { break }; + let runtime = rt.clone(); + routes.spawn(async move { + if route_delivery(&runtime, &to, &xml).await.is_err() { + runtime.logger.event(Level::Warn, "push", None, + "notification-routing-failed", &[("reason", "route-failed")]); + } + }); + } + } + } + // Dropping JoinSet aborts in-flight routes, including on worker cancellation. +} async fn route_delivery(rt: &Runtime, to: &str, xml: &str) -> Result { let domain = protocol::bare(to) .rsplit_once('@') @@ -3836,7 +3937,7 @@ async fn incoming_federated(rt: Runtime, stanza: crate::federation::FederatedSta } return Ok(()); } - let muc_result = { + let muc_result = if is_muc_destination(&rt.config, to) { let mut rooms = rt.mucs.lock().unwrap(); let mut out = None; for room in rooms.values_mut() { @@ -3846,6 +3947,8 @@ async fn incoming_federated(rt: Runtime, stanza: crate::federation::FederatedSta } } out + } else { + None }; if let Some(result) = muc_result { for reply in result.replies { @@ -3918,7 +4021,7 @@ async fn incoming_federated(rt: Runtime, stanza: crate::federation::FederatedSta } let notifications = message_pushes(&rt, &user, to, delivered, n)?; for (to, xml) in notifications { - let _ = route_delivery(&rt, &to, &xml).await; + enqueue_push_route(&rt, to, xml); } } Ok(()) diff --git a/src/sessions.rs b/src/sessions.rs index cecaec4..c61cf5a 100644 --- a/src/sessions.rs +++ b/src/sessions.rs @@ -115,6 +115,10 @@ impl Session { ensure!(!self.closed, "session closed"); let n = h.wrapping_sub(self.acked) as usize; ensure!(n <= self.pending.len(), "invalid stream acknowledgement"); + if n == 0 { + self.ack_requested = false; + return Ok(()); + } let previous = self.clone(); self.pending.drain(..n); self.acked = h; @@ -345,13 +349,29 @@ impl Hub { pub fn all(&self) -> Vec { self.sessions.lock().unwrap().values().cloned().collect() } + /// Filter immutable resource keys before taking any per-session lock. A slow + /// client from another account must not block this account's routing/carbons. + pub fn for_owners(&self, owners: &[&str]) -> Vec { + self.sessions + .lock() + .unwrap() + .iter() + .filter(|(jid, _)| owners.contains(&bare(jid))) + .map(|(_, session)| session.clone()) + .collect() + } pub fn deliver(&self, to: &str, xml: &str) -> usize { let roster_push = roxmltree::Document::parse(xml).ok().is_some_and(|d| { d.root_element() .attribute("id") .is_some_and(|id| id.starts_with("roster-")) }); - self.all() + let targets = if to.contains('/') { + self.get(to).into_iter().collect() + } else { + self.for_owners(&[to]) + }; + targets .into_iter() .filter(|s| { let mut s = s.lock().unwrap(); @@ -383,7 +403,7 @@ impl Hub { let bare = to.split_once('/').map(|(bare, _)| bare).unwrap_or(to); let mut max = None; let mut out = vec![]; - for s in self.all() { + for s in self.for_owners(&[bare]) { let p = { let state = s.lock().unwrap(); if state.owner != bare || !state.available || state.priority < 0 { diff --git a/tests/archive_edges.rs b/tests/archive_edges.rs new file mode 100644 index 0000000..c6f238d --- /dev/null +++ b/tests/archive_edges.rs @@ -0,0 +1,133 @@ +use rust_xmpp::{archive, storage}; +use std::{ + fs::{self, File}, + io::{Seek, SeekFrom, Write}, + path::{Path, PathBuf}, +}; + +const MAX_RECORD: usize = 16 * 1024 * 1024; + +fn path(root: &Path) -> PathBuf { + let p = storage::path(root, "example.org", Some("alice"), "archive").with_extension("list"); + fs::create_dir_all(p.parent().unwrap()).unwrap(); + p +} +fn record(id: &str) -> String { + format!( + "item({{name='message';attr={{xmlns='jabber:client'}};key='{id}';when=42;with='bob@example.org';{{name='body';attr={{}};'hello'}}}});\n" + ) +} +fn edges(root: &Path) -> anyhow::Result> { + archive::edges_store(root, "example.org", Some("alice"), "archive") +} + +#[test] +fn metadata_skips_large_malformed_middle_without_creating_cache() { + let t = tempfile::tempdir().unwrap(); + let p = path(t.path()); + let mut file = File::create(&p).unwrap(); + file.write_all(record("first").as_bytes()).unwrap(); + file.write_all(b"item(not valid Lua in the middle\n") + .unwrap(); + // A sparse >128 MiB history makes accidental full scans fail the record + // bound; only the endpoints are part of this metadata operation. + file.seek(SeekFrom::Start(129 * 1024 * 1024)).unwrap(); + file.write_all(b"\n").unwrap(); + file.write_all(record("last").as_bytes()).unwrap(); + drop(file); + let (first, last) = edges(t.path()).unwrap().unwrap(); + assert_eq!((first.id.as_str(), last.id.as_str()), ("first", "last")); + assert_eq!(first.when, 42.0); + assert_eq!(last.peer, "bob@example.org"); + assert!(!p.with_extension("lidx").exists()); + assert!(archive::load(t.path(), "example.org", "alice").is_err()); + + // An opaque native index is irrelevant and must remain untouched. + fs::write(p.with_extension("lidx"), b"stale binary index").unwrap(); + assert_eq!(edges(t.path()).unwrap().unwrap().1.id, "last"); + assert_eq!( + fs::read(p.with_extension("lidx")).unwrap(), + b"stale binary index" + ); +} + +#[test] +fn multiline_endpoints_match_native_scanner_with_blank_lines() { + let t = tempfile::tempdir().unwrap(); + let p = path(t.path()); + let first = record("first").replace(";", ";\n"); + let last = format!( + "item({{\nname='message';attr={{}};key='last';when=43;\n{{name='body';attr={{}};[=[{}]=]}}\n}});\n \t\n", + "long multiline text\n".repeat(1800) + ); + fs::write(&p, format!(" \t\n\n{first}\n{}{last}", record("middle"))).unwrap(); + let rows = archive::load(t.path(), "example.org", "alice").unwrap(); + let (a, b) = edges(t.path()).unwrap().unwrap(); + assert_eq!(a.id, rows.first().unwrap().id); + assert_eq!(b.id, rows.last().unwrap().id); + assert_eq!(b.xml, rows.last().unwrap().xml); +} + +#[test] +fn missing_empty_whitespace_and_single_record() { + let t = tempfile::tempdir().unwrap(); + assert!(edges(t.path()).unwrap().is_none()); + let p = path(t.path()); + for contents in ["", " \t\r\n\n"] { + fs::write(&p, contents).unwrap(); + assert!(edges(t.path()).unwrap().is_none()); + } + // EOF need not have a newline. + fs::write(&p, record("only").trim_end()).unwrap(); + let (first, last) = edges(t.path()).unwrap().unwrap(); + assert_eq!(first.id, "only"); + assert_eq!(last.id, first.id); + assert_eq!(last.xml, first.xml); +} + +#[test] +fn tail_padding_respects_record_bound() { + let t = tempfile::tempdir().unwrap(); + let p = path(t.path()); + let mut data = record("first").into_bytes(); + let last = record("last"); + data.extend_from_slice(last.as_bytes()); + data.resize(data.len() + MAX_RECORD - last.len(), b' '); + fs::write(&p, &data).unwrap(); + assert_eq!(edges(t.path()).unwrap().unwrap().1.id, "last"); + data.push(b' '); + fs::write(&p, data).unwrap(); + assert!(edges(t.path()).unwrap_err().to_string().contains("16 MiB")); +} + +#[test] +fn oversized_prefix_and_malformed_endpoints_fail() { + let t = tempfile::tempdir().unwrap(); + let p = path(t.path()); + let mut data = vec![b' '; MAX_RECORD + 1]; + data.extend_from_slice(b"\n"); + data.extend_from_slice(record("last").as_bytes()); + fs::write(&p, data).unwrap(); + assert!(edges(t.path()).unwrap_err().to_string().contains("16 MiB")); + fs::write(&p, format!("item(bad first);\n{}", record("last"))).unwrap(); + assert!(edges(t.path()).is_err()); + fs::write(&p, format!("{}item(bad last);\n", record("first"))).unwrap(); + assert!(edges(t.path()).is_err()); +} + +#[test] +fn endpoint_read_recovers_partial_append_before_seeking() { + let t = tempfile::tempdir().unwrap(); + let p = path(t.path()); + let committed = format!("{}{}", record("first"), record("last")); + fs::write(&p, format!("{committed}item({{broken partial")).unwrap(); + fs::write( + p.with_extension("rappend"), + (committed.len() as u64).to_le_bytes(), + ) + .unwrap(); + let (first, last) = edges(t.path()).unwrap().unwrap(); + assert_eq!((first.id.as_str(), last.id.as_str()), ("first", "last")); + assert_eq!(fs::read(&p).unwrap(), committed.as_bytes()); + assert!(!p.with_extension("rappend").exists()); +} diff --git a/tests/bind2_archive_latency_network.py b/tests/bind2_archive_latency_network.py new file mode 100644 index 0000000..6b8e79f --- /dev/null +++ b/tests/bind2_archive_latency_network.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +"""Measure real TLS/SASL2 Bind2 reconnects with a large personal MAM history. + +Usage: python3 tests/bind2_archive_latency_network.py --binary BINARY \ + --records 100000 --output REPORT.json + +Seeds valid native records before startup, then checks exact first/last metadata +on every fresh connection. Latency measurements have no performance threshold. +The executable is copied before use so concurrent rebuilds cannot replace it. +""" +import argparse +import datetime +import hashlib +import json +from pathlib import Path +import shutil +import socket +import statistics +import subprocess +import tempfile +import time +import xml.etree.ElementTree as ET + +from sasl2_bind import BIND2, SASL2, Client + +MAM = 'urn:xmpp:mam:2' +BASE_TIME = 1767225600 + + +def stamp(seconds): + return datetime.datetime.fromtimestamp(seconds, datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') + + +def distribution(values): + ordered = sorted(values) + return {'samples_ms': values, 'median_ms': statistics.median(values), + 'p95_ms': ordered[min(len(ordered) - 1, int(len(ordered) * .95))], + 'max_ms': ordered[-1]} + + +def exercise(binary, root, records, samples): + with socket.socket() as probe: + probe.bind(('127.0.0.1', 0)) + port = probe.getsockname()[1] + subprocess.run(['openssl', 'req', '-x509', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:P-256', + '-nodes', '-days', '1', '-subj', '/CN=localhost', '-addext', 'subjectAltName=DNS:localhost', + '-addext', 'basicConstraints=critical,CA:FALSE', '-keyout', str(root/'key.pem'), + '-out', str(root/'cert.pem')], check=True, capture_output=True) + config = root/'config.json' + config.write_text(json.dumps({'global': {'data_path': str(root/'data'), 'interfaces': ['127.0.0.1'], + 'c2s_ports': [port], 's2s_ports': [], 'http_ports': [], 'https_ports': [], + 'modules_enabled': ['tls', 'saslauth', 'sasl2', 'sasl2_bind2', 'mam', 'carbons', 'csi_simple', 'smacks'], + 'default_archive_policy': True, 'archive_expires_after': 'never'}, + 'hosts': {'localhost': {'options': {'authentication': 'internal_hashed', 'password_hash': 'SHA-256', + 'ssl': {'key': str(root/'key.pem'), 'certificate': str(root/'cert.pem')}}}}})) + subprocess.run([str(binary), 'create-user', str(config), 'alice', '--password-stdin'], + input='secret\n', text=True, check=True, capture_output=True) + archive = root/'data'/'localhost'/'archive'/'alice.list' + archive.parent.mkdir(parents=True, exist_ok=True) + with archive.open('w') as output: + for number in range(records): + output.write("item({name='message';attr={xmlns='jabber:client';type='chat';" + f"from='bob@localhost';stamp='{stamp(BASE_TIME + number)}'" + "};" + f"key='seed-{number}';when={BASE_TIME + number};with='bob@localhost';" + "{name='body';attr={};'seed personal history'}});\n") + expected = {'start': {'id': 'seed-0', 'timestamp': stamp(BASE_TIME)}, + 'end': {'id': f'seed-{records - 1}', 'timestamp': stamp(BASE_TIME + records - 1)}} + archive_bytes = archive.stat().st_size + index_before_start = archive.with_suffix('.lidx').exists() + assert not index_before_start, 'seed unexpectedly has a native index' + auth_ms, connect_ms, metadata_ms = [], [], [] + metadata_samples, iq_metadata_samples = [], [] + with (root/'server.log').open('w+') as log: + server = subprocess.Popen([str(binary), 'serve', str(config), '--experimental'], stdout=log, stderr=log) + try: + deadline = time.monotonic() + 30 + while True: + assert server.poll() is None, 'server stopped before readiness' + try: + with socket.create_connection(('127.0.0.1', port), timeout=.1): + break + except OSError: + assert time.monotonic() < deadline, 'server did not start' + time.sleep(.05) + for sample in range(samples): + # Each sample reconnects and authenticates the same account. + # Client verifies the advertised SASL2/Bind2 inline features. + connected = time.perf_counter() + client = Client(port, root/'cert.pem') + client.sock.settimeout(30) + try: + begun = time.perf_counter() + response = client.auth(f"HistoryReconnect") + arrived = time.perf_counter() + auth_ms.append((arrived - begun) * 1000) + connect_ms.append((arrived - connected) * 1000) + jid = response.find('{' + SASL2 + '}authorization-identifier') + assert jid is not None and jid.text.startswith('alice@localhost/HistoryReconnect/'), 'missing bound JID' + bound = response.find('{' + BIND2 + '}bound') + assert bound is not None, 'missing Bind2 bound result' + metadata = bound.find('{' + MAM + '}metadata') + assert metadata is not None, 'missing MAM metadata' + actual = {} + for edge in ('start', 'end'): + node = metadata.find('{' + MAM + '}' + edge) + assert node is not None, f'missing MAM {edge}' + actual[edge] = dict(node.attrib) + assert actual == expected, (actual, expected) + assert len(list(metadata)) == 2, 'unexpected MAM metadata children' + metadata_samples.append(actual) + # Session is immediately bound; the post-success features + # must not ask this client to perform legacy resource bind. + assert b'xmpp-bind' not in client.until(b'') + query_id = f'metadata-{sample}' + begun = time.perf_counter() + client.send(f"") + iq = ET.fromstring(client.until(b'')) + metadata_ms.append((time.perf_counter() - begun) * 1000) + assert iq.get('type') == 'result' and iq.get('id') == query_id, 'metadata IQ failed' + iq_metadata = iq.find('{' + MAM + '}metadata') + assert iq_metadata is not None, 'metadata IQ payload missing' + iq_actual = {} + for edge in ('start', 'end'): + node = iq_metadata.find('{' + MAM + '}' + edge) + assert node is not None, f'missing metadata IQ {edge}' + iq_actual[edge] = dict(node.attrib) + assert iq_actual == expected, (iq_actual, expected) + assert len(list(iq_metadata)) == 2, 'unexpected metadata IQ children' + iq_metadata_samples.append(iq_actual) + finally: + client.close() + assert archive.stat().st_size == archive_bytes, 'reconnect modified seeded history' + finally: + server.terminate() + try: + server.wait(timeout=5) + except subprocess.TimeoutExpired: + server.kill() + server.wait() + return {'status': 'pass', 'seeded_personal_archive_records': records, 'archive_bytes': archive_bytes, + 'archive_expires_after': 'never', 'index_present_before_start': index_before_start, + 'reconnect_samples': samples, 'expected_metadata': expected, 'observed_metadata': metadata_samples, + 'mam_metadata_iq': distribution(metadata_ms), 'observed_iq_metadata': iq_metadata_samples, + 'sasl2_bind2_success': distribution(auth_ms), 'tcp_starttls_to_bind2_success': distribution(connect_ms)} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--binary', required=True) + parser.add_argument('--records', type=int, default=100000) + parser.add_argument('--samples', type=int, default=10) + parser.add_argument('--output') + args = parser.parse_args() + assert args.records > 0 and args.samples > 0 + source = Path(args.binary).resolve() + with tempfile.TemporaryDirectory(prefix='xmpp-bind2-archive-latency-') as directory: + root = Path(directory) + binary = root/'rust-xmpp' + shutil.copy2(source, binary) + report = {'binary_source': str(source), 'binary_sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), + 'scope': 'real loopback TCP/STARTTLS/SASL2 Bind2; isolated personal MAM fixture; no production latency claim', + 'timing': 'raw ordered samples; auth timer starts before authenticate and ends at parsed success; full timer includes TCP/STARTTLS/features; metadata IQ timer runs from send to parsed result', + 'result': exercise(binary, root, args.records, args.samples)} + text = json.dumps(report, indent=2) + '\n' + if args.output: + Path(args.output).write_text(text) + print(text, end='') + + +if __name__ == '__main__': + main() diff --git a/tests/message_latency_network.py b/tests/message_latency_network.py new file mode 100644 index 0000000..c5282c7 --- /dev/null +++ b/tests/message_latency_network.py @@ -0,0 +1,255 @@ +#!/usr/bin/env python3 +"""Measure real STARTTLS direct/MUC delivery with durable SM and CSI. + +Usage: python3 tests/message_latency_network.py --binary target/release/rust-xmpp +Reports loopback median/p95/max, not a production latency guarantee. There are +no millisecond performance assertions: bounded delivery, exact counts, SM +counters and durable CSI buffering/urgent flush are the regression assertions. +The source executable is copied before testing so concurrent rebuilds are safe. +""" +import argparse +import asyncio +import collections +import datetime +import hashlib +import json +import pathlib +import shutil +import socket +import ssl +import statistics +import subprocess +import tempfile +import time + +from muc_sm_load_network import Client, MUC, start +from muc_restart_network import stop + + +class TimedBodies(collections.Counter): + def __init__(self): + super().__init__() + self.arrivals = {} + + def __setitem__(self, key, value): + self.arrivals.setdefault(key, time.perf_counter()) + super().__setitem__(key, value) + + +def distribution(values): + values = sorted(value * 1000 for value in values) + return {'samples': len(values), 'median_ms': statistics.median(values), + 'p95_ms': values[min(len(values) - 1, int(len(values) * .95))], + 'max_ms': values[-1], 'samples_ms': values} + + +async def bounded(operation): + # A functional timeout, deliberately much wider than a performance budget. + return await asyncio.wait_for(operation, 20) + + +async def body(client, text): + await bounded(client.wait(lambda: client.bodies[text] == 1, text)) + return client.bodies.arrivals[text] + + +def slot(root, client): + paths = list((root / 'data').rglob(client.token + '.json')) + assert len(paths) == 1, 'missing or duplicate durable SM record' + return json.loads(paths[0].read_text()) + + +async def queued(root, client, text): + # Observe persisted queue state instead of assuming a short socket timeout + # proves buffering. Bob sends no input/acks that could flush CSI here. + deadline = time.monotonic() + 20 + while time.monotonic() < deadline: + record = slot(root, client) + if any(text in xml for xml in record['csi']['queue']): + assert client.bodies[text] == 0, 'buffered message leaked onto wire' + return + assert client.bodies[text] == 0, 'inactive CSI failed to hold headline' + await asyncio.sleep(.01) + raise AssertionError('headline did not enter durable CSI queue') + + +async def csi_state(root, client, state): + # Alternate first so persisted state proves this exact control was handled, + # including resetting any temporary flushing window. A ping on the receiver + # would itself cause CSI activity and invalidate the buffering experiment. + for target in (state != 'inactive', state == 'inactive'): + await client.send(f"<{'inactive' if target else 'active'} xmlns='urn:xmpp:csi:0'/>") + deadline = time.monotonic() + 20 + while slot(root, client)['csi']['inactive'] != target: + assert time.monotonic() < deadline, 'CSI state was not durably handled' + await asyncio.sleep(.001) + + +async def exercise(root, port, rounds, archive, history_records): + context = ssl.create_default_context(cafile=str(root / 'cert.pem')) + clients = [] + report = {'mam_enabled': archive, 'sm_enabled': True, 'rounds': rounds, + 'seeded_muc_archive_records': history_records if archive else 0} + try: + for number in range(2): + client = await bounded(Client.connect(number, port, context, 2)) + clients.append(client) + client.bodies = TimedBodies() + # Explicit acks between samples avoid racing inbound ack activity + # with inactive-CSI assertions. SM remains enabled throughout. + client.auto_ack = False + await bounded(client.enable()) + await client.stanza('') + await bounded(client.fence(f'connected-{number}')) + await client.ack() + alice, bob = clients + room = 'latency@rooms.localhost' + for client in clients: + await client.stanza(f"") + await bounded(client.wait(lambda c=client: c.presences.get(f'{room}/Nick-{c.number}'), 'MUC self presence')) + assert client.presences[f'{room}/Nick-{client.number}'].get('type') != 'error' + for client in clients: + await bounded(client.fence(f'joined-{client.number}')) + await client.ack() + + for state in ('active', 'inactive'): + measurements = collections.defaultdict(list) + for turn in range(rounds): + # Reset CSI immediately before each sample: an important output + # opens a configured temporary flushing window for later output. + await csi_state(root, bob, state) + text = f'{state}-direct-{turn}' + begun = time.perf_counter() + await alice.stanza(f"{text}") + arrived = await body(bob, text) + measurements['direct_peer'].append(arrived - begun) + reply = text + '-reply' + await bob.stanza(f"{reply}") + measurements['direct_application_rtt'].append(await body(alice, reply) - begun) + await csi_state(root, bob, state) + text = f'{state}-muc-{turn}' + begun = time.perf_counter() + await alice.stanza(f"{text}") + echo, peer = await asyncio.gather(body(alice, text), body(bob, text)) + measurements['muc_sender_echo'].append(echo - begun) + measurements['muc_peer'].append(peer - begun) + for client in clients: + await client.ack() + report[state] = {name: distribution(values) for name, values in measurements.items()} + + # A low-priority headline is actually held; a normal chat body must + # release it in order even while the receiver remains CSI inactive. + await csi_state(root, bob, 'inactive') + held, urgent = 'queued-before-urgent', 'urgent-flush-body' + await alice.stanza(f"{held}") + await bounded(alice.fence('headline-routed')) + await queued(root, bob, held) + begun = time.perf_counter() + await alice.stanza(f"{urgent}") + held_at, urgent_at = await asyncio.gather(body(bob, held), body(bob, urgent)) + assert held_at <= urgent_at, 'urgent flush reordered queued output' + report['urgent_flush'] = distribution([urgent_at - begun]) + report['headline_durably_buffered'] = True + + # Explicit activation must independently drain low-priority output. + await bob.ack() + await csi_state(root, bob, 'inactive') + held = 'queued-before-active' + await alice.stanza(f"{held}") + await bounded(alice.fence('activation-headline-routed')) + await queued(root, bob, held) + await bob.send("") + await body(bob, held) + report['activation_drained_queue'] = True + for client in clients: + await bounded(client.fence(f'final-{client.number}')) + await client.ack() + await bounded(client.handled()) + assert not client.errors, client.errors + assert all(count == 1 for count in client.bodies.values()), 'duplicate wire delivery' + archives = list((root / 'data' / 'localhost' / 'archive').glob('*.list')) + records = sum(sum(line.startswith('item(') for line in path.open()) for path in archives) + assert (records > 0) == archive, ('MAM toggle did not affect actual archive storage', records) + report['personal_archive_records'] = records + muc_archive = root / 'data' / 'rooms%2elocalhost' / 'muc_log' / 'latency.list' + muc_records = sum(line.startswith('item(') for line in muc_archive.open()) if muc_archive.exists() else 0 + assert muc_records == (history_records + 2 * rounds if archive else 0), ('MUC archive seed/append mismatch', muc_records) + report['muc_archive_records'] = muc_records + report['wire_body_deliveries'] = sum(sum(client.bodies.values()) for client in clients) + assert report['wire_body_deliveries'] == rounds * 8 + 3 + report['status'] = 'pass' + return report + finally: + await asyncio.gather(*(client.close_raw() for client in clients), return_exceptions=True) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--binary', default='target/release/rust-xmpp') + parser.add_argument('--rounds', type=int, default=20) + parser.add_argument('--history-records', type=int, nargs='+', default=[0], + help='MUC native archive sizes to seed before starting each isolated server') + parser.add_argument('--output', help='optional JSON measurement report') + args = parser.parse_args() + assert args.rounds > 0 + assert all(count >= 0 for count in args.history_records) + with tempfile.TemporaryDirectory(prefix='xmpp-message-latency-') as directory: + work = pathlib.Path(directory) + binary = work / 'rust-xmpp' + shutil.copy2(pathlib.Path(args.binary).resolve(), binary) + report = {'binary_sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), + 'scope': 'loopback STARTTLS; isolated fixture; no production latency claim', 'cases': []} + cases = [(False, 0)] + [(True, count) for count in args.history_records] + for archive, history_records in cases: + root = work / (f'mam-on-{history_records}' if archive else 'mam-off') + root.mkdir() + subprocess.run(['openssl', 'req', '-x509', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:P-256', + '-nodes', '-days', '1', '-subj', '/CN=localhost', '-addext', 'subjectAltName=DNS:localhost', + '-addext', 'basicConstraints=critical,CA:FALSE', '-keyout', str(root/'key.pem'), + '-out', str(root/'cert.pem')], check=True, capture_output=True) + with socket.socket() as probe: + probe.bind(('127.0.0.1', 0)) + port = probe.getsockname()[1] + modules = ['tls', 'saslauth', 'smacks', 'csi_simple', 'ping', 'disco'] + if archive: + modules.append('mam') + config = root / 'config.json' + config.write_text(json.dumps({'global': {'data_path': str(root/'data'), 'interfaces': ['127.0.0.1'], + 'c2s_ports': [port], 's2s_ports': [], 'http_ports': [], 'https_ports': [], + 'modules_enabled': modules, 'default_archive_policy': True, 'archive_expires_after': 'never', + 'ssl': {'key': str(root/'key.pem'), 'certificate': str(root/'cert.pem')}}, + 'hosts': {'localhost': {'options': {'authentication': 'internal_hashed', 'password_hash': 'SHA-256'}}, + 'rooms.localhost': {'component': 'muc', 'options': {'muc_room_locking': False, + 'modules_enabled': ['muc_mam'] if archive else [], + 'muc_log_expires_after': 604800}}}})) + for number in range(2): + subprocess.run([str(binary), 'create-user', str(config), f'load-{number}', '--password-stdin'], + input='load-test-password\n', text=True, check=True, capture_output=True) + if archive and history_records: + # Native Prosody `.list` fixture, matching archive_mam.rs. All + # timestamps are recent, so retention scans must retain them. + # Seeding occurs before any server opens this isolated store. + archive_path = root / 'data' / 'rooms%2elocalhost' / 'muc_log' / 'latency.list' + archive_path.parent.mkdir(parents=True, exist_ok=True) + now = time.time() + stamp = datetime.datetime.fromtimestamp(now, datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') + with archive_path.open('w') as output: + for number in range(history_records): + output.write("item({name='message';attr={xmlns='jabber:client';type='groupchat';" + f"from='latency@rooms.localhost/Seed';stamp='{stamp}'" + "};" + f"key='seed-{number}';when={now};with='message ModuleResult { + let doc = roxmltree::Document::parse(xml).unwrap(); + muc.handle("alice@test/a", doc.root_element()) + .unwrap() + .unwrap() +} + +fn room(muc: &mut Muc, name: &str) { + send( + muc, + &format!( + "" + ), + ); + send( + muc, + &format!( + "" + ), + ); +} + +fn chat(muc: &mut Muc) -> ModuleResult { + send( + muc, + "Fresh", + ) +} + +fn mark(path: &Path) -> SystemTime { + let marker = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_000_000); + fs::File::options() + .write(true) + .open(path) + .unwrap() + .set_times(fs::FileTimes::new().set_modified(marker)) + .unwrap(); + fs::metadata(path).unwrap().modified().unwrap() +} + +#[test] +fn groupchat_skips_native_rewrites_and_archive_retention_scan() { + let temp = tempfile::tempdir().unwrap(); + let mut muc = Muc::new(temp.path().into(), "rooms.test".into()); + muc.set_defaults(serde_json::json!({"persistent":true,"archiving":true})); + muc.set_archive_retention(Some(60.0)); + room(&mut muc, "r"); + room(&mut muc, "other"); + + let config = storage::path(temp.path(), "rooms.test", Some("r"), "config"); + let other = storage::path(temp.path(), "rooms.test", Some("other"), "config"); + let index = storage::path(temp.path(), "rooms.test", None, "persistent"); + let journal = storage::path(temp.path(), "rooms.test", None, "rust_muc_checkpoint"); + let config_time = mark(&config); + let other_time = mark(&other); + let index_time = mark(&index); + let journal_time = mark(&journal); + + // An unreadable historic record makes any accidental full archive scan fail. + // Appending a fresh record needs only the existing file length, never its XML. + let log = storage::path(temp.path(), "rooms.test", Some("r"), "muc_log").with_extension("list"); + fs::create_dir_all(log.parent().unwrap()).unwrap(); + let historic = b"item(this is intentionally invalid historic archive data);\n"; + fs::write(&log, historic).unwrap(); + let delivered = chat(&mut muc); + assert_eq!(delivered.deliveries.len(), 1); + let contents = fs::read(&log).unwrap(); + assert!(contents.starts_with(historic)); + assert!(contents.len() > historic.len()); + assert!(archive::load_store(temp.path(), "rooms.test", Some("r"), "muc_log").is_err()); + for (path, before) in [ + (&config, config_time), + (&other, other_time), + (&index, index_time), + ] { + assert_eq!(fs::metadata(path).unwrap().modified().unwrap(), before); + } + assert_ne!( + fs::metadata(&journal).unwrap().modified().unwrap(), + journal_time + ); + assert!(fs::read_to_string(journal).unwrap().contains("Fresh")); +} + +#[test] +fn native_exports_repair_missing_files_and_export_changed_config() { + let temp = tempfile::tempdir().unwrap(); + let mut muc = Muc::new(temp.path().into(), "rooms.test".into()); + muc.set_defaults(serde_json::json!({"persistent":true})); + room(&mut muc, "r"); + room(&mut muc, "other"); + let config = storage::path(temp.path(), "rooms.test", Some("r"), "config"); + let other = storage::path(temp.path(), "rooms.test", Some("other"), "config"); + let index = storage::path(temp.path(), "rooms.test", None, "persistent"); + let original = fs::read(&config).unwrap(); + fs::remove_file(&config).unwrap(); + fs::remove_file(&index).unwrap(); + assert_eq!(chat(&mut muc).deliveries.len(), 1); + assert_eq!(fs::read(&config).unwrap(), original); + let recovered = storage::load(temp.path(), "rooms.test", None, "persistent") + .unwrap() + .unwrap(); + assert_eq!( + recovered.get("r@rooms.test"), + Some(&storage::LuaValue::Bool(true)) + ); + assert_eq!( + recovered.get("other@rooms.test"), + Some(&storage::LuaValue::Bool(true)) + ); + let other_time = mark(&other); + let index_time = mark(&index); + let result = send( + &mut muc, + "Updated", + ); + assert!(result.replies[0].contains("result")); + assert!(fs::read_to_string(config).unwrap().contains("Updated")); + assert_eq!(fs::metadata(other).unwrap().modified().unwrap(), other_time); + assert_eq!( + fs::metadata(&index).unwrap().modified().unwrap(), + index_time + ); + + // Export failures are nonfatal after the authoritative room commit, and + // exports must be retried even if no configuration changed since failure. + fs::remove_file(&index).unwrap(); + fs::create_dir(&index).unwrap(); + assert_eq!(chat(&mut muc).deliveries.len(), 1); + fs::remove_dir(&index).unwrap(); + assert_eq!(chat(&mut muc).deliveries.len(), 1); + let recovered = storage::load(temp.path(), "rooms.test", None, "persistent") + .unwrap() + .unwrap(); + assert_eq!( + recovered.get("r@rooms.test"), + Some(&storage::LuaValue::Bool(true)) + ); + assert_eq!( + recovered.get("other@rooms.test"), + Some(&storage::LuaValue::Bool(true)) + ); +} diff --git a/tests/personal_message_latency_network.py b/tests/personal_message_latency_network.py new file mode 100644 index 0000000..51900bb --- /dev/null +++ b/tests/personal_message_latency_network.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python3 +"""Separate personal-chat wire delivery, handled SM ACK and client receipt timing. + +Native personal MAM/roster fixtures, real loopback STARTTLS, durable SM/CSI. +A forced CSI dwell is reported explicitly and is not a server performance sample. +The default exercises both the runtime defaults (urgent encrypted/receipt payloads) +and an explicit empty importance list (native policy). Use --expect-held for the +old binary; --csi-policy default limits a baseline run to its default policy. +""" +import argparse +import asyncio +import collections +import hashlib +import json +import pathlib +import shutil +import socket +import ssl +import subprocess +import tempfile +import time +import xml.etree.ElementTree as ET + +from message_latency_network import bounded, csi_state, distribution, slot +from muc_sm_load_network import Client, CLIENT, SM, start +from muc_restart_network import stop + + +class ObservedReader: + """Observe complete wire stanzas while retaining the existing client's parser.""" + def __init__(self, reader, client): + self.reader, self.client = reader, client + self.parser = ET.XMLPullParser(events=('start', 'end')) + self.parser.feed("") + self.root = next(self.parser.read_events())[1] + self.depth = 0 + + def __getattr__(self, name): + return getattr(self.reader, name) + + async def read(self, size): + chunk = await self.reader.read(size) + self.parser.feed(chunk) + for event, node in self.parser.read_events(): + self.depth += 1 if event == 'start' else -1 + if event == 'end' and self.depth == 0: + now = time.perf_counter() + if node.tag == f'{{{CLIENT}}}message' and node.get('id'): + self.client.message_times[node.get('id')].append(now) + if node.tag == f'{{{SM}}}a': + self.client.ack_times[int(node.get('h'))] = now + self.root.remove(node) + return chunk + + +class MeasuredClient(Client): + def __init__(self, *args): + super().__init__(*args) + self.message_times = collections.defaultdict(list) + self.ack_times = {} + self.reader = ObservedReader(self.reader, self) + + +async def seen(client, identifier): + await bounded(client.wait(lambda: client.message_times[identifier], identifier)) + assert len(client.message_times[identifier]) == 1 + return client.message_times[identifier][0] + + +async def send_measured(sender, receiver, identifier, payload, typ='chat'): + begun = time.perf_counter() + await sender.stanza(f"{payload}") + await bounded(sender.handled()) + ack_at = sender.ack_times[sender.inputs] + return begun, ack_at + + +async def exercise(root, port, args, policy): + clients = [] + try: + context = ssl.create_default_context(cafile=str(root/'cert.pem')) + for n in range(2): + client = await bounded(MeasuredClient.connect(n, port, context, 2)) + clients.append(client) + client.auto_ack = False + await bounded(client.enable()) + await client.stanza('') + await bounded(client.fence(f'connected-{n}')) + await client.ack() + alice, bob = clients + results = {} + for state in ('active', 'inactive'): + values = collections.defaultdict(list) + for turn in range(args.rounds): + await csi_state(root, alice, 'active') + await csi_state(root, bob, state) + identifier = f'{state}-body-{turn}' + begun, ack_at = await send_measured(alice, bob, identifier, 'personal test') + delivery = await seen(bob, identifier) + receipt_id = identifier + '-receipt' + # Receipt generation belongs to the receiving client; the server + # does not synthesize XEP-0184 receipts on SM acknowledgement. + receipt_sent = time.perf_counter() + await bob.stanza(f"") + receipt = await seen(alice, receipt_id) + values['delivery'].append(delivery-begun) + values['sender_sm_handled'].append(ack_at-begun) + values['client_receipt_end_to_end'].append(receipt-begun) + values['receipt_return_leg'].append(receipt-receipt_sent) + for client in clients: + await client.ack() + results[state] = {name: distribution(v) for name, v in values.items()} + + payloads = { + 'receipt_only': "", + 'omemo_legacy_only': "
AA==
AA==
", + 'omemo_2_only': "
AA==
AA==
", + 'omemo_with_eme': "AA==", + } + payloads.update({f'marker_{name}': + f"<{name} xmlns='urn:xmpp:chat-markers:0' id='earlier-message'/>" + for name in ('received', 'displayed', 'acknowledged')}) + payloads['low_priority_headline'] = 'held low priority' + for name, payload in payloads.items(): + for state in ('active', 'inactive'): + await csi_state(root, alice, 'active') + await csi_state(root, bob, state) + identifier = name + '-' + state + begun, ack_at = await send_measured(alice, bob, identifier, payload, + 'headline' if name == 'low_priority_headline' else 'chat') + deadline = time.monotonic() + 20 + while True: + buffered = any(identifier in xml for xml in slot(root, bob)['csi']['queue']) + if buffered or bob.message_times[identifier]: + break + assert time.monotonic() < deadline, identifier + await asyncio.sleep(.001) + expect_held = state == 'inactive' and ( + name == 'low_priority_headline' or ( + name != 'omemo_with_eme' and (policy == 'native' or args.expect_held))) + assert buffered == expect_held, (policy, identifier, buffered, expect_held) + activation = None + if buffered: + assert not bob.message_times[identifier] + await asyncio.sleep(args.csi_dwell) + assert not bob.message_times[identifier], 'CSI unexpectedly emitted held payload' + activation = time.perf_counter() + await bob.send("") + delivered = await seen(bob, identifier) + results[identifier] = {'delivery_ms': (delivered-begun)*1000, + 'sender_sm_handled_ms': (ack_at-begun)*1000, + 'durably_csi_buffered': buffered, + 'forced_dwell_seconds': args.csi_dwell if buffered else 0, + 'after_activation_ms': (delivered-activation)*1000 if activation else None} + for client in clients: + await client.ack() + + await csi_state(root, bob, 'active') + # Keep receiving/draining but deliberately withhold recipient ACKs. + for n in range(args.backlog): + await alice.stanza(f"unacked backlog") + await seen(bob, f'backlog-{n}') + if args.backlog: + await seen(bob, f'backlog-{args.backlog-1}') + await bounded(alice.handled()) + pending = len(slot(root, bob)['pending']) + begun, ack_at = await send_measured(alice, bob, 'after-backlog', 'after backlog') + delivery = await seen(bob, 'after-backlog') + results['sm_backlog'] = {'seeded_messages': args.backlog, 'durable_pending_before_sample': pending, + 'delivery_ms': (delivery-begun)*1000, 'sender_sm_handled_ms': (ack_at-begun)*1000} + for client in clients: + await client.ack() + assert not client.errors, client.errors + results['status'] = 'pass' + return results + finally: + await asyncio.gather(*(c.close_raw() for c in clients), return_exceptions=True) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--binary', default='target/release/rust-xmpp') + parser.add_argument('--rounds', type=int, default=3) + parser.add_argument('--history-records', type=int, default=100000) + parser.add_argument('--roster-sizes', type=int, nargs='+', default=[0, 5000, 10000]) + parser.add_argument('--backlog', type=int, default=500) + parser.add_argument('--csi-dwell', type=float, default=2) + parser.add_argument('--csi-policy', choices=('default', 'native', 'both'), default='both', + help='native explicitly configures csi_important_payloads=[]; both verifies override') + parser.add_argument('--expect-held', action='store_true', + help='baseline binaries: expect native holds even when option is absent') + parser.add_argument('--output') + args = parser.parse_args() + assert args.rounds > 0 and args.history_records >= 0 + assert all(count >= 0 for count in args.roster_sizes) + assert 0 <= args.backlog < 4000 and args.csi_dwell >= 0 + with tempfile.TemporaryDirectory(prefix='xmpp-personal-latency-') as directory: + work = pathlib.Path(directory) + binary = work/'rust-xmpp' + shutil.copy2(pathlib.Path(args.binary).resolve(), binary) + report = {'binary_sha256': hashlib.sha256(binary.read_bytes()).hexdigest(), + 'scope': 'loopback STARTTLS; fixture only; forced CSI dwell explicitly separated', 'cases': []} + policies = ('default', 'native') if args.csi_policy == 'both' else (args.csi_policy,) + for roster_size, policy in ((n, p) for n in args.roster_sizes for p in policies): + root = work/f'roster-{roster_size}-{policy}' + root.mkdir() + subprocess.run(['openssl', 'req', '-x509', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:P-256', + '-nodes', '-days', '1', '-subj', '/CN=localhost', '-addext', 'subjectAltName=DNS:localhost', + '-keyout', str(root/'key.pem'), '-out', str(root/'cert.pem')], check=True, capture_output=True) + with socket.socket() as probe: + probe.bind(('127.0.0.1', 0)) + port = probe.getsockname()[1] + config = root/'config.json' + config.write_text(json.dumps({'global': {'data_path': str(root/'data'), 'interfaces': ['127.0.0.1'], + 'c2s_ports': [port], 's2s_ports': [], 'http_ports': [], 'https_ports': [], + 'modules_enabled': ['tls', 'saslauth', 'smacks', 'csi_simple', 'ping', 'mam', 'roster'], + 'default_archive_policy': 'roster' if roster_size else True, 'archive_expires_after': 'never', + 'ssl': {'key': str(root/'key.pem'), 'certificate': str(root/'cert.pem')}}, + 'hosts': {'localhost': {'options': {'authentication': 'internal_hashed', 'password_hash': 'SHA-256'}}}})) + if policy == 'native': + configured = json.loads(config.read_text()) + configured['global']['csi_important_payloads'] = [] + config.write_text(json.dumps(configured)) + for n in range(2): + subprocess.run([str(binary), 'create-user', str(config), f'load-{n}', '--password-stdin'], + input='load-test-password\n', text=True, check=True, capture_output=True) + archive = root/'data'/'localhost'/'archive'/f'load%2d{n}.list' + archive.parent.mkdir(parents=True, exist_ok=True) + now = time.time() + with archive.open('w') as output: + for i in range(args.history_records): + output.write("item({name='message';attr={xmlns='jabber:client';type='chat'};" + f"key='seed-{i}';when={now};with='load-{1-n}@localhost';" + "{name='body';attr={};'native personal history'}});\n") + if roster_size: + roster = root/'data'/'localhost'/'roster'/f'load%2d{n}.dat' + roster.parent.mkdir(parents=True, exist_ok=True) + with roster.open('w') as output: + output.write("return { [false]={version=1};\n") + output.write(f"['load-{1-n}@localhost']={{subscription='none'}};\n") + for i in range(roster_size-1): + output.write(f"['contact-{i}@example.invalid']={{subscription='none'}};\n") + output.write('}\n') + with (root/'server.log').open('w+') as log: + server = start(str(binary), config, port, log) + try: + results = asyncio.run(exercise(root, port, args, policy)) + counts = [sum(line.startswith('item(') for line in path.open()) + for path in sorted((root/'data'/'localhost'/'archive').glob('*.list'))] + expected = args.history_records + 4*args.rounds + 10 + args.backlog + 1 + assert counts == [expected, expected], (counts, expected) + results['final_personal_mam_records_per_user'] = counts + results.update({'csi_policy': policy, 'baseline_expect_held': args.expect_held, + 'roster_contacts_per_user': roster_size, + 'seeded_personal_mam_records_per_user': args.history_records, + 'archive_policy': 'roster' if roster_size else 'always'}) + report['cases'].append(results) + if args.output: + pathlib.Path(args.output).write_text(json.dumps(report, indent=2)+'\n') + print(f'personal latency: roster={roster_size} csi={policy} pass', flush=True) + finally: + stop(server) + result = json.dumps(report, indent=2)+'\n' + if args.output: + pathlib.Path(args.output).write_text(result) + print(result, end='') + + +if __name__ == '__main__': + main() diff --git a/tests/push_latency_network.py b/tests/push_latency_network.py new file mode 100644 index 0000000..6477421 --- /dev/null +++ b/tests/push_latency_network.py @@ -0,0 +1,296 @@ +#!/usr/bin/env python3 +"""Personal delivery must not await a stalled external XEP-0357 gateway. + +Real c2s and s2s STARTTLS; Bob hibernates or goes offline with registered push. The +account domain is chat.localhost and the external push service is localhost, +which is not a configured local host. Its standard s2s endpoint is a local +fixture on 127.0.0.1:5269; the special-use localhost name avoids external DNS. +After verified TLS it reads the server's stream but never sends features. +--expect-blocked demonstrates the old bug in a bounded two-second observation; +the default asserts both durable deliveries and Alice's handled SM ACK while +the real gateway transport remains stalled. This is a local regression fixture, +not an APNs/FCM or production-client validation. +""" +import argparse +import asyncio +import hashlib +import json +import os +import pathlib +import shutil +import socket +import ssl +import subprocess +import tempfile +import time + +from message_latency_network import slot +import muc_sm_load_network as network +from muc_sm_load_network import SM, start + +PUSH = 'urn:xmpp:push:0' +GATEWAY = 'localhost' +DOMAIN = 'chat.localhost' +network.STREAM = network.STREAM.replace("to='localhost'", f"to='{DOMAIN}'") + + +class Client(network.Client): + def __init__(self, *args): + super().__init__(*args) + self.jid = self.jid.replace('@localhost/', f'@{DOMAIN}/') + + async def fence(self, identifier): + await self.stanza(f"") + result = await self.wait(lambda: self.iqs.pop(identifier, None), identifier) + assert result.get('type') == 'result' + + +def openssl(root, *args): + subprocess.run(['openssl', *args], cwd=root, check=True, capture_output=True) + + +def certificates(root): + openssl(root, 'req', '-x509', '-newkey', 'ec', '-pkeyopt', + 'ec_paramgen_curve:P-256', '-nodes', '-days', '1', '-subj', + '/CN=Push latency fixture CA', '-addext', + 'basicConstraints=critical,CA:TRUE', '-keyout', 'ca.key', '-out', 'ca.pem') + openssl(root, 'req', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:P-256', + '-nodes', '-subj', '/CN=localhost', '-keyout', 'key.pem', '-out', 'server.csr') + (root/'extensions').write_text('basicConstraints=critical,CA:FALSE\n' + 'keyUsage=critical,digitalSignature\nextendedKeyUsage=serverAuth,clientAuth\n' + 'subjectAltName=DNS:localhost,DNS:chat.localhost\n') + openssl(root, 'x509', '-req', '-in', 'server.csr', '-CA', 'ca.pem', + '-CAkey', 'ca.key', '-CAcreateserial', '-days', '1', '-extfile', + 'extensions', '-out', 'cert.pem') + + +async def poll(predicate, description, timeout=5): + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + if predicate(): + return + await asyncio.sleep(.01) + raise AssertionError(description) + + +class Blackhole: + def __init__(self, root): + self.context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + self.context.load_cert_chain(root/'cert.pem', root/'key.pem') + self.seen = asyncio.Event() + self.tasks = set() + self.writers = set() + self.errors = [] + self.closed = False + self.snapshot = lambda: None + self.pending_at_stream = None + + async def accept(self, reader, writer): + self.tasks.add(asyncio.current_task()) + self.writers.add(writer) + try: + stream = await reader.readuntil(b'>') + if stream.startswith(b'') + assert b'stream:stream' in stream and GATEWAY.encode() in stream + header = ("") + writer.write((header + "" + "").encode()) + await writer.drain() + assert b'starttls' in await reader.readuntil(b'>') + writer.write(b"") + await writer.drain() + await writer.start_tls(self.context) + stream = await reader.readuntil(b'>') + if stream.startswith(b'') + assert b'stream:stream' in stream and GATEWAY.encode() in stream + writer.write(header.encode()) + await writer.drain() + self.pending_at_stream = self.snapshot() + self.seen.set() + # Keep transport open; features are never sent and no route completes. + await reader.read() + self.closed = True + except asyncio.CancelledError: + raise + except Exception as error: + self.errors.append(repr(error)) + finally: + writer.close() + self.writers.discard(writer) + self.tasks.discard(asyncio.current_task()) + + async def close(self): + for task in list(self.tasks): + task.cancel() + await asyncio.gather(*self.tasks, return_exceptions=True) + for writer in list(self.writers): + writer.close() + + +async def exercise(root, binary, config, port, args, log): + gateway = Blackhole(root) + try: + listener = await asyncio.start_server(gateway.accept, '127.0.0.1', 5269) + except OSError as error: + raise RuntimeError(f'push fixture needs an unused {GATEWAY}:5269: {error}') from error + clients = [] + server = None + try: + # rustls-native-certs uses this explicit fixture trust bundle; identity + # verification still checks the remote JID's DNS SAN during real TLS. + previous = os.environ.get('SSL_CERT_FILE') + os.environ['SSL_CERT_FILE'] = str(root/'ca.pem') + try: + server = start(str(binary), config, port, log) + finally: + if previous is None: + os.environ.pop('SSL_CERT_FILE', None) + else: + os.environ['SSL_CERT_FILE'] = previous + context = ssl.create_default_context(cafile=str(root/'ca.pem')) + for number in range(2): + client = await asyncio.wait_for(Client.connect(number, port, context, 2), 10) + clients.append(client) + client.auto_ack = False + if number == 0 or args.recipient == 'hibernating': + await client.enable() + await client.stanza('') + await client.fence(f'ready-{number}') + if client.token: + await client.handled() + await client.ack() + alice, bob = clients + await bob.stanza(f"" + f"") + response = await bob.wait(lambda: bob.iqs.get('push-enable'), 'push registration') + assert response.get('type') == 'result' + if bob.token: + await bob.handled() + await bob.ack() + await poll(lambda: bool(slot(root, bob).get('push_identifier')), 'missing durable push binding') + else: + registration = list((root/'data').rglob('cloud_notify/*.dat')) + assert len(registration) == 1 and 'phone' in registration[0].read_text(), 'missing native push registration' + await bob.close_raw() + mode = 'hibernating' if bob.token else 'removed' + await poll(lambda: any('session-disconnected' in line and mode in line + and bob.jid in line for line in (root/'server.log').read_text().splitlines()), + f'Bob did not enter {mode} state') + if not bob.token: + assert len(list((root/'data').rglob('rust_smacks/*.json'))) == 1, 'offline Bob unexpectedly has an SM slot' + + def pending_state(): + if bob.token: + pending = slot(root, bob)['pending'] + else: + pending = [path.read_text() for path in (root/'data').rglob('offline/*.list')] + return {identifier: any(identifier in stanza for stanza in pending) + for identifier in ('push-first', 'push-second')} + + gateway.snapshot = pending_state + before = alice.inputs + began = time.perf_counter() + for identifier in ('push-first', 'push-second'): + await alice.stanza(f"" + f"{identifier}") + await alice.send(f"") + # Observe for the fixed interval even if a faulty implementation emits an + # early ACK. Durable pending state and a real blocked gateway are required. + await asyncio.sleep(args.bound) + present = pending_state() + acknowledgements = [int(node.get('h')) for node in alice.controls[f'{{{SM}}}a']] + seen_at_bound = gateway.seen.is_set() + assert not gateway.errors and not gateway.closed, (gateway.errors, gateway.closed) + if not args.expect_blocked or bob.token: + assert present['push-first'], 'first message was not durably delivered before push' + if args.expect_blocked: + assert not present['push-second'], 'old blocking behavior was not reproduced' + assert not acknowledgements, acknowledgements + assert slot(root, alice)['handled'] == before, 'first message marked handled before blocked push' + else: + assert present['push-second'], 'second message blocked behind external push' + assert acknowledgements == [alice.inputs], acknowledgements + assert slot(root, alice)['handled'] == alice.inputs + assert not alice.errors, alice.errors + assert gateway.seen.is_set(), f'no real post-TLS push attempt: {gateway.errors}' + assert not gateway.errors and not gateway.closed, (gateway.errors, gateway.closed) + if not args.expect_blocked: + assert gateway.pending_at_stream['push-first'], 'push started before first durable recipient delivery' + elif not bob.token: + assert not present['push-first'], 'old offline ordering bug was not reproduced' + assert not gateway.pending_at_stream['push-first'] + return {'status': 'reproduced-blocking' if args.expect_blocked else 'pass', + 'recipient_state': args.recipient, + 'durable_pending_at_gateway_stream': gateway.pending_at_stream, + 'observation_seconds': args.bound, 'elapsed_seconds': time.perf_counter()-began, + 'gateway_post_tls_stream_observed': gateway.seen.is_set(), + 'gateway_post_tls_stream_at_bound': seen_at_bound, + 'blocked_stage': 'post-tls-features' if gateway.seen.is_set() else 'external-route-before-tcp', + 'durable_pending': present, + 'sender_sm_ack_h': acknowledgements, 'sender_inputs': alice.inputs, + 'sender_handled_before': before} + finally: + # Kill before closing the blackhole: releasing it could complete the old + # awaited route and would invalidate this bounded reproducer. + if server is not None: + server.kill() + server.wait(timeout=5) + listener.close() + await listener.wait_closed() + await gateway.close() + await asyncio.gather(*(client.close_raw() for client in clients), return_exceptions=True) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--binary', default='target/release/rust-xmpp') + parser.add_argument('--expect-blocked', action='store_true') + parser.add_argument('--recipient', choices=('hibernating', 'offline'), default='hibernating') + parser.add_argument('--bound', type=float, default=2) + parser.add_argument('--output') + args = parser.parse_args() + assert 0 < args.bound < 10, 'observation must precede the 30-second federation timeout' + with tempfile.TemporaryDirectory(prefix='xmpp-push-latency-') as directory: + root = pathlib.Path(directory) + binary = root/'rust-xmpp' + shutil.copy2(pathlib.Path(args.binary).resolve(), binary) + certificates(root) + with socket.socket() as probe: + probe.bind(('127.0.0.1', 0)) + port = probe.getsockname()[1] + config = root/'config.json' + config.write_text(json.dumps({'global': {'data_path': str(root/'data'), + 'interfaces': ['127.0.0.1'], 'c2s_ports': [port], 's2s_ports': [], + 'http_ports': [], 'https_ports': [], + 'modules_enabled': ['tls', 'saslauth', 'smacks', 'ping', 'cloud_notify', 's2s'], + 'ssl': {'key': str(root/'key.pem'), 'certificate': str(root/'cert.pem')}}, + 'hosts': {DOMAIN: {'options': {'authentication': 'internal_hashed', + 'password_hash': 'SHA-256'}}}})) + for number in range(2): + subprocess.run([str(binary), 'create-user', str(config), f'load-{number}', + '--password-stdin'], input='load-test-password\n', text=True, + check=True, capture_output=True) + with (root/'server.log').open('w+') as log: + try: + report = asyncio.run(exercise(root, binary, config, port, args, log)) + except BaseException: + log.seek(0) + print(log.read()) + raise + report['binary_version'] = subprocess.run([str(binary), '--version'], + check=True, capture_output=True, text=True).stdout.strip() + report['binary_sha256'] = hashlib.sha256(binary.read_bytes()).hexdigest() + report['scope'] = 'loopback TLS fixture; stalled external XMPP push service; no APNs/FCM' + result = json.dumps(report, indent=2)+'\n' + if args.output: + pathlib.Path(args.output).write_text(result) + print(result, end='') + + +if __name__ == '__main__': + main() diff --git a/tests/session_routing_isolation.rs b/tests/session_routing_isolation.rs new file mode 100644 index 0000000..8bf4c2f --- /dev/null +++ b/tests/session_routing_isolation.rs @@ -0,0 +1,62 @@ +use rust_xmpp::sessions::Hub; +use std::{sync::mpsc, thread, time::Duration}; +use tokio::sync::mpsc as async_mpsc; + +#[test] +fn unrelated_busy_session_does_not_block_account_routing_or_carbons_selection() { + let hub = Hub::default(); + let (a_tx, _a_rx) = async_mpsc::channel(8); + let (b_tx, mut b_rx) = async_mpsc::channel(8); + let a = hub + .bind("alice@x/r", "a", a_tx, Duration::from_secs(30)) + .unwrap(); + let b = hub + .bind("bob@x/r", "b", b_tx, Duration::from_secs(30)) + .unwrap(); + b.lock().unwrap().available = true; + let held = a.lock().unwrap(); + let (done, result) = mpsc::channel(); + let worker = thread::spawn(move || { + assert_eq!(hub.message_targets("bob@x").len(), 1); + assert_eq!(hub.for_owners(&["bob@x", "bob@x"]).len(), 1); + assert_eq!(hub.deliver("bob@x", "bare"), 1); + assert_eq!(hub.deliver("bob@x/r", "full"), 1); + done.send(()).unwrap(); + }); + let completed_while_locked = result.recv_timeout(Duration::from_secs(2)).is_ok(); + drop(held); + worker.join().unwrap(); + assert!( + completed_while_locked, + "routing waited on unrelated account's session lock" + ); + assert_eq!(b_rx.try_recv().unwrap(), "bare"); + assert_eq!(b_rx.try_recv().unwrap(), "full"); +} + +#[test] +fn duplicate_acknowledgement_does_not_rewrite_durable_slot() { + let dir = tempfile::tempdir().unwrap(); + let hub = Hub::persistent(dir.path()).unwrap(); + let (tx, _rx) = async_mpsc::channel(8); + let session = hub + .bind("bob@x/r", "b", tx, Duration::from_secs(30)) + .unwrap(); + let mut state = session.lock().unwrap(); + state.enable(true).unwrap(); + let path = dir + .path() + .join(format!("{}.json", state.resume_id.as_deref().unwrap())); + let marker = std::time::UNIX_EPOCH + Duration::from_secs(1_000_000); + std::fs::File::options() + .write(true) + .open(&path) + .unwrap() + .set_times(std::fs::FileTimes::new().set_modified(marker)) + .unwrap(); + state.ack_requested = true; + state.acknowledge(0).unwrap(); + assert!(!state.ack_requested); + assert_eq!(std::fs::metadata(path).unwrap().modified().unwrap(), marker); + assert!(state.acknowledge(1).is_err()); +}