Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions apps/starry/mosquitto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Starry Mosquitto App

This case runs Mosquitto MQTT broker inside StarryOS through the app runner.

## Mosquitto功能介绍

Mosquitto是一个轻量级的MQTT消息代理(broker),实现了MQTT协议3.1/3.1.1/5.0版本。

### 核心功能:
1. **消息代理** - 作为MQTT broker,负责接收、路由和分发消息
2. **发布/订阅模式** - 支持发布者(publisher)和订阅者(subscriber)模式
3. **主题路由** - 支持多级主题(如 `sensor/room1/temperature`)和通配符订阅(`+` 单级、`#` 多级)
4. **QoS支持** - 支持三种QoS级别:
- QoS 0: 最多一次(fire and forget)
- QoS 1: 至少一次(acknowledged delivery)
- QoS 2: 恰好一次(assured delivery)
5. **保留消息** - 支持retained messages,新订阅者立即收到最后一条消息
6. **持久化会话** - 支持持久化客户端会话,断线重连后可恢复
7. **认证授权** - 支持用户名/密码认证和ACL访问控制
8. **WebSocket支持** - 可通过WebSocket协议提供MQTT服务
9. **集群支持** - 支持多broker桥接和集群

### 典型应用场景:
- 物联网(IoT)设备通信
- 传感器数据收集
- 智能家居系统
- 实时消息推送
- 移动应用后端消息服务

## 运行命令

默认运行全部测试(smoke + normal + stress):

```bash
cargo xtask starry app run -t mosquitto --arch x86_64
```

也可以单独运行某个级别:

```bash
# 仅 Smoke 测试
cargo xtask starry app run -t mosquitto --arch x86_64 --qemu-config qemu-x86_64-smoke.toml

# 仅普通测试
cargo xtask starry app run -t mosquitto --arch x86_64 --qemu-config qemu-x86_64-normal.toml

# 仅压力测试
cargo xtask starry app run -t mosquitto --arch x86_64 --qemu-config qemu-x86_64-stress.toml
```

## 测试内容

### Smoke测试
- 基本发布/订阅
- 多主题测试
- 通配符订阅
- QoS级别测试

### 普通测试
- 基本发布/订阅
- 多消息测试
- 通配符主题
- QoS 0/1/2级别
- 保留消息
- 持久化会话
- 大消息负载
- 多客户端并发
- 主题特殊字符

### 压力测试
- 高频消息发布/订阅
- 多客户端并发压力
- 大消息压力测试
- 通配符压力测试
- 混合QoS压力测试
- 持久化重启测试

## 文件结构

```
apps/starry/mosquitto/
├── prebuild.sh # 构建脚本,安装mosquitto到rootfs
├── test_mosquitto.sh # 统一入口,按序运行全部测试
├── mosquitto-smoke-tests.sh # Smoke测试脚本
├── mosquitto-tests.sh # 普通测试脚本
├── mosquitto-stress-tests.sh # 压力测试脚本
├── build-*.toml # 构建配置
├── qemu-x86_64.toml # 默认配置(运行全部测试)
├── qemu-x86_64-smoke.toml # 仅Smoke测试
├── qemu-x86_64-normal.toml # 仅普通测试
├── qemu-x86_64-stress.toml # 仅压力测试
└── README.md # 本文件
```

## 依赖

- mosquitto MQTT broker
- mosquitto-clients (mosquitto_pub, mosquitto_sub)
11 changes: 11 additions & 0 deletions apps/starry/mosquitto/build-x86_64-unknown-none.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
target = "x86_64-unknown-none"
env = { AX_IP = "10.0.2.15", AX_GW = "10.0.2.2" }
log = "Warn"
features = [
"ax-hal/x86-pc",
"qemu",
"ax-driver/plat-static",
"ax-driver/virtio-blk",
"ax-driver/virtio-net",
]
plat_dyn = false
182 changes: 182 additions & 0 deletions apps/starry/mosquitto/mosquitto-smoke-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#!/bin/sh
set -eu

mosquitto_pid=""
test_done=0

# Pre-cleanup: kill any leftover mosquitto server processes and stale temp files!
# Use pidof for exact name match; pkill would also match this script's name "mosquitto-*"
for pid in $(pidof mosquitto 2>/dev/null); do
kill -9 "$pid" 2>/dev/null || true
done
rm -rf /var/lib/mosquitto/mosquitto* 2>/dev/null || true
sleep 1

