сообщения больше не выполняется полный 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). - Личные сообщения и 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).
63 lines
2.2 KiB
Rust
63 lines
2.2 KiB
Rust
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());
|
|
}
|