Files
JoeAllen 96865c0588 perf: 深度优化消息内存占用
- 消息缓冲 Vec → VecDeque:原来溢出时 drain(0..n) 每条消息 O(n)
  搬移,高频消息下产生大量拷贝;环形缓冲均摊 O(1),并按配置上限
  预分配避免反复扩容
- connection_id/topic/payload 改 Arc<str>:引擎侧主题驻留
  (10k 上限,超出整体重建),同主题数千条记录只存一份;
  消息列表每帧克隆最多 300 条用于渲染,payload 共享后零拷贝
- 单条 payload 历史保留上限 256KB(retained_payload,UTF-8
  边界安全截断),超大报文不再长期占据环形缓冲;消息行显示
  「已截断」徽章;发布记录改用实际发送字节(修 Base64/Hex
  历史内容与真实报文不一致的隐患)
- live 测试适配 Arc<str>;补截断边界单元测试(22 个 lib 测试 +
  2 个 live 测试通过)
2026-09-29 01:07:32 +08:00

115 lines
3.5 KiB
Rust

//! 真实 MQTT 引擎连通性测试:连接公共 broker,订阅并验证消息回环。
//! 默认忽略;设置 MQTTX_LIVE=1 并加 --ignored 运行(依赖外网)。
use std::time::{Duration, Instant};
use mqttx_desktop::model::{
ConnectionConfig, ConnectionStatus, ProtocolVersion, PublishParams, Subscription, TransportKind,
};
use mqttx_desktop::mqtt::{EngineEvent, MqttEngine};
#[test]
#[ignore = "需外网:MQTTX_LIVE=1 cargo test --test engine_live -- --ignored"]
fn v5_tcp_pubsub_roundtrip() {
let (tx, rx) = smol::channel::unbounded();
let engine = MqttEngine::new(tx);
let mut cfg = ConnectionConfig::new();
cfg.name = "live-v5".into();
cfg.host = "broker.emqx.io".into();
cfg.port = 1883;
cfg.transport = TransportKind::Tcp;
cfg.protocol = ProtocolVersion::V5;
cfg.auto_reconnect = false;
cfg.auto_resubscribe = false;
let cid = cfg.id.clone();
let topic = format!("mqttx/gpui-test/{}/{}", cid, uuid::Uuid::new_v4());
engine.connect(cfg);
assert!(wait_connected(&rx), "未能在 15 秒内连接 broker.emqx.io");
engine.subscribe(cid.clone(), Subscription::new(cid.clone(), topic.clone(), 0));
assert!(wait_subscribe(&rx, &topic), "订阅未确认");
// 等 broker 传播订阅状态
std::thread::sleep(Duration::from_millis(500));
engine.publish(
cid.clone(),
PublishParams {
topic: topic.clone(),
payload: "hello-gpui".into(),
qos: 0,
..Default::default()
},
);
assert!(wait_message(&rx, &topic), "未收到自己发布的消息(回环失败)");
}
#[test]
#[ignore = "需外网:MQTTX_LIVE=1 cargo test --test engine_live -- --ignored"]
fn v311_tcp_connect() {
let (tx, rx) = smol::channel::unbounded();
let engine = MqttEngine::new(tx);
let mut cfg = ConnectionConfig::new();
cfg.host = "broker.emqx.io".into();
cfg.port = 1883;
cfg.protocol = ProtocolVersion::V311;
cfg.auto_reconnect = false;
cfg.auto_resubscribe = false;
engine.connect(cfg);
assert!(wait_connected(&rx), "MQTT 3.1.1 连接失败");
}
fn pump<F: FnMut(&EngineEvent) -> bool>(
rx: &smol::channel::Receiver<EngineEvent>,
timeout: Duration,
mut pred: F,
) -> bool {
let deadline = Instant::now() + timeout;
while Instant::now() < deadline {
match rx.try_recv() {
Ok(ev) => {
if pred(&ev) {
return true;
}
}
Err(_) => std::thread::sleep(Duration::from_millis(30)),
}
}
false
}
fn wait_connected(rx: &smol::channel::Receiver<EngineEvent>) -> bool {
pump(rx, Duration::from_secs(15), |ev| match ev {
EngineEvent::Status {
status: ConnectionStatus::Connected,
..
} => true,
EngineEvent::Status {
status: ConnectionStatus::Error,
error,
..
} => panic!("连接错误: {error:?}"),
_ => false,
})
}
fn wait_subscribe(rx: &smol::channel::Receiver<EngineEvent>, topic: &str) -> bool {
pump(rx, Duration::from_secs(8), |ev| match ev {
EngineEvent::SubscribeResult { topic: t, ok, .. } => t == topic && *ok,
_ => false,
})
}
fn wait_message(rx: &smol::channel::Receiver<EngineEvent>, topic: &str) -> bool {
pump(rx, Duration::from_secs(10), |ev| match ev {
EngineEvent::Message(m) => &*m.topic == topic && &*m.payload == "hello-gpui",
_ => false,
})
}