start_mosquitto() {
# Kill any existing mosquitto processes (handles auto-started instances)
for pid in $(pidof mosquitto 2>/dev/null); do
kill -9 "$pid" 2>/dev/null || true
done
sleep 2

mkdir -p /var/lib/mosquitto/mosquitto
chmod 777 /var/lib/mosquitto/mosquitto
cat > /var/lib/mosquitto/mosquitto-test.conf << 'EOF'
listener 1883
socket_domain ipv4
allow_anonymous true
persistence false
log_dest stderr
log_type error
log_type warning
connection_messages true
EOF

/usr/sbin/mosquitto -c /var/lib/mosquitto/mosquitto-test.conf > /var/lib/mosquitto/mosquitto-smoke.log 2>&1 &
mosquitto_pid=$!

i=0
while [ "$i" -lt 30 ]; do
if mosquitto_pub -h 127.0.0.1 -p 1883 -t test/ping -m "ping" 2>/dev/null; then
return 0
fi
i=$((i + 1))
sleep 1
done

echo "=== mosquitto-smoke.log ==="
cat /var/lib/mosquitto/mosquitto-smoke.log
echo "MOSQUITTO_SMOKE_TEST_FAILED"
exit 1
}

stop_mosquitto() {
if [ -n "$mosquitto_pid" ]; then
kill "$mosquitto_pid" >/dev/null 2>&1 || true
i=0
while kill -0 "$mosquitto_pid" >/dev/null 2>&1 && [ "$i" -lt 10 ]; do
i=$((i + 1))
sleep 1
done
kill -9 "$mosquitto_pid" >/dev/null 2>&1 || true
wait "$mosquitto_pid" >/dev/null 2>&1 || true
mosquitto_pid=""
fi
}

cleanup() {
stop_mosquitto
# Kill any remaining mosquitto processes (including stale ones)
for pid in $(pidof mosquitto 2>/dev/null); do
kill -9 "$pid" 2>/dev/null || true
done
}

on_exit() {
rc=$?
if [ "$test_done" -ne 1 ]; then
echo "MOSQUITTO_SMOKE_TEST_FAILED"
fi
cleanup
exit "$rc"
}
trap on_exit EXIT

echo "MOSQUITTO_SMOKE_STAGE start"
start_mosquitto

echo "MOSQUITTO_SMOKE_STAGE basic-pub-sub"
# Test basic publish/subscribe
mosquitto_sub -h 127.0.0.1 -p 1883 -t test/smoke -C 1 -W 5 > /var/lib/mosquitto/smoke-sub.out 2>&1 &
sub_pid=$!
sleep 1
mosquitto_pub -h 127.0.0.1 -p 1883 -t test/smoke -m "hello-smoke"
wait "$sub_pid" || true
grep -q 'hello-smoke' /var/lib/mosquitto/smoke-sub.out

echo "MOSQUITTO_SMOKE_STAGE multiple-topics"
# Test multiple topics
mosquitto_sub -h 127.0.0.1 -p 1883 -t test/topic1 -C 1 -W 5 > /var/lib/mosquitto/smoke-topic1.out 2>&1 &
sub1_pid=$!
mosquitto_sub -h 127.0.0.1 -p 1883 -t test/topic2 -C 1 -W 5 > /var/lib/mosquitto/smoke-topic2.out 2>&1 &
sub2_pid=$!
sleep 1
mosquitto_pub -h 127.0.0.1 -p 1883 -t test/topic1 -m "msg1"
mosquitto_pub -h 127.0.0.1 -p 1883 -t test/topic2 -m "msg2"
wait "$sub1_pid" || true
wait "$sub2_pid" || true
grep -q 'msg1' /var/lib/mosquitto/smoke-topic1.out
grep -q 'msg2' /var/lib/mosquitto/smoke-topic2.out

echo "MOSQUITTO_SMOKE_STAGE wildcard-sub"
# Test wildcard subscription
mosquitto_sub -h 127.0.0.1 -p 1883 -t test/wildcard/# -C 2 -W 5 > /var/lib/mosquitto/smoke-wildcard.out 2>&1 &
sub_wc_pid=$!
sleep 1
mosquitto_pub -h 127.0.0.1 -p 1883 -t test/wildcard/a -m "wild-a"
mosquitto_pub -h 127.0.0.1 -p 1883 -t test/wildcard/b -m "wild-b"
wait "$sub_wc_pid" || true
grep -q 'wild-a' /var/lib/mosquitto/smoke-wildcard.out
grep -q 'wild-b' /var/lib/mosquitto/smoke-wildcard.out

