- gpui-kit 0.6 原生 UI:连接管理、消息流/日志、发布预设、全局变量、 设置、阿里云连接预设、原生 Logo - MQTT 5.0/3.1.1 引擎(rumqttc,TCP/TLS/WS/WSS),独立 tokio runtime + 事件泵,真实 broker 端到端测试 - 连接表单:保存前可一键测试连接(宽松校验,自动生成临时 Client ID), 高级属性(认证/MQTT 5 属性/遗嘱)按需折叠显示,WS 路径仅 WS/WSS 显示 - bug 修复:Hex 奇数长度显式报错、测试连接唯一 Client ID、Base64/Hex 发布发送真实字节、v5 发布记录携带 Content-Type/用户属性、预设应用 清除旧 Content-Type、模板时间基准统一;补 8 个单元测试 - Gitea 发布:Generic Package 上传脚本(bash/PowerShell)+ Actions release 工作流(tag 触发,双平台构建),README 使用说明
115 lines
3.5 KiB
Rust
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,
|
|
})
|
|
}
|