echo "MOSQUITTO_SMOKE_STAGE qos-levels"
# Test QoS 0
mosquitto_sub -h 127.0.0.1 -p 1883 -t test/qos0 -q 0 -C 1 -W 5 > /var/lib/mosquitto/smoke-qos0.out 2>&1 &
sub_qos0_pid=$!
sleep 1
mosquitto_pub -h 127.0.0.1 -p 1883 -t test/qos0 -q 0 -m "qos0-msg"
wait "$sub_qos0_pid" || true
grep -q 'qos0-msg' /var/lib/mosquitto/smoke-qos0.out

# Test QoS 1
mosquitto_sub -h 127.0.0.1 -p 1883 -t test/qos1 -q 1 -C 1 -W 5 > /var/lib/mosquitto/smoke-qos1.out 2>&1 &
sub_qos1_pid=$!
sleep 1
mosquitto_pub -h 127.0.0.1 -p 1883 -t test/qos1 -q 1 -m "qos1-msg"
wait "$sub_qos1_pid" || true
grep -q 'qos1-msg' /var/lib/mosquitto/smoke-qos1.out

echo "MOSQUITTO_SMOKE_STAGE last-will-testament"
# Test Last Will and Testament - embedded devices use LWT to notify offline status
# Subscribe to LWT topic first
mosquitto_sub -h 127.0.0.1 -p 1883 -t devices/status -C 1 -W 10 > /var/lib/mosquitto/smoke-lwt.out 2>&1 &
sub_lwt_pid=$!
sleep 1
# Start a client with LWT message set; must use SIGKILL (-9) to trigger LWT (clean disconnect won't)
mosquitto_sub -h 127.0.0.1 -p 1883 -t dummy -i "lwt-device" --will-topic devices/status --will-payload "device-offline" --will-qos 1 --will-retain -W 30 > /dev/null 2>&1 &
lwt_client_pid=$!
sleep 2
# SIGKILL forces unexpected disconnect, which triggers the will message
kill -9 "$lwt_client_pid" 2>/dev/null || true
wait "$lwt_client_pid" 2>/dev/null || true
wait "$sub_lwt_pid" || true
grep -q 'device-offline' /var/lib/mosquitto/smoke-lwt.out

echo "MOSQUITTO_SMOKE_STAGE keepalive"
# Test keep-alive - embedded devices need periodic ping to maintain connection
mosquitto_sub -h 127.0.0.1 -p 1883 -t test/keepalive -C 1 -W 10 -k 5 > /var/lib/mosquitto/smoke-keepalive.out 2>&1 &
sub_ka_pid=$!
sleep 1
# Client with 5s keep-alive sends pings automatically (minimum allowed)
mosquitto_pub -h 127.0.0.1 -p 1883 -t test/keepalive -m "alive-msg" -i "keepalive-pub" -k 5
wait "$sub_ka_pid" || true
grep -q 'alive-msg' /var/lib/mosquitto/smoke-keepalive.out

echo "MOSQUITTO_SMOKE_STAGE sensor-data"
# Test typical embedded sensor data pattern (small JSON payloads)
mosquitto_sub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -C 3 -W 5 > /var/lib/mosquitto/smoke-sensor.out 2>&1 &
sub_sensor_pid=$!
sleep 1
mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -m '{"temp":22.5,"hum":65.2,"ts":1717000000}'
mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -m '{"temp":22.6,"hum":65.0,"ts":1717000001}'
mosquitto_pub -h 127.0.0.1 -p 1883 -t devices/sensor01/telemetry -m '{"temp":22.4,"hum":65.5,"ts":1717000002}'
wait "$sub_sensor_pid" || true
grep -q '"temp":22.5' /var/lib/mosquitto/smoke-sensor.out
grep -q '"temp":22.6' /var/lib/mosquitto/smoke-sensor.out
grep -q '"temp":22.4' /var/lib/mosquitto/smoke-sensor.out

test_done=1
trap - EXIT
cleanup

echo "MOSQUITTO_SMOKE_TEST_PASSED"
Loading